セクションアナライザー開発
アナライザはDockerイメージとして出荷され、CIパイプラインコンテキスト内で実行されます。このガイドでは、アナライザ全体の開発とテストのプラクティスについて説明します。
共有モジュール
共通の動作やインターフェースのために、アナライザ間で共有されるGoモジュールが多数あります:
-
command
Go パッケージは CLI インターフェイスを実装しています。 -
common
プロジェクトは、ロギング、証明書処理、ディレクトリ検索機能のための雑多な共有モジュールを提供します。 -
report
Go パッケージのReport
とFinding
構造体は JSON レポートをマーシャルします。 -
template
プロジェクトは新しいアナライザーの足場となります。
分析器の使い方
アナライザはDockerイメージとして出荷されます。例えば、作業ディレクトリをスキャンするためにSemgrepDockerイメージを実行します:
-
cd
をスキャンしたいソースコードのディレクトリにコピーします。 -
docker login registry.gitlab.com
を実行し、ユーザー名と個人またはプロジェクトのアクセストークンを、少なくともread_registry
のスコープで指定します。 -
Dockerイメージを実行してください:
docker run \ --interactive --tty --rm \ --volume "$PWD":/tmp/app \ --env CI_PROJECT_DIR=/tmp/app \ -w /tmp/app \ registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep:latest /analyzer run
- Dockerコンテナは、アナライザ・カテゴリに対応するレポート・ファイル名で、マウントされたプロジェクト・ディレクトリにレポートを生成します。例えば、SASTは
gl-sast-report.json
という名前のファイルを生成します。
アナライザの開発
アナライザーをアップデートするには
- Goソースコードを修正します。
- 新しいDockerイメージをビルドします。
- テストプロジェクトに対してアナライザーを実行します。
- 生成されたレポートを期待されるものと比較してください。
analyzer
という名前のDockerイメージを作成する方法は以下の通りです:
docker build -t analyzer .
例えば、Secret Detectionをテストするには以下を実行します:
wget https://gitlab.com/gitlab-org/security-products/ci-templates/-/raw/master/scripts/compare_reports.sh
sh ./compare_reports.sh sd test/fixtures/gl-secret-detection-report.json test/expect/gl-secret-detection-report.json \
| patch -Np1 test/expect/gl-secret-detection-report.json && Git commit -m 'Update expectation' test/expect/gl-secret-detection-report.json
rm compare_reports.sh
自分の環境用にバイナリをコンパイルして、それを内部で実行することもできますが、analyze
、run
、アナライザーの実行時依存関係が欠落しているため、おそらく動作しません。
以下はSpotBugsに基づいた例です:
go build -o analyzer
./analyzer search test/fixtures
./analyzer convert test/fixtures/app/spotbugsXml.Xml > ./gl-sast-report.json
実行基準
SASTを有効にするには、GitLab CI/CD設定に定義済みのテンプレートを含める必要があります。
以下の独立した基準によって、プロジェクトでどのアナライザーを実行する必要があるかが決まります:
- SAST テンプレートでは、
rules:exists
を使用して、特定のファイルの存在に基づいて実行する解析ツ ールを決定します。たとえば、Brakeman アナライザーは、.rb
ファイルとGemfile
. - 各分析ツールは、実際の分析を実行する前に、カスタマイズ可能な一致インターフェイスを実行します。例えばFlawfinder は C/C++ ファイルをチェックします。
- 一般的なファイル拡張子で実行されるいくつかのアナライザーでは、CI/CD変数に基づくチェックがあります。例えばKubernetesのマニフェストはYAMLで記述されているため、Kubesecは
SCAN_KUBERNETES_MANIFESTS
がtrueに設定されている場合にのみ実行されます。
ステップ1は、プロジェクトに適していないアナライザーを実行するために費やされるコンピュートクォータの浪費を防ぐのに役立ちます。しかし、技術的な制約から、大規模なプロジェクトには使用できません。そのため、ステップ2は不一致の解析器が早期に終了できるようにするための最終チェックの役割を果たします。
分析装置のテスト方法
Dependency Scanning アナライザがダウンストリームパイプライン機能を使用して、テストプロジェクトを使用してアナライザをテストする方法をビデオで説明します:
ローカル変更のテスト
アナライザの共有モジュール (command
やreport
など) の内部変更をテストするには、go mod replace
ディレクティブを使用して、リモートでタグ付けされたバージョンのコマンドを使用する代わりに、command
をローカルの変更でロードすることができます。例えば
go mod edit -replace gitlab.com/gitlab-org/security-products/analyzers/command/v3=/local/path/to/command
また、go.mod
ファイルを手動で更新することでも、同じ結果を得ることができます:
module gitlab.com/gitlab-org/security-products/analyzers/awesome-analyzer/v2
replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /path/to/command
require (
...
gitlab.com/gitlab-org/security-products/analyzers/command/v3 v2.19.0
)
Dockerでのローカル変更のテスト
Dockerをreplace
、go.mod
:
-
command
の内部をアナライザーのディレクトリにコピーします。cp -r /path/to/command path/to/analyzer/command
. - アナライザの
Dockerfile
:COPY command /command
にコピー文を追加します。 -
replace
ステートメントを更新して、上記のステップのCOPY
ステートメントのコピー先と一致するようにします:replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /command
アナライザ・スクリプト
analyzer-scriptsリポジトリには、ほとんどのアナライザーに対応するスクリプトがあります。GitLab CI のような環境でアナライザのビルドや実行、デバッグを行うことができ、特にアナライザの変更をローカルで検証するのに便利です。
詳細はプロジェクトのREADMEを参照ください。
バージョンアップとリリースプロセス
GitLabセキュリティ製品は、GitLab RailsのMAJOR.MINOR
とは独立したバージョン管理システムを使用しています。全ての製品はセマンティック・バージョニングのバリエーションを使用し、Dockerイメージとして利用可能です。
Patch
バージョンバンプは、内部ツール(すなわちbandit
)のMinor
バージョンバンプに対応する傾向があり、私たちのスキャナに対するより重要な変更のためにMinor
バンプをより柔軟に予約することができます。ラッピングされたスキャナによる変更を壊す場合は、別のリポジトリに新しいアナライザを作成することを考慮する必要があります。
分析器はこの方式に従ってDockerイメージとしてリリースされます:
- デフォルトブランチにプッシュすると、
edge
イメージタグが上書きされます。 - 任意の
awesome-feature
ブランチにプッシュすると、それにマッチするawesome-feature
イメージタグが生成されます。 - 各 Git タグは、対応する
Major.Minor.Patch
イメージタグを生成します。手動ジョブでは、対応するMajor
とlatest
の画像タグを上書きして、このMajor.Minor.Patch
を指すようにできます。
たいていの場合、MAJOR
のイメージに依存するのが好ましいでしょう。 は、最新のアドバイザリやツールへのパッチで自動的に最新の状態に保たれます。同梱の CI テンプレートはメジャーバージョンに固定されていますが、ユーザはバージョンを直接上書きすることができます。
新しいanalyzer Dockerイメージをリリースするには、2つの異なるオプションがあります:
次の図は、新しいバージョンのanalyzerがリリースされたときに作成されるDockerタグを説明したものです:
私たちの継続的デプロイのフローでは、GitLab Railsアプリケーションに対応するものがない新しいコンポーネントについては、コンポーネントはいつでもリリースできます。コンポーネントが既存のアプリケーションに統合されるまでは、私たちの標準的なリリースサイクルやプロセスによってインテグレーションが妨げられることはありません。
手動リリースプロセス
- 新しいIRMA TRUpointの
CHANGELOG.md
入力が正しいことを確認してください。 - リリース・ソース(通常は
master
またはmain
ブランチ)にパイプラインが通っていることを確認してください。 - プロジェクト・ウィンドウの左側にある [デプロイ]メニューを選択し、[Windows] サブメニューを選択して、アナライザー・プロジェクトの新しいリリースを作成します。
-
New release]を選択して、[New Release]ページを開きます。
-
Create tag v2.4.2
タグ名**ドロップダウンに、CHANGELOG.md
で使用したものと同じバージョンを入力します(例:v2.4.2
)。 -
リリース・タイトル・テキスト・ボックスに、上記で使用したものと同じバージョンを入力します(例:
v2.4.2
)。 -
Release notes
テキストボックスには、対応するバージョンの注釈をコピーしてCHANGELOG.md
に貼り付けます。 - その他の設定はデフォルトのままにしてください。
- リリースの作成を選択します。
-
上記のプロセスに従って新しいリリースを作成すると、新しい Git タグがTag name
で作成されます。これにより、指定されたタグのバージョンで新しいパイプラインがトリガーされ、新しいanalyzer Dockerイメージがビルドされます。
analyzerがanalyzer.yml
テンプレート を使用している場合、上記の新規リリースプロセスの一部としてトリガーされたパイプラインは、自動的に新しいバージョンのanalyzer Dockerイメージをタグ付けし、デプロイします。
analyzerがanalyzer.yml
テンプレートを使用していない場合は、手動で新しいバージョンのanalyzer Dockerイメージにタグ付けしてデプロイする必要があります:
- プロジェクトウィンドウの左側にあるCI/CDメニューを選択し、パイプラインサブメニューを選択します。
- 新しいパイプラインが、
v2.4.2
のようなタグで実行されているはずです。 - パイプラインが完了すると、
blocked
の状態になります。 - ウィンドウの右側にある
Manual job
再生ボタンを選択し、tag version
アナライザーの新しいバージョンのDockerイメージにタグ付けしてデプロイします。
Gitタグを作成するタイミングは、あなたの最善の判断で決めてください。判断がつかない場合は、他の人の意見を聞いてください。
自動リリースプロセス
自動リリース処理を使用する前に、以下の処理を行う必要があります:
-
CREATE_GIT_TAG: true
をCI/CD
環境変数として設定します。 - CI/CD プロジェクト設定の
Variables
を確認してください。プロジェクトがすでにプロジェクトグループからGITLAB_TOKEN
環境変数を継承している場合を除き、complete read/write access to the API
でプロジェクトアクセストークンを作成し、GITLAB_TOKEN
をこのトークンを参照するCI/CD
環境変数 として設定します。
上記の手順が完了すると、自動リリース処理は以下のように実行されます:
- プロジェクトのメンテナーが MR をデフォルトブランチにマージします。
- デフォルトのパイプラインが起動し、
upsert git tag
ジョブが実行されます。-
CHANGELOG.md
の最新バージョンが Git タグのひとつにマッチする場合、ジョブは実行されません。 - そうでない場合、このジョブはreleases API を使って新しいリリースと Git タグを自動的に作成します。バージョンとメッセージはプロジェクトの
CHANGELOG.md
ファイルの最新のエントリから取得されます。
-
- 新しい Git タグに対してパイプラインが自動的にトリガーされます。このパイプラインは、アナライザの
latest
、major
、minor
、patch
Dockerイメージをリリースします。
アナライザーをリリースした後の手順
- 新しいバージョンのアナライザーのDockerイメージがタグ付けされ、デプロイされたら、対応するテストプロジェクトでテストしてください。
-
関連するグループのSlackチャンネルでリリースをアナウンスしてください。メッセージの例
ANALYZER_NAME
ANALYZER_VERSION
をリリースしました。LINK_TO_RELEASE
プッシュされた Git タグは絶対に削除しないでください。Go パッケージのレジストリで使われたりキャッシュされたりする可能性が高いからです。
コンテナイメージの場所
コンテナレジストリへの書き込みアクセス者を制限するため、すべてのイメージは以下の場所に公開されます。
- グループ
https://gitlab.com/security-products/
- プロジェクトパス:
https://gitlab.com/security-products/<NAME>
(例) - レジストリのアドレス:
registry.gitlab.com/security-products/<NAME>[/<IMAGE_NAME>]:[TAG]
- 権限
- トップレベルグループ
- メンテナー
@gitlab-org/secure/managers
,@gitlab-org/govern/managers
- メンテナー
- プロジェクトレベル
-
read_registry
、write_registry
アクセス権を持つデプロイトークンを使用してイメージをプッシュします。 - このトークンは、生成元プロジェクト (すなわち、
security-products
名前空間のプロジェクト) の保護されマスクされた変数として、作成者によって入力されます。
-
- トップレベルグループ
- プロジェクトの設定
- 可視性、プロジェクト機能、権限。
- プロジェクトの可視性:公開。ユーザーがアクセスをリクエストできる」のチェックを外してください。
- イシュー:無効にします。
- リポジトリ:「プロジェクトメンバーのみ」に設定。無効にします:マージリクエスト、フォーク、Git LFS、パッケージ、CI/CD。
- 残りの項目を無効にします:アナリティクス、要件、Wiki、スニペット、ページ、オペレーション。
- サービスデスク: 無効
- 可視性、プロジェクト機能、権限。
Sec Sectionの各グループが担当します:
- アーティファクトの非推奨および削除スケジュールの管理、およびそのためのイシューの作成。
- 新しい場所でのプロジェクトの作成と設定。
- リリースのアーティファクトを新しい場所にプッシュするビルドの設定。
- それぞれのサポート契約に従って、古い場所にあるイメージを削除したり保持したりします。
Goのセキュリティとビルドの修正
Goで実装されたセキュア・アナライザのDockerfile
、MINOR
リビジョンではなく、MAJOR
リリースのGoを参照する必要があります。これにより、分析器のコンパイルに使用されるGoのバージョンに、その時点で利用可能なすべてのセキュリティ修正が含まれていることが保証されます。たとえば、解析器のマルチステージ Dockerfile では、golang:1.15-alpine
イメージを使用して解析器 CLI をビルドする必要がありますが、golang:1.15.4-alpine
は使用しないでください。
Goのリビジョン(MINOR
)がリリースされ、そのリビジョンにセキュ リティ修正が含まれる場合、プロジェクトのメンテナーは、Secureアナライザを再ビルド する必要があるかどうかを確認する必要があります。ビルドに使用された Go のバージョンは、リリースに対応するbuild
ジョブのログに表示されます。
また、stringsコマンドを使ってGoのバイナリから抽出することもできます。解析器の最新のイメージが影響を受けるバージョンのGoでビルドされている場合は、再構築する必要があります。イメージを再構築するには、メンテナーは次のいずれかを行います:
- 安定リリースに対応する Git タグの新しいパイプラインを起動します。
- 新しい Git タグを作成し、
BUILD
の番号をインクリメントします。 - デフォルトブランチのパイプラインをトリガーし、
PUBLISH_IMAGES
変数に空でない値を設定します。
いずれにせよ、新しいDockerイメージがビルドされ、同じイメージタグで公開されます:MAJOR.MINOR.PATCH
とMAJOR
。
このワークフローでは、同じGoのリリース(MAJOR
)のリビジョン(MINOR
)間の完全な互換性を想定しています。互換性にイシューがある場合、プロジェクトパイプラインはテストを実行するときに失敗します。その場合、互換性の問題が解決するまで、DockerfileでMINOR
リビジョンのGoを参照し、その例外を文書化する必要があるかもしれません。
Dockerfile
、GoのMINOR
リビジョンはプロジェクトの変更履歴に記載されていません。
ビルドタグを使うのが理にかなっている場合があります。例えば、Dockerイメージを新しいレジストリにプッシュする場合などです。
再構築する Git タグ
新しいGitタグを作成してアナライザーを再構築する場合、新しいタグのバージョンは以前と同じMAJOR.MINOR.PATCH
、BUILD
(semverで定義)番号がインクリメントされます。
例えば、アナライザーの最新リリースがv1.2.3
、対応するDockerイメージが影響を受けるバージョンのGoを使ってビルドされた場合、メンテナーはv1.2.3+1
イメージを再構築 v1.2.3+1
するためのGitタグを作成します。v1.2.3+1
最新リリースが v1.2.3+1
, であれば、v1.2.3+2
を作成します。
ビルド番号は自動的にイメージタグから削除されます。例として、gemnasium
プロジェクトで Git タグv1.2.3+1
を作成すると、パイプラインがイメージを再構築し、gemnasium:1.2.3
としてプッシュします。
再構築のために作成された Git タグには、新しいビルドが必要な理由を説明するシンプルなメッセージが表示されます。例:Rebuild with Go 1.15.6
。このタグにはリリースノートはなく、リリースは作成されません。
Analyzerをリビルドするための新しいGitタグを作成するには、以下の手順に従います:
-
新しい Git タグを作成し、メッセージを指定します。
git tag -a v1.2.3+1 -m "Rebuild with Go 1.15.6"
-
タグをリポジトリにプッシュします
git push origin --tags
- Git タグ用の新しいパイプラインが起動し、新しい画像がビルドされてタグが付けられます。
-
master
ブランチに対して新しいパイプラインを実行し、テスト一式を実行し、新しくタグ付けされたイメージに対して新しい脆弱性レポーターを生成します。上記のステップ3.
でトリガーされたリリースパイプラインは、テストのサブセットのみを実行し、例えばContainer Scanning
分析を実行しないので、これは必要です。
毎月のリリースプロセス
毎月18日に行います。ただし、これはソフトな期限であり、数日後に行っても問題はありません。
まず、このリポジトリのスクリプトを使って、リリースのための新しいイシューを作成してください:./scripts/release_issue.rb MAJOR.MINOR
。このイシューがリリースの全プロセスを案内します。一般的には、以下の作業を行う必要があります:
- GitLabドキュメントのサポートされているテクノロジーのリストを確認してください。
-
CI ジョブの定義が正確であることを確認します。ベンダリングされたCI/CDテンプレートで ENV varsのすべてがツールごとにツールごとに
docker run
、Dockerコンテナに伝搬されます。- SAST vendored CI/CD テンプレート
- 依存関係のスキャン vendored CI/CD テンプレート
- ライセンススキャン vendored CI/CD template
- コンテナスキャン CI/CDテンプレート
必要に応じて、最後のGitタグに対応するパイプラインに移動し、このイメージのビルドを制御する手動ジョブをトリガーします。
- パイプラインで現在使われているボットアカウント
- アカウント名
@group_2452873_bot
- 用途:リリース/タグの作成に使用します。
- メンバーグループ
gitlab-org/security-products
- 最大ロール
Developer
- 関連する
GITLAB_TOKEN
の範囲: - 関連する
GITLAB_TOKEN
の有効期限:
- アカウント名
依存関係の更新
アナライザー・ソースで使用されているすべての依存関係およびアップストリーム・スキャナー(もしあれば)は、主にセキュリティ修正と破壊的でない変更を含む月次ペースで更新されます。