Amazon Web Services ブログ

AWS における耐量子署名、パート 1: ML-DSA によるソフトウェアサプライチェーンの構築

本ブログは 2026 年 10 月 12 日に公開された AWS Blog “Quantum-resistant signing on AWS, Part 1: Build a software supply chain with ML-DSA” を翻訳したものです。

ソフトウェアサプライチェーン攻撃は、頻度と巧妙さの両面で増しています。最近注目を集めた、ビルドシステムやオープンソースの依存関係の侵害事例は、ソフトウェアの完全性を検証する信頼メカニズムを攻撃者が標的にするケースが増えていることを示しています。こうした信頼メカニズムはデジタル署名アルゴリズムに依存しており、現在その多くが RSA (Rivest-Shamir-Adleman) や ECDSA (Elliptic Curve Digital Signature Algorithm) などの従来型のアルゴリズムを使用しています。十分に強力な量子コンピュータによってこれらの署名が偽造できるようになると、攻撃者は署名済みアーティファクトに不正なコードを挿入したり、ビルドアテステーションを捏造したり、正当な発行元になりすましたりできる可能性があります。耐量子署名を今から使用しておくことで、将来出現する可能性のある脅威に備えることができます。

米国国家安全保障局 (NSA) が公開した Commercial National Security Algorithm Suite 2.0 (CNSA 2.0) は、2025 年以降、米国国家安全保障システム (NSS) に対して、ソフトウェアとファームウェアの署名に耐量子方式を「サポートし優先する (support and prefer)」ことを求めており、2030 年までには耐量子署名のみを使用することを義務付けています。EU サイバーレジリエンス法 (CRA) は 2027 年 12 月に全面適用されます。CRA は、製品のライフサイクル全体を通じて、検証可能な形でソフトウェアの完全性を維持することを製造業者に求めています。米国連邦機関にソフトウェアを提供する組織や欧州市場で製品を販売する組織は、時期が重なる複数の期限に直面しており、今すぐ対応を始める必要があります。

Amazon Web Services (AWS) は、本番環境に対応した一般提供済みのサービスで、耐量子ソフトウェアサプライチェーンを今すぐ構築するための構成要素を提供しています。この記事では、ML-DSA (Module-Lattice-Based Digital Signature Algorithm) キーを AWS Key Management Service (AWS KMS) で、ML-DSA 証明書階層を AWS Private Certificate Authority で、ML-DSA トラストアンカーを AWS Identity and Access Management (IAM) Roles Anywhere で用意し、それらを組み合わせて、バイナリ、コンテナイメージ、ソフトウェア部品表 (SBOM) を対象とするエンドツーエンドの署名アーキテクチャを構築する方法を紹介します。

この記事は、NIST FIPS 204 で標準化された ML-DSA 署名を AWS で導入するための 2 部構成シリーズのパート 1 です。2026 年 10 月時点で、このシリーズは、ML-DSA の信頼のルート (root of trust) の確立から組織全体でのアルゴリズムポリシーの適用まで、ソフトウェアサプライチェーン全体にわたる耐量子署名を扱うエンドツーエンドのガイドとして、クラウドプロバイダーが提供する初めてのものです。パート 1 はビルダー向けで、署名パイプラインの構築と運用の手順を説明します。パート 2「SCP と IAM による ML-DSA アルゴリズムポリシーの強制」はセキュリティチームとガバナンスチーム向けで、ここで選択したアルゴリズムを、組織全体にわたる予防的コントロールと発見的コントロールに落とし込む方法を紹介します。

「今収集し、後で偽造する (harvest now, forge later)」脅威を理解する

暗号解読能力を持つ量子コンピュータ (CRQC) が実現すると、現在の公開鍵暗号の安全性を支えている数学的問題を効率的に解けるようになります。計算量の多さから現在は現実的でない攻撃も、CRQC を使用すれば一気に現実的なものになります。ポスト量子暗号 (PQC) に関する議論のほとんどは、データの機密性に対する「今収集し、後で復号する (harvest now, decrypt later)」脅威に焦点を当てています。転送中のデータを保護する非対称鍵は CRQC を使用すれば効率的に導出できるため、保護されるはずだったデータが露呈してしまいます。デジタル署名も、非対称暗号と同じ数学的問題に依存しており、CRQC が実現すればその安全性は破られます。つまり、ソフトウェアサプライチェーンも、機密性ではなく完全性を標的とする同様の脅威にさらされています。署名済みアーティファクトを今のうちに記録しておいた攻撃者は、将来 CRQC を使用して、まったく別のアーティファクトに対する署名を偽造できます。

2026 年に ECDSA P-256 で署名され、組み込みデバイスのフリートにデプロイされたファームウェアを例に考えてみましょう。これらのデバイスは、15 年間の運用期間中、起動のたびにファームウェアの署名を検証します。また、デプロイ後に再署名のために回収することはできません。2035 年に CRQC が稼働した場合、攻撃者は改ざんしたファームウェアに対して有効に見える署名を作成でき、フリート内のすべてのデバイスが次回の再起動時にそれを本物として受け入れてしまいます。ソフトウェアの完全性を検証する主な手段として古典的なデジタル署名に依存している組織にとって、これは検証チェーンの重要な部分が弱体化することを意味します。CNSA 2.0 がデジタル署名に厳しいタイムラインを定めているのはこのためです。今日署名するアーティファクトは、運用期間全体にわたって信頼できる状態を維持しなければなりません。

ML-DSA は、古典コンピュータと量子コンピュータのどちらからの攻撃にも耐えられるように設計されています。AWS KMS、AWS Private CA、AWS IAM Roles Anywhere はいずれも ML-DSA をサポートしているため、追加のツールなしで、サプライチェーン全体にわたって将来の署名偽造の脅威に今すぐ対処できます。

アーキテクチャの概要: 耐量子サプライチェーンの 5 つの柱

このアーキテクチャは、連携してソフトウェアデリバリーパイプラインを保護する 5 つの信頼の柱で構成されています。

  1. AWS KMS での ML-DSA キー管理 – すべての署名キーは、FIPS 140-3 セキュリティレベル 3 のハードウェアセキュリティモジュール (HSM) で生成、保護されます。プライベートキーが HSM の境界の外に出ることはありません。
  2. AWS Private CA による ML-DSA 公開鍵基盤 (PKI) – 証明書階層 (ルート CA、下位 CA、エンドエンティティ証明書) によって ML-DSA パブリックキーをアイデンティティにバインドし、誰が何に署名したかを明確にします。CA のプライベートキーは、サービスが管理するハードウェア保護された HSM で生成、保存され、HSM の境界の外に出ることはありません。
  3. 耐量子ワークロードアイデンティティ (外部ビルドエージェント向け) – AWS の外部で実行され、X.509 証明書で認証する継続的インテグレーションと継続的デリバリー (CI/CD) エージェントについては、ML-DSA 証明書を使用する IAM Roles Anywhere によって、署名者のアイデンティティを同じ耐量子の信頼のルートに結び付けます。
  4. ML-DSA アーティファクト署名 – ビルド出力 (バイナリ、コンテナイメージのマニフェスト、パッケージ) には、AWS KMS の ML-DSA キーで署名します。署名はアーティファクトと一緒に Amazon Simple Storage Service (Amazon S3) または Amazon Elastic Container Registry (Amazon ECR) に保存します。
  5. ML-DSA SBOM 完全性アテステーション – 各リリースの SBOM を、記述対象のアーティファクトをダイジェストで指定する in-toto Statement でラップし、その Statement に同じ ML-DSA コード署名キーで署名します。これにより、依存関係のマニフェストが改ざんされていないこと、そして添付先のアーティファクトに対応するものであることを、耐量子の方式で証明できます。

これらの柱によって信頼のチェーンが形成されます。AWS Private CA は自身の HSM でルート CA キーを保護し、アイデンティティを AWS KMS のコード署名キーにバインドする証明書を発行します。IAM Roles Anywhere はそれらの証明書を使用してビルドエージェントを認証し、認証されたエージェントは、自身が生成するすべてのアーティファクトと SBOM に署名します。

Figure 1: End-to-end quantum-resistant software supply chain on AWS

図 1: AWS におけるエンドツーエンドの耐量子ソフトウェアサプライチェーン

図 1 では、このアーキテクチャを 4 つのレイヤーに分け、構築する順に番号を付けて示しています。

  1. 信頼のルート (柱 1 と 2) – AWS Private CA の階層を確立し、AWS KMS でコード署名キーを作成します。
  2. ワークロードアイデンティティ (柱 3) – CA を IAM Roles Anywhere のトラストアンカーとして登録し、ビルドエージェントに ML-DSA 証明書を発行します。これにより、署名者のアイデンティティを同じ耐量子の信頼のルートまでたどれるようにします。
  3. アーティファクト署名 (柱 4 と 5) – 認証されたビルドエージェントを使用して、バイナリ、コンテナイメージ、SBOM に署名します。
  4. 検証と適用 – デプロイ時に署名を検証し、ML-DSA のみを許可するポリシーを適用します。

前提条件

この手順を実行するには、以下が必要です。

  • AWS KMS、AWS Private CA、IAM Roles Anywhere、Amazon ECR でリソースを作成する権限を持つ AWS アカウント。
  • AWS Command Line Interface (AWS CLI) v2 (適切な認証情報を設定済みのもの)。
  • ワークロードの認証に使用する IAM Roles Anywhere 認証情報ヘルパー (aws_signing_helper) v1.8.0 以降。ML-DSA キーと証明書に対応した最初のリリースです。IAM Roles Anywhere のドキュメントからダウンロードできます。
  • OpenSSL 3.5 以降 (ML-DSA 署名の検証と mu の計算に必要)。
  • ORAS CLI v1.2 以降 (コンテナイメージに Open Container Initiative (OCI) リファラーアーティファクトを添付するために使用)。代わりに、カスタムプラグインを使用した Notation CLI や、OCI Referrers API をサポートする任意の OCI 準拠クライアントを使用することもできます。
  • jq (SBOM アテステーションに使用する in-toto Statement の作成と解析、および ORAS 出力の解析に使用)。
  • SBOM の例で使用する Amazon Inspector SBOM Generator (Sbomgen)、または CycloneDX JSON 形式の SBOM を生成できる別のツール。Sbomgen は Linux (x86-64 および ARM64) でのみ動作するため、該当する手順は Linux のビルドエージェントまたはコンテナで実行してください。Sbomgen は、oras login が Docker の設定ファイルに保存したレジストリ認証情報を使用します。--username オプション、または INSPECTOR_SBOMGEN_USERNAME と INSPECTOR_SBOMGEN_PASSWORD の環境変数で認証情報を渡すこともできます。
  • Java 11 以降と Apache Maven (「ML-DSA PKI 基盤の構築」のステップ 4 で、コード署名用の証明書署名リクエスト (CSR) を生成する diy-code-signing-kms-private-ca サンプルの実行に使用)。
  • Amazon ECR にプッシュ済みのコンテナイメージ (コンテナ署名の例で使用)。

ML-DSA PKI 基盤の構築

まず、サプライチェーンの信頼の基点となる証明書階層を作成します。AWS Private CA では、認証機関 (CA) を作成すると、その CA の署名キーがハードウェア保護された HSM 内で生成、保存されます。ルート CA には ML-DSA-87 (NIST セキュリティカテゴリ 5。AES-256 の全数鍵探索と同等以上に破ることが困難であると定義されています) を使用します。これは、最も長期間使用されるトラストアンカーであるルート CA を保護するためです。下位 CA には ML-DSA-65 (NIST セキュリティカテゴリ 3) を使用し、頻繁に発行される証明書の署名サイズを抑えつつ、セキュリティとのバランスを取ります。

ここで使用するパラメータセット ML-DSA-87 と ML-DSA-65 は、このシリーズのパート 2 で強制可能なコントロールに落とし込むアルゴリズムポリシーの例でも、承認済みのセットとして使われています。組織で別のセットを標準として採用している場合は、以降のコマンド内のパラメータセットをそのセットに置き換えてください。ビルド手順自体は変わりません。

ステップ 1: AWS Private CA でルート CA を作成する

KeyAlgorithm: ML_DSA_87 を指定すると、Private CA が内部で ML-DSA-87 キーペアを生成します。CA 用に別途 AWS KMS キーを作成する必要はありません。

aws acm-pca create-certificate-authority \
  --certificate-authority-configuration '{
    "KeyAlgorithm": "ML_DSA_87",
    "SigningAlgorithm": "ML_DSA_87",
    "Subject": {
      "CommonName": "PQC Supply Chain Root CA",
      "Organization": "Example Corp",
      "Country": "US"
    }
  }' \
  --certificate-authority-type ROOT

作成直後のルート CA は PENDING_CERTIFICATE 状態です。証明書に自己署名してアクティブ化します。ルート CA の有効期間はこの手順で設定します (ルート CA では 10 年が一般的です)。

# Retrieve the root CA's CSR
aws acm-pca get-certificate-authority-csr \
  --certificate-authority-arn <root-ca-arn> \
  --output text > root-ca.csr

# Self-sign the root CA certificate (valid for 10 years)
ROOT_CERT_ARN=$(aws acm-pca issue-certificate \
  --certificate-authority-arn <root-ca-arn> \
  --csr fileb://root-ca.csr \
  --signing-algorithm ML_DSA_87 \
  --validity Value=3650,Type=DAYS \
  --template-arn arn:aws:acm-pca:::template/RootCACertificate/V1 \
  --query CertificateArn --output text)

# Retrieve and install the self-signed root certificate
aws acm-pca get-certificate \
  --certificate-authority-arn <root-ca-arn> \
  --certificate-arn $ROOT_CERT_ARN \
  --query Certificate --output text > root-ca-cert.pem

aws acm-pca import-certificate-authority-certificate \
  --certificate-authority-arn <root-ca-arn> \
  --certificate fileb://root-ca-cert.pem

ステップ 2: コード署名用の下位 CA を作成する

aws acm-pca create-certificate-authority \
  --certificate-authority-configuration '{
    "KeyAlgorithm": "ML_DSA_65",
    "SigningAlgorithm": "ML_DSA_65",
    "Subject": {
      "CommonName": "PQC Code Signing CA",
      "Organization": "Example Corp",
      "Country": "US"
    }
  }' \
  --certificate-authority-type SUBORDINATE

作成直後の下位 CA は PENDING_CERTIFICATE 状態で、まだルートとはリンクされていません。下位 CA の CSR にルート CA で署名して、アクティブ化します。

# Retrieve the subordinate CA's certificate signing request
aws acm-pca get-certificate-authority-csr \
  --certificate-authority-arn <sub-ca-arn> \
  --output text > sub-ca.csr

# Sign the CSR using the root CA (this establishes the trust hierarchy)
SUB_CERT_ARN=$(aws acm-pca issue-certificate \
  --certificate-authority-arn <root-ca-arn> \
  --csr fileb://sub-ca.csr \
  --signing-algorithm ML_DSA_87 \
  --validity Value=1825,Type=DAYS \
  --template-arn arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen0/V1 \
  --query CertificateArn --output text)

# Retrieve the signed certificate and import it to activate the subordinate CA
aws acm-pca get-certificate \
  --certificate-authority-arn <root-ca-arn> \
  --certificate-arn $SUB_CERT_ARN \
  --query Certificate --output text > sub-ca-cert.pem

aws acm-pca import-certificate-authority-certificate \
  --certificate-authority-arn <sub-ca-arn> \
  --certificate fileb://sub-ca-cert.pem \
  --certificate-chain fileb://root-ca-cert.pem

ステップ 3: AWS KMS でコード署名キーを作成する

ビルドエージェントはこのキーでアーティファクトに署名するため、ビルドエージェントの IAM ロールには、このキーに対する kms:Sign 権限が必要です。下位 CA が発行するエンドエンティティ証明書によって、アイデンティティがこのキーのパブリックキーにバインドされます。

aws kms create-key \
  --key-spec ML_DSA_65 \
  --key-usage SIGN_VERIFY \
  --description "PQC code-signing key for supply chain" \
  --tags TagKey=Purpose,TagValue=CodeSigning

CI/CD スクリプトから参照しやすいように、エイリアスを作成します。

aws kms create-alias \
  --alias-name alias/pqc-code-signing \
  --target-key-id <key-id-from-above>

ステップ 4: エンドエンティティのコード署名証明書を発行する

証明書を発行するには CSR が必要です。ML-DSA プライベートキーは AWS KMS の HSM の外に出ないため、OpenSSL を使用してローカルで CSR を生成することはできません。代わりに、サブジェクト名とパブリックキーを含む CSR の TBS (to-be-signed) 構造を作成し、aws kms sign を呼び出してリモートで署名したうえで、それらを組み合わせて最終的な CSR を作成します。

AWS KMS で管理されるプライベートキーを使用して ML-DSA CSR を作成し、AWS KMS で署名する実装例については、「AWS Private CA と AWS KMS を使用したポスト量子 (ML-DSA) コード署名」と、GitHub で公開されている diy-code-signing-kms-private-ca サンプル (Java、Maven でビルド) を参照してください。この手順は AWS CLI だけでは完結しません。CSR はコードで作成して署名する必要があり、このサンプルがそのリファレンス実装です。

code-signing.csr ファイルが用意できたら、下位 CA から証明書を発行します。

# Issue a code-signing certificate valid for one year, signed by the subordinate CA using ML-DSA-65.
# Replace <sub-ca-arn> with the ARN that create-certificate-authority returned for the subordinate CA in Step 2.
CODE_SIGNING_CERT_ARN=$(aws acm-pca issue-certificate \
  --certificate-authority-arn <sub-ca-arn> \
  --csr fileb://code-signing.csr \
  --signing-algorithm ML_DSA_65 \
  --validity Value=365,Type=DAYS \
  --template-arn arn:aws:acm-pca:::template/CodeSigningCertificate/V1 \
  --query CertificateArn --output text)

# Retrieve the issued certificate
aws acm-pca get-certificate \
  --certificate-authority-arn <sub-ca-arn> \
  --certificate-arn $CODE_SIGNING_CERT_ARN \
  --query Certificate --output text > code-signing-cert.pem

この証明書によって、署名者のアイデンティティが AWS KMS のコード署名キーマテリアルにバインドされます。なお、検証者が証明書の確認だけで署名を検証できる期間は、証明書の有効期間 (この例では 365 日) で決まります。AWS Private CA では、発行元 CA 自身の証明書の有効期限を超えない範囲で、発行する証明書の有効期間を自由に選択できます。この例では、ステップ 2 で作成した下位 CA 証明書の有効期間が 1,825 日であるため、後述の 3 年のオプションもその範囲内に収まります。証明書の有効期限が切れた後も検証できる状態を維持する必要があるアーティファクトについては、次のアプローチを検討してください。

  • 証明書の有効期間の延長 – プライベート PKI では発行ポリシーを自組織で管理できるため、コード署名証明書を複数年の有効期間 (例えば、Value=1095,Type=DAYS で 3 年) で発行するのが一般的です。
  • 信頼されたタイムスタンプ (RFC 3161) – 署名時に、タイムスタンプ局 (TSA) から取得した RFC 3161 タイムスタンプで各署名に副署します。タイムスタンプによって、証明書の有効期間中に署名が作成されたことが証明されるため、無期限に検証できるようになります。AWS はマネージド TSA を提供していないため、サードパーティの TSA を使用するか、独自の TSA を運用してください。
  • 再署名 – 証明書の有効期限が切れる前に、新しく発行した証明書で、現在使用中のアーティファクトに再署名します。

署名を検証する必要があるシステムに、証明書チェーン (ルート CA 証明書、下位 CA 証明書、エンドエンティティ証明書) を配布します。

CI/CD パイプラインでの ML-DSA によるアーティファクトの署名

PKI 階層の準備ができたら、ML-DSA 署名をビルドプロセスに組み込みます。方法はアーティファクトの種類によって異なります。ML-DSA-65 の署名サイズは 3,309 バイト (ECDSA P-256 では 64 バイト) ですが、ML-DSA に対する AWS KMS の Sign オペレーションのレイテンシーは、既存の非対称オペレーションと同程度です。署名サイズの増加は、数メガバイトのコンテナイメージやパッケージと一緒に保存する場合にはほとんど影響しません。ただし、低帯域幅のリンク経由で送信される組み込みデバイスイメージなど、サイズに制約のある環境では考慮しておく必要があります。

バイナリとパッケージの署名

コンパイル済みのバイナリやパッケージなど、ほとんどのビルド出力は、aws kms sign に渡すメッセージに対して AWS KMS が設けている 4,096 バイトの上限をはるかに超えるサイズです。パイプラインのデフォルトには EXTERNAL_MU メソッドを使用してください。この方法では、OpenSSL 3.5 を使用して 64 バイトのメッセージ代表値 (mu) を外部で計算し、mu だけを AWS KMS に渡します。任意のサイズのアーティファクトを処理でき、アーティファクトが大きくなっても変更は不要です。AWS KMS では、--message-type RAW を使用して、最大 4,096 バイトまでのコンテンツを直接渡すこともできます。ただし、RAW は、後述のコンテナイメージの例で扱う 71 文字のマニフェストダイジェストのように、構造上サイズが固定されている入力にのみ使用してください。現時点で上限に収まるアーティファクトでも、いずれ上限を超える可能性が高く、その時点で RAW に依存しているパイプラインは失敗します。どちらの方法でも、暗号学的に同一の署名が生成されます。検証者はどちらの方法が使用されたかを知る必要はなく、いずれの場合も標準的な ML-DSA 検証を適用できます。

# Retrieve the public key
aws kms get-public-key --key-id alias/pqc-code-signing \
  --query PublicKey --output text | base64 --decode > pk.der

# Extract raw public key bytes from the DER-encoded SubjectPublicKeyInfo.
# The BIT STRING starts at offset 17 for all ML-DSA key sizes. 
# Expected output: 1,312 bytes (ML-DSA-44), 1,952 bytes (ML-DSA-65), or 2,592 bytes (ML-DSA-87).

openssl asn1parse -inform DER -in pk.der -strparse 17 -noout -out pk_raw.bin

# Compute mu per FIPS 204 Section 6.2
printf '\x00\x00' | cat - artifact.bin > m_prime.bin
openssl dgst -shake256 -xoflen 64 -binary pk_raw.bin > pk_hash.bin
cat pk_hash.bin m_prime.bin | openssl dgst -shake256 -xoflen 64 -binary > mu.bin

# Sign the mu value
aws kms sign \
  --key-id alias/pqc-code-signing \
  --message fileb://mu.bin \
  --message-type EXTERNAL_MU \
  --signing-algorithm ML_DSA_SHAKE_256 \
  --query Signature --output text | base64 --decode > artifact.bin.sig

.sig ファイルは、アーティファクトと一緒に Amazon S3 またはパッケージリポジトリに保存します。アーティファクトと署名の両方の完全性を保護するために、S3 Object Lock (WORM 保護) を有効にするか、少なくとも書き込みアクセスを制限したうえで S3 バージョニングを有効にしてください。攻撃者がどちらかのファイルを変更または削除できる状態では、検証結果を信頼できません。包括的なガイダンスについては、「Amazon S3 のセキュリティのベストプラクティス」を参照してください。

コンテナイメージの署名

コンテナイメージの署名には、OCI Image and Distribution Specifications v1.1 で定義されている OCI リファラーパターンを使用します。リファラーとは、署名や SBOM などのアーティファクトのうち、そのマニフェストの subject フィールドで別のイメージを指定しているものです。Amazon ECR をはじめ、このパターンをサポートするレジストリは、クライアントがイメージのリファラーを要求すると、これらのアーティファクトを返します。この方法では、AWS KMS の ML-DSA キーで署名を生成し、それをイメージのリファラーとして保存します。

# Repository URI used by ORAS here and in the SBOM steps; replace the account ID and Region
ECR_URI=111122223333.dkr.ecr.us-east-1.amazonaws.com/myapp

# Authenticate ORAS to Amazon ECR
aws ecr get-login-password --region us-east-1 | \
  oras login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com

# Get the image manifest digest
IMAGE_DIGEST=$(aws ecr batch-get-image \
  --repository-name myapp \
  --image-ids imageTag=v1.2.0 \
  --query 'images[0].imageId.imageDigest' --output text)

# Sign the digest. It is a fixed 71 characters, so RAW is safe here (see Binary and package signing).
# AWS CLI v2 expects blob parameters to be base64, so write the digest to a file and pass it with fileb://
echo -n "$IMAGE_DIGEST" > digest.txt
aws kms sign \
  --key-id alias/pqc-code-signing \
  --message fileb://digest.txt \
  --message-type RAW \
  --signing-algorithm ML_DSA_SHAKE_256 \
  --query Signature --output text | base64 --decode > image.mldsa.sig

# Attach signature as OCI referrer using ORAS
oras attach $ECR_URI@$IMAGE_DIGEST \
  --artifact-type "application/vnd.example.mldsa-signature.v1" \
  image.mldsa.sig:application/octet-stream

デプロイ時には、アドミッションコントローラーがリファラーアーティファクトを取得して ML-DSA 署名を検証し、その後でイメージの実行を許可します。検証ワークフロー全体とアドミッションコントロールの実装については、この記事の後半にある「デプロイ前のコンテナイメージ署名の検証」を参照してください。

SBOM の署名

SBOM は、ソフトウェアリリースに含まれるすべてのコンポーネント、ライブラリ、依存関係をまとめた構造化インベントリです。パッケージ名、バージョン、サプライヤー、依存関係を記載します。組織は SBOM を使用して脆弱性の追跡やライセンスコンプライアンスの検証を行い、侵害されたコンポーネントが公表された際に迅速に対応します。

SBOM ファイルだけに署名した場合、署名後にインベントリが改ざんされていないことは証明できますが、そのインベントリがどのアーティファクトを記述しているかは証明できません。イメージの署名と SBOM の署名が互いに独立していると、クリーンなイメージに対して正当に署名された SBOM を手に入れた攻撃者は、それを別の署名済みイメージに添えて提示し、両者が対応していると主張できてしまいます。SBOM を OCI リファラーとしてイメージに添付するだけでは、このギャップは解消されません。リファラーマニフェストの subject フィールドはリファラーをプッシュする人が設定するものであり、関連するアーティファクトを見つけるための仕組みにすぎず、暗号学的なバインドではないためです。バインドは、署名の対象となるバイト列の中に含める必要があります。

このバインドを実現するには、署名の前に SBOM を in-toto Statement でラップします。Statement は、記述対象のアーティファクトを subject フィールドでダイジェストにより指定し、SBOM を predicate として保持します。イメージマニフェストのダイジェストが署名対象のコンテンツに含まれるため、検証者は手元の SBOM が、これからデプロイするイメージに対して発行されたものであることを確認できます。SBOM やダイジェストが差し替えられていれば、検証は失敗します。イメージのファイルシステムに SBOM を埋め込むと、イメージダイジェストが SBOM のバイト列もカバーするようになるため、この方法でも両者をバインドできます。この記事で Statement を使う方法を採用しているのは、完成したイメージをスキャンして生成した SBOM、バイナリやファームウェアなどファイルシステムを持たないアーティファクト、既にレジストリにあるイメージのいずれにも適用でき、さらにイメージをプルしなくてもレジストリから SBOM を読み取れるためです。

任意のツール (コンテナイメージの場合は Amazon Inspector SBOM Generator (Sbomgen) など) で SBOM を生成して Statement でラップし、バイナリと同じ EXTERNAL_MU の手順で Statement に署名します。

# Scan the pushed image by digest so the inventory describes exactly the manifest you signed.
# Sbomgen reuses the registry login from the oras login step in the previous section.
inspector-sbomgen container --image $ECR_URI@$IMAGE_DIGEST -o sbom.json

# Wrap the SBOM in an in-toto Statement whose subject is the image manifest digest.
# This puts the digest inside the signed bytes, which binds this SBOM to this image.
jq -n \
  --arg name "$ECR_URI" \
  --arg digest "${IMAGE_DIGEST#sha256:}" \
  --slurpfile sbom sbom.json \
  '{
    "_type": "https://in-toto.io/Statement/v1",
    "subject": [{"name": $name, "digest": {"sha256": $digest}}],
    "predicateType": "https://cyclonedx.org/bom",
    "predicate": $sbom[0]
  }' > sbom.statement.json

# Sign using EXTERNAL_MU (same mu computation as binary signing above,
# with sbom.statement.json as the input)
# ... compute mu from sbom.statement.json ...
aws kms sign \
  --key-id alias/pqc-code-signing \
  --message fileb://mu.bin \
  --message-type EXTERNAL_MU \
  --signing-algorithm ML_DSA_SHAKE_256 \
  --query Signature --output text | base64 --decode > sbom.statement.json.sig

# Attach the Statement and its signature to the image as an OCI referrer so
# verifiers discover them alongside the image signature
oras attach $ECR_URI@$IMAGE_DIGEST \
  --artifact-type "application/vnd.example.mldsa-sbom-attestation.v1" \
  sbom.statement.json:application/vnd.in-toto+json \
  sbom.statement.json.sig:application/octet-stream

Statement とその .sig ファイルは必ずセットで配布してください。SBOM 自体は Statement の predicate フィールドに格納されており、検証者は検証後にそれを抽出します。同じパターンで、SBOM をバイナリやパッケージにバインドすることもできます。その場合は、イメージマニフェストのダイジェストの代わりに、ファイルの SHA-256 をサブジェクトダイジェストに設定します。バインドを完結させるサブジェクトの確認を含めた検証ワークフロー全体については、この記事の後半にある「バイナリまたは SBOM の署名の検証」セクションで説明します。

ビルドエージェント用の耐量子ワークロードアイデンティティ

ML-DSA キーによるアーティファクトの署名で保護できるのは、アーティファクト自体の完全性です。これとは別に、AWS の外部で実行されるビルドエージェント (オンプレミスの Jenkins、セルフホスト型の GitHub Actions ランナー、サードパーティの CI/CD システム) は、通常 RSA や ECDSA で署名された X.509 証明書や OIDC トークンを使用して認証します。これらの認証情報は、パイプラインにおける古典暗号への依存となります。ML-DSA 証明書を使用する IAM Roles Anywhere は、この依存を解消します。外部のビルドエージェントが提示する認証情報も、それを保証する CA も、量子攻撃に脆弱なアルゴリズムに依存しなくなります。(リクエストを伝送する TLS 接続では、現在のパブリック TLS と同様に、引き続き従来型の証明書で AWS エンドポイントが認証されます。これはトランスポート層の問題であり、この記事で扱う署名アイデンティティとは別のものです。) IAM ロールがアタッチされ、AWS 上で実行されるビルドエージェントには、この依存はありません。こうしたビルドエージェントの API リクエストは AWS Signature Version 4 (SigV4) で認証されます。SigV4 は、対称方式のハッシュベースメッセージ認証コード (HMAC-SHA256) を使用します。このような対称方式は既に耐量子であると考えられているため、追加の対応は必要ありません。

ステップ 1: ワークロードアイデンティティ用の CA をトラストアンカーとして登録する

このウォークスルーでは、前の手順で作成した下位 CA を再利用します。こうすることで、2 つ目の CA の月額料金を避けられます。以降のコマンドも、この CA を前提としています。本番環境では、コード署名用の CA とは別に、ワークロードアイデンティティ証明書専用の下位 CA を使用してください。これにより、いずれかの CA が侵害されて失効させる必要が生じた場合の影響範囲を限定でき、2 種類の証明書にそれぞれ異なる発行ポリシーを適用できます。

# Use the ARN that create-certificate-authority returned when you created the
# subordinate CA earlier. If you no longer have it, list your CAs and copy the
# ARN of the SUBORDINATE one.
aws acm-pca list-certificate-authorities \
  --query "CertificateAuthorities[?Type=='SUBORDINATE'].[Arn,Status,CertificateAuthorityConfiguration.Subject.CommonName]" \
  --output table
SUB_CA_ARN=arn:aws:acm-pca:us-east-1:111122223333:certificate-authority/abc-123   # replace with yours

# Register the subordinate CA as an IAM Roles Anywhere trust anchor
aws rolesanywhere create-trust-anchor \
  --name "PQC-CI-CD-Trust-Anchor" \
  --source "sourceType=AWS_ACM_PCA,sourceData={acmPcaArn=$SUB_CA_ARN}" \
  --enabled

ステップ 2: ビルドエージェントのロールと、それを参照するプロファイルを作成する

IAM Roles Anywhere プロファイルでは、トラストアンカーとして登録した CA が発行した証明書で認証したワークロードが引き受けられる IAM ロールを指定します。まず、ロールを作成します。ロールの信頼ポリシーでは、IAM Roles Anywhere がロールを引き受けられる条件を、トラストアンカー経由であること、かつサブジェクトのコモンネームがビルドエージェントを示す証明書であることに限定します。これらの条件がないと、トラストアンカーの CA が発行したどの証明書でもロールを引き受けられてしまいます。ロールのアクセス許可ポリシーでは、署名に必要な権限だけを、コード署名キーに対してのみ付与します。信頼ポリシーを build-agent-trust.json として保存し、トラストアンカーの ARN を、ステップ 1 で create-trust-anchor が返した ARN に置き換えます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"Service": "rolesanywhere.amazonaws.com"},
      "Action": ["sts:AssumeRole", "sts:TagSession", "sts:SetSourceIdentity"],
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:rolesanywhere:us-east-1:111122223333:trust-anchor/ta-id"
        },
        "StringEquals": {
          "aws:PrincipalTag/x509Subject/CN": "pqc-build-agent-01"
        }
      }
    }
  ]
}

アクセス許可ポリシーを build-agent-permissions.json として保存し、リソースをキーの ARN に置き換えます (ARN は aws kms describe-key --key-id alias/pqc-code-signing --query KeyMetadata.Arn --output text で確認できます)。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["kms:Sign", "kms:GetPublicKey", "kms:DescribeKey"],
      "Resource": "<code-signing-key-arn>"
    }
  ]
}

ロールを作成してポリシーをアタッチし、そのロールを参照するプロファイルを作成します。

aws iam create-role \
  --role-name PQCBuildAgentRole \
  --assume-role-policy-document file://build-agent-trust.json

aws iam put-role-policy \
  --role-name PQCBuildAgentRole \
  --policy-name pqc-code-signing \
  --policy-document file://build-agent-permissions.json

aws rolesanywhere create-profile \
  --name "PQC-Build-Agent-Profile" \
  --role-arns "arn:aws:iam::111122223333:role/PQCBuildAgentRole" \
  --enabled

ステップ 3: ビルドエージェントの証明書を発行し、認証情報ヘルパーを設定する

OpenSSL を使用してビルドエージェントの ML-DSA-65 キーペアと CSR をローカルで生成し、下位 CA からクライアント認証証明書を発行します。その後、その証明書を提示するように IAM Roles Anywhere 認証情報ヘルパーを設定します。

# Generate the build agent's key pair and CSR. The CN must match the
# aws:PrincipalTag/x509Subject/CN condition in the role's trust policy.
openssl genpkey -algorithm ML-DSA-65 -out build-agent-mldsa-key.pem
chmod 400 build-agent-mldsa-key.pem
openssl req -new -key build-agent-mldsa-key.pem \
  -subj "/C=US/O=Example Corp/CN=pqc-build-agent-01" \
  -out build-agent.csr

# Issue a 30-day client authentication certificate from the subordinate CA
# registered as the trust anchor in Step 1.
BUILD_AGENT_CERT_ARN=$(aws acm-pca issue-certificate \
  --certificate-authority-arn $SUB_CA_ARN \
  --csr fileb://build-agent.csr \
  --signing-algorithm ML_DSA_65 \
  --validity Value=30,Type=DAYS \
  --template-arn arn:aws:acm-pca:::template/EndEntityClientAuthCertificate/V1 \
  --query CertificateArn --output text)

aws acm-pca get-certificate \
  --certificate-authority-arn $SUB_CA_ARN \
  --certificate-arn $BUILD_AGENT_CERT_ARN \
  --query Certificate --output text > build-agent-mldsa.pem

# In production, store the private key in a TPM or HSM rather than as a plaintext file.
aws_signing_helper credential-process \
  --certificate build-agent-mldsa.pem \
  --private-key build-agent-mldsa-key.pem \
  --trust-anchor-arn arn:aws:rolesanywhere:us-east-1:111122223333:trust-anchor/ta-id \
  --profile-arn arn:aws:rolesanywhere:us-east-1:111122223333:profile/profile-id \
  --role-arn arn:aws:iam::111122223333:role/PQCBuildAgentRole

ヘルパーは、ビルドロールに権限が限定された短期間有効な AWS Security Token Service (AWS STS) の認証情報を生成するため、長期間有効な AWS アクセスキーが不要になります。本番環境では、Trusted Platform Module (TPM)、HSM、ファイルのアクセス許可を制限した暗号化認証情報ストアなど、ハードウェアベースのストレージで ML-DSA プライベートキーを保護してください。ここで示しているプレーンテキストファイルのパスは、デモンストレーション用です。このプライベートキーはコード署名インフラストラクチャへのアクセスを認可するものなので、他の署名キーと同等のレベルで保護する必要があります。Linux のビルドエージェントでは、少なくともファイルの所有者をサービスアカウントにしたうえで、chmod 400 でアクセスを制限してください。また、PKCS#11 プロバイダーを使用して、未加工のキーをディスクに一切保存しない構成も検討してください。

検証とポリシーの適用

署名アーキテクチャの強さは、検証の強さで決まります。署名を生成するだけでは全体の半分にすぎません。残りの半分は、デプロイパイプライン、Kubernetes のアドミッションコントローラー、パッケージをインストールするエンジニアなど、アーティファクトをデプロイするシステムや人に対して、アーティファクトのデプロイや実行の前に署名を検証し、信頼できるかどうかを判断するための具体的な手段を提供することです。

信頼チェーンの配布

検証者が署名を確認するには、まずコード署名証明書を発行した CA を信頼している必要があります。この信頼はトラストストアによって確立されます。トラストストアとは、システムが信頼できるものとして扱うルート CA 証明書をローカルにまとめたものです。トラストストアは、オペレーティングシステム (Linux の /etc/pki/ca-trust/、macOS の Keychain など)、言語ランタイム (Java の cacerts)、コンテナベースイメージ、カスタムアプリケーションの設定などに存在します。

この記事で構築するようなプライベート PKI 階層の場合、ルート CA 証明書はデフォルトのパブリックトラストストアには含まれていません。署名を検証するすべてのシステムのトラストストアに、ルート CA 証明書を明示的に追加する必要があります。一般的な方法は次のとおりです。

  • ビルドプロセスでルート CA 証明書をコンテナベースイメージに組み込む
  • 構成管理 (AWS Systems Manager Parameter Store、AWS Secrets Manager、または既存の構成ツール) を通じて配布する
  • バージョニングとアクセスログ記録を有効にした内部の S3 バケットで公開する
  • 保護対象のイメージと一緒に、OCI アーティファクトとして Amazon ECR に保存する

トラストストアの管理は、認証情報の管理と同じくらい厳密に行ってください。攻撃者が不正なルート証明書をトラストストアに挿入できれば、偽造した署名を有効に見せかけることができてしまいます。トラストストアへの書き込みアクセスを制限し、AWS CloudTrail またはシステムレベルの監査ログで変更を監査してください。

証明書チェーンをエクスポートするには、ルート CA に加えて、署名の検証に関係する証明書を発行する下位 CA をエクスポートします。

# Export the root CA certificate
aws acm-pca get-certificate-authority-certificate \
  --certificate-authority-arn <root-ca-arn> \
  --query Certificate --output text > root-ca.pem

# Export the subordinate CA certificate. Select only the Certificate field: for a
# subordinate CA this call also returns CertificateChain, and --output text would
# print both on one tab-separated line, producing a file that OpenSSL can't parse.
aws acm-pca get-certificate-authority-certificate \
  --certificate-authority-arn <sub-ca-arn> \
  --query Certificate --output text > sub-ca.pem
  
# Bundle the full chain for verifiers
cat root-ca.pem sub-ca.pem > trust-chain.pem

検証者はこのチェーンを使用して、コード署名のパブリックキーが信頼できる CA によって発行されたものであることを確認します。

ウォークスルーを簡潔にするため、この記事の CA は失効設定なしで作成しており、以降の検証コマンドでも失効ステータスは確認しません。本番環境では、下位 CA に証明書失効リスト (CRL) または OCSP (Online Certificate Status Protocol) レスポンダーを設定してください (AWS Private CA ユーザーガイドの「AWS Private CA 証明書の失効方法を計画する」を参照してください。どちらも ML-DSA CA で使用できます)。CRL を使用する場合は、信頼チェーンと一緒に CRL を配布し、オプション -crl_check -CRLfile <crl-file> を後述の openssl verify コマンドに追加します。<crl-file> には、AWS Private CA が S3 バケットに公開する CRL を指定します。これにより、失効したコード署名証明書は検証に失敗するようになります。

バイナリまたは SBOM の署名の検証

まずコード署名証明書を信頼チェーンに照らして検証し、想定どおりの署名者に発行されたコード署名証明書であることを確認します。そのうえでパブリックキーを抽出し、OpenSSL 3.5 で署名を検証します。2 つ目の確認は重要です。チェーンの確認だけでは、前のセクションで発行したビルドエージェント用のクライアント証明書を含め、CA 階層が発行したすべての証明書が受け入れられてしまいます。そのため、検証者の設定で想定するサブジェクトを固定してください。

# Step 1: Verify that the code-signing certificate chains to the trusted root CA and carries the
# Code Signing extended key usage. -purpose codesign (OpenSSL 3.2 and later) rejects a certificate
# that chains correctly but was issued for another purpose, such as a build agent's client
# authentication certificate from the same subordinate CA.
# trust-chain.pem contains the root CA and subordinate CA certificates distributed in the previous section.
openssl verify -CAfile trust-chain.pem -purpose codesign code-signing-cert.pem
# Confirm that the certificate was issued to the signer you expect. Replace <signer-cn> with the
# common name in your code-signing certificate's subject.
openssl x509 -in code-signing-cert.pem -noout -subject -nameopt RFC2253 | grep -q "CN=<signer-cn>" || { echo "Unexpected signer"; exit 1; }

# Step 2: Extract the public key from the verified certificate.
openssl x509 -in code-signing-cert.pem -pubkey -noout > signing-key.pem

# Step 3: Verify the artifact signature using the trusted public key.
openssl pkeyutl -verify \
  -pubin -inkey signing-key.pem \
  -in artifact.bin \
  -sigfile artifact.bin.sig \
  -rawin

検証に成功すると Signature Verified Successfully (署名の検証に成功しました) と出力され、終了ステータス 0 が返されます。検証に失敗すると Signature Verification Failure (署名の検証に失敗しました) と出力され、0 以外の終了ステータスが返されます。シェルスクリプトでは、各コマンドの終了ステータスを確認するか、set -e を指定してブロックを実行してください。こうすることで、証明書チェーンの確認に失敗した場合は署名の検証前にスクリプトが停止し、署名の確認に失敗した場合は後続の処理がブロックされます。

SBOM の場合は、sbom.statement.json を -in の入力ファイル、sbom.statement.json.sig を -sigfile の署名ファイルとして指定して同じ 3 つのステップを実行し、さらに 4 つ目のステップとして、検証済みの Statement 内のサブジェクトダイジェストが、これからデプロイするアーティファクトのダイジェストと一致することを確認します。署名の検証によって Statement が本物であることが証明され、サブジェクトの確認によって Statement が別のアーティファクトではなくこのアーティファクトを記述していることが証明されます。比較に使うダイジェストは、Statement からではなく、必ずアーティファクト自体から取得してください。イメージの場合はレジストリから取得し、バイナリの場合はファイルから計算します。イメージの場合、このダイジェストはイメージ署名の検証に使用するダイジェストと同じものです。そのため、2 つの確認を組み合わせることで、この SBOM がこの署名済みイメージを記述していることを確かめられます。

# Step 4 (SBOM only): the signed Statement must name the image being deployed.
# Resolve the digest from Amazon ECR, not from the Statement.
IMAGE_DIGEST=$(aws ecr batch-get-image \
  --repository-name myapp \
  --image-ids imageTag=v1.2.0 \
  --query 'images[0].imageId.imageDigest' --output text)
SUBJECT_DIGEST=$(jq -r '.subject[0].digest.sha256' sbom.statement.json)
[ "sha256:$SUBJECT_DIGEST" = "$IMAGE_DIGEST" ] || { echo "SBOM does not describe this image"; exit 1; }

# Only now extract the SBOM for downstream tooling
jq '.predicate' sbom.statement.json > sbom.json

バイナリの場合は、サブジェクトダイジェストを sha256sum artifact.bin の出力と比較します。署名とサブジェクトのどちらかの確認に失敗した場合は、その SBOM を拒否してください。

デプロイ前のコンテナイメージ署名の検証

Amazon ECR の OCI リファラーアーティファクトから ML-DSA 署名をプルし、イメージマニフェストのダイジェストに対して検証します。

# Pull the signature referrer. ORAS 1.2 lists referrers under "manifests";
# ORAS 1.3 and later list them under "referrers". The jq filter accepts either.
oras discover $ECR_URI@$IMAGE_DIGEST \
  --artifact-type "application/vnd.example.mldsa-signature.v1" --format json | \
  jq -r '(.referrers // .manifests)[0].digest' | \
  xargs -I{} oras pull $ECR_URI@{} -o /tmp/sig/

# Re-derive the image digest and verify
echo -n "$IMAGE_DIGEST" > /tmp/digest.txt
openssl pkeyutl -verify \
  -pubin -inkey signing-key.pem \
  -in /tmp/digest.txt \
  -sigfile /tmp/sig/image.mldsa.sig \
  -rawin

# Exit code 0 = image is authentic; non-zero = reject deployment

同じ oras discover コマンドに --artifact-type "application/vnd.example.mldsa-sbom-attestation.v1" を指定すると、SBOM アテステーションとその署名を取得できます。取得したら、サブジェクトの確認も含め、前のセクションで説明した手順で検証してください。ここで示した jq フィルターは、指定したタイプの最初のリファラーを取得します。レジストリがリファラーを返す順序には依存しないでください。また、イメージを再署名した後は、リファラーが複数存在することを想定しておく必要があります。本番環境の検証者は、そのタイプのリファラーをすべて確認し、トラストストアまでチェーンをたどれる証明書で少なくとも 1 つの署名が検証できた場合に、イメージを受け入れるようにしてください。最初のリファラーだけを確認する方法では、正しく署名されたイメージを誤って拒否することはあっても、署名されていないイメージを受け入れることはありません。

デプロイ時にこれらのチェックを適用するには、Kubernetes のアドミッションコントローラーでチェックを実行します。アドミッションコントローラーは、API サーバーがポッドを受け入れる前に呼び出すコンポーネントで、リクエストを拒否できます。アドミッションコントローラーは、検証用のアドミッション Webhook として独自に作成するか (Kubernetes ドキュメントの「Dynamic Admission Control」を参照)、Open Policy Agent (OPA) Gatekeeper (OPA ポリシーエンジンで評価したポリシーを適用するアドミッション Webhook) を使用し、制約から呼び出される Gatekeeper の外部データプロバイダーとして検証手順をパッケージ化します。イメージ署名に基づいて Amazon EKS へのデプロイを制御する実例については、「AWS Signer と Amazon EKS におけるコンテナイメージ署名の提供開始」を参照してください。同記事では、Kyverno を使用してアドミッション時に AWS Signer の署名を検証しており、代替手段として Gatekeeper やカスタム Webhook についても説明しています。この記事の ML-DSA 署名リファラーは、これらのツールではそのまま検証できないカスタムアーティファクトタイプであるため、このセクションの検証手順は独自に用意したコードで実行します。どちらの設計でも、コントローラーはポッドがスケジュールされる前に実行され、Amazon ECR に有効な ML-DSA 署名リファラーがないイメージや、SBOM アテステーションがデプロイ対象のイメージを指定していないイメージを拒否します。

予防的コントロールと発見的コントロール

署名の検証によって、信頼されていないアーティファクトがデプロイ時に使用されるのを防げます。組織レベルのコントロールは、それよりも早い段階で、より広い範囲に適用されます。予防的コントロールは、チームが従来型の署名キーを新たに作成することを防ぎます。発見的コントロールはすべての署名オペレーションを記録するため、どのプリンシパルがいつ各アーティファクトに署名したかを監査できます。

予防的ガードレール。セキュリティ上重要なアカウントで従来型の署名キーの作成をブロックし、新しい署名ワークロードすべてに ML-DSA の使用を強制するには、次のような AWS Organizations サービスコントロールポリシー (SCP) を使用します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RequirePQCSigningKeys",
      "Effect": "Deny",
      "Action": "kms:CreateKey",
      "Resource": "*",
      "Condition": {
        "StringNotLike": {
          "kms:KeySpec": "ML_DSA_*"
        },
        "StringEquals": {
          "kms:KeyUsage": "SIGN_VERIFY"
        }
      }
    }
  ]
}

この SCP により、チームは RSA や ECDSA の署名キーを新たに作成できなくなり、新しいワークロードでは耐量子署名が唯一の選択肢になります。なお、この SCP で制限されるのはアルゴリズムファミリーであり、パラメータセットではありません。そのため、このアーキテクチャでは使用しない ML-DSA-44 キーの作成は引き続き許可されます。このシリーズのパート 2 は、まさにこの点から始まります。パート 2 では、完全なアルゴリズムポリシー (その例では ML-DSA-65 と ML-DSA-87 を承認し、ML-DSA-44 を除外) を、SCP、IAM のアクセス許可の境界、AWS KMS キーポリシーで kms:KeySpec 条件キーを使用した多層的なコントロールとして表現する方法を紹介します。さらに、既存のキーの使用を制限する方法や、アルゴリズムの条件キーがない AWS Private CA などの領域を管理する方法も説明します。この SCP とパート 2 のパラメータセット用の SCP は組み合わせて使用します。両方をアタッチすると、新しい署名キーはすべて承認済みのパラメータセットを使用しなければならなくなります。

監査証跡。AWS CloudTrail は、すべての kms:Sign および kms:Verify API コールをログに記録し、各アーティファクトがいつ、どのプリンシパルによって署名されたかを示す変更不可能な記録を提供します。組織の証跡を使用し、Amazon Athena でそのログをクエリすることで、複数のアカウントにわたる署名アクティビティを分析し、デプロイイベントと関連付けてください。

規制のタイムラインと推奨アクション

次の表は、規制上のマイルストーンと、この記事で説明したアーキテクチャを使用して今すぐ実行できる具体的なアクションの対応を示しています。この情報は一般的な情報提供のみを目的としたものであり、法律上またはコンプライアンス上の助言ではありません。組織固有の義務については、法務チームやコンプライアンスチームに確認してください。PQC に関する世界各国の規制タイムラインの概要については、「Migrating to Post-Quantum Cryptography」を参照してください。

規制 期限 規制の文言 AWS でのアクション
CNSA 2.0: サポートと優先 2025 年 (適用中) CNSA 2.0 タイムライン (2022 年 9 月、FAQ v2.1 は 2024 年 12 月): ソフトウェアとファームウェアの署名は、2025 年までに CNSA 2.0 アルゴリズムを「サポートし優先する (support and prefer)」必要がある AWS KMS で ML-DSA キーを作成し、既存の従来型の署名と並行して ML-DSA によるアーティファクトの署名を開始する
CNSA 2.0: 新規システムの調達 2027 年 1 月 CNSA 2.0 FAQ v2.1 (2024 年 12 月): 「2027 年 1 月 1 日以降、すべての新規 NSS 調達は、デプロイ時に CNSA 2.0 に準拠している必要がある (All new NSS acquisitions must be CNSA 2.0 compliant at deployment, effective 1 January 2027)」 ML-DSA PKI を本格運用し、IAM Roles Anywhere のトラストアンカーで ML-DSA を使用し、すべての新規ビルドに ML-DSA 署名を付与する
EU サイバーレジリエンス法 2027 年 12 月 11 日 規則 (EU) 2024/2847、附属書 I、第 I 部 (2)(f): 製品は「保存、送信、またはその他の方法で処理されるデータ (個人データかその他のデータかを問わない)、コマンド、プログラム、設定の完全性を、ユーザーが許可していない操作や変更から保護し、破損について報告する (protect the integrity of stored, transmitted or otherwise processed data, personal or other, commands, programs and configuration against any manipulation or modification not authorised by the user, and report on corruptions)」必要がある。第 II 部 (7): 製造業者は「アップデートを安全に配布するメカニズムを提供する (provide for mechanisms to securely distribute updates)」必要がある EU 市場向けに出荷するすべてのソフトウェアアップデートに ML-DSA コード署名を適用し、すべてのリリースに署名済みの SBOM を添付する
CNSA 2.0: 排他的使用 2030 年 CNSA 2.0 タイムライン: ソフトウェアとファームウェアの署名は、2030 年までに CNSA 2.0 アルゴリズム「のみを使用する (exclusively use)」必要がある サプライチェーンから従来型の署名キーを削除し、SCP によって ML-DSA キー以外の作成を禁止する
PCI DSS 4.0 要件 12.3.3 2025 年 3 月から必須 PCI DSS v4.0.1、要件 12.3.3: 「使用中の暗号スイートとプロトコルを文書化し、少なくとも 12 か月に 1 回レビューする (Cryptographic cipher suites and protocols in use are documented and reviewed at least once every 12 months)」(使用中の暗号スイートとプロトコルの最新のインベントリを含む) AWS KMS で暗号インベントリを文書化し、ML-DSA キーと従来型のキーを区別するタグを付け、移行の進捗状況を追跡する

NSS のお客様およびその他の CNSA 2.0 採用組織への注意事項: CNSA 2.0 は、NSA が NSS に要求する耐量子アルゴリズムスイートです。NSS とは、機密情報を扱う連邦システム、または諜報、暗号、軍の指揮統制、兵器の各機能をサポートする連邦システムを指します。CNSA 2.0 では、ソフトウェアとファームウェアの署名を含め、あらゆる署名用途で ML-DSA を使用する場合、ML-DSA-87 パラメータセットのみが許可されています。(ソフトウェアとファームウェアの署名については、ステートフルなハッシュベースの方式である LMS と XMSS も承認されていますが、この記事では扱いません。) この記事のコード署名の例で使用している ML-DSA-65 パラメータセットは、商用ワークロードには適していますが、NSS では許可されていません。CNSA 2.0 が拘束力を持つのは NSS に対してのみですが、その範囲を大きく超えて自主的に採用されています。採用しているのは、米国および同盟国で米国の防衛市場や諜報市場に製品を供給し、その製品が NSS の要件を満たす必要があるサプライヤーや、米国内外の商用組織です。商用組織が CNSA 2.0 を保守的なベースラインとして採用するのは、CNSA 2.0 が NIST の最高セキュリティカテゴリを指定しており、後でパラメータの選択を見直す必要がなくなるためです。システムが CNSA 2.0 の対象範囲に該当する場合や、CNSA 2.0 への準拠を選択した場合は、すべての署名キーと証明書で ML-DSA-87 を使用してください。このシリーズのパート 2 では、この置き換えを強制可能にする方法を紹介します。パート 2 の例で ML-DSA-44 を除外している kms:KeySpec のコントロールをそのまま利用し、ML_DSA_87 を唯一の承認済みキー仕様として指定できます。

米国政府と EU の商用市場の両方を対象とする組織にとって、2027 年 1 月と 2027 年 12 月の期限は 1 つの移行期間に集約されます。今すぐ着手すれば、テスト、キーローテーションの計画、証明書チェーンの検証のための余裕を確保できます。

クリーンアップ

これまでの手順と例では、多数の暗号リソースを作成しました。AWS Private CA では CA ごとに、AWS KMS ではキーごとに月額料金が発生します。継続的に料金が発生しないように、使用していないリソースは削除してください。まず、既存のリソースを一覧表示し、繰り返し実行したことで生じた重複も含めて、作成したすべてのリソースを把握します。以下のコマンドは 1 つのリージョンを対象とします。複数のリージョンで作業した場合は、リージョンごとに --region を指定してコマンドを繰り返し実行してください。

# List every private CA with its type, status, key algorithm, and subject.
# A CA you already deleted shows DELETED until its restoration window ends.
aws acm-pca list-certificate-authorities \
  --query 'CertificateAuthorities[].[Arn,Type,Status,CertificateAuthorityConfiguration.KeyAlgorithm,CertificateAuthorityConfiguration.Subject.CommonName]' \
  --output table

# List every ML-DSA key in AWS KMS with its state and creation date.
# A key already scheduled for deletion shows PendingDeletion.
for KEY_ID in $(aws kms list-keys --query 'Keys[].KeyId' --output text); do
  aws kms describe-key --key-id "$KEY_ID" \
    --query 'KeyMetadata.[KeyId,KeySpec,KeyState,CreationDate]' --output text
done | grep ML_DSA

# Show which alias points at which key. A key that no alias points at
# is usually a leftover from an earlier run.
aws kms list-aliases --query 'Aliases[].[AliasName,TargetKeyId]' --output text | grep -v '^alias/aws/'

AWS Private CA には、CA が発行した証明書を一覧表示するコマンドはありません。後述の失効手順でシリアル番号が必要な場合は、aws acm-pca create-certificate-authority-audit-report を使用して監査レポートを生成してください。このコマンドは、CA が発行または失効させたすべての証明書の一覧を、サービスに書き込みアクセスを許可した S3 バケットに出力します。

一覧で見つかった余分なコピーも含めて不要なリソースをそれぞれ削除し、再度一覧を表示して何も残っていないことを確認します。

# Revoke any issued end-entity certificates while the subordinate CA is still active
aws acm-pca revoke-certificate \
  --certificate-authority-arn <sub-ca-arn> \
  --certificate-serial <serial-number> \
  --revocation-reason CESSATION_OF_OPERATION

# Delete the IAM Roles Anywhere resources that reference the CA
aws rolesanywhere delete-profile --profile-id <profile-id>
aws rolesanywhere delete-trust-anchor --trust-anchor-id <trust-anchor-id>

# Delete the build agent role that the profile referenced, and the local copy of its private key
aws iam delete-role-policy --role-name PQCBuildAgentRole --policy-name pqc-code-signing
aws iam delete-role --role-name PQCBuildAgentRole
rm -f build-agent-mldsa-key.pem

# Delete the AWS KMS code-signing key (schedule 7-day waiting period).
# ScheduleKeyDeletion doesn't accept an alias, so resolve the key ID first.
KEY_ID=$(aws kms describe-key --key-id alias/pqc-code-signing \
  --query KeyMetadata.KeyId --output text)
aws kms schedule-key-deletion --key-id $KEY_ID --pending-window-in-days 7

# Remove the alias. It survives key deletion and would otherwise show up in the
# listing above on your next run.
aws kms delete-alias --alias-name alias/pqc-code-signing

# Disable and delete the subordinate CA
aws acm-pca update-certificate-authority \
  --certificate-authority-arn <sub-ca-arn> --status DISABLED
aws acm-pca delete-certificate-authority \
  --certificate-authority-arn <sub-ca-arn> --permanent-deletion-time-in-days 7

# Disable and delete the root CA
aws acm-pca update-certificate-authority \
  --certificate-authority-arn <root-ca-arn> --status DISABLED
aws acm-pca delete-certificate-authority \
  --certificate-authority-arn <root-ca-arn> --permanent-deletion-time-in-days 7

長期的な運用を前提にこの構成を応用する場合は、ログの保持について計画してください。CloudTrail のイベント履歴に保持されるのは直近 90 日間の管理イベントのみであり、証跡の代わりにはなりません。前述の監査証跡を実現するには、保持要件に合ったライフサイクルポリシーとアクセスコントロールを設定した S3 バケットに配信する証跡を作成してください。

まとめ

この記事では、AWS KMS での ML-DSA 署名、AWS Private CA での ML-DSA 証明書階層、IAM Roles Anywhere を通じた ML-DSA ワークロード認証を組み合わせて、AWS で耐量子ソフトウェアサプライチェーンを構築する方法を紹介しました。このアーキテクチャは、認証されたビルドエージェントから、署名済みのバイナリ、コンテナイメージ、SBOM、デプロイ時の検証とポリシーの適用に至るまで、パイプライン全体をカバーしています。

この記事で使用した ML-DSA の機能は、いずれも一般提供されています。AWS Private CA と IAM Roles Anywhere は、すべての商用 AWS リージョン、AWS GovCloud (米国) リージョン、中国リージョンで ML-DSA をサポートしています。AWS KMS は、商用 AWS リージョンで ML-DSA をサポートしています。標準化団体やサードパーティのツールによる PQC 対応が確定するのを待つ必要はありません。必要な基本要素は既にそろっています。

まずは AWS KMS で最初の ML-DSA キーを作成し、テスト用のアーティファクトに署名してみてください。次に PKI 階層を構築し、ビルドエージェント向けに IAM Roles Anywhere を統合して、コンテナと SBOM のワークフローに ML-DSA 署名を追加していきましょう。

パイプラインの構築は、作業の半分にすぎません。残りの半分は、アカウント、チーム、標準が変化しても、選択したアルゴリズムが引き続き確実に適用されるようにすることです。これが、このシリーズのパート 2「SCP と IAM による ML-DSA アルゴリズムポリシーの強制」のテーマです。パート 2 は、この課題を担当するセキュリティチームとガバナンスチームを対象としています。

詳細については、以下を参照してください。


Harshvardhan Chunawala

Harshvardhan Chunawala

Harshvardhan は AWS の Solutions Architect 兼 Security SME です。Amazon Leo、Amazon Security、AWS Agentic AI と連携し、チーム横断の取り組みを主導しています。クラウドセキュリティ分野で 10 年以上の経験を持つ Golden Jacket 受賞者で、カーネギーメロン大学ではアドバイザリーボードメンバー、客員教員、研究者を務めています。世界中の経営幹部、企業のリーダー、スタートアップの創業者に対し、安全でスケーラブルなクラウドプラットフォームの構築について助言しています。

本ブログは Security Solutions Architect の 中島 章博 が翻訳しました。