流出したシークレットへの自動対応
- プラン: Ultimate
- 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated
GitLabシークレット検出は、特定の種類の流出したシークレットを検出すると自動的に対応します。自動応答では次のことができます:
- シークレットを自動的に失効させます。
- シークレットを発行したパートナーに通知します。パートナーは、シークレットを失効させたり、オーナーに通知したり、その他の方法で不正利用から保護したりできます。
サポートされているシークレットの種類とアクション
GitLabは、以下の種類のシークレットに対する自動応答をサポートしています:
| シークレットの種類 | 実行されたアクション | GitLab.comでサポートされています | GitLab Self-Managedでサポートされています |
|---|---|---|---|
| GitLab パーソナルアクセストークン | トークンを即座に失効させ、オーナーにメールを送信します。1 | ✅ | ✅ |
| Amazon Web Services(AWS)IAMアクセスキー | AWSに通知します。 | ✅ | ⚙ |
| Google Cloud サービスアカウントキー、APIキー、およびOAuthクライアントシークレット | Google Cloudに通知します。 | ✅ | ⚙ |
| Postman APIキー | Postmanに通知します。Postmanはキーオーナーに通知します。 | ✅ | ⚙ |
コンポーネントの凡例:
- ✅ - デフォルトで利用可能
- ⚙ - トークン失効APIを使用した手動インテグレーションが必要です
機能の可用性
認証情報は、シークレット検出によって発見された場合にのみ後処理されます:
- 公開プロジェクトでは、公開された認証情報が増大する脅威をもたらすためです。プライベートプロジェクトへの拡張は、イシュー391379で検討されています。
- GitLab Ultimateを使用するプロジェクトでは、技術的な理由のためです。すべてのプランへの拡張は、イシュー391763で追跡されています。
トークンの自動失効を有効にする
GitLab.comでは、トークンの自動失効はデフォルトで有効になっており、アクションは不要です。
GitLab Self-ManagedおよびGitLab Dedicatedでは、管理者がsecret_detection_token_revocation_enabledをtrueに設定することで有効にする必要があります。この設定にはUIがなく、アプリケーション設定APIまたはRailsコンソールを介して設定する必要があります。
管理者のアクセストークンを使用して、アプリケーション設定APIを使用します。
現在の値を確認するには、レスポンス内のsecret_detection_token_revocation_enabledフィールドを見つけます:
curl --header "PRIVATE-TOKEN: <your_admin_access_token>" \
--url "https://gitlab.example.com/api/v4/application/settings"この設定を有効にするには:
curl --request PUT \
--header "PRIVATE-TOKEN: <your_admin_access_token>" \
--data "secret_detection_token_revocation_enabled=true" \
--url "https://gitlab.example.com/api/v4/application/settings"Railsコンソールセッションを開きます。
現在の値を確認するには:
::Gitlab::CurrentSettings.secret_detection_token_revocation_enabled?この設定を有効にするには:
::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_enabled: true)高レベルアーキテクチャ
この図は、後処理フックがGitLabアプリケーションでシークレットを失効させる方法を示しています:
%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
accTitle: Architecture diagram
accDescr: How a post-processing hook revokes a secret in the GitLab application.
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: GET revocable keys types
GitLab token revocation API-->>-GitLab Sidekiq: OK
GitLab Sidekiq->>+GitLab token revocation API: POST revoke revocable keys
GitLab token revocation API-->>-GitLab Sidekiq: ACCEPTED
GitLab token revocation API-->>+Partner API: revoke revocable keys
Partner API-->>+GitLab token revocation API: ACCEPTED
- シークレット検出ジョブを含むパイプラインが完了し、スキャンレポート(1)が生成されます。
- レポートはサービスクラスによって処理され(2)、トークンの失効が可能であれば非同期ワーカーをスケジュールします。
- 非同期ワーカー(3)は、外部にデプロイされたHTTPサービス(4および5)と通信し、どの種類のシークレットを自動的に失効できるかを決定します。
- ワーカーは、GitLabトークン失効APIが失効できる検出されたシークレットのリストを送信します(6および7)。
- GitLabトークン失効APIは、失効可能な各トークンをそれぞれのベンダーのパートナーAPIに送信します(8および9)。
流出した認証情報の通知のためのパートナープログラム
GitLabは、パートナーが発行した認証情報がGitLab.comのパブリックリポジトリで流出した場合に、パートナーに通知します。クラウドまたはSaaS製品を運用しており、これらの通知を受け取ることに興味がある場合は、エピック4944で詳細をご覧ください。パートナーは、GitLabトークン失効APIによって呼び出されるパートナーAPIを実装する必要があります。
パートナーAPIを実装する
パートナーAPIは、GitLabトークン失効APIとインテグレーションし、流出したトークンの失効リクエストを受信して応答します。このサービスは、べき等でレート制限された、公開アクセス可能なHTTP APIである必要があります。
サービスへのリクエストには、1つ以上の流出したトークンと、リクエスト本文の署名を含むヘッダーを含めることができます。GitLabからの正当なリクエストであることを証明するために、この署名を使用して受信リクエストを検証することを強くお勧めします。以下の図は、流出したトークンを受信、検証、および失効させるために必要なステップを示しています:
%%{init: { "fontFamily": "GitLab Sans" }}%%
sequenceDiagram
accTitle: Partner API data flow
accDescr: How a partner API should receive and respond to leaked token revocation requests.
autonumber
GitLab token revocation API-->>+Partner API: Send new leaked credentials
Partner API-->>+GitLab public keys endpoint: Get active public keys
GitLab public keys endpoint-->>+Partner API: One or more public keys
Partner API-->>+Partner API: Verify request is signed by GitLab
Partner API-->>+Partner API: Respond to leaks
Partner API-->>+GitLab token revocation API: HTTP status
- GitLabトークン失効APIは、パートナーAPIに失効リクエストを送信します(1)。リクエストには、公開キー識別子とリクエスト本文の署名を含むヘッダーが含まれています。
- パートナーAPIは、GitLabから公開キーのリストをリクエストします(2)。レスポンス(3)には、キーローテーションの場合に複数の公開キーが含まれる可能性があり、リクエストヘッダー内の識別子でフィルタリングする必要があります。
- パートナーAPIは、公開キー(4)を使用して、実際のリクエスト本文に対して署名を検証します。
- パートナーAPIは、流出したトークンを処理し、自動失効(5)を伴う場合があります。
- パートナーAPIは、適切なHTTPステータスコードでGitLabトークン失効API(6)に応答します:
- 成功応答コード(HTTP 200~299)は、パートナーがリクエストを受信して処理したことを確認します。
- エラーコード(HTTP 400以上)は、GitLabトークン失効APIにリクエストの再試行を促します。
失効リクエスト
このJSONスキーマドキュメントは、失効リクエストの本文を記述します:
{
"type": "array",
"items": {
"description": "A leaked token",
"type": "object",
"properties": {
"type": {
"description": "The type of token. This is vendor-specific and can be customized to suit your revocation service",
"type": "string",
"examples": [
"my_api_token"
]
},
"token": {
"description": "The substring that was matched by the secret detection analyzer. In most cases, this is the entire token itself",
"type": "string",
"examples": [
"XXXXXXXXXXXXXXXX"
]
},
"url": {
"description": "The URL to the raw source file hosted on GitLab where the leaked token was detected",
"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のインスタンスが流出したと判断されています。トークンの値は、流出したトークンを含むファイルのrawコンテンツへの公開アクセス可能なURLに加えて、提供されます。
リクエストには2つの特別なヘッダーが含まれています:
| ヘッダー | タイプ | 説明 |
|---|---|---|
Gitlab-Public-Key-Identifier | 文字列 | このリクエストに署名するために使用されるキーペアの固有識別子。主にキーローテーションを支援するために使用されます。 |
Gitlab-Public-Key-Signature | 文字列 | リクエスト本文のbase64エンコードされた署名。 |
これらのヘッダーをGitLab公開キーエンドポイントと合わせて使用すると、失効リクエストが正当なものであったことを検証できます。
公開キーエンドポイント
GitLabは、失効リクエストを検証するために使用される公開キーを取得するための、公開アクセス可能なエンドポイントを維持しています。エンドポイントはリクエストに応じて提供できます。
このJSONスキーマドキュメントは、公開キーエンドポイントのレスポンス本文を記述します:
{
"type": "object",
"properties": {
"public_keys": {
"description": "An array of public keys managed by GitLab used to sign token revocation requests.",
"type": "array",
"items": {
"type": "object",
"properties": {
"key_identifier": {
"description": "A unique identifier for the keypair. Match this against the value of the Gitlab-Public-Key-Identifier header",
"type": "string"
},
"key": {
"description": "The value of the public key",
"type": "string"
},
"is_current": {
"description": "Whether the key is currently active and signing new requests",
"type": "boolean"
}
}
}
}
}
}例:
{
"public_keys": [
{
"key_identifier": "6917d7584f0fa65c8c33df5ab20f54dfb9a6e6ae",
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEN05/VjsBwWTUGYMpijqC5pDtoLEf\nuWz2CVZAZd5zfa/NAlSFgWRDdNRpazTARndB2+dHDtcHIVfzyVPNr2aznw==\n-----END PUBLIC KEY-----\n",
"is_current": true
}
]
}リクエストの検証
上記APIレスポンスから取得した対応する公開キーを使用して、Gitlab-Public-Key-Signatureヘッダーとリクエスト本文を照合することで、失効リクエストが正当なものであるかを確認できます。署名の生成にはSHA256ハッシュを使用したECDSAを使用しており、その署名は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("") # obtained from the public keys endpoint
signature_header = "" # obtained from the `Gitlab-Public-Key-Signature` header
request_body = str.encode(r'') # obtained from the revocation request body
pk = load_pem_public_key(public_key)
decoded_signature = base64.b64decode(signature_header)
pk.verify(decoded_signature, request_body, ec.ECDSA(hashes.SHA256())) # throws if unsuccessful
print("Signature verified!")主なステップは次のとおりです:
- 使用している暗号ライブラリに適した形式に公開キーを読み込みます。
Gitlab-Public-Key-Signatureヘッダー値をBase64デコードします。- デコードされた署名に対して本文を検証し、SHA256ハッシュを使用したECDSAを指定します。