누설된 시크릿에 대한 자동 응답

Tier: Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

GitLab Secret Detection은 특정 유형의 누설된 시크릿을 발견하면 자동으로 응답합니다. 자동 응답은 다음과 같을 수 있습니다:

  • 시크릿을 자동으로 취소합니다.
  • 시크릿을 발행한 파트너에게 알립니다. 파트너는 시크릿을 취소하거나 소유자에게 알리거나, 그 외 남용에 대비할 수 있습니다.

지원되는 시크릿 유형 및 조치

GitLab은 다음 유형의 시크릿에 대한 자동 응답을 지원합니다:

시크릿 유형 취해지는 조치 GitLab.com에서 지원됨 Self-managed에서 지원됨
GitLab 개인 액세스 토큰 토큰 즉시 취소, 소유자에게 이메일 전송 15.9 이상
Amazon Web Services (AWS) IAM 액세스 키 AWS에 알림
Google Cloud 서비스 계정 키, API 키OAuth 클라이언트 시크릿 Google Cloud에 알림
Postman API 키 Postman에 알림; Postman은 키 소유자에게 알림

컴포넌트 상징

기능 가용성

시크릿 검색이 발견했을 때 자격 증명은 다음과 같습니다:

  • 공개 프로젝트에서, 공개적으로 노출된 자격 증명은 증가된 위협을 야기하므로 후처리됩니다. 사설 프로젝트 확장은 이슈 391379에서 고려됩니다.
  • 기술적인 이유로 GitLab Ultimate 프로젝트에서만 후처리됩니다. 모든 티어에 대한 확장은 이슈 391763에서 추적됩니다.

고수준 아키텍처

다음 다이어그램은 GitLab 애플리케이션 내에서 후처리 후크가 시크릿을 취소하는 방법을 설명합니다:

sequenceDiagram autonumber GitLab Rails-->+GitLab Rails: gl-secret-detection-report.json GitLab Rails->>+GitLab Sidekiq: StoreScansService GitLab Sidekiq-->+GitLab Sidekiq: ScanSecurityReportSecretsWorker GitLab Sidekiq-->+GitLab Token Revocation API: revocable keys types 가져오기 GitLab Token Revocation API-->>-GitLab Sidekiq: OK GitLab Sidekiq->>+GitLab Token Revocation API: 시크릿 취소 요청 GitLab Token Revocation API-->>-GitLab Sidekiq: ACCEPTED GitLab Token Revocation API-->>+Partner API: 시크릿 취소 Partner API-->>+GitLab Token Revocation API: ACCEPTED
  1. Secret Detection 작업이 완료된 파이프라인은 스캔 보고서를 생성합니다 (1).
  2. 보고서는 서비스 클래스에 의해 처리되어, 토큰 취소가 가능한 경우 비동기 워커가 예약됩니다 (2).
  3. 비동기 워커 (3)는 외부 배포 HTTP 서비스와 통신하여, 자동으로 취소할 수 있는 시크릿 유형을 결정합니다 (45).
  4. 워커는 GitLab Token Revocation API가 시크릿을 자동으로 취소할 수 있는 목록을 보냅니다 (67).
  5. GitLab Token Revocation API는 각 취소 가능한 토큰을 해당 업체의 Partner API에 보냅니다 (89). 자세한 정보는 GitLab Token Revocation API 문서를 참조하세요.

누설된 자격 증명 알림을 위한 파트너 프로그램

GitLab은 GitLab.com의 공개 저장소에서 누설된 자격 증명에 대한 파트너 알림합니다. 클라우드 또는 SaaS 제품을 운영하고 해당 알림을 받고 싶은 경우, 장비 4944에서 자세히 알아보세요. 파트너는 GitLab Token Revocation API에서 호출되는 파트너 API를 구현해야 합니다.

파트너 API 구현

파트너 API는 GitLab 토큰 폐기 API와 통신하여 유출된 토큰 폐기 요청을 수신하고 응답하는 기능을 통합합니다. 해당 서비스는 멱등성과 요청 속도 제한을 갖춘 공개적으로 접근 가능한 HTTP API여아 합니다.

서비스에 대한 요청은 하나 이상의 유출된 토큰과 요청 바디의 서명이 포함된 헤더를 포함할 수 있습니다. 우리는 이 서명을 사용하여 들어오는 요청을 확인하여, 이것이 GitLab로부터의 진정한 요청임을 증명하는 것이 강력히 권장됩니다. 아래 다이어그램은 유출된 토큰을 수신하고 확인하며 폐기하기 위한 필수 단계를 자세히 설명합니다:

sequenceDiagram autonumber GitLab Token Revocation API-->>+파트너 API: 새로운 유출 자격 증명 전송 파트너 API-->>+GitLab 공개 키 엔드포인트: 활성 공개 키 가져오기 GitLab 공개 키 엔드포인트-->>+파트너 API: 하나 이상의 공개 키 파트너 API-->>+파트너 API: 요청이 GitLab에 의해 서명되었는지 확인 파트너 API-->>+파트너 API: 유출에 응답 파트너 API-->>+GitLab 토큰 폐기 API: HTTP 상태
  1. GitLab Token Revocation API는 (1) 폐기 요청을 파트너 API로 전송합니다. 해당 요청에는 요청 바디의 공개 키 식별자와 서명이 포함된 헤더가 있습니다.
  2. 파트너 API는 (2) GitLab로부터 공개 키 목록을 요청합니다. 응답 (3) 에는 키 회전을 위해 여러 공개 키가 포함될 수 있으며, 요청 헤더의 식별자로 필터링되어야 합니다.
  3. 파트너 API는 서명을 확인합니다. 이 과정에서 공개 키 (4) 가 사용된 실제 요청 바디와의 일치 여부를 확인합니다.
  4. 파트너 API는 유출된 토큰을 처리하며, 이는 자동 폐기를 포함할 수 있습니다 (5).
  5. 파트너 API는 GitLab 토큰 폐기 API에 적절한 HTTP 상태 코드로 응답 (6) 합니다:
    • 성공적인 응답 코드 (HTTP 200~299)는 파트너가 요청을 수신하고 처리했음을 인정합니다.
    • 오류 코드 (HTTP 400 이상)는 GitLab 토큰 폐기 API가 요청을 다시 시도하게 합니다.

폐기 요청

이 JSON 스키마 문서는 폐기 요청의 본문을 설명합니다:

{
    "type": "array",
    "items": {
        "description": "유출된 토큰",
        "type": "object",
        "properties": {
            "type": {
                "description": "토큰의 유형입니다. 이는 공급 업체별이며 귀하의 폐기 서비스에 맞게 사용자 정의할 수 있습니다",
                "type": "string",
                "examples": [
                    "my_api_token"
                ]
            },
            "token": {
                "description": "시크릿 탐지 분석기에서 일치하는 부분입니다. 대부분의 경우, 이것이 전체 토큰 자체입니다",
                "type": "string",
                "examples": [
                    "XXXXXXXXXXXXXXXX"
                ]
            },
            "url": {
                "description": "GitLab에 호스팅된 소스 파일의 원시 URL입니다. 여기서 유출된 토큰이 감지되었습니다",
                "type": "string",
                "examples": [
                    "https://gitlab.example.com/some-repo/-/raw/abcdefghijklmnop/compromisedfile1.java"
                ]
            }
        }
    }
}

예시:

[{"type": "my_api_token", "token": "XXXXXXXXXXXXXXXX", "url": "https://example.com/some-repo/-/raw/abcdefghijklmnop/compromisedfile1.java"}]

이 예시에서, 시크릿 탐지는 my_api_token의 인스턴스가 유출되었음을 확인했습니다. 토큰의 값뿐만 아니라 유출된 파일의 원시 내용에 대한 공개적으로 접근 가능한 URL도 제공됩니다.

요청에는 두 가지의 특수 헤더가 포함됩니다:

헤더 타입 설명
Gitlab-Public-Key-Identifier 문자열 이 요청을 서명하는 데 사용된 키 쌍의 고유 식별자입니다. 주로 키 회전을 지원하는 데 사용됩니다.
Gitlab-Public-Key-Signature 문자열 요청 본문의 base64로 인코딩된 서명입니다.

이 헤더를 사용하여 GitLab 공개 키 엔드포인트와 함께 토큰 폐기 요청이 진정한지 확인할 수 있습니다.

공개 키 엔드포인트

GitLab은 토큰 폐기 요청을 확인하기 위해 사용되는 공개 키를 검색하기 위한 공개적으로 접근 가능한 엔드포인트를 유지합니다. 해당 엔드포인트는 요청 시 제공될 수 있습니다.

이 JSON 스키마 문서는 공개 키 엔드포인트의 응답 본문을 설명합니다:

{
    "type": "object",
    "properties": {
        "public_keys": {
            "description": "토큰 폐기 요청을 서명하는 데 사용되는 GitLab이 관리하는 공개 키의 배열입니다.",
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "key_identifier": {
                        "description": "키 쌍의 고유 식별자입니다. 이를 Gitlab-Public-Key-Identifier 헤더의 값과 일치시키세요",
                        "type": "string"
                    },
                    "key": {
                        "description": "공개 키의 값입니다",
                        "type": "string"
                    },
                    "is_current": {
                        "description": "키가 현재 활성 상태이며 새 요청에 서명하는지 여부입니다",
                        "type": "boolean"
                    }
                }
            }
        }
    }
}

예시:

{
    "public_keys": [
        {
            "key_identifier": "6917d7584f0fa65c8c33df5ab20f54dfb9a6e6ae",
            "key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEN05/VjsBwWTUGYMpijqC5pDtoLEf\nuWz2CVZAZd5zfa/NAlSFgWRDdNRpazTARndB2+dHDtcHIVfzyVPNr2aznw==\n-----END PUBLIC KEY-----\n",
            "is_current": true
        }
    ]
}

요청 확인하기

Gitlab-Public-Key-Signature 헤더를 사용하여 API 응답에서 가져온 해당 공개 키를 사용하여 취소 요청이 진정한지 확인할 수 있습니다. 우리는 이 서명을 생성하기 위해 ECDSA와 SHA256 해싱을 사용하며, 그 후에는 헤더 값으로 base64로 인코딩합니다.

아래의 Python 스크립트는 서명을 확인하는 방법을 보여줍니다. 암호 작업을 위해 인기 있는 pyca/cryptography 모듈을 사용합니다.

import hashlib
import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.hazmat.primitives.asymmetric import ec

public_key = str.encode("")      # 공개 키 엔드포인트에서 얻음
signature_header = ""            # `Gitlab-Public-Key-Signature` 헤더에서 얻음
request_body = str.encode(r'')   # 취소 요청 본문에서 얻음

pk = load_pem_public_key(public_key)
decoded_signature = base64.b64decode(signature_header)

pk.verify(decoded_signature, request_body, ec.ECDSA(hashes.SHA256()))  # 실패 시 예외 발생

print("서명이 확인되었습니다!")

주요 단계는 다음과 같습니다:

  1. 공개 키를 암호 라이브러리에서 사용할 수 있는 형식으로 로드합니다.
  2. Gitlab-Public-Key-Signature 헤더 값의 base64 디코딩.
  3. ECDSA 및 SHA256 해싱을 지정하여 서명을 본문과 대조합니다.