CA 発行の証明書を使い、Notation と Azure Key Vault を使ってコンテナー イメージに署名する
信頼される証明機関 (CA) が発行した証明書を使ってコンテナー イメージに署名し、確認することは、重要なセキュリティ プラクティスです。 このセキュリティ対策は、コンテナー イメージの発行元とコンテナー イメージ自体の両方の ID を責任を持って識別、認可、検証するのに役立ちます。 GlobalSign、DigiCert などの信頼される証明機関 (CA) は、ユーザーまたは組織の ID を検証し、デジタル証明書のセキュリティを維持し、リスクや悪用があった場合には直ちに証明書を取り消すという重要な役割を担っています。
信頼された CA から発行された証明書を使ってコンテナー イメージに署名し、確認するために不可欠なコンポーネントの一部を次に示します。
- Notation は、Notary Project コミュニティによって開発され、Microsoft がサポートするオープンソースのサプライ チェーン セキュリティ ツールで、コンテナー イメージとその他の成果物の署名と確認をサポートします。
- 暗号化キー、シークレット、証明書を管理するためのクラウドベース サービスである Azure Key Vault (AKV) は、署名キーを使ってセキュリティで保護された方法で証明書を保存および管理するために役立ちます。
- Notation の拡張機能である Notation AKV プラグイン azure-kv は、Azure Key Vault に保存されているキーを使って、コンテナー イメージと成果物のデジタル署名の署名と確認を行います。
- Azure Container Registry (ACR) を使うと、署名済みイメージにこれらのシグネチャをアタッチできるので、これらのコンテナー イメージの保存と管理に役立ちます。
イメージを確認するときに、イメージの整合性と署名者の身元を検証するためにシグネチャが使われます。 これにより、コンテナー イメージが改ざんされておらず、信頼できる発行元であることを確認できます。
この記事の内容:
- notation CLI と AKV プラグインをインストールする
- AKV で CA から発行された証明書を作成する、またはインポートする
- ACR タスクを使ってコンテナー イメージをビルドおよびプッシュする
- Notation CLI と AKV プラグインを使用して、コンテナー イメージに署名する
- Notation CLI を使ってコンテナー イメージのシグネチャを確認する
- タイムスタンプ
前提条件
- コンテナー イメージと署名を格納するために Azure Container Registry を作成または使用する
- Azure キー コンテナーを作成するか既存のものを使う。
- 最新の Azure CLI をインストールして構成するか、Azure Cloud Shell 内でコマンドを実行する
Note
証明書のみを保存するために、新しい Azure Key Vault を作成することをお勧めします。
notation CLI と AKV プラグインをインストールする
Linux amd64 環境に Notation v1.2.0 をインストールします。 Notation インストール ガイドに従って、他の環境用のパッケージをダウンロードします。
# Download, extract and install curl -Lo notation.tar.gz https://github.com/notaryproject/notation/releases/download/v1.2.0/notation_1.2.0_linux_amd64.tar.gz tar xvzf notation.tar.gz # Copy the notation cli to the desired bin directory in your PATH, for example cp ./notation /usr/local/bin
Linux amd64 環境上に、Notation Azure Key Vault プラグイン
azure-kv
v1.2.0 をインストールします。Note
Notation Azure Key Vault プラグインの URL と SHA256 チェックサムは、プラグインのリリース ページで確認できます。
notation plugin install --url https://github.com/Azure/notation-azure-kv/releases/download/v1.2.0/notation-azure-kv_1.2.0_linux_amd64.tar.gz --sha256sum 06bb5198af31ce11b08c4557ae4c2cbfb09878dfa6b637b7407ebc2d57b87b34
使用可能なプラグインを一覧表示し、バージョンが
1.2.0
であるazure-kv
プラグインが一覧に含まれていることを確認します。notation plugin ls
環境変数を構成する
Note
このガイドでは、AKV と ACR を構成するときに便利な環境変数を使います。 実際のリソースに合わせて、これらの環境変数の値を更新してください。
AKV と証明書の環境変数を構成する
AKV_SUB_ID=myAkvSubscriptionId AKV_RG=myAkvResourceGroup AKV_NAME=myakv # Name of the certificate created or imported in AKV CERT_NAME=wabbit-networks-io # X.509 certificate subject CERT_SUBJECT="CN=wabbit-networks.io,O=Notation,L=Seattle,ST=WA,C=US"
ACR とイメージの環境変数を構成します。
ACR_SUB_ID=myAcrSubscriptionId ACR_RG=myAcrResourceGroup # Name of the existing registry example: myregistry.azurecr.io ACR_NAME=myregistry # Existing full domain of the ACR REGISTRY=$ACR_NAME.azurecr.io # Container name inside ACR where image will be stored REPO=net-monitor TAG=v1 # Source code directory containing Dockerfile to build IMAGE_SOURCE=https://github.com/wabbit-networks/net-monitor.git#main
Azure CLI を使用してサインインする
az login
Azure CLI とそのサインイン方法について詳しくは、「Azure CLI を使用してサインインする」をご参照ください。
AKV で CA から発行された証明書を作成する、またはインポートする
証明書の要件
署名と検証用に証明書を作成する場合、証明書は Notary Project の証明書要件を満たしている必要があります。
ルート証明書と中間証明書の要件は次のとおりです。
basicConstraints
拡張機能が存在し、クリティカルとマークされている必要があります。CA
フィールドはtrue
に設定する必要があります。keyUsage
拡張機能が存在し、critical
とマークされている必要があります。keyCertSign
のビット位置は "必ず" 設定します。
CA から発行される証明書の要件は次のとおりです。
- X.509 証明書のプロパティ:
- サブジェクトには、共通名 (
CN
)、国 (C
)、州または都道府県 (ST
)、組織 (O
) を含める必要があります。 このチュートリアルでは、サブジェクトとして$CERT_SUBJECT
を使います。 - X.509 キー使用フラグは
DigitalSignature
のみにする必要があります。 - 拡張キー使用法 (EKU) は空または
1.3.6.1.5.5.7.3.3
(コード署名の場合) にする必要があります。
- サブジェクトには、共通名 (
- キーのプロパティ:
exportable
プロパティはfalse
に設定する必要があります。- Notary Project の仕様からサポートされているキーの種類とサイズを選びます。
重要
Image Integrity と正常に統合するには、証明書のコンテンツ タイプを PEM に設定する必要があります。
Note
このガイドでは、バージョン 1.0.1 の AKV プラグインを使います。 以前のバージョンのプラグインには、証明書チェーン内の証明書を特定の順序で指定する必要があるという制限がありました。 バージョン 1.0.1 のプラグインにはこの制限がないため、バージョン 1.0.1 以降を使うことをお勧めします。
CA から発行された証明書を作成する
証明書署名要求の作成の手順に従って、証明書署名要求 (CSR) を作成します。
重要
CSR をマージするときは、必ず CA ベンダーから返送されたチェーン全体をマージしてください。
AKV に証明書をインポートする
証明書をインポートするには:
- 証明書チェーン全体を使って CA ベンダーから証明書ファイルを取得します。
- 証明書のインポートの手順に従って、証明書を Azure Key Vault にインポートします。
Note
作成またはインポート後に証明書に証明書チェーンが含まれていない場合は、CA ベンダーから中間証明書とルート証明書を取得できます。 中間証明書 (存在する場合) とルート証明書を含む PEM ファイルを提供するようベンダーに依頼できます。 このファイルは、コンテナー イメージの署名の手順 5 で使用できます。
Notation CLI と AKV プラグインを使用して、コンテナー イメージに署名する
ACR と AKV を使用する場合は、適切なアクセス許可を付与して安全で制御されたアクセスを確保することが不可欠です。 特定のシナリオに応じて、ユーザー プリンシパル、サービス プリンシパル、マネージド ID など、さまざまなエンティティに対してアクセスを承認できます。 このチュートリアルでは、サインインしている Azure ユーザーに対してアクセスを承認します。
ACR へのオーサリング アクセス
ACR でコンテナー イメージをビルドして署名するには、AcrPull
および AcrPush
ロールが必要です。
ACR リソースを含むサブスクリプションを設定します
az account set --subscription $ACR_SUB_ID
ロールを割り当てます
USER_ID=$(az ad signed-in-user show --query id -o tsv) az role assignment create --role "AcrPull" --role "AcrPush" --assignee $USER_ID --scope "/subscriptions/$ACR_SUB_ID/resourceGroups/$ACR_RG/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME"
コンテナー イメージをビルドし、ACR にプッシュする
ご自身の個人 Azure ID を使用して、お使いの ACR に対する認証を行います。
az acr login --name $ACR_NAME
重要
お使いのシステム上に Docker がインストールされており、az acr login
または docker login
を使用してお使いの ACR に対する認証を行う場合、ご自身の資格情報は既に格納されており、Notation に使用できます。 この場合、お使いの ACR に対して notation login
をもう一度実行して認証する必要はありません。 Notation の認証オプションについて詳しくは、「Authenticate with OCI-compliant registries」をご参照ください。
ACR タスクを使用して新しいイメージをビルドし、プッシュします。 タグは変更可能であり、上書き可能なので、常に
digest
を使って署名対象のイメージを識別します。DIGEST=$(az acr build -r $ACR_NAME -t $REGISTRY/${REPO}:$TAG $IMAGE_SOURCE --no-logs --query "outputImages[0].digest" -o tsv) IMAGE=$REGISTRY/${REPO}@$DIGEST
このチュートリアルでは、イメージが既にビルドされており、レジストリに格納されている場合、そのタグは便宜上、そのイメージ用の識別子として機能します。
IMAGE=$REGISTRY/${REPO}@$TAG
AKV へのオーサリング アクセス
Azure RBAC を使用する (推奨)
AKV リソースを含むサブスクリプションを設定する
az account set --subscription $AKV_SUB_ID
ロールを割り当てます
証明書に信頼チェーン全体が含まれている場合、プリンシパルに次のロールを割り当てる必要があります。
- シークレットを読み取るための
Key Vault Secrets User
- 証明書を読み取るための
Key Vault Certificates User
- 署名操作のための
Key Vault Crypto User
USER_ID=$(az ad signed-in-user show --query id -o tsv) az role assignment create --role "Key Vault Secrets User" --role "Key Vault Certificates User" --role "Key Vault Crypto User" --assignee $USER_ID --scope "/subscriptions/$AKV_SUB_ID/resourceGroups/$AKV_RG/providers/Microsoft.KeyVault/vaults/$AKV_NAME"
証明書にチェーンが含まれていない場合、プリンシパルに次のロールを割り当てる必要があります。
- 証明書を読み取るための
Key Vault Certificates User
- 署名操作のための
Key Vault Crypto User
USER_ID=$(az ad signed-in-user show --query id -o tsv) az role assignment create --role "Key Vault Certificates User" --role "Key Vault Crypto User" --assignee $USER_ID --scope "/subscriptions/$AKV_SUB_ID/resourceGroups/$AKV_RG/providers/Microsoft.KeyVault/vaults/$AKV_NAME"
- シークレットを読み取るための
Azure RBAC を使用した Key Vault へのアクセスの詳細については、「アクセスの管理に Azure RBAC を使用する」を参照してください。
アクセス ポリシーを使用する (レガシ)
AKV リソースを含むサブスクリプションを設定するには、次のコマンドを実行します。
az account set --subscription $AKV_SUB_ID
証明書に証明書チェーン全体が含まれている場合、プリンシパルにはキー アクセス許可 Sign
、シークレット アクセス許可 Get
、証明書アクセス許可 Get
を付与する必要があります。 プリンシパルにこれらのアクセス許可を付与するには:
USER_ID=$(az ad signed-in-user show --query id -o tsv)
az keyvault set-policy -n $AKV_NAME --key-permissions sign --secret-permissions get --certificate-permissions get --object-id $USER_ID
証明書にチェーンが含まれていない場合は、プリンシパルにキー アクセス許可 Sign
と証明書アクセス許可 Get
を付与する必要があります。 プリンシパルにこれらのアクセス許可を付与するには:
USER_ID=$(az ad signed-in-user show --query id -o tsv)
az keyvault set-policy -n $AKV_NAME --key-permissions sign --certificate-permissions get --object-id $USER_ID
プリンシパルへのポリシーの割り当てについて詳しくは、アクセス ポリシーを割り当てるをご参照ください。
AKV の証明書を使用してコンテナー イメージに署名する
証明書のキー ID を取得します。 AKV 内の証明書には複数のバージョンを含めることができます。次のコマンドを使って、最新バージョン
$CERT_NAME
証明書のキー ID を取得します。KEY_ID=$(az keyvault certificate show -n $CERT_NAME --vault-name $AKV_NAME --query 'kid' -o tsv)
このキー ID を使って、COSE シグネチャ形式でこのコンテナー イメージに署名します。
証明書に証明書チェーン全体が含まれている場合は、次のコマンドを実行します。
notation sign --signature-format cose $IMAGE --id $KEY_ID --plugin azure-kv
証明書にチェーンが含まれていない場合は、
--plugin-config ca_certs=<ca_bundle_file>
パラメーターを使って PEM ファイル内の CA 証明書を AKV プラグインに渡し、次のコマンドを実行します。notation sign --signature-format cose $IMAGE --id $KEY_ID --plugin azure-kv --plugin-config ca_certs=<ca_bundle_file>
AKV で認証を実施する場合、既定では、次の資格情報の種類が有効になっていれば順番に試行されます。
資格情報の種類を指定する場合は、
credential_type
という追加のプラグイン構成を使用します。 たとえば、次に示すように、Azure CLI 資格情報を使用するようにcredential_type
をazurecli
に明示的に設定できます:notation sign --signature-format cose --id $KEY_ID --plugin azure-kv --plugin-config credential_type=azurecli $IMAGE
さまざまな資格情報の種類の
credential_type
値については、次の表を参照してください。資格情報の種類 credential_type
の値環境資格情報 environment
ワークロード ID 資格情報 workloadid
マネージド ID 資格情報 managedid
Azure CLI の資格情報 azurecli
署名されたイメージと関連する署名のグラフを表示します。
notation ls $IMAGE
次の出力例では、ダイジェスト
sha256:d7258166ca820f5ab7190247663464f2dcb149df4d1b6c4943dcaac59157de8e
によって識別される型application/vnd.cncf.notary.signature
のシグネチャが$IMAGE
に関連付けられています。myregistry.azurecr.io/net-monitor@sha256:17cc5dd7dfb8739e19e33e43680e43071f07497ed716814f3ac80bd4aac1b58f └── application/vnd.cncf.notary.signature └── sha256:d7258166ca820f5ab7190247663464f2dcb149df4d1b6c4943dcaac59157de8e
Notation CLI を使用してコンテナー イメージを確認する
シグネチャ検証のためにルート証明書を名前付き信頼ストアに追加します。 ルート証明書がない場合は、CA から取得できます。 次の例では、ルート証明書
$ROOT_CERT
を$STORE_NAME
信頼ストアに追加します。STORE_TYPE="ca" STORE_NAME="wabbit-networks.io" notation cert add --type $STORE_TYPE --store $STORE_NAME $ROOT_CERT
ルート証明書を一覧表示して、
$ROOT_CERT
が正常に追加されたことを確認します。notation cert ls
検証前に信頼ポリシーを構成します。
信頼ポリシーを使用すると、ユーザーは微調整された確認ポリシーを指定できます。 信頼ポリシーを構成するために以下のコマンドを使用します。
cat <<EOF > ./trustpolicy.json { "version": "1.0", "trustPolicies": [ { "name": "wabbit-networks-images", "registryScopes": [ "$REGISTRY/$REPO" ], "signatureVerification": { "level" : "strict" }, "trustStores": [ "$STORE_TYPE:$STORE_NAME" ], "trustedIdentities": [ "x509.subject: $CERT_SUBJECT" ] } ] } EOF
上記の
trustpolicy.json
ファイルには、wabbit-networks-images
という 1 つの信頼ポリシーが定義されています。 この信頼ポリシーは、$REGISTRY/$REPO
リポジトリに保存されているすべての成果物に適用されます。 型$STORE_TYPE
の名前付き信頼ストア$STORE_NAME
にはルート証明書が含まれています。 また、ユーザーが X.509 サブジェクト$CERT_SUBJECT
を使用して、特定の ID を信頼することも前提としています。 詳しくは、「Trust Store and Trust Policy Specification」をご参照ください。notation policy
を使って、trustpolicy.json
から信頼ポリシー構成をインポートします。notation policy import ./trustpolicy.json
信頼ポリシー構成を表示して、インポートが成功したことを確認します。
notation policy show
notation verify
を使ってイメージの整合性を確認します。notation verify $IMAGE
信頼ポリシーを使用してイメージが正常に検証されると、検証済みイメージの sha256 ダイジェストが、成功の出力メッセージで返されます。 出力の例:
Successfully verified signature for myregistry.azurecr.io/net-monitor@sha256:17cc5dd7dfb8739e19e33e43680e43071f07497ed716814f3ac80bd4aac1b58f
タイムスタンプ
Notation v1.2.0 リリース以降、Notation では RFC 3161 準拠のタイムスタンプがサポートされています。 この機能強化により、タイムスタンプ機関 (TSA) を信頼することで、証明書の有効期間内に作成された署名の信頼が延長され、証明書の有効期限が切れた後でも署名の検証が成功します。 イメージ署名者は、信頼された TSA によって生成されたタイムスタンプを使用してコンテナー イメージに署名する必要があります。 イメージ検証者は、タイムスタンプを検証するために、イメージ署名者と関連付けられている TSA の両方を信頼し、信頼ストアと信頼ポリシーを使用して信頼を確立する必要があります。 タイムスタンプにより、証明書の有効期限切れによるイメージの再署名を定期的に行う必要がなくなるため、コストを削減できます。これは、有効期間の短い証明書を使用する場合に特に重要です。 タイムスタンプを使用した署名および検証方法の詳細については、Notary Project のタイムスタンプ ガイドを参照してください。
よく寄せられる質問
証明書の有効期限が切れている場合はどうすればよいですか?
証明書の有効期限が切れている場合は、信頼された CA ベンダーから新しい証明書と新しい秘密キーを取得する必要があります。 期限切れの証明書を使用してコンテナー イメージに署名することはできません。 証明書の有効期限が切れる前に署名されたイメージの場合、タイムスタンプで署名された場合でも検証に成功する可能性があります。 タイムスタンプがない場合、署名の検証は失敗します。検証に成功するには、新しい証明書を使用してそれらのイメージにもう一度署名する必要があります。
証明書が失効している場合はどうすればよいですか?
証明書が取り消されると、署名は無効になります。 これは、秘密キーの侵害や証明書所有者の所属の変更など、いくつかの理由で発生する可能性があります。 この問題を解決するには、まず、ソース コードとビルド環境が最新で安全であることを確認する必要があります。 次に、ソース コードからコンテナー イメージをビルドし、信頼された CA ベンダーから新しい証明書と新しい秘密キーを取得し、このガイドに従って新しい証明書で新しいコンテナー イメージに署名します。
次のステップ
Notation には、Azure Pipeline と GitHub Actions ワークフロー上の CI/CD ソリューションも用意されています。
- Azure Pipeline で Notation を使用してコンテナー イメージに署名して検証する
- GitHub Actions ワークフローで Notation を使用してコンテナー イメージに署名して検証する
AKS または Kubernetes で署名されたイメージのデプロイを検証するには: