上級 40分 Lesson 2

KMS — キーポリシー・エンベロープ暗号化・マルチリージョン

KMSキーポリシー、グラント、エンベロープ暗号化、マルチリージョンキー、各サービスとの連携を徹底解説

AWS KMS SCS-C03 暗号化 Security

KMS (Key Management Service) 概論

AWSの暗号化エコシステムの中核を担うKMS。単なる「キー保管庫」ではなく、認可・監査・ローテーション・リージョン間レプリケーションを統合したエンタープライズグレードのキーライフサイクル管理サービスです。

試験では「何ができて何ができないか」「どのサービスとどう連携するか」「ポリシー設計の落とし穴」が頻出。実装レベルの理解が求められます。


1. KMSキーの種類と構成

1.1 カスタマー管理キー (CMK) vs AWS管理キー

特性AWS管理キーカスタマー管理キー
所有者AWSユーザー
キーポリシー編集不可
キーローテーション自動(年1回)手動 / 自動有効化
削除不可7~30日の待機期間あり
コスト無料$1/月 + API呼び出し
クロスアカウント利用一部可(S3等)グラントで完全制御可
リージョン複製不可マルチリージョンなら可

重要な誤解を正す

AWS管理キーは「AWSが管理している=安全」ではなく、単に「ユーザー側で何もしなくていい」という意味です。暗号化は変わりません。差は制御可能性です。

1.2 キーの種類(使途別)

KMS キー:

  • 対称キー (Symmetric) — DEFAULT

    • CloudHSM互換で暗号化・複合化・署名・HMAC に使用
  • 非対称キー (Asymmetric)

    • RSA (2048, 3072, 4096)
    • ECC (NIST, SM2)
    • エンベロープ暗号化・署名検証・TLS証明書署名に使用
  • HMAC キー

    • メッセージ認証・ペイロード改ざん検知

KMSキー構成図

Loading diagram...


2. キーポリシー (Key Policy) — 詳細解説

キーポリシーはIAMポリシーの親玉です。IAMポリシーがあっても、キーポリシーで明示的に許可していなければ動きません。

2.1 キーポリシーの構造

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Enable IAM policies",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111111111111:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "Allow use of the key for encryption",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111111111111:role/EC2-Role"
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncrypt*",
        "kms:GenerateDataKey*",
        "kms:DescribeKey"
      ],
      "Resource": "*"
    },
    {
      "Sid": "Allow attachment of persistent resources",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": [
        "kms:Decrypt",
        "kms:GenerateDataKey"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "111111111111"
        }
      }
    }
  ]
}

2.2 試験で狙われるポイント

クロスアカウント暗号化のキーポリシー

別のAWSアカウント(例:222222222222)からこのキーを使いたい場合:

{
  "Sid": "Allow use of the key from another account",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::222222222222:role/RemoteRole"
  },
  "Action": [
    "kms:Decrypt",
    "kms:DescribeKey",
    "kms:GenerateDataKey"
  ],
  "Resource": "*"
}

重要: キーポリシーの変更には kms:PutKeyPolicy 権限が必要。多くのユーザーが忘れるのは、root アカウント(IAMの頂点)であってもキーポリシーで許可していなければ変更できないということです。

{
  "Sid": "Allow key policy management",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111111111111:user/admin"
  },
  "Action": "kms:PutKeyPolicy",
  "Resource": "*"
}

2.3 ConditionでのIP制限

{
  "Sid": "Allow from specific IP",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111111111111:role/EC2-Role"
  },
  "Action": "kms:Decrypt",
  "Resource": "*",
  "Condition": {
    "IpAddress": {
      "aws:SourceIp": "10.0.0.0/8"
    }
  }
}

3. グラント (Grants) — 短期的な権限委譲

キーポリシーは長期的・アカウント横断的な権限設定に使うのに対し、グラントは短期的・プログラマティックな権限付与です。

3.1 グラントの3要素

  • Grantee: 権限を得る主体 (IAMロール、サービス等)
  • Operations: 許可する操作 (Encrypt, Decrypt, GenerateDataKey等)
  • Constraints: 制約条件 (暗号化コンテキスト、有効期限等)

3.2 グラント作成と削除

グラント作成

aws kms create-grant \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --grantee-principal arn:aws:iam::111111111111:role/LambdaRole \
  --operations Decrypt GenerateDataKey \
  --constraints EncryptionContextSubset={Department=Finance} \
  --region ap-northeast-1

グラント削除

aws kms retire-grant \
  --grant-token <token> \
  --region ap-northeast-1

3.3 グラントの制約条件

{
  "EncryptionContextSubset": {
    "Department": "Finance",
    "Project": "Q1-2026"
  }
}

この場合、Department=FinanceProject=Q1-2026 が両方含まれる暗号化コンテキストでのみデータキーが生成されます。

重要: グラント制約は「少なくとも含まれなければいけない」という意味で、追加のコンテキストがあってもOKです。


4. キーローテーション (Key Rotation)

4.1 自動ローテーション vs 手動ローテーション

種類対象周期既存データへの影響
自動ローテーション対称キーのみ年1回(365日)なし(キーマテリアルは複数世代管理)
手動ローテーション全種類のキーユーザー定義キーそのものを新規作成するため、古いキーは別途保持

キーローテーション比較図

Loading diagram...

4.2 自動ローテーション設定

CLI で有効化

aws kms enable-key-rotation \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1

自動ローテーションの仕組み

  1. AWSが年1回、新しいキーマテリアルを生成
  2. 新しいマテリアルを「カレント」に
  3. 古いマテリアルは「過去」として保持
  4. 復号化時には自動的に適切なマテリアルを使い分け

既存データは自動で復号可能 — これが自動ローテーションの最大の利点です。

4.3 手動ローテーション(キーのエイリアス変更パターン)

# 新しいキーを作成
NEW_KEY_ID=$(aws kms create-key \
  --description "New rotation key" \
  --key-usage ENCRYPT_DECRYPT \
  --region ap-northeast-1 \
  --query 'KeyMetadata.KeyId' \
  --output text)

# 古いキーの別名を別のキーに変更
aws kms update-alias \
  --alias-name alias/my-app-key \
  --target-key-id $NEW_KEY_ID \
  --region ap-northeast-1

# 古いキーは無効化しないで保持(既存データの復号に必要)
aws kms schedule-key-deletion \
  --key-id old-key-id \
  --pending-window-in-days 30 \
  --region ap-northeast-1

重要: 手動ローテーション後、古いキーはすぐ削除してはいけません。既存の暗号化データを復号化する際に必要です。


5. マルチリージョンキー (Multi-Region Keys)

複数リージョンにレプリケートされたキー。ディザスタリカバリーや低遅延アクセスが必要なグローバルアプリケーション向け。

5.1 マルチリージョンキーの特性

Primary Key (主キー): プライマリリージョンに存在
├─ ローテーション管理はここで一元実施
├─ ポリシー変更もここで一元実施
└─ キーマテリアルは自動的にすべてのレプリカに同期

Replica Keys (レプリカキー): 各リージョンに独立存在
├─ 読み取り専用(ローカル修正不可)
├─ ローカルAPI呼び出しで高速アクセス可能
└─ プライマリが削除されるとレプリカも自動削除

5.2 マルチリージョンキー作成

プライマリキーを作成

aws kms create-key \
  --description "Multi-region key for global app" \
  --multi-region \
  --region us-east-1

セカンダリリージョンにレプリケート

aws kms replicate-key \
  --key-id arn:aws:kms:us-east-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --replica-region ap-northeast-1 \
  --description "Replica in Tokyo" \
  --region us-east-1

5.3 マルチリージョンキーの制限

  • 複合化のみ: レプリカキーで新規暗号化はできません(プライマリで暗号化したデータは復号可)
  • ローテーション: プライマリで自動ローテーション設定すると、すべてのレプリカに自動同期
  • 削除: プライマリを削除するとレプリカも自動削除(待機期間なし)
  • キーポリシー: プライマリの変更がレプリカに同期

ユースケース: グローバルなSaaS、CDNバックエンド、マルチリージョンデータベース


6. 非対称キー (Asymmetric Keys)

公開鍵で暗号化、秘密鍵で復号化 — または署名検証。クロスアカウントやサードパーティとの暗号化連携が必要な場合に使用。

6.1 非対称キーの用途

RSA キー
├─ ENCRYPT_DECRYPT: 4KB未満のデータ暗号化(エンベロープ暗号化ではなく直接暗号化)
└─ SIGN_VERIFY: メッセージ署名

ECC キー
├─ SIGN_VERIFY: 高速署名(TLS証明書署名、JWTトークン署名)
└─ メッセージ認証

SM2 キー (中国リージョンのみ)
└─ ENCRYPT_DECRYPT / SIGN_VERIFY

6.2 公開鍵の取得と外部利用

aws kms get-public-key \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1 \
  --query 'PublicKey' \
  --output text | base64 -d > public-key.der

取得した公開鍵をサードパーティに配布 → サードパーティがデータを暗号化 → AWSで秘密鍵で復号化

6.3 非対称キー使用時の注意点

  • パフォーマンス: 対称キーより遥かに遅い(通常は4KBまでのデータ用)
  • 大容量データ: エンベロープ暗号化(データキー使用)に頼る
  • グラント対応: 非対称キーでもグラント制約をサポート

7. HMACキー (Message Authentication)

HMACキーは暗号化ではなく、メッセージ改ざん検知に使用。

7.1 HMAC操作

# HMAC生成
aws kms generate-mac \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/hmac-key-id \
  --message "sensitive data" \
  --mac-algorithm HMAC_SHA_256 \
  --region ap-northeast-1

# HMAC検証
aws kms verify-mac \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/hmac-key-id \
  --message "sensitive data" \
  --mac "base64-encoded-mac" \
  --mac-algorithm HMAC_SHA_256 \
  --region ap-northeast-1

用途: API呼び出しの真正性検証、ファイルダウンロード後の改ざん確認、WebhookペイロードのHMAC署名


8. エンベロープ暗号化 (Envelope Encryption)

KMSの最も重要な概念。大容量データを効率的に暗号化するパターン。

8.1 仕組み

暗号化フロー:

  1. ユーザーデータ (MB~GB)
  2. KMSで「データキー」を生成(KMS内で暗号化)
  3. 平文のデータキーをアプリが受け取る
  4. アプリがユーザーデータをこのデータキーで暗号化
  5. 暗号化されたユーザーデータ + 暗号化されたデータキー を保存

復号化フロー:

  1. 暗号化されたデータキーをKMSに送信
  2. KMSが秘密鍵で復号化 → 平文のデータキーを返却
  3. アプリが平文のデータキーでユーザーデータを復号化

エンベロープ暗号化の流れ図

Loading diagram...

8.2 エンベロープ暗号化のメリット

  1. スケーラビリティ: KMS API呼び出しはマスターキー生成時のみ
  2. 高速化: 実際の暗号化/復号化はアプリ内で実施(ハードウェアアクセラレーション活用可能)
  3. 監査分離: KMSログには「このデータキーを生成した」という記録のみ(ユーザーデータそのものは見えない)

8.3 CLI で エンベロープ暗号化を実装

# [1] 4KBのデータキーを生成(KMS内で暗号化)
aws kms generate-data-key \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --key-spec AES_256 \
  --region ap-northeast-1 \
  > datakey.json

# [2] JSON から平文キーを抽出
PLAINTEXT_KEY=$(jq -r '.Plaintext' datakey.json | base64 -d | xxd -p)
ENCRYPTED_KEY=$(jq -r '.CiphertextBlob' datakey.json)

# [3] OpenSSL で実際のデータを暗号化
openssl enc -aes-256-cbc -in myfile.txt -out myfile.txt.enc -K $PLAINTEXT_KEY -iv 00000000000000000000000000000000 -S 0

# [4] 暗号化されたデータキー + 暗号化ファイルを保存
cat myfile.txt.enc > myfile.bundled
echo $ENCRYPTED_KEY >> myfile.bundled

# [復号化]
# [5] 暗号化されたデータキーから暗号化ファイルを分離
split -b -50 myfile.bundled header_and_file
ENCRYPTED_KEY=$(tail -1 header_and_file)

# [6] KMS で復号化
PLAINTEXT_KEY=$(aws kms decrypt \
  --ciphertext-blob $ENCRYPTED_KEY \
  --region ap-northeast-1 \
  --query 'Plaintext' \
  --output text | base64 -d | xxd -p)

# [7] データを復号化
openssl enc -d -aes-256-cbc -in myfile.txt.enc -out myfile.txt -K $PLAINTEXT_KEY -iv 00000000000000000000000000000000

9. 他サービスとの連携パターン

9.1 Amazon S3 — サーバーサイド暗号化

暗号化方式説明キー管理ユースケース
SSE-S3S3が管理するキーAWS自動管理コンプライアンス要件なし
SSE-KMSカスタマー管理キーユーザーが制御コンプライアンス、監査、キー回転
SSE-Cクライアント提供キークライアント側管理キー管理を完全に手元で実施

SSE-KMS の設定

# S3にSSE-KMS付きでアップロード
aws s3 cp myfile.txt s3://my-bucket/myfile.txt \
  --sse aws:kms \
  --sse-kms-key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012

# デフォルトキーでアップロード
aws s3 cp myfile.txt s3://my-bucket/myfile.txt \
  --sse aws:kms

S3のバケットデフォルト暗号化設定

{
  "Rules": [
    {
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012"
      },
      "BucketKeyEnabled": true
    }
  ]
}

重要: BucketKeyEnabled: true で、KMS API呼び出しを削減(コスト最適化)

9.2 Amazon EBS — ボリューム暗号化

# 暗号化されたEBSボリュームを作成
aws ec2 create-volume \
  --size 100 \
  --availability-zone ap-northeast-1a \
  --encrypted \
  --kms-key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1

EC2インスタンスのデフォルト暗号化設定

aws ec2 enable-ebs-encryption-by-default \
  --region ap-northeast-1

これ以降、指定なしで暗号化ボリュームが作成されます(デフォルトキーで)。

9.3 Amazon RDS — データベース暗号化

# 暗号化されたRDSクラスタを作成
aws rds create-db-cluster \
  --db-cluster-identifier my-cluster \
  --engine aurora-postgresql \
  --master-username admin \
  --master-user-password 'Password123!' \
  --storage-encrypted \
  --kms-key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1

重要: RDSは自動バックアップも同じKMSキーで暗号化されます。キーを削除するとバックアップは回復不可。

9.4 AWS Secrets Manager との連携

Secrets Managerは必ずKMSキーで暗号化(SSE-KMS相当)。

# カスタムキーで暗号化されたシークレットを作成
aws secretsmanager create-secret \
  --name prod/db/password \
  --secret-string 'MyDatabasePassword123!' \
  --kms-key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1

9.5 Lambda — 環境変数の暗号化

# Lambda 関数で暗号化された環境変数を設定
aws lambda update-function-configuration \
  --function-name my-function \
  --environment Variables="{DB_PASSWORD=encrypted_value}" \
  --kms-key-arn arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1

Lambda実行ロールのキーポリシーに kms:Decrypt を許可する必要があります。

9.6 CloudTrail — ログの暗号化

aws cloudtrail create-trail \
  --name my-trail \
  --s3-bucket-name my-cloudtrail-bucket \
  --include-global-service-events \
  --kms-key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1

CloudTrail自体がS3に書き込む際、このKMSキーで暗号化します。


10. Re-encrypt (再暗号化)

既存のKMS暗号化データを別のキーで再暗号化する操作。キー交換や権限分離が必要な場合に使用。

10.1 Re-encrypt の2つのパターン

パターン1: 同じキーで再暗号化(マテリアルローテーション後)

aws kms re-encrypt \
  --ciphertext-blob $(cat encrypted-data) \
  --source-key-id arn:aws:kms:ap-northeast-1:111111111111:key/old-key \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/old-key \
  --region ap-northeast-1

これにより新しいキーマテリアルで暗号化し直されます(キー世代管理)。

パターン2: 別のキーで再暗号化(部門ごとのキー分離)

aws kms re-encrypt \
  --ciphertext-blob $(cat encrypted-data) \
  --source-key-id arn:aws:kms:ap-northeast-1:111111111111:key/finance-key \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/security-key \
  --region ap-northeast-1

10.2 Re-encrypt の特徴

  • ユーザーに暗号化データが見えない: KMS内で直接変換(復号化 → 再暗号化)
  • 監査ログ: 「source key」と「destination key」の両方が記録される
  • 権限: kms:ReEncryptFromkms:ReEncryptTo の両方が必要

キーポリシー設定例:

{
  "Sid": "Allow re-encrypt operations",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111111111111:role/DataManager"
  },
  "Action": [
    "kms:ReEncryptFrom",
    "kms:ReEncryptTo",
    "kms:DescribeKey"
  ],
  "Resource": "*"
}

11. CloudHSM (Hardware Security Module) との関係

KMSはソフトウェアベースですが、より高いセキュリティ要件(HSM検証、自社管理キー等)の場合はCloudHSMの利用を検討します。

特性KMSCloudHSM
基盤AWSマネージドサーバー専有HSMハードウェア
キー管理AWSが保持ユーザーが秘密鍵を保有
**コンプライアンスFIPS 140-2 Level 2FIPS 140-2 Level 3
コスト$1/月 + API呼び出し$200/月 + NAT ゲートウェイ
スケーラビリティAWS側で自動スケールユーザーがクラスタ構築
KMS連携CloudHSMをKMSのキーストアとして使用可能CloudHSMキーをKMS経由でアクセス可能

重要: 「KMSだけでは足りないのか?」という質問が試験に出ます。答え:ほとんどのケースKMSで十分。CloudHSMは規制産業(金融、医療)や「AWSがキーを見られない」という要件の場合のみ。


12. 削除待機期間 (Deletion Pending)

KMSキーを削除する際、即座に削除されるのではなく、7~30日間の待機期間が設定されます。

# 削除をスケジュール(30日待機)
aws kms schedule-key-deletion \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --pending-window-in-days 30 \
  --region ap-northeast-1

待機期間中の状態

  • キーは「Pending Deletion」状態
  • 暗号化・復号化操作は 不可
  • 既存のグラントは失効
  • キーポリシー変更は不可
  • キー削除をキャンセル可能

削除をキャンセル

aws kms cancel-key-deletion \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --region ap-northeast-1

ベストプラクティス: 「削除予定」の古いキーは、CloudTrailで監査後に確認してからキャンセルするフローを構築。誤った削除スケジュールの回復時間を確保。


13. クォータと制限

13.1 キーあたりの制限

制限対応
カスタマー管理キー/アカウント1,000個サポートリクエストで増加可
グラント/キー50,000個セット用途では大丈夫
キーポリシーサイズ32KBほぼ達しない(通常1KB前後)
キーエイリアスリージョンごと制限なし無制限

13.2 API レート制限

ベースライン: 秒あたりの操作数

一般的なオペレーション(Encrypt, Decrypt, GenerateDataKey)
└─ 5,500 requests/秒(東京リージョン)
└─ リージョンによって異なる

エンベロープ暗号化では「データキー生成」が1リクエスト
└─ 数MB のデータ暗号化 = 1リクエスト
└─ 通常のアプリケーション(秒あたり数百リクエスト)では問題なし

スロットリング対策

import time
import boto3

kms = boto3.client('kms')

def generate_data_key_with_retry(key_id, retries=3, backoff=1):
    for attempt in range(retries):
        try:
            response = kms.generate_data_key(
                KeyId=key_id,
                KeySpec='AES_256'
            )
            return response
        except kms.exceptions.ThrottlingException:
            if attempt < retries - 1:
                time.sleep(backoff * (2 ** attempt))
            else:
                raise

14. 暗号化コンテキスト (Encryption Context)

暗号化時に追加のメタデータを含める仕組み。復号化時に同じコンテキストが必要です。

14.1 用途

暗号化コンテキスト
└─ データ改ざん検知
└─ 監査ログの情報充実
└─ 複数ユーザーの同じ鍵でのデータ分離

14.2 実装例

# 暗号化時にコンテキストを含める
aws kms generate-data-key \
  --key-id arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012 \
  --key-spec AES_256 \
  --encryption-context UserId=user-123,DocumentId=doc-456 \
  --region ap-northeast-1

# 復号化時に同じコンテキストが必要
aws kms decrypt \
  --ciphertext-blob $(cat encrypted-data) \
  --encryption-context UserId=user-123,DocumentId=doc-456 \
  --region ap-northeast-1

コンテキストが異なると復号失敗

# これは失敗(コンテキストが異なる)
aws kms decrypt \
  --ciphertext-blob $(cat encrypted-data) \
  --encryption-context UserId=user-789 \
  --region ap-northeast-1
# エラー: "Ciphertext could not be decrypted."

CloudTrail ログでのコンテキスト表示

CloudTrailはKMSのすべての操作を記録。暗号化コンテキストも記録されるため、監査トレイルが充実します。


15. できないこと・制約一覧

15.1 キーの操作に関する制限

できないこと:

  • キーマテリアルの直接エクスポート(秘密鍵)
  • マルチリージョンキーのレプリカでの暗号化
  • 有効期限のあるキーの管理(キーそのものには有効期限概念なし)
  • キーの名前変更(説明は可、エイリアスで対応)
  • リージョン間のキー移動(マルチリージョンキーで対応、単一リージョンキーは新規作成)

15.2 リージョン制限

KMSはリージョナルサービス:

  • キーはリージョンを超えて移動できない
  • グローバルサービス(IAM等)はリージョンごとの異なるキーを使用
  • マルチリージョンキーで部分的に解決(複合化のみ)

15.3 権限・ポリシーの制限

できないこと:

  • キーポリシー未設定での使用(必ず何らかのポリシーが必要)
  • ユーザー側でKMSキーを実際に「見る」こと(公開鍵取得は可)
  • キーポリシーをIAMコンソールで一元管理(キーコンソールのみ)
  • グラント制約の「OR条件」指定(AND のみ)

15.4 データサイズの制限

直接暗号化(非対称キー)

最大 4,096 バイト

GenerateDataKey

最大 1,024 バイト(通常256または512バイト)

大容量データ

エンベロープ暗号化で対応(実装側で何TB でも可能)


16. ベストプラクティス

16.1 キーポリシー設計

原則: 最小権限の法則

{
  "Sid": "Allow specific role for specific operations",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111111111111:role/EC2-Application"
  },
  "Action": [
    "kms:Decrypt",
    "kms:DescribeKey",
    "kms:GenerateDataKey"
  ],
  "Resource": "*"
}

悪い例: 過度な権限付与

{
  "Sid": "Allow everything (WRONG)",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111111111111:role/EC2-Application"
  },
  "Action": "kms:*",
  "Resource": "*"
}

16.2 キーローテーション戦略

対称キー(S3, EBS 等)
└─ 自動ローテーション有効化(年1回)
└─ 既存データは自動で復号可能

非対称キー
└─ 署名/暗号化の有効期限に合わせ手動ローテーション
└─ 新キーへの移行期間を設定

敏感な用途(金融、医療)
└─ 90日ごとの手動ローテーション検討

16.3 監査とログ

# CloudTrail で KMS操作を監視(構文例)
aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=ResourceName,AttributeValue=my-kms-key \
  --region ap-northeast-1

監視すべき操作

kms:DeleteKey(削除スケジュール)
kms:DisableKey(キー無効化)
kms:PutKeyPolicy(ポリシー変更)
kms:CreateGrant(グラント作成)
kms:RetireGrant(グラント削除)
kms:Decrypt(復号化 — 大量操作は不正アクセスの兆候)

16.4 クロスアカウント利用時の考慮

キーオーナー(アカウントA)の設定

{
  "Sid": "Allow another account to use the key",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::222222222222:root"
  },
  "Action": [
    "kms:Decrypt",
    "kms:DescribeKey",
    "kms:GenerateDataKey"
  ],
  "Resource": "*"
}

キー利用者(アカウントB)の IAMポリシー

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:DescribeKey",
        "kms:GenerateDataKey"
      ],
      "Resource": "arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012"
    }
  ]
}

重要: キーポリシー + IAMポリシー 両方が許可している必要があります。


17. 試験で狙われるポイント(最終チェックリスト)

  • キーポリシー変更にはユーザー/ロール + kms:PutKeyPolicy 権限が必要
  • AWS管理キーはキーポリシー編集不可
  • 自動ローテーションは対称キーのみ
  • マルチリージョンキーのレプリカは「読み取り専用」(暗号化は不可)
  • グラント制約は「AND」のみ(OR は不可)
  • エンベロープ暗号化で大容量データを効率的に暗号化
  • S3 の SSE-KMS で BucketKeyEnabled=true で KMS API呼び出し削減
  • Re-encrypt は「ユーザーに暗号文が見えない」ことが重要
  • クロスアカウント利用には「キーポリシー + IAMポリシー」両方が必要
  • キー削除は 7~30 日の待機期間あり(キャンセル可能)
  • CloudHSM は「AWSがキーを見られない」要件の場合のみ
  • 暗号化コンテキストは復号化時に同じコンテキストが必要
  • KMS はリージョナルサービス(グローバルキーは不可)

18. 実装パターン(Pythonコード例)

18.1 エンベロープ暗号化の実装例

import boto3
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import os

kms = boto3.client('kms')

def envelope_encrypt(key_id, plaintext):
    """
    エンベロープ暗号化
    1. KMSでデータキーを生成
    2. データキーでプレーンテキストを暗号化
    3. 暗号化されたデータキー + 暗号化データを返す
    """
    # [1] KMS からデータキーを取得
    response = kms.generate_data_key(
        KeyId=key_id,
        KeySpec='AES_256'
    )
    
    plaintext_key = response['Plaintext']
    encrypted_key = response['CiphertextBlob']
    
    # [2] IV を生成
    iv = os.urandom(16)
    
    # [3] AES-256-CBC で暗号化
    cipher = Cipher(
        algorithms.AES(plaintext_key),
        modes.CBC(iv),
        backend=default_backend()
    )
    encryptor = cipher.encryptor()
    
    # PKCS7 パディングを手動実装
    padding_length = 16 - (len(plaintext) % 16)
    padded_plaintext = plaintext + bytes([padding_length] * padding_length)
    
    ciphertext = encryptor.update(padded_plaintext) + encryptor.finalize()
    
    # [4] 暗号化されたキー + IV + 暗号文をまとめて返す
    return {
        'encrypted_key': base64.b64encode(encrypted_key).decode(),
        'iv': base64.b64encode(iv).decode(),
        'ciphertext': base64.b64encode(ciphertext).decode()
    }


def envelope_decrypt(encrypted_data):
    """
    エンベロープ復号化
    """
    encrypted_key = base64.b64decode(encrypted_data['encrypted_key'])
    iv = base64.b64decode(encrypted_data['iv'])
    ciphertext = base64.b64decode(encrypted_data['ciphertext'])
    
    # [1] KMS で暗号化されたキーを復号化
    response = kms.decrypt(CiphertextBlob=encrypted_key)
    plaintext_key = response['Plaintext']
    
    # [2] AES-256-CBC で復号化
    cipher = Cipher(
        algorithms.AES(plaintext_key),
        modes.CBC(iv),
        backend=default_backend()
    )
    decryptor = cipher.decryptor()
    padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize()
    
    # [3] パディングを除去
    padding_length = padded_plaintext[-1]
    plaintext = padded_plaintext[:-padding_length]
    
    return plaintext


# 使用例
key_id = 'arn:aws:kms:ap-northeast-1:111111111111:key/12345678-1234-1234-1234-123456789012'
secret_data = b'This is my sensitive data'

encrypted = envelope_encrypt(key_id, secret_data)
decrypted = envelope_decrypt(encrypted)

print(f"Original: {secret_data}")
print(f"Decrypted: {decrypted}")
assert secret_data == decrypted, "Decryption failed!"

18.2 グラント管理

def create_grant_with_constraints(key_id, grantee_principal, operations, context):
    """
    暗号化コンテキスト制約付きグラントを作成
    """
    response = kms.create_grant(
        KeyId=key_id,
        GranteePrincipal=grantee_principal,
        Operations=operations,
        Constraints={
            'EncryptionContextSubset': context
        }
    )
    return response['GrantToken']


def retire_grant(grant_token):
    """
    グラントを削除
    """
    kms.retire_grant(GrantToken=grant_token)


# 使用例
grant_token = create_grant_with_constraints(
    key_id='arn:aws:kms:ap-northeast-1:111111111111:key/...',
    grantee_principal='arn:aws:iam::111111111111:role/LambdaRole',
    operations=['Decrypt', 'GenerateDataKey'],
    context={
        'Department': 'Finance',
        'Project': 'Q1-2026'
    }
)

# 後で削除
retire_grant(grant_token)

19. よくある間違いと対策

19.1 「IAMポリシーがあれば大丈夫」

❌ 間違い

{
  "Effect": "Allow",
  "Action": "kms:Decrypt",
  "Resource": "arn:aws:kms:ap-northeast-1:111111111111:key/..."
}

✓ 正解:キーポリシーで以下も許可

{
  "Sid": "Allow IAM policy use",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111111111111:role/MyRole"
  },
  "Action": "kms:Decrypt",
  "Resource": "*"
}

19.2 「古いキーはすぐ削除できる」

❌ 間違い:既存データが復号不可になる

aws kms schedule-key-deletion --key-id old-key --pending-window-in-days 7
# 古いデータはもう復号できない!

✓ 正解:過去ログの確認期間を確保

# CloudTrail で最後の使用日時を確認
aws cloudtrail lookup-events --lookup-attributes AttributeKey=ResourceName,AttributeValue=old-key

# 90日程度の待機期間を確保
aws kms schedule-key-deletion --key-id old-key --pending-window-in-days 90

19.3 「エンベロープ暗号化は複雑」

❌ 誤解:boto3 / SDK がサポート

✓ Boto3 の高レベルAPI:

from boto3.dynamodb.conditions import Key
from botocore.config import Config

# AWS SDK では暗号化コンテキスト自動処理
config = Config(s3={'use_accelerate_endpoint': True})
client = boto3.client('s3', config=config)

実装の複雑さは「何を暗号化するか」による。単純な用途なら1行で完結。


最後に

KMSはAWSのセキュリティの要(かなめ)。試験出題の約15~20%を占めます。

重要な心構え

  1. ポリシーが2段階 — キーポリシー + IAMポリシー
  2. できないこと理解 — 秘密鍵エクスポート、リージョン移動、即時削除
  3. 監査を忘れない — CloudTrail/CloudWatch ログ監視
  4. エンベロープ暗号化 — スケーラビリティの鍵

最後の模擬試験では「キーポリシー編集問題」「クロスアカウント利用問題」「グラント制約問題」が必ず出ます。上記の実装例を手で動かして体に染み込ませてください。

頑張ってください。合格を祈ります。