概要
AWS KMSの Encrypt APIにデータを渡せば、KMSキーで直接暗号化できます。ただし渡せるサイズには上限があり、対称暗号化キーの場合は 4,096バイト(4KB) です。データベースの認証情報やAPIキーのような小さな秘密情報ならこれで足りますが、ログファイルやバックアップのような大きなデータは通せません。
では大きなデータはどう暗号化するのか。答えがエンベロープ暗号化です。KMSから「データキー」を発行してもらい、実データはそのデータキーでローカルに暗号化し、データキー自体はKMSキーで暗号化して一緒に保管します。S3のSSE-KMSやEBSの暗号化も、内部ではこの仕組みで動いています。
この記事では、直接暗号化が4KBで止まることを実際に確認したうえで、GenerateDataKey を使って大きなファイルを暗号化・復号し、両者の使い分けを整理します。

クラウドおさる直接暗号化が4KBで止まるのを確かめてから、データキーで大きなファイルを暗号化・復号するところまで、一緒に通すでござる。「小さな秘密は直接、大きなデータはデータキー」、この線引きを手で覚えるのが今日の狙いでござるな。
この記事のメリット
EncryptAPIで暗号化できるサイズの上限を、キーの種類別に把握できるようになる- エンベロープ暗号化でKMSが何を返し、手元で何をするのかを説明できるようになる
GenerateDataKeyが返す2つの値の役割を区別できるようになる- 「認証情報は直接、大きなデータはデータキー」という使い分けの判断ができるようになる
- SCS試験で暗号化方式の選択を問う設問に正確に答えられるようになる
執筆者とキャラクター紹介
執筆者:土肥(とひ)
株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。


クラウドおさる



はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。



基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。



猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。
技術解説
直接暗号化で渡せるサイズ
Encrypt APIに渡せる平文の最大サイズは、KMSキーの種類と暗号化アルゴリズムで決まります。
| キーの種類 | 暗号化アルゴリズム | 最大サイズ |
|---|---|---|
| 対称暗号化キー | SYMMETRIC_DEFAULT | 4,096バイト |
| RSA_2048 | RSAES_OAEP_SHA_1 / RSAES_OAEP_SHA_256 | 214バイト / 190バイト |
| RSA_3072 | RSAES_OAEP_SHA_1 / RSAES_OAEP_SHA_256 | 342バイト / 318バイト |
| RSA_4096 | RSAES_OAEP_SHA_1 / RSAES_OAEP_SHA_256 | 470バイト / 446バイト |
覚えるのは「対称キーで4KB」です。非対称キーはさらに小さく、数百バイトしか入りません。
公式ドキュメントが挙げる直接暗号化のユースケースは、個人識別情報(PII)・データベースのパスワード・その他の小さな機密情報です。裏を返すと、それ以外はエンベロープ暗号化を使うことになります。
エンベロープ暗号化とデータキー
データキーは、AWS KMSの外に持ち出して使える暗号化キーです。KMSキー自体はダウンロードできませんが、データキーは手元に返されます。
GenerateDataKey を呼ぶと、2つの値が返ります。
| 返る値 | 中身 | 使い道 |
|---|---|---|
Plaintext | 平文のデータキー | 手元でデータを暗号化・復号するのに使う。使い終わったらメモリから消す |
CiphertextBlob | KMSキーで暗号化されたデータキー | 暗号化したデータと一緒に保管する。復号のときにKMSへ渡す |
流れにすると次のようになります。
暗号化するとき
GenerateDataKeyでデータキーを2つの形で受け取る- 平文のデータキーで実データを暗号化する(KMSは通らないのでサイズ制限がない)
- 平文のデータキーをメモリから消す
- 暗号化したデータと、暗号化されたデータキーを一緒に保管する
復号するとき
- 保管しておいた暗号化データキーを
Decryptに渡し、平文のデータキーを取り戻す - そのデータキーで実データを復号する
- 平文のデータキーをメモリから消す





Plaintext は手元で使ったらメモリから消し、CiphertextBlob はデータに添えて保管する、ここが押さえどころでござる。猿山のバナナ倉庫でいえば、親鍵(KMSキー)は長老会から一歩も出さず、当番には小分けの鍵を渡し、使い終わったら封をした控えだけを荷に括り付けておく形でござるな。
なぜKMSに大きなデータを通さないのか
理由は3つあります。
| 観点 | 直接暗号化 | エンベロープ暗号化 |
|---|---|---|
| サイズ | 4KBまで | 制限なし(手元で暗号化するため) |
| 通信 | データそのものがネットワークを往復する | データは手元から出ない。往復するのはデータキーだけ |
| コスト・スループット | データ量に比例してAPIコールが増える | 1つのデータキーで大量のデータを暗号化できる |
S3のSSE-KMS・EBSの暗号化・Secrets Managerも、内部ではこの方式です。「マネージドな暗号化」の中身がエンベロープ暗号化だと理解しておくと、権限設計で kms:GenerateDataKey* が必要になる理由もつながります。
使い分けの判断
| 対象 | 方式 |
|---|---|
| データベース認証情報・APIキー・パスワード | 直接暗号化(Encrypt)。ただし実運用ではSecrets ManagerやParameter Storeを使うほうが管理が楽 |
| ログファイル・バックアップ・画像などのファイル | エンベロープ暗号化(GenerateDataKey) |
| S3・EBS・RDSなどに置くデータ | 各サービスの暗号化機能(内部でエンベロープ暗号化が使われる) |
設問に「4KBを超える」「大量のデータ」「アプリケーション側で暗号化する」といった言葉があればエンベロープ暗号化、「認証情報」「小さなシークレット」であれば直接暗号化が候補になります。
実践
カスタマー管理キーを作成し、AWS CloudShellから直接暗号化が4KBで止まることを確認したうえで、データキーを使って大きなファイルを暗号化・復号します。
前提条件
- リージョン:
ap-northeast-1(東京) - KMSの操作権限とAWS CloudShellの利用権限を持つIAMユーザーまたはロールでコンソールにログイン済みであること
このハンズオンで作成するリソースは以下のとおりです。
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| KMSカスタマー管理キー | envelope-lab-key | 直接暗号化とデータキー発行の検証用 |
KMSのカスタマー管理キーは1本あたり月 1 USD の課金対象で、日割りされます。APIコールにも料金がかかりますが、この手順の回数であればごくわずかです。
手順1: カスタマー管理キーを作成する
AWSマネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。
上部の検索バーに KMS と入力し、表示された「Key Management Service」を選択します。
左側ナビゲーションの「カスタマー管理型のキー」を選択し、「キーの作成」をクリックします。
キーの作成は6つのステップに分かれたウィザードになっています。
ステップ1「キーを設定」 では、以下が既定で選ばれていることを確認して「次へ」をクリックします。
- キーのタイプ:
対称 - キーの使用法:
暗号化および復号化 - キーマテリアルのオリジン:
KMS - 推奨 - リージョン:
単一リージョンキー
ステップ2「ラベルを追加」 で、エイリアスに envelope-lab-key を入力します。説明とタグは空のままにします。


ステップ3「キーの管理アクセス許可を定義」 と ステップ4「キーの使用法アクセス許可を定義」 で、自分がログインしているIAMユーザーまたはロールにチェックを入れて「次へ」をクリックします。ステップ5「キーポリシーを編集」は、生成されたポリシーをそのまま使うので変更しません。
ステップ6「確認」 で内容を確認し、「完了」をクリックします。
作成されたキーの詳細画面で、キーIDとエイリアスを確認します。


手順2: 小さな値を直接暗号化する
コンソール画面左下のフッターにある「CloudShell」をクリックして、AWS CloudShellを開きます。初回は「AWS CloudShell へようこそ」のダイアログが表示されるので、「閉じる」をクリックします。シェルが起動して ~ $ のプロンプトが出れば準備完了です。
データベースのパスワードを想定した短い文字列を暗号化します。
aws kms encrypt \
--key-id alias/envelope-lab-key \
--plaintext "$(echo -n 'P@ssw0rd-for-db' | base64)" \
--query CiphertextBlob \
--output textBase64の暗号文が返ります。これが Encrypt APIによる直接暗号化です。


手順3: 4KBを超えるデータで失敗することを確認する
5KBのダミーファイルを作り、同じように暗号化を試みます。
head -c 5120 /dev/urandom > big.bin
aws kms encrypt \
--key-id alias/envelope-lab-key \
--plaintext fileb://big.bin \
--query CiphertextBlob \
--output textValidationException となり、平文が長すぎる旨のエラーが返ります。対称暗号化キーの上限である4,096バイトを超えたためです。





5KBを渡しただけで ValidationException でござった。対称暗号化キーで4,096バイト、非対称キーならさらに小さく、Encrypt に大きなデータをそのまま通す道は無いのでござる。
手順4: データキーを発行する
GenerateDataKey でデータキーを発行します。平文のデータキーと、暗号化されたデータキーの両方が返ることを確認します。
aws kms generate-data-key \
--key-id alias/envelope-lab-key \
--key-spec AES_256 \
--output json > datakey.json
# 平文のデータキー(このあとファイルの暗号化に使う)
jq -r .Plaintext datakey.json | base64 --decode > plain.key
# 暗号化されたデータキー(暗号化データと一緒に保管する)
jq -r .CiphertextBlob datakey.json | base64 --decode > encrypted.keydatakey.json の中身を表示し、Plaintext と CiphertextBlob の2つが入っていることを確認します。平文のデータキーをそのまま画面に出さないよう、先頭だけを表示します。
jq '{KeyId, CiphertextBlob: (.CiphertextBlob[0:44] + "..."), Plaintext: (.Plaintext[0:8] + "...(省略)")}' datakey.jsonKeyId には、このデータキーを暗号化したKMSキーのARNが入ります。復号のときにキーを指定しなくてよいのは、この情報が暗号化データキーの中に含まれているためです。


手順5: データキーで大きなファイルを暗号化する
手順3で作った5KBのファイルを、平文のデータキーで暗号化します。暗号化はローカルで行うため、KMSのサイズ制限は関係ありません。
openssl enc -aes-256-cbc -pbkdf2 \
-in big.bin -out big.bin.enc \
-pass file:plain.key
# 平文のデータキーは役目を終えたので削除する
shred -u plain.key 2>/dev/null || rm -f plain.key
ls -l big.bin big.bin.enc encrypted.keyここでは手順を短くするため、データキーを openssl のパスフレーズとして渡し、PBKDF2 で導出した鍵で暗号化する簡略版にしています。-pass file: はファイルの1行目だけを読むため、バイナリのデータキーに改行が含まれるとそこまでしか使われません(暗号化と復号で同じように読まれるので、復号はできます)。データキーそのものを AES の鍵として使う場合は、-K と -iv で16進の鍵と IV を渡します。
暗号化されたファイル big.bin.enc と、暗号化されたデータキー encrypted.key が残ります。この2つをセットで保管するのがエンベロープ暗号化です。


手順6: 復号する
保管しておいた暗号化データキーをKMSに渡して平文のデータキーを取り戻し、ファイルを復号します。
aws kms decrypt \
--ciphertext-blob fileb://encrypted.key \
--query Plaintext \
--output text | base64 --decode > plain.key
openssl enc -d -aes-256-cbc -pbkdf2 \
-in big.bin.enc -out big.bin.dec \
-pass file:plain.key
# 元のファイルと一致することを確認する
cmp big.bin big.bin.dec && echo "一致しました"cmp が差分なしで終わり、元のファイルと復号したファイルが一致することを確認します。


decrypt では暗号化に使ったKMSキーを指定していません。暗号化データキーの中にどのキーで暗号化されたかの情報が含まれているためです(対称キーの場合)。復号する側には、そのキーに対する kms:Decrypt の権限が必要です。



暗号化の方式を選ぶとき、データの大きさと「アプリケーション側で暗号化するか」に目を向けるのが試験の観点でござるな。認証情報のような小さな値か、ファイルやログのような大きなデータか、そこで直接暗号化とエンベロープ暗号化を分けるのでござる。
まとめ
| 方式 | 使うAPI | 扱えるサイズ | 向いている対象 |
|---|---|---|---|
| 直接暗号化 | Encrypt / Decrypt | 対称キーで4,096バイトまで | 認証情報・パスワード・PIIなどの小さな値 |
| エンベロープ暗号化 | GenerateDataKey + ローカルの暗号化 | 制限なし | ファイル・ログ・バックアップなどの大きなデータ |
Encryptに渡せるのは対称暗号化キーで4,096バイトまで。非対称キーはさらに小さいGenerateDataKeyは平文のデータキーと暗号化されたデータキーを返す。前者は使い終わったら消し、後者はデータに添えて保管する- エンベロープ暗号化ではデータ本体がネットワークを往復しないため、サイズ・コスト・スループットの面で有利になる
- S3のSSE-KMSやEBSの暗号化も内部はエンベロープ暗号化。だから権限設計で
kms:GenerateDataKey*が必要になる
参照先
- Encrypt – AWS Key Management Service
- データキーを生成する – AWS Key Management Service
- GenerateDataKey – AWS Key Management Service
- Decrypt – AWS Key Management Service
- AWS KMS の概念 – AWS Key Management Service











