mcpField
I
implementing-aws-nitro-enclave-security

implementing-aws-nitro-enclave-security

github.com/mukul975セキュリティ35.2k38 回インストール8 週間前に更新
リポジトリ

implementing-aws-nitro-enclave-security について

AWS Nitro Enclavesで機密データを扱うエンジニア向けの実装ガイドです。環境構築やイメージ作成、アテステーションに基づくKMSポリシー、vsock通信、検証、運用を扱います。

主な機能

  1. 01Nitro Enclaves環境の構成
  2. 02EIFイメージのビルドと署名
  3. 03アテステーション対応KMSポリシー
  4. 04安全なvsock通信の実装
  5. 05アテステーション文書の検証
  6. 06エンクレーブの起動と監視

活用シーン

  1. 01個人情報や金融データの隔離処理
  2. 02検証済みイメージへのKMS復号制限
  3. 03アテステーションによる複数エンクレーブの認証
  4. 04親インスタンスからエンクレーブへの復号移行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mukul975/anthropic-cybersecurity-skills --skill implementing-aws-nitro-enclave-security

インストール後、Claude Code で/implementing-aws-nitro-enclave-securityを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE
references/
api-reference.md
scripts/
agent.py

詳細

AWS Nitro Enclave のセキュリティを実装する

使用するタイミング

  • EC2 インスタンスのオペレーターや管理者から隔離しなければならない機密データ(PII、PHI、金融記録、暗号化シークレット)を処理する場合
  • 親インスタンス上の root レベルのアクセスでもエンクレーブのメモリや状態を読み取れない、コンフィデンシャルコンピューティングのパイプラインを構築する場合
  • 検証済みの特定のエンクレーブイメージのハッシュに KMS の復号権限を紐付ける、暗号化証明(アテステーション)のワークフローを実装する場合
  • 2 つ以上のエンクレーブがデータを交換する前にアテステーションで相互認証する、マルチパーティ計算環境をデプロイする場合
  • 現在親インスタンス上でシークレットを復号しているワークロードを、復号処理をエンクレーブの境界内へ移行することで強化する場合

以下の場合は使用しないでください:ワークロードがハードウェアレベルの隔離を必要とする機密データを扱わない場合、インスタンスタイプが Nitro Enclaves をサポートしない場合(少なくとも 4 vCPU の Nitro ベースのインスタンスが必要)、またはレイテンシの制約により vsock 通信のオーバーヘッドが許容できない場合。

前提条件

  • Nitro 対応の EC2 インスタンス(m5.xlarge 以上、C5、R5、M6i ファミリー)を起動する権限を持つ AWS アカウント
  • 親 EC2 インスタンス上にインストールされた AWS CLI v2 および nitro-cli ツールセット(Amazon Linux 2 または AL2023)
  • エンクレーブイメージファイル(EIF)をビルドするために親インスタンスにインストールされた Docker
  • エンクレーブの IAM ロールにキーポリシーの権限を付与した AWS KMS の対称鍵
  • エンクレーブ側の KMS 操作に使用する aws-nitro-enclaves-sdk-c または Python の aws-encryption-sdk
  • /etc/nitro_enclaves/allocator.yaml で十分なメモリと vCPU を割り当てて構成された Nitro Enclaves アロケーターサービス

ワークフロー

ステップ 1:Nitro Enclaves 環境を構成する

エンクレーブの起動をサポートするように親 EC2 インスタンスを設定します。

  • Nitro Enclaves CLI をインストールする:Amazon Linux 2 では、ツールとアロケーターをインストールします:
    sudo amazon-linux-extras install aws-nitro-enclaves-cli
    sudo yum install aws-nitro-enclaves-cli-devel -y
    sudo systemctl enable --now nitro-enclaves-allocator.service
    sudo systemctl enable --now docker
    sudo usermod -aG ne ec2-user
    sudo usermod -aG docker ec2-user
    
  • メモリと CPU の割り当てを構成する:/etc/nitro_enclaves/allocator.yaml を編集して、エンクレーブ用のリソースを予約します。エンクレーブには、親インスタンスから切り出される専用のメモリが必要です:
    ---
    memory_mib: 4096
    cpu_count: 2
    
    アロケーターを再起動します:sudo systemctl restart nitro-enclaves-allocator.service
  • セットアップを検証する:nitro-cli describe-enclaves を実行して、CLI が Nitro ハイパーバイザーと通信できることを確認します。空の JSON 配列 [] は、エンクレーブが実行されておらず、セットアップが正しいことを示します。
ステップ 2:エンクレーブイメージファイル(EIF)をビルドする

機密ワークロードを署名済みのエンクレーブイメージにパッケージ化します。

  • アプリケーションの Dockerfile を作成する:エンクレーブは最小限の Linux 環境で動作します。アプリケーションは vsock のみを介して通信します:

    FROM amazonlinux:2
    
    RUN yum install -y python3 python3-pip && \
        pip3 install boto3 cbor2 cryptography requests
    
    COPY enclave_app.py /app/enclave_app.py
    
    WORKDIR /app
    CMD ["python3", "enclave_app.py"]
    
  • nitro-cli で EIF をビルドする:Docker イメージをエンクレーブイメージファイルに変換し、PCR の測定値を取得します:

    docker build -t enclave-app:latest .
    nitro-cli build-enclave \
      --docker-uri enclave-app:latest \
      --output-file enclave-app.eif
    

    出力には、重要な 3 つの PCR 値が含まれます:

    • PCR0:エンクレーブイメージファイルの SHA-384 ハッシュ(イメージ全体のダイジェスト)
    • PCR1:Linux カーネルとブートストラッププロセスの SHA-384 ハッシュ
    • PCR2:アプリケーションコードの SHA-384 ハッシュ これらの値を記録してください。アテステーションに基づくアクセス制御のために KMS キーポリシーで使用されます。
  • 署名済み EIF をビルドする(本番環境では推奨):署名証明書を生成し、それを使用して PCR8 を作成します:

    openssl ecparam -name secp384r1 -genkey -noout -out enclave_key.pem
    openssl req -new -key enclave_key.pem -sha384 \
      -nodes -subj "/CN=Enclave Signer" -out enclave_csr.pem
    openssl x509 -req -days 365 -in enclave_csr.pem \
      -signkey enclave_key.pem -sha384 -out enclave_cert.pem
    
    nitro-cli build-enclave \
      --docker-uri enclave-app:latest \
      --output-file enclave-app.eif \
      --private-key enclave_key.pem \
      --signing-certificate enclave_cert.pem
    

    PCR8(署名証明書のハッシュ)により、特定の証明書で署名されたあらゆるイメージを信頼する KMS ポリシーを作成できるため、ポリシーを変更せずにイメージを更新できます。

Step 3: KMS アテステーションベースのキーポリシーを設定する

検証済みのエンクレーブに限定して復号を許可する KMS キーポリシーを作成します。

  • PCR0(イメージハッシュ)を使用したポリシー: キーを特定のエンクレーブビルドに固定します。コードを変更するたびに新しい PCR0 が生成されるため、ポリシーの更新が必要になります:
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowEnclaveDecrypt",
          "Effect": "Allow",
          "Principal": {
            "AWS": "arn:aws:iam::111122223333:role/EnclaveParentRole"
          },
          "Action": [
            "kms:Decrypt",
            "kms:GenerateDataKey"
          ],
          "Resource": "*",
          "Condition": {
            "StringEqualsIgnoreCase": {
              "kms:RecipientAttestation:ImageSha384": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
            }
          }
        }
      ]
    }
    
  • PCR8(署名証明書)を使用したポリシー: 特定の証明書で署名されたエンクレーブであればすべて信頼し、ポリシーを変更せずにイメージのローテーションを可能にします:
    {
      "Condition": {
        "StringEqualsIgnoreCase": {
          "kms:RecipientAttestation:PCR8": "ab3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890abcdef"
        }
      }
    }
    
  • 多層防御のための複数 PCR ポリシー: PCR0(イメージ)と PCR1(カーネル)を組み合わせ、アプリケーションとブート環境の両方が想定どおりの値と一致することを確認します:
    {
      "Condition": {
        "StringEqualsIgnoreCase": {
          "kms:RecipientAttestation:PCR0": "<pcr0-hex>",
          "kms:RecipientAttestation:PCR1": "<pcr1-hex>"
        }
      }
    }
    
  • IAM ロールポリシー: 親インスタンスの IAM ロールには kms:Decrypt 権限が必要ですが、KMS キーポリシーの条件により、有効なアテステーションドキュメントを添付したエンクレーブからのリクエストの場合にのみ実際の復号が成功します。
Step 4: セキュアな vsock 通信を実装する

親とエンクレーブの間の通信チャネルを確立します。

  • vsock アーキテクチャ: エンクレーブが外部と通信する唯一の方法は vsock(仮想ソケット)を経由することです。vsock は CID(Context Identifier)とポート番号を使用します。親インスタンスの CID は常に 3 であり、エンクレーブの CID は起動時に割り当てられます。
  • 親側のプロキシサーバー: 親はプロキシを実行し、エンクレーブからの KMS API 呼び出しを vsock 経由で AWS KMS エンドポイントに転送します:
    import socket
    import json
    import boto3
    
    VSOCK_CID = 3  # Parent CID
    VSOCK_PORT = 5000
    
    def start_proxy():
        sock = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
        sock.bind((VSOCK_CID, VSOCK_PORT))
        sock.listen(5)
    
        kms_client = boto3.client('kms', region_name='us-east-1')
    
        while True:
            conn, addr = sock.accept()
            data = conn.recv(65536)
            request = json.loads(data.decode())
    
            if request['action'] == 'decrypt':
                response = kms_client.decrypt(
                    CiphertextBlob=bytes.fromhex(request['ciphertext']),
                    Recipient={
                        'KeyEncryptionAlgorithm': 'RSAES_OAEP_SHA_256',
                        'AttestationDocument': bytes.fromhex(request['attestation_doc'])
                    }
                )
                conn.sendall(json.dumps({
                    'ciphertext_for_recipient': response['CiphertextForRecipient'].hex()
                }).encode())
            conn.close()
    
  • エンクレーブ側のクライアント: エンクレーブアプリケーションは、/dev/nsm にある Nitro Security Module(NSM)デバイスからアテステーションドキュメントを取得し、それを KMS の復号リクエストに添付して、エンクレーブの一時公開鍵で暗号化されたデータを受け取ります:
    import socket
    import json
    from cryptography.hazmat.primitives.asymmetric import rsa, padding
    from cryptography.hazmat.primitives import hashes, serialization
    
    PARENT_CID = 3
    VSOCK_PORT = 5000
    
    def get_attestation_document(public_key_der):
        """Request attestation document from NSM device."""
        # Uses the aws-nitro-enclaves-nsm-api
        # NSM provides: module_id, digest (SHA384), timestamp, PCRs,
        # certificate (from Nitro PKI), cabundle, public_key, user_data, nonce
        import nsm_util
        nsm_fd = nsm_util.nsm_lib_init()
        attestation_doc = nsm_util.nsm_get_attestation_doc(
            nsm_fd,
            public_key=public_key_der,
            user_data=None,
            nonce=None
        )
        return attestation_doc
    
    def decrypt_via_parent(ciphertext_hex):
        """Send decrypt request through vsock to parent proxy."""
        private_key = rsa.generate_private_key(
            public_exponent=65537, key_size=2048
        )
        public_key_der = private_key.public_key().public_bytes(
            serialization.Encoding.DER,
            serialization.PublicFormat.SubjectPublicKeyInfo
        )
    
        attestation_doc = get_attestation_document(public_key_der)
    
        sock = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
        sock.connect((PARENT_CID, VSOCK_PORT))
        sock.sendall(json.dumps({
            'action': 'decrypt',
            'ciphertext': ciphertext_hex,
            'attestation_doc': attestation_doc.hex()
        }).encode())
    
        response = json.loads(sock.recv(65536).decode())
        sock.close()
    
        # KMS encrypted the plaintext to the enclave's public key
        # Only the enclave's private key can decrypt it
        ciphertext_for_recipient = bytes.fromhex(
            response['ciphertext_for_recipient']
        )
        plaintext = private_key.decrypt(
            ciphertext_for_recipient,
            padding.OAEP(
                mgf=padding.MGF1(algorithm=hashes.SHA256()),
                algorithm=hashes.SHA256(),
                label=None
            )
        )
        return plaintext
    
Step 5: アテステーションドキュメントを検証する

信頼を確立するために、エンクレーブからのアテステーションドキュメントを検証します。

  • アテステーションドキュメントの構造: ドキュメントは CBOR でエンコードされ、COSE_Sign1 で署名されています。含まれる項目は次のとおりです:

    • module_id: NSM モジュールの識別子
    • digest: ハッシュアルゴリズム(SHA-384)
    • timestamp: ドキュメントが作成された時点の Unix エポックミリ秒
    • pcrs: PCR インデックスから測定値へのマップ(PCR0〜PCR15)
    • certificate: Nitro PKI によって署名された NSM の x509 証明書
    • cabundle: NSM 証明書から AWS Nitro ルート CA までの証明書チェーン
    • public_key: エンクレーブの一時公開鍵(アテステーションのリクエスト時に提供)
    • user_data: アプリケーションが定義する任意のデータ(最大 512 バイト)
    • nonce: 鮮度を検証するための任意のノンス
  • 検証手順:

    1. COSE_Sign1 構造をデコードし、ペイロードと証明書を取り出す
    2. 埋め込まれた証明書の公開鍵を使用して COSE 署名を検証する
    3. NSM 証明書から CA バンドルを経由し、AWS Nitro Attestation PKI のルート証明書(https://aws-nitro-enclaves.amazonaws.com/AWS_NitroEnclaves_Root-G1.zip で入手可能)までの証明書チェーンを検証する
    4. ルート CA 証明書が想定の AWS ルートと一致することを確認する: aws.nitro-enclaves の CN
    5. ドキュメントのタイムスタンプの時点で、チェーン内のどの証明書も期限切れでないことを確認する
    6. PCR0、PCR1、PCR2 の値を、エンクレーブビルドの出力から得た想定の測定値と比較する
    7. ノンスが提供されている場合は、リプレイ攻撃を防ぐためにノンスが一致することを確認する
  • アテステーション検証コード:

    import cbor2
    from cose import CoseMessage
    from cryptography import x509
    from cryptography.x509.oid import NameOID
    
    def validate_attestation(attestation_bytes, expected_pcrs, expected_nonce=None):
        cose_msg = CoseMessage.decode(attestation_bytes)
        payload = cbor2.loads(cose_msg.payload)
    
        # Verify certificate chain
        cert = x509.load_der_x509_certificate(payload['certificate'])
        cabundle = [x509.load_der_x509_certificate(c) for c in payload['cabundle']]
    
        # Check root CA is AWS Nitro
        root = cabundle[-1]
        cn = root.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
        assert cn == 'aws.nitro-enclaves', f'Unexpected root CA: {cn}'
    
        # Verify PCR measurements
        pcrs = payload['pcrs']
        for idx, expected_value in expected_pcrs.items():
            actual = pcrs.get(idx, b'').hex()
            assert actual == expected_value, f'PCR{idx} mismatch: {actual}'
    
        # Verify nonce freshness
        if expected_nonce:
            assert payload.get('nonce') == expected_nonce, 'Nonce mismatch'
    
        return payload
    
ステップ 6: エンクレーブの起動と監視

エンクレーブを実行し、運用監視を実装します:

  • エンクレーブを起動する:

    nitro-cli run-enclave \
      --eif-path enclave-app.eif \
      --cpu-count 2 \
      --memory 4096 \
      --enclave-cid 16 \
      --debug-mode
    

    注: --debug-mode は開発用にエンクレーブコンソールを有効にします。エンクレーブの出力を読み取れるようになり、分離の保証が損なわれるため、本番環境では削除してください。

  • エンクレーブの状態を確認する:

    nitro-cli describe-enclaves
    

    想定される出力には "State": "RUNNING"、割り当てられた EnclaveCID、メモリ、CPU 数、エンクレーブのフラグが含まれます。

  • エンクレーブコンソールを読み取る(デバッグモードのみ):

    nitro-cli console --enclave-id <enclave-id>
    
  • エンクレーブを終了する:

    nitro-cli terminate-enclave --enclave-id <enclave-id>
    
  • CloudWatch モニタリング: 親インスタンスがエンクレーブの正常性メトリクスを報告するように構成します。エンクレーブにはネットワークアクセスがないため、ヘルスチェックは vsock プロキシを経由する必要があります:

    # Parent-side health check over vsock
    def check_enclave_health(enclave_cid, port=5001):
        try:
            sock = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
            sock.settimeout(5)
            sock.connect((enclave_cid, port))
            sock.sendall(b'HEALTH_CHECK')
            response = sock.recv(1024)
            sock.close()
            return response == b'OK'
        except (socket.timeout, ConnectionRefusedError):
            return False
    

主要な概念

用語定義
Nitro EnclaveNitro ベースの EC2 インスタンス上で Nitro Hypervisor によって作成される分離された仮想マシンです。永続ストレージ、ネットワークアクセス、対話型アクセスはなく、親インスタンスの root ユーザーであってもアクセスできません
Attestation DocumentNitro Security Module が生成する CBOR エンコードされ COSE で署名されたドキュメントです。PCR の測定値、AWS Nitro ルート CA までの証明書チェーン、任意のユーザー提供データを含みます
PCR (Platform Configuration Register)エンクレーブのイメージ(PCR0)、カーネル/ブートストラップ(PCR1)、アプリケーション(PCR2)、IAM ロール(PCR4)、インスタンス ID(PCR3)、署名証明書(PCR8)を一意に識別する SHA-384 ハッシュの測定値です
Vsock親 EC2 インスタンスとそのエンクレーブの間の唯一の通信チャネルとなる仮想ソケットです。CID(Context Identifier)とポートでアドレス指定します
EIF (Enclave Image File)nitro-cli が Docker イメージから構築するパッケージ化されたエンクレーブイメージです。カーネル、ramdisk、アプリケーションを含み、ビルド時に PCR の測定値を生成します
Nitro Security Module (NSM)エンクレーブ内のカスタム Linux デバイス(/dev/nsm)です。アテステーションドキュメントの生成とハードウェア乱数生成を提供します
COSE_Sign1NSM の秘密鍵でアテステーションドキュメントに署名するために使用される、CBOR Object Signing and Encryption の単一署名者構造です
kms:RecipientAttestationAWS KMS の条件キーのプレフィックスです。一致する PCR 値を持つ有効なアテステーションドキュメントが提示された場合にのみ復号/生成操作が成功するよう、キーポリシーで強制できます

ツールとシステム

  • nitro-cli: エンクレーブイメージファイルのビルド、エンクレーブの起動/終了、エンクレーブコンソール出力の読み取りを行う AWS CLI ツールです
  • AWS KMS: Nitro Enclaves 向けのアテステーションベースの条件キーをネイティブにサポートする鍵管理サービスです。レスポンスはエンクレーブの一時公開鍵で暗号化されます
  • aws-nitro-enclaves-sdk-c: エンクレーブ側の KMS 操作のための C SDK です。アテステーションドキュメントの生成と vsock プロキシ通信を処理します
  • kmstool-enclave-cli: エンクレーブ内で実行され、アテステーション付きで KMS Decrypt と GenerateRandom 操作を行う、ビルド済みの CLI ツールです(SDK 付属)
  • Nitro Enclaves ACM: エンクレーブ内で TLS 証明書をプロビジョニングし、HTTPS エンドポイントを確立する AWS Certificate Manager の統合機能です
  • CloudTrail: Recipient パラメータを含む Decrypt や GenerateDataKey などの KMS API 呼び出しを記録し、エンクレーブ発の暗号操作の監査を可能にします

一般的なシナリオ

シナリオ: Nitro Enclave での PII トークン化サービスの実装

背景: ヘルスケア SaaS 企業が、PHI を含む患者レコードを処理しています。規制により、PHI の復号化とトークン化は、オペレーターがアクセスできるインスタンス上では決して行われてはなりません。同社は Nitro Enclave をデプロイし、この Enclave が暗号化された患者レコードを受け取り、アテステーションを伴う KMS を使用して Enclave 内で復号化し、PII フィールドをトークン化して、トークン化されたレコードのみを vsock 経由で返します。

アプローチ:

  1. トークン化ロジック、kmstool-enclave-cli バイナリ、暗号化されたレコードを受け付ける vsock サーバーを含む Docker イメージとしてトークン化アプリケーションをビルドします
  2. nitro-cli build-enclave で EIF をビルドし、ビルド出力から PCR0、PCR1、PCR2 を記録します
  3. kms:RecipientAttestation:ImageSha384 条件に PCR0 を一致させたキーポリシーを含む KMS キーを作成し、この特定の Enclave ビルドのみが患者レコードを復号化できるようにします
  4. キーに対する kms:Decrypt 権限を持つ IAM ロールを付与して親インスタンスをデプロイしますが、KMS 条件により、復号化は認証済みの Enclave 内でのみ成功します
  5. 親アプリケーションは HTTPS 経由で暗号化された患者レコードを受け取り、vsock ポート 5000 経由で Enclave に渡し、トークン化されたレコードを受け取ります
  6. Enclave は NSM にアテステーションドキュメントを要求し、それを KMS Decrypt 呼び出しに添付し、エフェメラル RSA キーで暗号化された平文を受け取り、ローカルで復号化して PII(SSN、DOB、名前)をトークン化し、{ssn: "tok_a8f3...", dob: "tok_b2e1...", name: "tok_c9d4..."} を返します
  7. CloudTrail のログには RecipientAttestation パラメーター付きの Decrypt 呼び出しが表示され、すべての復号化が Enclave の境界内で行われていることが確認できます

落とし穴:

  • 本番環境で Enclave をデバッグモードで実行すると、コンソールへのアクセスが可能になり、規制当局が求める機密性の保証が損なわれます
  • アテステーション条件を設けず、IAM ロールのみを使用するように KMS キーポリシーを設定すると、親インスタンスが Enclave を経由せずに直接復号化できてしまいます
  • allocator.yaml で十分なメモリを確保しないと、Enclave の起動時に不明瞭な「resource not available」エラーで失敗します
  • vsock のメッセージフレーミングを実装しないと、大きなレコードが 64KB のソケットバッファ境界で切り詰められます
  • ビルドのたびに PCR0 が変わることを忘れると、デプロイのたびに KMS ポリシーの更新が必要になります。本番環境では、ビルドとポリシー更新を切り離すために PCR8(署名証明書)を使用してください

出力形式

## Nitro Enclave Security Assessment

**Enclave Image**: enclave-tokenizer.eif
**Build Date**: 2026-03-19T14:30:00Z
**Instance Type**: m5.2xlarge
**Allocated Resources**: 2 vCPUs, 4096 MiB memory

### PCR Measurements
| PCR | Value | Bound in KMS Policy |
|-----|-------|---------------------|
| PCR0 (Image) | a1b2c3d4e5f6... | Yes |
| PCR1 (Kernel) | f6e5d4c3b2a1... | Yes |
| PCR2 (Application) | 1a2b3c4d5e6f... | No |
| PCR8 (Signing Cert) | 9f8e7d6c5b4a... | Yes (production) |

### KMS Key Policy Verification
- Key ARN: arn:aws:kms:us-east-1:111122223333:key/mrk-abc123
- Attestation condition: kms:RecipientAttestation:ImageSha384 = PCR0
- Signing cert condition: kms:RecipientAttestation:PCR8 = <cert-hash>
- Parent role: arn:aws:iam::111122223333:role/EnclaveParentRole
- Direct decrypt from parent: BLOCKED (attestation required)
- Decrypt from verified enclave: ALLOWED

### Security Posture
- [PASS] Debug mode disabled in production launch command
- [PASS] Vsock is the only communication channel (no network interface)
- [PASS] Attestation document nonce verification implemented
- [PASS] Certificate chain validates to AWS Nitro root CA
- [WARN] PCR0 used in policy; consider PCR8 for deployment flexibility
- [FAIL] Health check endpoint does not verify enclave attestation freshness

コメント