Packer によって作成された AMI を暗号化したくない時に考慮すること

Packer によって作成される一時的なインスタンスはデフォルト EBS 暗号化の設定に則って作成されます。

コンバンハ、千葉(幸)です。

Packer で何も考えずに AMI を作成したところ、 AMI に含まれるスナップショットがデフォルトキー(aws/ebs)で暗号化された状態で出来上がりました。

そのままだと別の AWS アカウントに共有をかけられないので、暗号化なしの状態で作成したいです。

どのように回避すれば良いのかを確認しました。なお、今回は AMI に単一のスナップショットのみが含まれている場合を想定しています。

先にまとめ

  • AWS のデフォルト EBS 暗号化設定が有効な場合、それを Packer 側の設定で上書きすることはできない
  • 「デフォルト EBS 暗号化」が無効な場合、 Packer テンプレート内のencrypt_bootにより暗号化有無をコントロールできる
    • デフォルト(指定なし)ではソース AMI の設定を引き継ぐ
    • true の場合、暗号化される
    • false の場合、暗号化されない(ただしソース AMI が暗号化なしの場合のみ)
  • Packer テンプレート内のkms_key_idによりどの鍵で暗号化するかを指定できる
    • 省略した場合、デフォルトの暗号化キーが使用される

encrypt_boot,kms_key_idを指定している例は以下です。

Packer テンプレート例

{
  "builders": [
    {
      "type": "amazon-ebs",
      "region": "ap-northeast-1",
      "source_ami": "ami-0f9ae750e8274075b",
      "instance_type": "t2.micro",
      "ssh_username": "ec2-user",
      "ami_name": "packer101-ami",
      "encrypt_boot": true,
      "kms_key_id": "17cb2f30-f3ac-429a-96c9-147aafdxxxxx"
    }
  ],
    "provisioners": [
      {
        "type":  "shell",
        "inline": [
          "sudo yum -y install httpd",
        ]
      }
    ]
}

encrypt_bootに false を指定しても以下のケースでは暗号化された AMI が出来上がりますので、注意が必要です。

  • デフォルト EBS 暗号化が有効である
  • ソース AMI が暗号化されている

Packer による AMI の作成

簡単におさらいしておくと、 Packer による AMI の作成は以下のイメージとなります。

ソースとして指定した AMI から一時的なインスタンスが作成され、必要な設定が終わったのちにそのインスタンスから AMI が作成される、という流れです。

暗号化された AMI のアカウント間 共有

AMI に含まれる単一のスナップショットが暗号化されている状態を、本エントリでは「暗号化された AMI 」と呼称します。(実際には暗号化されているのは EBS スナップショットである、ということは覚えておいてください。)

ここで以下の AMI について考えます。

  • 暗号化なしの AMI
  • デフォルトキーで暗号化された AMI
  • 独自のキーで暗号化された AMI

それぞれのアカウント間 共有の可否をまとめると、以下のようになります。

暗号化された AMI を共有する場合、共有先のアカウントは暗号化に使用されている KMS キーへもアクセスできる必要があります。クロスアカウントとなるため、「共有元のキーポリシー」「共有先エンティティのアイデンティティベースポリシー」の両方で許可が必要です。

エイリアスにaws/プレフィックスを持つデフォルトキーはキーポリシーの編集ができず、そのキーポリシーでは自アカウントからのアクセスしか許可されていません。

よって、デフォルトキーで暗号化された AMI はそもそもの「 AMI の共有」の時点で対応しない仕様になっています。

Packer で作成したゴールデンイメージを他のアカウントにも共有したい、という場面において、デフォルトキーによる暗号化は避けなくてはなりません。

デフォルト EBS 暗号化の設定

Packer によって作成される AMI の暗号化について大きな影響を及ぼすのがデフォルト EBS 暗号化設定です。これは 2019年5月に対応した機能です。

ここではリージョン単位で以下が設定できます。

  • 有効か無効か(デフォルト:無効)
  • どの暗号化キーを使用するか(デフォルト:alias/aws/ebs

有効にした場合、対象リージョンでの EBS ボリュームの作成時や EBS スナップショットのコピー時に、指定された暗号化キーによる暗号化が強制されます。

この設定は以下 AWS CLI コマンドで確認できます。

% aws ec2 get-ebs-encryption-by-default
{
    "EbsEncryptionByDefault": false
}
% aws ec2 get-ebs-default-kms-key-id
{
    "KmsKeyId": "arn:aws:kms:ap-northeast-1:012345678901:key/4be5a422-bccf-4fd3-a09a-45f44a4xxxxx"
}

マネジメントコンソールからの確認の場合、 EC2 ダッシュボードから確認・設定が可能です。

EC2_EBSdefaultencryption

EC2_Encrypted_Packer

Packer による設定の上書きはできない

Packer のリファレンスを見ると、encrypt_boot部で以下の記載があります。

Please note that if you are using an account with the global "Always encrypt new EBS volumes" option set to true, Packer will be unable to override this setting, and the final image will be encryoted whether you set this value or not.

デフォルト暗号化が有効な場合、 Packer による設定の上書きができず、ここで指定された暗号化キーによって暗号化された AMI が作成される、とあります。

よって、デフォルト KMS キーでの暗号化を避けるためには、「デフォルト EBS 暗号化」設定を無効にしておくか、有効にしつつもカスタマー独自の KMS キーを指定しておく必要があります。

暗号化された AMI から暗号化なしのものを作成できるか

(以降、表現の簡略化のため「暗号化された EBS ボリュームをルートボリュームとする EC2 インスタンス」のことを単純に暗号化されたインスタンスと呼称します。)

暗号化されていない AMI を作成したいとなった時、ソース AMI の状態も考慮する必要があります。

暗号化された AMI からは、暗号化なしの AMI も暗号化なしのインスタンスも作成できません。できるのは、別の暗号化キーで暗号化し直すことだけです。整理すると以下のようになります。

Packer による AMI 作成時にもこの制約を考慮する必要があります。ソース AMI が暗号化されている場合、Packer により作成されるテンポラリなインスタンスも暗号化されます。よって、最終的に作成される AMI も暗号化された状態となります。

暗号化なしの AMI を作成したい場合、ソース AMI も暗号化なしのものを指定する必要があります。

暗号化なしのインスタンスを作成するには

Packer による操作とは外れた話となりますが、「暗号化を解く」場合には以下のようなステップを踏む必要があります。

  • 暗号化されていない EBS ボリュームを作成する
  • 暗号化された EBS ボリュームから暗号化されていない EBS ボリュームへデータをコピーする
  • 暗号化されていない EBS ボリュームを正とする

ここではデータ移行用の別インスタンスを使用する想定で書いていますが、元々のインスタンス 1 台のみで完結させることも可能です。

Packer でこのような操作を行うことはできないため、暗号化されたソース AMI から暗号化なしの AMI は作成できません。

何パターンか試してみよう

Packer により暗号化なしの AMI を作成したい場合は、以下を満たす必要があることが分かりました。

  • デフォルト EBS 暗号化が無効である
  • ソース AMI が暗号化なしである

ここまでで本旨は語ってしまったのですが、せっかくなので実際の挙動を確認します。

  1. デフォルト EBS 暗号化が有効で encrypt_boot が false
  2. ソース AMI が暗号化ありで encrypt_boot が false
  3. デフォルト EBS 暗号化有効で kms_key_id で別のキーを指定

今回使用している Packer のバージョンは以下の通りです。

% packer --version
1.7.2

1. デフォルト EBS 暗号化が有効で encrypt_boot が false

以下条件です。

  • デフォルト EBS 暗号化:有効
  • ソース AMI の暗号化:なし
  • encrypt_boot:false

デフォルト EBS 暗号化を有効にします。

% aws ec2 enable-ebs-encryption-by-default
{
    "EbsEncryptionByDefault": true
}

暗号化に使用する KMS キーをデフォルトのものにします。

% aws ec2 reset-ebs-default-kms-key-id
{
    "KmsKeyId": "arn:aws:kms:ap-northeast-1:012345678901:key/4be5a422-bccf-4fd3-a09a-45f44a4xxxxx"
}

以下のテンプレートを指定して、 Packer でビルドします。ソース AMI はコミュニティ AMI のもので、もちろん暗号化されていません。

default_encryption_true.json

{
  "builders": [
    {
      "type": "amazon-ebs",
      "region": "ap-northeast-1",
      "source_ami": "ami-0ca38c7440de1749a",
      "instance_type": "t3.micro",
      "ssh_username": "ec2-user",
      "ami_name": "ami_1",
      "encrypt_boot": false,
      "vpc_id": "vpc-0e4acafc38414468c",
      "subnet_id": "subnet-0caa45223899b4b73",
      "associate_public_ip_address": true,
      "security_group_ids": "sg-0a597e5b2a9a1d86d"
    }
  ],
    "provisioners": [
      {
        "type":  "shell",
        "inline": [
          "sudo yum -y install httpd"
        ]
      }
    ]
}

5分足らずで作成が完了しました。

% packer build default_encryption_true.json

(中略)

==> Wait completed after 4 minutes 53 seconds

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:
ap-northeast-1: ami-0c10ca99f0d9d9938

作成された AMI に紐づくスナップショットを確認すると、デフォルト KMS キーによって暗号化されています。

% AMIID=ami-0c10ca99f0d9d9938
% aws ec2 describe-snapshots --filters "Name=description,Values=*$AMIID" | jq '.Snapshots[] | .Encrypted, .KmsKeyId'
true
"arn:aws:kms:ap-northeast-1:012345678901:key/4be5a422-bccf-4fd3-a09a-45f44a4xxxxx"

2. ソース AMI が暗号化ありで encrypt_boot が false

以下条件です。

  • デフォルト EBS 暗号化:無効
  • ソース AMI の暗号化:あり
  • encrypt_boot:false

デフォルト EBS 暗号化を無効にします。

% aws ec2 disable-ebs-encryption-by-default
{
    "EbsEncryptionByDefault": false
}

ソース AMI として先ほど作成した暗号化済み AMI を指定したテンプレートを作成します。

sourceami_encryption_true.json

{
  "builders": [
    {
      "type": "amazon-ebs",
      "region": "ap-northeast-1",
      "source_ami": "ami-0c10ca99f0d9d9938",
      "instance_type": "t3.micro",
      "ssh_username": "ec2-user",
      "ami_name": "ami_2",
      "encrypt_boot": false,
      "vpc_id": "vpc-0e4acafc38414468c",
      "subnet_id": "subnet-0caa45223899b4b73",
      "associate_public_ip_address": true,
      "security_group_ids": "sg-0a597e5b2a9a1d86d"
    }
  ],
    "provisioners": [
      {
        "type":  "shell",
        "inline": [
          "sudo yum -y install tree"
        ]
      }
    ]
}

上記テンプレートを指定しビルドを実行します。

% packer build sourceami_encryption_true.json

(中略)

==> Wait completed after 3 minutes 23 seconds

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:
ap-northeast-1: ami-0bb9c2b149fd274f3

出来上がった AMI のスナップショットを確認すると、ソース AMI と同じ KMS キーで暗号化されていることが分かります。

% AMIID=ami-0bb9c2b149fd274f3
% aws ec2 describe-snapshots --filters "Name=description,Values=*$AMIID" | jq '.Snapshots[] | .Encrypted, .KmsKeyId'
true
"arn:aws:kms:ap-northeast-1:012345678901:key/4be5a422-bccf-4fd3-a09a-45f44a4xxxxx"

3. デフォルト EBS 暗号化有効で kms_key_id で別のキーを指定

以下条件です。

  • デフォルト EBS 暗号化:有効
    • デフォルトの暗号化キー:aws/ebs
  • ソース AMI の暗号化:なし
  • encrypt_boot:true
  • kms_key_id:独自の KMS キー

デフォルト EBS 暗号化を有効にします。

% aws ec2 enable-ebs-encryption-by-default
{
    "EbsEncryptionByDefault": true
}

暗号化に使用する KMS キーをデフォルトのものにします。

% aws ec2 reset-ebs-default-kms-key-id
{
    "KmsKeyId": "arn:aws:kms:ap-northeast-1:012345678901:key/4be5a422-bccf-4fd3-a09a-45f44a4xxxxx"
}

ソース AMI をコミュニティ AMI(暗号化なし) 、kms_key_idとして独自の KMS キーを指定したテンプレートを用意します。

specify_kms_key_id.json

{
  "builders": [
    {
      "type": "amazon-ebs",
      "region": "ap-northeast-1",
      "source_ami": "ami-0ca38c7440de1749a",
      "instance_type": "t3.micro",
      "ssh_username": "ec2-user",
      "ami_name": "ami_3",
      "encrypt_boot": true,
      "kms_key_id": "17cb2f30-f3ac-429a-96c9-147aafdxxxxx",
      "vpc_id": "vpc-0e4acafc38414468c",
      "subnet_id": "subnet-0caa45223899b4b73",
      "associate_public_ip_address": true,
      "security_group_ids": "sg-0a597e5b2a9a1d86d"
    }
  ],
    "provisioners": [
      {
        "type":  "shell",
        "inline": [
          "sudo yum -y install tree"
        ]
      }
    ]
}

なお、kms_key_idはキー ID だけでなく、ARN、エイリアスで指定することもできます。

ビルドを実行しました。これまでとは違った処理が含まれます。

% packer build specify_kms_key_id.json

(中略)

==> amazon-ebs: Creating AMI qbm3G4D from instance i-03281f47173e12864
    amazon-ebs: AMI: ami-0b2767de8a6fcc8a3
==> amazon-ebs: Waiting for AMI to become ready...
==> amazon-ebs: Copying/Encrypting AMI (ami-0b2767de8a6fcc8a3) to other regions...
    amazon-ebs: Copying to: ap-northeast-1
    amazon-ebs: Waiting for all copies to complete...
==> amazon-ebs: Deregistering the AMI and deleting unencrypted temporary AMIs and snapshots
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Cleaning up any extra volumes...
==> amazon-ebs: No volumes to clean up, skipping
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' finished after 10 minutes 26 seconds.

==> Wait completed after 10 minutes 26 seconds

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:
ap-northeast-1: ami-0db5b620f2c38d880

流れとしては以下となります。

  1. デフォルトの暗号化キーで暗号化されたテンポラリなインスタンスが作成される
  2. 上記インスタンスからテンポラリな AMI (デフォルト暗号化キーで暗号化)が作成される
  3. 上記の AMI がコピーされ、コピー時に kms_key_id で指定した暗号化キーで暗号化される

テンポラリなインスタンスを作成する時点で最終的な暗号化キーが指定されているわけではない、ということが分かりました。

最終的に作成された AMI は、kms_key_idで指定した KMS キーで暗号化されています。

% AMIID=ami-0db5b620f2c38d880
% aws ec2 describe-snapshots --filters "Name=description,Values=*$AMIID*" | jq '.Snapshots[] | .Encrypted, .KmsKeyId'
true
"arn:aws:kms:ap-northeast-1:012345678901:key/17cb2f30-f3ac-429a-96c9-147aafdxxxxx"

終わりに

Packer で暗号化されていない AMI を作成したい、という話でした。おさらいをしておくと、以下を満たす必要があります。

  • デフォルト EBS 暗号化が無効である
  • ソース AMI が暗号化なしである

改めて考えると Packer どうこうと言うよりは AWS の仕様の話でしたね。とは言え、Packer 側で暗号化に関するパラメータが存在するものの AWS 側の設定を(常に)上書きできるわけではない、ということは覚えておいて損はないかと思います。

また、kms_key_idで指定した暗号化キーがソースインスタンスやソース AMI のものと異なる場合、AMI のコピーを間に挟むことで実現することも分かりました。

3.のケースではソースインスタンスを初めから独自の KMS キーで暗号化して起ちあげることを想定していたので、少し驚きました。

もろもろの挙動を把握して、良い Packer ライフをお過ごしください。

以上、 チバユキ (@batchicchi) がお送りしました。

参考