TECHSTEP

ITインフラ関連の記事を公開してます。

GitLab Secret detectionを利用する

今回はGitLabのSecret detection機能を検証します。

docs.gitlab.com

背景

GitLabのSecret detection機能は、あらかじめ設定したルールを元に秘匿情報を検出し、表示する機能です。これは開発言語やフレームワークによらず、すべてのテキストファイルに対して実行されます。

Secret detectionはGitLabの提供するテンプレートを .gitlab-ci.yml から呼び出す形で利用しますが、デフォルトのルールはこちらのファイルで定義されています。本記事投稿時点では、GitLabの各種トークンのほか、AWS/GCP/Alibabaなどのクラウドプロバイダー、GitHub/Bitbucket/CircleCIなどのリポジトリ・CI/CDサービス、Twitter / Facebook / Slack / Stripe / New Relic / Terraform / Pulumi などなど、幅広いサービスに対応しています。

Secret detectionを利用する上での前提条件は以下の通りです。

  • Self-managed版の場合、GitLab RunnerはLinuxベースのマシンで docker または kubernetes executorを使用します。
  • 利用者自らRunnerを管理している場合、Dockerバージョンは 19.03.0 以外を使用する必要があります。
  • Secret detectionは GitLab CI/CDの test stageで実行するため、.gitlab-ci.yml には test stageを含む必要があります。

検証

検証時は以下の環境で実施しました。

  • バージョン: GitLab SaaS版 (Freeプラン)
  • Project: secret-detection-test

Secret detectionの有効化

Secret detectionを有効にする方法はいくつかありますが、ここではGitLab UIから有効にする方法をとりました。

GitLab左メニューの 安全セキュリティ設定 を選択し、遷移後の画面から 秘密の検出 という項目を探して マージリクエスト経由で設定 を選択します。

Merge Requestの作成画面に遷移するので、問題なければMerge Requestを作成します。

ここで作成されるのは以下のファイルです。

# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
include:
- template: Security/Secret-Detection.gitlab-ci.yml

Merge Requestをマージしてファイルを配置します。

次にテスト用のテキストファイルを用意します。ここではテスト用に適当な秘匿情報を設定しています。

# This string is a test GitLab personal access token and does not actually exist.
glpat-ABCDE12345abcde12345

# This string is an AWS access token for testing purposes and does not actually exist.
AKIAABCD1234ABCD1234

こちらをコミットするとパイプラインが起動し、 secret_detection というJobが実行されます。

ログを確認すると leaks found: 2 というメッセージがあり、2つの秘匿情報を検知したことが確認できます。

Job実行後はアーティファクトが作成されるので、そちらでも結果を確認できます。 gl-secret-detection-report.json というファイルを見ると、詳細を確認できます。

{
    "version": "15.0.7",
    "vulnerabilities": [
        {
            "id": "00391aa879ffd87b871be42e0fb0b2392b86fd30e2b787d11108f4901e3e70ba",
            "category": "secret_detection",
            "name": "AWS Access Token",
            "description": "AWS Access Token secret has been found in commit 308186b4.",
            "cve": "test-secret.md:9617414f9b1407a4db5c2969de7975c94945da3bc7dfc069c0ffb121dd13bac2:AWS",
            "severity": "Critical",
            "confidence": "Unknown",
            "raw_source_code_extract": "AKIAABCD1234ABCD1234",
            "scanner": {
                "id": "gitleaks",
                "name": "Gitleaks"
            },
            "location": {
                "file": "test-secret.md",
                "commit": {
                    "author": "Futa Yamaji",
                    "date": "2024-01-19T23:28:58Z",
                    "message": "Add test-secret.md",
                    "sha": "308186b46921e4a731137f68905efdfa1f1016af"
                },
                "start_line": 5
            },
            "identifiers": [
                {
                    "type": "gitleaks_rule_id",
                    "name": "Gitleaks rule ID AWS",
                    "value": "AWS"
                }
            ]
        },
        {
            "id": "9b99cb58930095348b1d8d4a7c6fa50b8ee8b0815e366020b5f6c70b9cfb1ba7",
            "category": "secret_detection",
            "name": "GitLab Personal Access Token",
            "description": "GitLab Personal Access Token secret has been found in commit 308186b4.",
            "cve": "test-secret.md:f0e30bf67ace880b5349fc092ffb83b87d2e997cd91a93555c6c81193a750a1b:gitlab_personal_access_token",
            "severity": "Critical",
            "confidence": "Unknown",
            "raw_source_code_extract": "glpat-ABCDE12345abcde12345",
            "scanner": {
                "id": "gitleaks",
                "name": "Gitleaks"
            },
            "location": {
                "file": "test-secret.md",
                "commit": {
                    "author": "Futa Yamaji",
                    "date": "2024-01-19T23:28:58Z",
                    "message": "Add test-secret.md",
                    "sha": "308186b46921e4a731137f68905efdfa1f1016af"
                },
                "start_line": 2
            },
            "identifiers": [
                {
                    "type": "gitleaks_rule_id",
                    "name": "Gitleaks rule ID gitlab_personal_access_token",
                    "value": "gitlab_personal_access_token"
                }
            ]
        }
    ],
    "dependency_files": [],
    "scan": {
        "analyzer": {
            "id": "secrets",
            "name": "secrets",
            "url": "https://gitlab.com/gitlab-org/security-products/analyzers/secrets",
            "vendor": {
                "name": "GitLab"
            },
            "version": "5.1.18"
        },
        "scanner": {
            "id": "gitleaks",
            "name": "Gitleaks",
            "url": "https://github.com/zricethezav/gitleaks",
            "vendor": {
                "name": "GitLab"
            },
            "version": "8.18.1"
        },
        "type": "secret_detection",
        "start_time": "2024-01-19T23:29:07",
        "end_time": "2024-01-19T23:29:07",
        "status": "success"
    }
}

許容する秘匿情報を指定する

プロジェクトによっては、テスト用のパスワードなどをファイルに記載する場合もあるかと思います。Secret detectionは #gitleaks:allow という文字列を追加することで検知を無効化することもできます。

docs.gitlab.com

先ほど作成した test-secret.md を以下のように修正します。

# This string is a test GitLab personal access token and does not actually exist.
glpat-ABCDE12345abcde12345 #gitleaks:allow

# This string is an AWS access token for testing purposes and does not actually exist.
AKIAABCD1234ABCD1234 #gitleaks:allow

修正後のJobを見ると、先ほどあった leaksfound: 2 というメッセージは無くなっています。

アーティファクトを見ても検知されておらず、無効化できていることが確認できます。

{
    "version": "15.0.7",
    "vulnerabilities": [],
    "dependency_files": [],
    "scan": {
        "analyzer": {
            "id": "secrets",
            "name": "secrets",
            "url": "https://gitlab.com/gitlab-org/security-products/analyzers/secrets",
            "vendor": {
                "name": "GitLab"
            },
            "version": "5.1.18"
        },
        "scanner": {
            "id": "gitleaks",
            "name": "Gitleaks",
            "url": "https://github.com/zricethezav/gitleaks",
            "vendor": {
                "name": "GitLab"
            },
            "version": "8.18.1"
        },
        "type": "secret_detection",
        "start_time": "2024-01-19T23:39:00",
        "end_time": "2024-01-19T23:39:01",
        "status": "success"
    }
}

SECRET_DETECTION_HISTORIC_SCANの有効化

Secret detection機能はデフォルトでは最新のGitリポジトリの情報だけを利用します。これに対し過去の履歴も含めて秘匿情報を検知したい場合は SECRET_DETECTION_HISTORIC_SCAN という変数を true に設定します。

docs.gitlab.com

include:
- template: Security/Secret-Detection.gitlab-ci.yml

#以下を追加
secret_detection:
  variables:
    SECRET_DETECTION_HISTORIC_SCAN: "true"

上記修正を .gitlab-ci.yml に行い、パイプラインを起動すると、先ほどは検知されなかった秘匿情報の漏洩を検知します。

アーティファクトを見ると、 #gitleaks:allow 設定前のコミットに対して秘匿情報を検知していることが確認できます。

{
    "version": "15.0.7",
    "vulnerabilities": [
        {
            "id": "00391aa879ffd87b871be42e0fb0b2392b86fd30e2b787d11108f4901e3e70ba",
            "category": "secret_detection",
            "name": "AWS Access Token",
            "description": "AWS Access Token secret has been found in commit 308186b4.",
            "cve": "test-secret.md:9617414f9b1407a4db5c2969de7975c94945da3bc7dfc069c0ffb121dd13bac2:AWS",
            "severity": "Critical",
            "confidence": "Unknown",
            "raw_source_code_extract": "AKIAABCD1234ABCD1234",
            "scanner": {
                "id": "gitleaks",
                "name": "Gitleaks"
            },
            "location": {
                "file": "test-secret.md",
                "commit": {
                    "author": "Futa Yamaji",
                    "date": "2024-01-19T23:28:58Z",
                    "message": "Add test-secret.md",
                    "sha": "308186b46921e4a731137f68905efdfa1f1016af"
                },
                "start_line": 5
            },
            "identifiers": [
                {
                    "type": "gitleaks_rule_id",
                    "name": "Gitleaks rule ID AWS",
                    "value": "AWS"
                }
            ]
        },
        {
            "id": "9b99cb58930095348b1d8d4a7c6fa50b8ee8b0815e366020b5f6c70b9cfb1ba7",
            "category": "secret_detection",
            "name": "GitLab Personal Access Token",
            "description": "GitLab Personal Access Token secret has been found in commit 308186b4.",
            "cve": "test-secret.md:f0e30bf67ace880b5349fc092ffb83b87d2e997cd91a93555c6c81193a750a1b:gitlab_personal_access_token",
            "severity": "Critical",
            "confidence": "Unknown",
            "raw_source_code_extract": "glpat-ABCDE12345abcde12345",
            "scanner": {
                "id": "gitleaks",
                "name": "Gitleaks"
            },
            "location": {
                "file": "test-secret.md",
                "commit": {
                    "author": "Futa Yamaji",
                    "date": "2024-01-19T23:28:58Z",
                    "message": "Add test-secret.md",
                    "sha": "308186b46921e4a731137f68905efdfa1f1016af"
                },
                "start_line": 2
            },
            "identifiers": [
                {
                    "type": "gitleaks_rule_id",
                    "name": "Gitleaks rule ID gitlab_personal_access_token",
                    "value": "gitlab_personal_access_token"
                }
            ]
        }
    ],
    "dependency_files": [],
    "scan": {
        "analyzer": {
            "id": "secrets",
            "name": "secrets",
            "url": "https://gitlab.com/gitlab-org/security-products/analyzers/secrets",
            "vendor": {
                "name": "GitLab"
            },
            "version": "5.1.18"
        },
        "scanner": {
            "id": "gitleaks",
            "name": "Gitleaks",
            "url": "https://github.com/zricethezav/gitleaks",
            "vendor": {
                "name": "GitLab"
            },
            "version": "8.18.1"
        },
        "type": "secret_detection",
        "start_time": "2024-01-19T23:53:55",
        "end_time": "2024-01-19T23:53:55",
        "status": "success"
    }
}

編集中のテキストからSecretを検知する

Secret detectionとは別ですが、GitLabはIssueやMerge request、コメントなどに記入するとき、そのテキストにGitLab Personal Access Token / GitLab Feed Token が含まれていると警告を表示してくれます。

docs.gitlab.com

試しにIssueを作成するときにテスト用のPersonal Access Tokenを含めた状態で作成してみます。

すると以下のように、トークンが含まれていることを警告してくれます。

これはMerge requestなども同様で、以下のように警告を表示します。

Secretを検知したときは?

Secret detectionは秘匿情報が含まれることを検知してくれますが、その後の対応は利用者が実施する必要があります。

GitLabのドキュメントでは以下のように案内しています。

  • Secretを検知した場合、まずは利用中のSecretをローテーションすべきです。GitLabはいくつかのタイプのSecretを自動的に失効させる機能もありますが、対応していないものは手動で対応しなければなりません。
  • リポジトリの履歴からSecret情報を削除するだけでなく、既存のFork / Cloneからも削除する必要があります。

docs.gitlab.com

※参考:

engineering.mercari.com

その他

Ultimateプランでは以下の機能も利用できます。

  • Merge request / パイプラインの Security タブでの検知情報の表示
  • Vulnerability reportの利用
  • Security Dashboardの利用
  • Rulesetのカスタマイズ: 定義済みのルールを無効化・上書きしたり、リモートの設定ファイルを指定できます。
  • 漏洩したSecretに対する自動対応: 特定のSecretは自動的に削除したり、パートナーに通知して無効化したりできます。

docs.gitlab.com

docs.gitlab.com