皆様こんにちは。
Terraformを利用して、AWSで高可用性アーキテクトの構築をしていきます。
今回はデータベース、ストレージ・ファイルシステムのデータ保護をするためにKMSを作成して暗号化設定をしていきます。

1.高可用性アーキテクト構築目次

目次はこちら

2.KMSの概要

AWS Key Management Service (AWS KMS) は、データの保護に使用される暗号化キーの作成と制御を容易にするマネージドサービスです。AWS KMS はハードウェアセキュリティモジュール (HSM) を使用して AWS KMS keys を保護し、FIPS 140-2 暗号化モジュール検証プログラムで検証します。

引用元:AWS Key Management Service

KMSの主な機能として、鍵管理機能とデータ暗号化機能があります。このうち、データ暗号化機能としては下記3つのAPIがあります。

  • Encrypt(データを暗号化)
  • Decrypt(データを複合化)
  • GenerateDataKey(ユーザーがデータの暗号化に利用するためのカスタマーデータキーを生成)

マスターキーとデータキー

KMSでは、主にマスターキー(CMK)とデータキー(CDK)の2つの鍵を管理します。CMKはデータキーを暗号化するための鍵で、CDKはデータを暗号化するための鍵です。
KMSでは、データキーでデータを暗号化し、データキーをマスターキーで暗号化しています(エンベロープ暗号化)。

類似サービスとしては「CloudHSM」があります。
KMSとCloudHSMの比較は下記の表の通りです。

サービス CloudHSM KMS
専有性 VPC内の専有ハードウェアデバイス AWSが管理するマルチテナント(共有で利用)
管理場所 ユーザー側が管理 AWS側が管理
費用 高価 安価

大規模なシステムにはCloudHSMを利用した方がいいでしょう。

3.仕組み図

下記は今回作成するKMSの仕組み図です。

CMKはCustomer Master key、CDKはCustomer Data keyの略称です。

4.KMS作成

全体のソースコードは下記の通りです。

#--------------------------------------
# KMSの作成
#----------------------------------------
resource "aws_kms_key" "higa_WordPress_KMS" {
  tags = {
    Name = "higa_WordPress_KMS"
  }

  //ポリシー設定
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [

      {
        Sid    = "Enable IAM User Permissions"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:root"
        }
        Action   = "kms:*",
        Resource = ["*"]
      },

      {
        Sid    = "Allow access for Key Administrators"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/CPI-HIGA"
        }
        Action = [
          "kms:Create*",
          "kms:Describe*",
          "kms:Enable*",
          "kms:List*",
          "kms:Put*",
          "kms:Update*",
          "kms:Revoke*",
          "kms:Disable*",
          "kms:Get*",
          "kms:Delete*",
          "kms:TagResource",
          "kms:UntagResource",
          "kms:ScheduleKeyDeletion",
          "kms:CancelKeyDeletion"
        ]
        Resource = ["*"]
      },

      {
        Sid    = "Allow use of the key"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/CPI-HIGA"
        }
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:ReEncrypt*",
          "kms:GenerateDataKey*",
          "kms:DescribeKey"
        ]
        Resource = ["*"]

      },

      {
        Sid    = "Allow attachment of persistent resources"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/CPI-HIGA"
        }
        Action = [
          "kms:CreateGrant",
          "kms:ListGrants",
          "kms:RevokeGrant"
        ]

        Resource = ["*"]
        Condition = {
          Bool = {
            "kms:GrantIsForAWSResource" = "true"
          }
        }
      }

    ]
  })
  //ここまでポリシー設定のコード
}

#エイリアスの作成
resource "aws_kms_alias" "higa_WordPress_KMS" {
  name          = "alias/higa_WordPress_KMS"
  target_key_id = aws_kms_key.higa_WordPress_KMS.key_id
}

4-1.暗号化鍵の作成

データベース、ストレージ、ファイルシステム等のデータを暗号化するための暗号化鍵の作成をしていきます。(4~7行目)

resource "aws_kms_key" "higa_WordPress_KMS" {
  tags = {
    Name = "higa_WordPress_KMS"
  }

//ポリシーを作成
(以下省略(4-1に記載))

}

上記のコードで暗号化鍵の作成ができます。KMSキーはキーポリシーが必要です。「4-1」で暗号化鍵の設定をしていきます。

キーのタイプについて

キーのタイプには対称鍵と非対称鍵があります。
対称鍵は暗号化と復号化に同じ鍵を使用します。
非対称鍵は暗号化と復号化に別の鍵を使用します。暗号化に使用する鍵は公開鍵と言い、復号に使用する鍵は秘密鍵と言います。

キータイプの設定はcustomer_master_key_specオプションで設定します。スペックの選択については、AWSキー管理サービスを参照してください。

customer_master_key_specオプションを設定しない場合、デフォルトのキー仕様であるSYMMETRIC_DEFAULTが設定されます。キーは対称鍵仕様です。

「3.仕組み図」より、EBS、RDS、EFSにKMSを使用します。

Amazon EBS は、対称 KMS キーのみをサポートします。非対称 KMS キーを使用して Amazon EBS ボリュームを暗号化することはできません。KMS キーが対称か非対称かを判断する方法については、非対称 KMS キーの識別 を参照してください。

引用元:KMS キーとデータキーを使用する

引用元の公式ドキュメントより、EBSは対称KMSのみをサポートするので、今回のKMS作成は対称鍵を選択します。
今回作成するKMSのキー仕様は「SYMMETRIC_DEFAULT」です。

4-2.キーポリシーの設定

暗号化鍵に使用するキーポリシーを下記の通りに作成します。(9~90行目)

  //ポリシー設定
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [

      {
        Sid    = "Enable IAM User Permissions"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:root"
        }
        Action   = "kms:*",
        Resource = ["*"]
      },

      {
        Sid    = "Allow access for Key Administrators"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/[IAMユーザー]"
        }
        Action = [
          "kms:Create*",
          "kms:Describe*",
          "kms:Enable*",
          "kms:List*",
          "kms:Put*",
          "kms:Update*",
          "kms:Revoke*",
          "kms:Disable*",
          "kms:Get*",
          "kms:Delete*",
          "kms:TagResource",
          "kms:UntagResource",
          "kms:ScheduleKeyDeletion",
          "kms:CancelKeyDeletion"
        ]
        Resource = ["*"]
      },

      {
        Sid    = "Allow use of the key"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/[IAMユーザー]"
        }
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:ReEncrypt*",
          "kms:GenerateDataKey*",
          "kms:DescribeKey"
        ]
        Resource = ["*"]

      },

      {
        Sid    = "Allow attachment of persistent resources"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/CPI-HIG[IAMユーザー]"
        }
        Action = [
          "kms:CreateGrant",
          "kms:ListGrants",
          "kms:RevokeGrant"
        ]

        Resource = ["*"]
        Condition = {
          Bool = {
            "kms:GrantIsForAWSResource" = "true"
          }
        }
      }

    ]
  })
  //ここまでポリシー設定のコード

ステートメントごとに分割して説明していきます。
Terraformを使用して、JSON形式でポリシードキュメントを記述する際はTerraform 公式ドキュメントを参照してください。

4-2-1

ソースコードは15~23行目に該当します。

      {
        Sid    = "Enable IAM User Permissions"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:root"
        }
        Action   = "kms:*",
        Resource = ["*"]
      },

上記のステートメントではrootユーザに対し、KMSに関する全ての権限を付与しています。
AWSアカウントのrootユーザーは削除することができないため、Sid = "Enable IAM User Permissions"を設定することで、管理者権限を持つ IAM user、IAM roleを誤って削除してしまってもrootユーザーから操作することができます。

4-2-2

ソースコードは25~48行目に該当します。

      {
        Sid    = "Allow access for Key Administrators"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/[IAMユーザー]"
        }
        Action = [
          "kms:Create*",
          "kms:Describe*",
          "kms:Enable*",
          "kms:List*",
          "kms:Put*",
          "kms:Update*",
          "kms:Revoke*",
          "kms:Disable*",
          "kms:Get*",
          "kms:Delete*",
          "kms:TagResource",
          "kms:UntagResource",
          "kms:ScheduleKeyDeletion",
          "kms:CancelKeyDeletion"
        ]
        Resource = ["*"]
      },

Sid = "Allow access for Key Administrators"で指定のユーザにKMSキーを管理する権限を付与しています。
ユーザーの指定は4~6行目のところで指定します。今回は私のIAMユーザーを指定しています。
上記のステートメントでは、キーの作成、一覧、削除、削除スケジュールの有効化、無効化などを設定しています。

4-2-3

ソースコードは50~65行目に該当します。

     {
        Sid    = "Allow use of the key"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::[アカウントID]:user/[IAMユーザー]"
        }
        Action = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:ReEncrypt*",
          "kms:GenerateDataKey*",
          "kms:DescribeKey"
        ]
        Resource = ["*"]

      },

上記ステートメントはSid = "Allow use of the key"で指定のユーザ(私のIAMユーザー)にKMSキーを使用する権限を付与しています。7~13行目のActionでデータの暗号化、複合化、データキーの生成を許可しています。

4-2-4

ソースコードは68~86行目に該当します。

      {
        Sid    = "Allow attachment of persistent resources"
        Effect = "Allow"
        Principal = {
          AWS = "arn:aws:iam::【アカウントID】:user/CPI-HIGA"
        }
        Action = [
          "kms:CreateGrant",
          "kms:ListGrants",
          "kms:RevokeGrant"
        ]

        Resource = ["*"]
        Condition = {
          Bool = {
            "kms:GrantIsForAWSResource" = "true"
          }
        }
      }

上記ステートメントでは、Sid = "Allow attachment of persistent resources"でAWSリソースがKMSキーを使用する権限を付与しています。
16行目の"kms:GrantIsForAWSResource" = "true"でAWSリソースがユーザーに代わって権限を作成し、AWSリソースが KMSキーを使用してユーザーのデータを暗号化できるようになります。

4-3.エイリアスの設定

エイリアスは、AWS KMS key のわかりやすい名前です。例えば、エイリアスを使用すると、1234abcd-12ab-34cd-56ef-1234567890ab の代わりに KMS キーを test-key として参照できます。

引用元:エイリアスの使用

ソースコードは93~97行目に該当します。

#エイリアスの作成
resource "aws_kms_alias" "higa_WordPress_KMS" {
  name          = "alias/higa_WordPress_KMS"
  target_key_id = aws_kms_key.higa_WordPress_KMS.key_id
}

上記でエイリアスの作成ができました。

下記はエイリアスの設定項目です。

使用するオプション 設定値 説明
name "ailias/【設定したいエイリアス名】" エイリアスの表示名
target_key_id aws_kms_key.リソース名.key_id 設定は必須です。エイリアスの対象となるキーの識別子は、ARNまたはkey_idのいずれかです。

上記より、マネジメントコンソール画面からKMSの作成、エイリアスの設定が確認できました。

5.まとめ

KMSは抽象的で苦手意識があったので、「暗号化されて安全なんだな~」くらいの認識でした。
この記事でKMSの概要や仕組み図を作成するにあたって、KMSの調査をし、アウトプットすることで理解が深まりました。特に、「CMK」「CDK」「エンベロープ暗号化」「対称鍵・非対称鍵」といった概念はこれまで苦手意識があったので、今回の記事作成を通して理解することができました。

また、TerraformでKMSを作成するにあたり、TerraformでJSON形式でポリシードキュメントを記述する際、JSONの記述と異なる部分(ダブルクォーテーション("")の有無、JSONではコロン(:)で記述しているが、Terraformではイコール(=)で記述している)という発見がありました。

6.参考文献

Last modified: 2022-06-24

Author