KMSキーポリシーの条件キー(kms:ViaService)によるサービス別アクセス制御

目次

概要

AWS KMSのカスタマー管理キーは、キーポリシーを使ってアクセスを細かく制御できます。KMS鍵タイプ(AWS所有/AWS管理/カスタマー管理)の違いについては過去の記事で解説していますが、本記事ではキーポリシーの 条件キー(Condition Key) に焦点を当てます。

特に kms:ViaService 条件キーは、KMSキーの使用を特定のAWSサービスからのリクエストに限定できる仕組みです。たとえば「このKMSキーはus-west-1リージョンのS3からのリクエストでのみ使用を許可する」といった制御が可能になります。

本記事では、kms:ViaService 条件キーを使ったキーポリシーを設定し、S3経由でのKMS操作は成功するが、直接のKMS API呼び出しでは失敗することを確認します。

kms:ViaService条件キーにより、S3経由のKMS操作は許可され、直接のKMS API呼び出しは拒否される構成を示す図解
kms:ViaService条件キーにより、S3経由のKMS操作は許可され、直接のKMS API呼び出しは拒否される構成を示す図解

この記事のメリット

  • KMSキーポリシーにおける条件キーの役割と記述方法を理解できる
  • kms:ViaService 条件キーの仕組みと記述形式を正確に把握できる
  • Principal に "AWS": "*" を指定した場合の kms:CallerAccount 条件キーによるアカウント制限の方法を学べる
  • S3のSSE-KMS暗号化設定と、KMSキーポリシーとの連携を実践できる
  • SCS試験で「KMSキーポリシーの条件キー」に関する問いに正確に答えられるようになる

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

執筆者:土肥(とひ)

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

土肥

クラウドおさる

クラウドおさる

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

クラウドおさる

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

クラウドおさる

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

技術解説

KMSキーポリシーの基本構造

KMSキーポリシーは、KMSキーへのアクセスを制御するリソースベースのポリシーです。IAMポリシーと同様に、Effect、Principal、Action、Resource、Condition で構成されます。

{
    "Sid": "ステートメントの識別子",
    "Effect": "Allow",
    "Principal": { "AWS": "..." },
    "Action": [ "kms:Decrypt", "kms:GenerateDataKey" ],
    "Resource": "*",
    "Condition": {
        "StringEquals": {
            "条件キー": "条件値"
        }
    }
}

キーポリシーの Resource は常に "*" です。キーポリシーはそのKMSキー自体に適用されるため、Resource にキーのARNを指定する必要はありません。

kms:ViaService 条件キーとは

kms:ViaService は、KMSキーの使用を 特定のAWSサービス経由のリクエストに限定する 条件キーです。AWSサービスがユーザーの代わりにKMS APIを呼び出す場合(たとえばS3がオブジェクトを暗号化する際にKMSを呼び出す場合)、KMSはリクエストの送信元サービスを識別できます。

kms:ViaService の値は以下の形式で指定します。

<サービス名>.<リージョン>.amazonaws.com

例:

  • S3(us-west-1): s3.us-west-1.amazonaws.com
  • EBS(ap-northeast-1): ec2.ap-northeast-1.amazonaws.com
  • RDS(ap-northeast-1): rds.ap-northeast-1.amazonaws.com

この条件キーを使うことで、以下のような制御が可能です。

制御の例kms:ViaService の値
東京リージョンのS3からのみ許可s3.ap-northeast-1.amazonaws.com
us-west-1のS3からのみ許可s3.us-west-1.amazonaws.com
東京リージョンのEBSからのみ許可ec2.ap-northeast-1.amazonaws.com

Principal “*” と kms:CallerAccount の組み合わせ

キーポリシーの Principal に "AWS": "*" を指定すると、すべてのAWSプリンシパルが対象になります。しかし、これだけでは他のAWSアカウントからのアクセスも許可されてしまいます。

そこで kms:CallerAccount 条件キーを組み合わせて、特定のアカウントに制限します。

"Principal": { "AWS": "*" },
"Condition": {
    "StringEquals": {
        "kms:CallerAccount": "111122223333"
    }
}

kms:CallerAccount は、リクエストを送ったプリンシパルが属するAWSアカウントIDと比較される条件キーです。この条件により、そのアカウント内のすべてのIAMエンティティ(ユーザー、ロール)からのリクエストが許可されます。

aws:PrincipalArn では代用できません。 aws:PrincipalArn はリクエスト元プリンシパルのARNそのもの(例: arn:aws:iam::111122223333:user/alice)と比較されるため、arn:aws:iam::111122223333:root を指定してもアカウント内のIAMユーザーには一致せず、リクエストは拒否されます。アカウント単位で判定したい場合は kms:CallerAccount(またはグローバル条件キーの aws:PrincipalAccount)を使います。

"Principal": { "AWS": "arn:aws:iam::111122223333:root" } と直接指定する方法もありますが、Principal に "*" を置き Condition で制限するパターンは、より柔軟な条件設定が可能です。

kms:ViaService と kms:CallerAccount の組み合わせ

この2つの条件キーを組み合わせることで、「特定アカウントの、特定リージョンの特定サービスからのリクエストのみ許可する」という厳密な制御が実現できます。

{
    "Sid": "Allow access through S3 for all principals in the account",
    "Effect": "Allow",
    "Principal": { "AWS": "*" },
    "Action": [
        "kms:Decrypt",
        "kms:GenerateDataKey"
    ],
    "Resource": "*",
    "Condition": {
        "StringEquals": {
            "kms:CallerAccount": "111122223333",
            "kms:ViaService": "s3.us-west-1.amazonaws.com"
        }
    }
}

このポリシーステートメントのポイントを整理します。

要素設定値意味
Principal"AWS": "*"すべてのAWSプリンシパルが対象
Actionkms:Decrypt, kms:GenerateDataKey復号とデータキー生成のみ許可(暗号化操作に必要な最小限の権限)
kms:CallerAccount自アカウントID特定アカウント内のエンティティに限定
kms:ViaServices3.us-west-1.amazonaws.comus-west-1リージョンのS3経由のリクエストのみ許可

Condition ブロック内の複数の条件キーは AND条件 で評価されます。したがって、kms:CallerAccount と kms:ViaService の両方の条件を満たすリクエストのみが許可されます。

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

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

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

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

実践

前提条件

  • リージョン: ap-northeast-1(東京)
  • IAMユーザーまたはロールに kms:* と s3:* の権限があること
  • 自身のAWSアカウントIDが確認できていること

作成するリソース一覧

リソース種別リソース名用途
KMSキーs3-via-service-keykms:ViaService条件付きのカスタマー管理キー
S3バケットkms-via-service-test-<アカウントID>SSE-KMS暗号化の検証用バケット

ステップ1: カスタマー管理KMSキーを作成する

まず、カスタマー管理のKMSキーを作成します。

  • AWSマネジメントコンソールにログインし、リージョンがap-northeast-1(東京)であることを確認します
  • 上部の検索バーにKMSと入力し、表示された「Key Management Service」を選択します
  • 左側ナビゲーションの「カスタマー管理型のキー」を選択します
  • 「キーの作成」をクリックします。キーの作成は6ステップのウィザードで進みます
  • 「ステップ 1: キーを設定」で以下を選択し、「次へ」をクリックします
  • キーのタイプ: 対称(デフォルト)
  • キーの使用法: 暗号化および復号化(デフォルト)
  • 「ステップ 2: ラベルを追加」で以下を入力します
  • エイリアス: s3-via-service-key
  • 説明: kms:ViaService条件キーの検証用
KMSキー作成ウィザードのラベル入力画面(エイリアスと説明)
KMSキー作成ウィザードのラベル入力画面(エイリアスと説明)
  • 「次へ」をクリックします
  • 「ステップ 3: キーの管理アクセス許可を定義」で、現在ログインしているIAMユーザーまたはロールにチェックを入れます
  • 「次へ」をクリックします
  • 「ステップ 4: キーの使用法アクセス許可を定義」では何も選択せずに「次へ」をクリックします(使用許可はキーポリシーで直接制御するため)

ステップ2: kms:ViaService条件付きのキーポリシーを設定する

「ステップ 5: キーポリシーを編集」でポリシーのプレビューが表示されます。「編集」をクリックしてエディタを開き、ポリシー全体を次の内容に置き換えます。

注意: ACCOUNT_ID はご自身のAWSアカウントID、USER_NAME はキー管理者にするIAMユーザー名に置き換えてください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": { "AWS": "arn:aws:iam::ACCOUNT_ID:user/USER_NAME" },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Enable*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowS3ViaServiceOnly",
            "Effect": "Allow",
            "Principal": { "AWS": "*" },
            "Action": [
                "kms:Decrypt",
                "kms:GenerateDataKey"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "kms:CallerAccount": "ACCOUNT_ID",
                    "kms:ViaService": "s3.ap-northeast-1.amazonaws.com"
                }
            }
        }
    ]
}

ここでのポイントは2つあります。

  • デフォルトで入っている Enable IAM User Permissions(アカウントのルートに kms:* を許可するステートメント)を削除する。このステートメントを残すと、IAMポリシーで kms:* を持つユーザーはキーポリシーの条件に関係なくKMS APIを直接呼べてしまい、kms:ViaService の効果を確認できません
  • キー管理者のステートメントに kms:Create* を含める。エイリアスの作成(kms:CreateAlias)にこの権限が必要で、含めないとキーは作成されてもエイリアスの作成が AccessDeniedException で失敗します

このステートメントにより、以下の条件をすべて満たすリクエストのみが kms:Decrypt と kms:GenerateDataKey の実行を許可されます。

  • 自アカウント内のIAMエンティティからのリクエストであること
  • ap-northeast-1リージョンのS3サービス経由のリクエストであること
KMSキーポリシーの編集画面(AllowS3ViaServiceOnlyステートメントを記述した状態)
KMSキーポリシーの編集画面(AllowS3ViaServiceOnlyステートメントを記述した状態)
  • 「次へ」をクリックし、「ステップ 6: 確認」で内容を確認して「完了」をクリックします

作成されたキーの詳細画面で、エイリアスが s3-via-service-key、ステータスが「有効」であることを確認します。

作成されたKMSキーの詳細画面(エイリアスとステータス)
作成されたKMSキーの詳細画面(エイリアスとステータス)

作成されたキーのARNを控えておきます。後のステップで使用します。

ステップ3: S3バケットを作成しSSE-KMS暗号化を設定する

作成したKMSキーを使って暗号化するS3バケットを作成します。

  • 上部の検索バーにS3と入力し、表示された「S3」を選択します
  • 「バケットを作成」をクリックします
  • AWS リージョンが「アジアパシフィック (東京) ap-northeast-1」であることを確認します
  • バケット名に kms-via-service-test-<アカウントID> と入力します(例: kms-via-service-test-111122223333)
  • 「デフォルトの暗号化」セクションで以下を設定します
  • 暗号化タイプ: AWS Key Management Service キーを使用したサーバー側の暗号化 (SSE-KMS) を選択
  • AWS KMS キー: AWS KMS キーから選択する を選択し、一覧から s3-via-service-key のキーARNを選択します
  • バケットキー: 有効にする のまま
S3バケット作成画面のデフォルト暗号化セクション(SSE-KMSが選択され、s3-via-service-keyが指定された状態)
S3バケット作成画面のデフォルト暗号化セクション(SSE-KMSが選択され、s3-via-service-keyが指定された状態)
  • その他の項目はデフォルトのままにします
  • 「バケットを作成」をクリックします

ステップ4: S3経由でのアップロードを確認する(成功)

S3コンソールからファイルをアップロードし、KMSキーが正常に使用されることを確認します。

  • 作成したバケット kms-via-service-test-<アカウントID> を開きます
  • 「アップロード」をクリックします
  • テスト用のファイル(テキストファイルなど)を選択します
  • 「アップロード」をクリックします
S3へのファイルアップロード成功画面
S3へのファイルアップロード成功画面

アップロードが成功します。S3がユーザーの代わりにKMS APIを呼び出してオブジェクトを暗号化しているため、kms:ViaService 条件が満たされ、KMSキーの使用が許可されています。

  • アップロードしたオブジェクトをクリックし、詳細画面の「サーバー側の暗号化設定」セクションを確認します
  • 暗号化タイプが SSE-KMS で、暗号化キー ARN が s3-via-service-key のものであることを確認します
アップロードしたオブジェクトの詳細画面(サーバー側の暗号化設定にSSE-KMSとs3-via-service-keyのARNが表示された状態)
アップロードしたオブジェクトの詳細画面(サーバー側の暗号化設定にSSE-KMSとs3-via-service-keyのARNが表示された状態)

ステップ5: 直接のKMS API呼び出しを確認する(失敗)

次に、AWS CLIを使ってKMS APIを直接呼び出し、kms:ViaService 条件により拒否されることを確認します。

KMSキーのキーIDを使って、直接 kms:GenerateDataKey を呼び出します。

aws kms generate-data-key \
    --key-id alias/s3-via-service-key \
    --key-spec AES_256 \
    --region ap-northeast-1

以下のようなエラーメッセージが表示されます。

An error occurred (AccessDeniedException) when calling the GenerateDataKey operation: User: arn:aws:iam::ACCOUNT_ID:user/USER_NAME is not authorized to perform: kms:GenerateDataKey on resource: arn:aws:kms:ap-northeast-1:ACCOUNT_ID:key/KEY_ID because no resource-based policy allows the kms:GenerateDataKey action
AWS CLIで直接KMS APIを呼び出した際のAccessDeniedエラー
AWS CLIで直接KMS APIを呼び出した際のAccessDeniedエラー

このエラーは、KMS APIが直接呼び出されたため kms:ViaService 条件(S3経由であること)が満たされず、リクエストが拒否されたことを示しています。

同じユーザーがS3経由ではKMSキーを使用でき、直接のAPI呼び出しでは使用できないことが確認できました。これが kms:ViaService 条件キーによるサービス別アクセス制御の効果です。

まとめ

本記事のポイントを整理します。

  • kms:ViaService は、KMSキーの使用を特定のAWSサービス経由のリクエストに限定する条件キーです。値は <サービス名>.<リージョン>.amazonaws.com の形式で指定します
  • Principal "AWS": "*" と kms:CallerAccount の組み合わせ により、すべてのプリンシパルを対象にしつつ、特定アカウントに制限できます。aws:PrincipalArn にアカウントのルートARNを指定してもIAMユーザーには一致しないため、アカウント単位の判定には使えません
  • Condition ブロック内の複数の条件キーはAND条件 で評価されます。kms:CallerAccount と kms:ViaService の両方を満たすリクエストのみが許可されます
  • S3のSSE-KMS暗号化 では、S3がユーザーの代わりにKMS APIを呼び出すため kms:ViaService 条件が満たされますが、ユーザーがKMS APIを直接呼び出す場合は条件が満たされず拒否されます
  • Action には暗号化操作に必要な最小限の権限(kms:Decrypt と kms:GenerateDataKey)のみを指定し、最小権限の原則 を適用します

参照先

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

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

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

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

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

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

この記事を書いた人

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

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

目次