Binary Authorization とは
概要
コンテナベースのアプリケーションに ソフトウェアサプライチェーンのセキュリティを提供する Google Cloud のサービスです。
補足
- ソフトウェアサプライチェーンとは
アプリケーションやサービス・プロダクトを作成する場合、コードや設定ファイル、ライブラリ、プラグイン、コンテナの依存関係等その他諸々(人、内製、委託 etc)が組み合わさって構成されることの総称です。
参考:ソフトウェアサプライチェーンの概要と、そのセキュリティを確保する方法 (Circle CI) - ソフトウェアサプライチェーン攻撃とは
ソフトウェアチェーンに悪意のあるコードを組み込む攻撃です。
一例として、Event Stream での事例を挙げます。
JavaScript のパッケージである Event Stream は OSS がメンテナンスされなくなりユーザーが好意でメンテし始めたことにより、悪意はなかったが、バックドアを作成できる悪意のあるパッケージを利用してしまい、それが 800万回ほどダウンロードされ利用される、ということがありました。
参考①:ソフトウェアサプライチェーン攻撃の事例分析と対策 (TERILOGY WORK)
参考②:A post-mortem of the malicious event-stream backdoor (snyk)
目的
- 信頼できるコンテナイメージのみをデプロイしたい
アプローチ
基本機能
- パイプライン (Cloud Build)
コンテナイメージのビルドが終わったタイミングで証明書を作成します。 - コンテナ基盤
Binary Authorization のポリシーに基づいて、証明書を検証します。
+α
- パイプライン (Cloud Build)
コンテナイメージのビルドが終わり コンテナイメージスキャン (ContainerAnalysis) の結果をもとに、証明書を作成します。
「脆弱性の検証」と「証明書の作成」は、grafeas/kritis というツールが担っていて Shopify/voucher というのも同じことをやってくれるそうです。 - コンテナ基盤
先と同様です。
仕組みを整理
パイプライン編
フロー
- (1) イメージビルド
- (2) イメージプッシュ (Artifact Registry のみ対応)
- (3) イメージスキャン (Artifact Registry の Container Analysis にてイメージスキャン)
- (4) 結果ポーリング
- (5) 証明書作成
パイプラインのサンプル (cloudbuild.yaml)
- 補足
waitFor
で step 内の Job に依存関係を定義できます。
参考:ビルドステップの順序の構成substitutions
は外部から注入できる変数になります。
参考:変数値の置換
timeout: 3600s
steps:
# build と push 省略
- name: gcr.io/$PROJECT_ID/kritis-signer
entrypoint: /bin/bash
args:
- '-e'
- '-c'
- >-
echo gcr.io/$PROJECT_ID/kritis-signer &&
/bin/cat image-digest.txt &&
/kritis/signer -mode check-and-sign -image $(/bin/cat image-digest.txt) -policy infrastructure/gcp/cloudbuild/binauthz/kritis-policy.yaml -vulnz_timeout 60m -kms_key_name ${_KMS_KEY_NAME} -kms_digest_alg ${_KMS_DIGEST_ALG} -note_name ${_NOTE_NAME}
waitFor: ['push']
id: vulnsign
substitutions:
_APPNAME: APPNAME
_DOCKER_FILE_PATH: DOCKER_FILE_PATH
_ARTIFACT_REGISTRY_BASE_URL: ARTIFACT_REGISTRY_BASE_URL
_KMS_KEY_NAME: KMS_KEY_NAME
_KMS_DIGEST_ALG: KMS_DIGEST_ALG
_NOTE_NAME: NOTE_NAME
kritis を深掘り
- 参考資料
1.Kritis Signer (https://github.com/grafeas/kritis/blob/master/docs/signer.md)
2.Kritis Binary Authorization (https://github.com/grafeas/kritis/blob/master/docs/binary-authorization.md) - 実際にパイプラインにいれているコマンド
/kritis/signer \
-mode check-and-sign \
-image $(/bin/cat image-digest.txt) \
-policy infrastructure/gcp/cloudbuild/binauthz/kritis-policy.yaml \
-vulnz_timeout 60m \
-kms_key_name ${_KMS_KEY_NAME} \
-kms_digest_alg ${_KMS_DIGEST_ALG} \
-note_name ${_NOTE_NAME}
重要そうなコマンドフラッグ
mode:string
このツール実行時の振る舞いを3種類から選択します。
1.check-and-sign
: ポリシーチェック & 署名
2.check-only
: ポリシーチェックのみ
3.bypass-and-sign
: 署名のみimage
証明書を作成したいコンテナイメージの指定します。
イメージタグではなくダイジェストを指定することが注意点です。vulnz_timeout
Artifact Registry の Container Analysis の結果が出るまでポーリングする時間です。
注意点としては、イメージサイズが大きい場合イメージスキャン(ContainerAnalysis)にも時間がかかるため、調整が必要になります (パイプライン自体のタイムアウトも考慮する必要があります)。
※ デフォルトは5分
その他、コマンドフラッグ何があるか知りたい方は実装の方見てみてください
・addBasicFlags
・addCheckFlags
・addSignFlags
証明書作るところはどのようなロジックかgrafeas/kritis/cmd
にエントリーポイント (main関数のいるところ) があります (こちら)
ここの kritis/signer
から追います
フロー
1.下準備 (フラッグのパースや外部クライアントの初期化等)
2.ポリシーチェック
- ポリシーファイルデコード
- Container Analysis の結果待機
コンテナイメージに紐づくオカレンスを取得して、結果が入っているかをループ
※ Occurence (オカレンス): ITの文脈だと多分 Attribute (属性・メタデータ) - コンテナイメージをもとに脆弱性情報を取得
- 読み込んだポリシーファイルをもとに検査
3.署名
- CloudKMS に問い合わせ署名に利用する鍵を取得
- ノート名のフォーマットを確認
- イメージに署名
・イメージに証明書 (attestation) が既にあるか確認
・証明書を作成
・証明書をアップロード
証明書からオカレンスのオブジェクトを作成し、(Google Cloud) Create Occurence API を呼び出します。
(参考) kritis の Policy はこのような感じになります (フォーマットは YAML)
API 定義は こちら
apiVersion: kritis.grafeas.io/v1beta1
kind: VulnzSigningPolicy
metadata:
name: kritis-policy
spec:
imageVulnerabilityRequirements:
# コンテナイメージに発見された脆弱性に対する許容度
# ENUM: BLOCK_ALL/LOW/MEDIUM/HIGH/CRITICAL/ALLOW_ALL
maximumFixableSeverity: CRITICAL
# 見つかった脆弱性のうち、修正プログラムが存在しないものに対する許容範囲
# ENUM: BLOCK_ALL/LOW/MEDIUM/HIGH/CRITICAL/ALLOW_ALL
maximumUnfixableSeverity: ALLOW_ALL
# フィルタにかけないCVEのリスト
allowlistCVEs: []
コンテナ基盤編
フロー
- Kubernetes Admission Webhook にて、マニフェスト適用時に Validation が行われる
- Admission Controller がコンテナイメージとダイジェストをもとに、Container Analysis へ問い合わせ検査
設置できるプラットフォーム
- GKE (Google Kubernetes Engine)
設定は、Addon を ON にしてあげるだけです。
クラスタ作成後でも再作成なしに設定可能で、管理コンポーネントは見えません。
GKEの設定ドキュメント - Cloud Run
GKE と同様になります。
CloudRun設定ドキュメント - Anthos clusters on VMWare (Preview)
ドキュメントでは Anthos は VMWare のみの案内ですが Admission Controller が Google API にアクセスできる環境ならどこでもできるはずです。
ValidatingWebhookConfiguration と Controller のマニフェストを手動でデプロイする必要があります。
マニフェストの場所gsutil cp gs://gke-on-prem-release/binauthz/manifest-0.2.2.yaml .
- Anthos Service Mesh
「おまっどうやってやるんやサービスメッシュが…」 というのが最初の感想でしたが、概要には情報はありませんでした。
GKE 以外で ASM が使える環境が Anthos ではありますので、それ向けかもしれません。
Anthos のバージョンとアップグレードのサポート
最後に、BinaryAuthorization の Policy を入れてあげて終了になります。
参考リンク
- gcloud CLI を使用して認証者を作成する
- gcloud CLI を使用してポリシーを構成する
ポリシーのパラメータについての解説が載っています。
フロー
認証者 (Attestor) の公開鍵作成
Admission Controller が証明書の検証ために使います。
Cloud KMS で 証明書を作っている方向けへのコマンド例 (terraform でも可)
gcloud --project="" container binauthz attestors public-keys add \
--attestor="" \
--keyversion-project="" \
--keyversion-location="" \
--keyversion-keyring="" \
--keyversion-key="" \
--keyversion=""
Binary Authorization Policy の読み込み (terraform でも可)
- 読み込み:
gcloud container binauthz policy export > /tmp/policy.yaml
- 書き込み:
gcloud container binauthz policy import /tmp/policy.yaml
(参考) BinaryAuthorization の Policy はこのような感じになります (フォーマットは YAML)evaluationMode: REQUIRE_ATTESTATION
にすると、証明書の検査をします。
1枚のポリシーがプロジェクト全体に適用されます。下記の 5つで範囲を絞れます。
- クラスタ単位
- デフォルト
- ASM (Service Identity ID)
- Kubernetes Service Account
- Kubernetes Namespace
# 用語
# Attestor: 認証者 (証明書作ったり許可したりする人)
---
# パラメータ
# defaultAdmissionRule.enforcementMode
# -> イメージがルールに違反している場合に施行者がどのように応答するか
# defaultAdmissionRule.evaluationMode
# -> デプロイ時に Binary Authorization 施行者が適用する制約のタイプ
# globalPolicyEvaluationMode
# -> Google 管理のシステムイメージを許可リストに登録するかどうか
# admissionWhitelistPatterns
# -> 特定のイメージのみ署名がなくても許可する
defaultAdmissionRule:
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
evaluationMode: REQUIRE_ATTESTATION
requireAttestationsBy:
- projects/hallo-ai-pf-pjt/attestors/built-by-cloud-build
globalPolicyEvaluationMode: ENABLE
# 形式: projects/${PROJECT_ID}/policy
name: projects/hallo-ai-pf-pjt/policy
admissionWhitelistPatterns:
- namePattern: quay.io/argoproj/**
- namePattern: ghcr.io/dexidp/**
- namePattern: public.ecr.aws/docker/library/**
注意globalPolicyEvaluationMode: true
にすると、 Google 管理のコンテナイメージに対しての検査をスキップしてくれるのですが、 たまに含み忘れているものも出てきます。その場合、ホワイトリストに追加する必要があります。
まとめ
- BinaryAuthorization を使うことで 認証・認可したイメージのみワークロードとして使うことができる
気軽に検証イメージをデプロイできないというのもあるので、使う環境は考慮する必要がありそうでした。
気軽にOFFにできるし、AUDIT_LOG だけ出すこともでき、許可していないものは軒並みデプロイできないので Kubernetes 管理者としては安心感もあると感じました。 - この機能を使って、何をどこまで担保したいのかは組織ごとに決めていく必要がある
例えば、
・本番環境デプロイまでのパイプラインがあり、様々なテスト(試験) をパスしたイメージだけをデプロイしたい
・一定以上の脅威のある脆弱性を含んだイメージをデプロイしたくない など - 気になる料金
・Cloud Run:無料
・Anthos:無料
・GKE:無料枠 ($12) / $0.016 per クラスタ - Container Analysis は今の所、OS Package / Go Package / Java Package の検査をしてくれる