KMSの直接暗号化と4KBの壁 ── データキーによるエンベロープ暗号化

目次

概要

AWS KMSの Encrypt APIにデータを渡せば、KMSキーで直接暗号化できます。ただし渡せるサイズには上限があり、対称暗号化キーの場合は 4,096バイト(4KB) です。データベースの認証情報やAPIキーのような小さな秘密情報ならこれで足りますが、ログファイルやバックアップのような大きなデータは通せません。

では大きなデータはどう暗号化するのか。答えがエンベロープ暗号化です。KMSから「データキー」を発行してもらい、実データはそのデータキーでローカルに暗号化し、データキー自体はKMSキーで暗号化して一緒に保管します。S3のSSE-KMSやEBSの暗号化も、内部ではこの仕組みで動いています。

この記事では、直接暗号化が4KBで止まることを実際に確認したうえで、GenerateDataKey を使って大きなファイルを暗号化・復号し、両者の使い分けを整理します。

直接暗号化とエンベロープ暗号化 ── 4KB を超えたらデータキーを使う
直接暗号化とエンベロープ暗号化 ── 4KB を超えたらデータキーを使う
クラウドおさる

直接暗号化が4KBで止まるのを確かめてから、データキーで大きなファイルを暗号化・復号するところまで、一緒に通すでござる。「小さな秘密は直接、大きなデータはデータキー」、この線引きを手で覚えるのが今日の狙いでござるな。

この記事のメリット

  • Encrypt APIで暗号化できるサイズの上限を、キーの種類別に把握できるようになる
  • エンベロープ暗号化でKMSが何を返し、手元で何をするのかを説明できるようになる
  • GenerateDataKey が返す2つの値の役割を区別できるようになる
  • 「認証情報は直接、大きなデータはデータキー」という使い分けの判断ができるようになる
  • SCS試験で暗号化方式の選択を問う設問に正確に答えられるようになる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

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

クラウドおさる

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

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

直接暗号化で渡せるサイズ

Encrypt APIに渡せる平文の最大サイズは、KMSキーの種類と暗号化アルゴリズムで決まります。

キーの種類暗号化アルゴリズム最大サイズ
対称暗号化キーSYMMETRIC_DEFAULT4,096バイト
RSA_2048RSAES_OAEP_SHA_1 / RSAES_OAEP_SHA_256214バイト / 190バイト
RSA_3072RSAES_OAEP_SHA_1 / RSAES_OAEP_SHA_256342バイト / 318バイト
RSA_4096RSAES_OAEP_SHA_1 / RSAES_OAEP_SHA_256470バイト / 446バイト

覚えるのは「対称キーで4KB」です。非対称キーはさらに小さく、数百バイトしか入りません。

公式ドキュメントが挙げる直接暗号化のユースケースは、個人識別情報(PII)・データベースのパスワード・その他の小さな機密情報です。裏を返すと、それ以外はエンベロープ暗号化を使うことになります。

エンベロープ暗号化とデータキー

データキーは、AWS KMSの外に持ち出して使える暗号化キーです。KMSキー自体はダウンロードできませんが、データキーは手元に返されます。

GenerateDataKey を呼ぶと、2つの値が返ります。

返る値中身使い道
Plaintext平文のデータキー手元でデータを暗号化・復号するのに使う。使い終わったらメモリから消す
CiphertextBlobKMSキーで暗号化されたデータキー暗号化したデータと一緒に保管する。復号のときにKMSへ渡す

流れにすると次のようになります。

暗号化するとき

  • GenerateDataKey でデータキーを2つの形で受け取る
  • 平文のデータキーで実データを暗号化する(KMSは通らないのでサイズ制限がない)
  • 平文のデータキーをメモリから消す
  • 暗号化したデータと、暗号化されたデータキーを一緒に保管する

復号するとき

  • 保管しておいた暗号化データキーを Decrypt に渡し、平文のデータキーを取り戻す
  • そのデータキーで実データを復号する
  • 平文のデータキーをメモリから消す
GenerateDataKey が返す2つの値と、その使いどころ
GenerateDataKey が返す2つの値と、その使いどころ
クラウドおさる

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 の実務経験があるなら、単価を上げにいく

AWS に特化したフリーランスエージェントです。以下は取り扱い案件の一例です。設計・SRE・セキュリティ・生成 AI の領域で、専門を掛け合わせるほど単価が上がります。

横にスクロールできます。掲載時点の情報のため、募集が終了している場合があります。条件の近い案件をご紹介しますので、お気軽にご相談ください。

実践

ハンズオンガイド7 ステップ画面 7 枚

コンソールの横に開いて、チェックしながら進めましょう。

ガイドを開く

別タブで開きます。チェックはこのブラウザに保存されます。

カスタマー管理キーを作成し、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とエイリアスを確認します。

作成された envelope-lab-key の詳細画面(キーIDとエイリアスが確認できる状態)
作成された envelope-lab-key の詳細画面(キー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 text

Base64の暗号文が返ります。これが Encrypt APIによる直接暗号化です。

直接暗号化が成功し、暗号文が返っている状態のCloudShell
直接暗号化が成功し、暗号文が返っている状態のCloudShell

手順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 text

ValidationException となり、平文が長すぎる旨のエラーが返ります。対称暗号化キーの上限である4,096バイトを超えたためです。

4KB超のファイルで暗号化が失敗し、ValidationExceptionが表示された状態
4KB超のファイルで暗号化が失敗し、ValidationExceptionが表示された状態
クラウドおさる

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.key

datakey.json の中身を表示し、Plaintext と CiphertextBlob の2つが入っていることを確認します。平文のデータキーをそのまま画面に出さないよう、先頭だけを表示します。

jq '{KeyId, CiphertextBlob: (.CiphertextBlob[0:44] + "..."), Plaintext: (.Plaintext[0:8] + "...(省略)")}' datakey.json

KeyId には、このデータキーを暗号化したKMSキーのARNが入ります。復号のときにキーを指定しなくてよいのは、この情報が暗号化データキーの中に含まれているためです。

GenerateDataKeyの応答(PlaintextとCiphertextBlobが返っている状態)
GenerateDataKeyの応答(PlaintextとCiphertextBlobが返っている状態)

手順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* が必要になる

参照先

フリーランス案件
クラウドおさる
クラウドキャリアフリーランス

AWS の実務経験があるなら、単価を上げにいく

AWS に特化したフリーランスエージェントです。以下は取り扱い案件の一例です。設計・SRE・セキュリティ・生成 AI の領域で、専門を掛け合わせるほど単価が上がります。

横にスクロールできます。掲載時点の情報のため、募集が終了している場合があります。条件の近い案件をご紹介しますので、お気軽にご相談ください。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次