日本語

ローカルスキャナーを使ったJenkinsのPRゲーティング

Aikido Local Scannerを使用すると、CIパイプラインでセキュリティゲートを適用できます。

クラウド接続されたワークスペース(GitHub、BitBucketなど)でもPRゲーティングを使用できます。CIのインテグレーションセクションをご覧ください。

PRゲーティングは、新しいコードがデフォルトブランチにマージされる前に、セキュリティ基準を満たしていることを保証します。スキャン対象はプルリクエストで導入された変更のみです。設定した重大度のしきい値以上の新しい問題が検出された場合、CIパイプラインは失敗します。

これにより、既存の検出結果は別途対処しつつ、新しい脆弱性の混入を防ぐことができます。

リリース時にチェックを適用したいチーム向けに、リリースゲーティングもサポートしています。

PRゲーティングを有効にするには、--fail-on <severity> オプションを追加して希望する重大度レベルを選択します。次に、--gating-mode pr オプションを追加して、PRゲーティングを実行することを指定します。また、ベースコミット(--base-commit-id <commit-id>)とヘッドコミット(--head-commit-id <commit-id>)も指定する必要があります。ベースコミットIDに対して以前にスキャンが実行されている場合は、スキャン結果がその結果と比較されます。そうでない場合は、デフォルトブランチでの最新のスキャン結果と比較されます。

Jenkins環境でのLocal Scannerのセットアップに関する一般的な情報については、こちらの記事をご覧ください。

仕組み

構成要素は3つあります。

  1. SCMとJenkinsの間のインテグレーション。
  2. Discover pull requests の動作を設定した Multibranch Pipelineジョブ。これにより、Jenkinsは開いている各プルリクエストをビルドします。PRビルドでは、Jenkinsはソースブランチをチェックアウトし、標準の変更リクエスト用環境変数(CHANGE_ID、CHANGE_TARGET、CHANGE_BRANCH)を公開します。
  3. Jenkinsfile から --gating-mode pr で実行される Aikido Local Scanner。
PR opened/updated  ──►  SCM sends webhook  ──►  Jenkins Multibranch PR build
                                                      │
                                                      ▼
                                        aikido-local-scanner --gating-mode pr
                                                      │
                                  new issues ≥ --fail-on?  ── yes ──► build FAILS
                                                      │                    │
                                                      no                   ▼
                                                      ▼            build status = FAILED
                                                build PASSES               │
                                                      │                    ▼
                                                      ▼          SCM blocks merge
                                              SCM checks pass

Multibranch Pipelineのセットアップ

プルリクエストのビルドには Multibranch Pipeline ジョブが必要です。

  1. Jenkinsで New Item → Multibranch Pipeline を選択し、名前を付けて OK を選択します。
  2. Branch Sources で、Add source → 使用しているSCMを選択 します。
  3. リポジトリ を選択します。
  4. Behaviors で Add → Discover pull requests を選択し、Discover branches を無効にします。
  5. Scan Multibranch Pipeline Triggers で、webhook trigger → Pull request opened or source branch updated オプションを有効にします。
  6. Build Configuration は by Jenkinsfile のままにし、Script Path = Jenkinsfile とします。
  7. Save を選択します。Jenkinsがリポジトリをスキャンし、開いている各プルリクエストのビルドを開始します。

JenkinsfileにAikido PRゲーティングステージを追加する

リポジトリのルートに Jenkinsfile を追加(または既存のものを拡張)します。以下のステージは プルリクエストのビルドでのみ 実行され、Gitからベースコミットとヘッドコミットを取得し、PRゲーティングモードでスキャナーを実行します。ゲートが失敗した場合にスキャナーがゼロ以外の終了コードを返すことで、ビルドが失敗します。

pipeline {
    agent any

    environment {
        // Picks up credentials as setup in https://help.aikido.dev/code-scanning/local-code-scanning/jenkins-setup-for-local-code-scanning#id-1-get-your-authentication-token
        AIKIDO_API_KEY = credentials('aikido-local-scanner-api-key')
        AIKIDO_REPO_NAME = 'my-repo'
    }

    stages {
        stage('Aikido PR Gating') {
            // CHANGE_ID is only set on pull request builds
            when { expression { env.CHANGE_ID != null } }
            steps {
                script {
                    // Ensure the target (destination) branch is available locally
                    sh "git fetch origin ${env.CHANGE_TARGET}"

                    // Head = tip of the PR source branch (what's being merged in)
                    def headCommit = sh(
                        script: 'git rev-parse HEAD',
                        returnStdout: true
                    ).trim()

                    // Base = tip of the destination branch (what it's merging into)
                    def baseCommit = sh(
                        script: "git rev-parse origin/${env.CHANGE_TARGET}",
                        returnStdout: true
                    ).trim()

                    echo "PR #${env.CHANGE_ID}: ${env.CHANGE_BRANCH} -> ${env.CHANGE_TARGET}"
                    echo "Base commit: ${baseCommit}"
                    echo "Head commit: ${headCommit}"

                    // Docker variant. The scanner exits non-zero when new issues
                    // at or above --fail-on are found, which fails the build.
                    sh """
                        docker run --rm \
                          -v "\$(pwd):/scan-target" \
                          aikidosecurity/local-scanner \
                          scan /scan-target \
                          --apikey "\$AIKIDO_API_KEY" \
                          --repositoryname "\$AIKIDO_REPO_NAME" \
                          --branchname "${env.CHANGE_BRANCH}" \
                          --gating-mode pr \
                          --fail-on critical \
                          --base-commit-id ${baseCommit} \
                          --head-commit-id ${headCommit}
                    """
                }
            }
        }
    }
}

Dockerではなく エージェントにスキャナーのバイナリがインストールされている場合 は、docker run … ブロックを以下に置き換えます。

sh """
    aikido-local-scanner scan ./ \
      --apikey "\$AIKIDO_API_KEY" \
      --repositoryname "\$AIKIDO_REPO_NAME" \
      --branchname "${env.CHANGE_BRANCH}" \
      --gating-mode pr \
      --fail-on critical \
      --base-commit-id ${baseCommit} \
      --head-commit-id ${headCommit}
"""
  • --fail-on critical は重大度のしきい値を設定します。より厳しくゲーティングするには、high、medium、または low に変更してください。

必要に応じて、SCMでゲートの適用を設定してください。