>  기사  >  백엔드 개발  >  pytest-mask-secrets를 사용하여 테스트 비밀 보호

pytest-mask-secrets를 사용하여 테스트 비밀 보호

WBOY
WBOY원래의
2024-08-12 18:43:59471검색

Securing Testing Secrets with pytest-mask-secrets

중요한 데이터를 안전하게 비공개로 유지하는 것은 소프트웨어 개발의 최우선 과제입니다. 일반적인 유출 벡터 중 하나인 애플리케이션 로그는 기밀이 존재하지 않도록 주의 깊게 보호됩니다. 비밀번호나 액세스 토큰이 노출될 수 있는 테스트 로그에도 동일한 우려와 위험이 적용됩니다. CI 워크플로를 실행하는 도구는 일반적으로 거의 노력하지 않고도 로그에서 민감한 데이터를 마스킹하는 메커니즘을 제공합니다. 이는 매우 편리하고 효율적이며 사용하기 쉽지만 특정 상황에서는 충분하지 않을 수 있습니다.

CI 워크플로 마스킹만으로는 충분하지 않은 이유

예를 들어 GitHub Actions는 비밀을 잘 처리합니다. 워크플로 내에 정의된 모든 비밀은 캡처된 출력에서 ​​자동으로 마스킹되며 이는 마치 매력처럼 작동합니다. 그러나 다른 CI 시스템과 마찬가지로 제한 사항이 있습니다. 출력 보고서가 파일에 저장되거나 junit이 생성되거나 원격 로그 저장소로 전송되는 등 다른 경로를 사용하는 경우 GitHub Actions에는 콘텐츠를 검사하고 비밀을 마스킹하는 기능이 없습니다.

또한 테스트가 항상 CI 워크플로 내에서 실행되는 것은 아니며, 그렇더라도 비밀은 여전히 ​​숨겨야 할 수 있습니다. 로컬에서 테스트를 실행하고 로그를 공유하여 문제를 논의한다고 상상해 보세요. 자신도 모르게 액세스 토큰에 URL을 포함하게 됩니다.

따라서 테스트 로그의 민감한 데이터를 처리하는 메커니즘을 갖추는 것은 모든 수준에서 필수적입니다. 가장 좋은 접근 방식은 이를 테스트 수준에서 직접 구현하거나 테스트 프레임워크 자체 내에서 구현하는 것입니다. 이렇게 하면 비밀이 기본 소스에서 유출되지 않고 시스템을 통해 전달되는 것을 방지할 수 있습니다.

적절한 수준에서 보호 추가

테스트에서 직접 비밀 마스킹을 유지하는 것은 상대적으로 비용이 많이 들고 오류가 발생하기 쉬우며 종종 패배하는 것처럼 느껴집니다. 예를 들어 토큰을 매개변수로 사용하여 URL을 디자인해야 한다고 가정해 보겠습니다. 요청에 사용할 URL은 로그에 있는 URL과 다르게 렌더링되어야 합니다.

반대로, 테스트 프레임워크 내에서 보고서 생성을 가로채는 것은 프로세스에 연결하고 기록을 수정하여 민감한 데이터를 제거할 수 있는 이상적인 기회를 제공합니다. 이 접근 방식은 테스트에 투명하고, 테스트 코드를 수정할 필요가 없으며, CI 워크플로의 비밀 마스킹 기능과 같은 기능을 합니다. 간단히 실행하고 비밀 관리를 잊어버리면 됩니다. 프로세스를 자동화하여 테스트 설정에 복잡성을 추가하지 않고도 중요한 데이터를 보호합니다.

이것은 정확히 pytest-mask-secrets가 수행하는 작업이며, 분명히 pytest가 테스트 실행에 사용될 때입니다. 많은 기능 중에서 pytest는 풍부하고 유연한 플러그인 시스템을 제공합니다. 이를 위해 모든 데이터가 이미 수집된 시점인 로그가 생성되기 직전에 프로세스에 연결할 수 있습니다. 이를 통해 레코드가 출력되기 전에 레코드에서 민감한 값을 쉽게 검색하고 제거할 수 있습니다.

테스트해보기: 실용적인 데모

이것이 어떻게 작동하는지 설명하기 위해 간단한 예가 가장 효과적입니다. 다음은 실제 테스트 시나리오를 나타내지는 않지만 pytest-mask-secrets를 아주 잘 보여주는 목적에 부합하는 간단한 테스트입니다.

import logging
import os


def test_password_length():
    password = os.environ["PASSWORD"]
    logging.info("Tested password: %s", password)
    assert len(password) > 18

이 예에는 비밀이 포함된 로그 메시지와 함께 실패할 가능성이 있는 어설션이 있습니다. 예, 로그에 비밀을 포함하는 것이 어리석은 것처럼 보일 수 있지만 토큰이 매개변수로 포함된 URL이 있고 자세한 디버그 로깅이 활성화된 시나리오를 고려해 보세요. 이러한 경우 요청과 같은 라이브러리는 실수로 이런 방식으로 비밀을 기록할 수 있습니다.

이제 테스트를 해볼 차례입니다. 먼저 테스트 목적에 필요한 비밀번호를 설정하세요.

(venv) $ export PASSWORD="TOP-SECRET"

다음으로 테스트를 실행합니다.

(venv) $ pytest --log-level=info test.py 
============================= test session starts ==============================
platform linux -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0
rootdir: /tmp/tmp.AvZtz7nHZS
collected 1 item                                                               

test.py F                                                                [100%]

=================================== FAILURES ===================================
_____________________________ test_password_length _____________________________

    def test_password_length():
        password = os.environ["PASSWORD"]
        logging.info("Tested password: %s", password)
>       assert len(password) > 18
E       AssertionError: assert 10 > 18
E        +  where 10 = len('TOP-SECRET')

test.py:8: AssertionError
------------------------------ Captured log call -------------------------------
INFO     root:test.py:7 Tested password: TOP-SECRET
=========================== short test summary info ============================
FAILED test.py::test_password_length - AssertionError: assert 10 > 18
============================== 1 failed in 0.03s ===============================

기본적으로 비밀 값은 출력에 두 번 나타납니다. 한 번은 캡처된 로그 메시지에, 한 번은 실패한 어설션에 나타납니다.

하지만 pytest-mask-secrets가 설치되어 있다면 어떨까요?

(venv) $ pip install pytest-mask-secrets

따라서 구성되었습니다. 비밀을 보유하는 환경 변수 목록을 알아야 합니다. 이는 MASK_SECRETS 변수를 설정하여 수행됩니다:

(venv) $ export MASK_SECRETS=PASSWORD

이제 테스트를 다시 실행해 보세요.

(venv) $ pytest --log-level=info test.py 
============================= test session starts ==============================
platform linux -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0
rootdir: /tmp/tmp.AvZtz7nHZS
plugins: mask-secrets-1.2.0
collected 1 item                                                               

test.py F                                                                [100%]

=================================== FAILURES ===================================
_____________________________ test_password_length _____________________________

    def test_password_length():
        password = os.environ["PASSWORD"]
        logging.info("Tested password: %s", password)
>       assert len(password) > 18
E       AssertionError: assert 10 > 18
E        +  where 10 = len('*****')

test.py:8: AssertionError
------------------------------ Captured log call -------------------------------
INFO     root:test.py:7 Tested password: *****
=========================== short test summary info ============================
FAILED test.py::test_password_length - AssertionError: assert 10 > 18
============================== 1 failed in 0.02s ===============================

이제 비밀 값 대신 비밀이 인쇄되었을 위치마다 별표가 나타납니다. 작업이 완료되었으며 이제 테스트 보고서에는 민감한 데이터가 없습니다.

마무리 생각

예를 보면 pytest-mask-secrets는 GitHub Actions가 기본적으로 수행하는 작업보다 더 많은 작업을 수행하지 않아 노력이 중복되는 것처럼 보일 수 있습니다. 그러나 앞서 언급한 것처럼 CI 워크플로 실행 도구는 캡처된 출력에서만 비밀을 마스크하므로 JUnit 파일과 기타 보고서는 변경되지 않습니다. pytest-mask-secrets가 없으면 중요한 데이터가 이러한 파일에 계속 노출될 수 있습니다. 이는 pytest에서 생성된 모든 보고서에 적용됩니다. 반면에 pytest-mask-secrets는 log_cli 옵션을 사용할 때 직접 출력을 마스킹하지 않으므로 CI 워크플로의 마스킹 기능은 여전히 ​​유용합니다. 민감한 데이터를 보호하려면 두 도구를 함께 사용하는 것이 가장 좋습니다.

이렇습니다. 시간을 내어 이 게시물을 읽어주셔서 감사합니다. 테스트 프로세스의 보안을 강화하기 위해 pytest-mask-secrets를 사용하는 데 귀중한 통찰력을 제공하셨기를 바랍니다.

즐거운 테스트를 즐겨보세요!

위 내용은 pytest-mask-secrets를 사용하여 테스트 비밀 보호의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.