Terraformで最新のAMIをEC2に設定する

# はじめに
EC2をTerraformで作成する際にとりあえず最新のAMIを設定したいと思ったので調査しました。

# 目次
[1. Terraformの記述（結論）](#1-Terraformの記述（結論）)
[2. AMI名エイリアスの導出方法](#2-AMI名エイリアスの導出方法)
[3. 参考](#3-参考)

# 1. Terraformの記述（結論）
dataブロックでAWS Systems Manager Parameter Store（以下、AWS SSM）を利用して最新のAMIを取得します。

```terraform:常に最新のAMIを取得するEC2の設定
data "aws_ssm_parameter" "amzn2_latest" {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2"
  // カーネル 4.14 の場合
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}

resource "aws_instance" "this" {
  ami                         = data.aws_ssm_parameter.amzn2_latest.value
  associate_public_ip_address = var.associate_public_ip_address
  instance_type               = var.instance_type
  key_name                    = var.key_name
  subnet_id                   = var.subnet_id
  iam_instance_profile        = var.iam_instance_profile
  vpc_security_group_ids      = var.vpc_security_group_ids
  user_data                   = var.user_data
  tags                        = merge(tomap({ Name = "${var.name}-ec2" }), var.tags)

  capacity_reservation_specification {
    capacity_reservation_preference = "none"
  }
}

```

# 2. AMI名エイリアスの導出方法
まず、なぜAMI名エイリアスの導出方法を記載するか説明します。
AWS SSMを利用する際に、AMIパラメータストアの名前空間を指定する必要があります。
名前空間は2つのパートから構成されます:

 - パラメータストア プレフィクス(ツリー): /aws/service/ami-amazon-linux-latest/
 - AMI名エイリアス: (例) amzn-ami-hvm-x86_64-gp2

この`AMI名エイリアス`がカーネル5系と4系で異なるため、導出方法を記載することとしました。

```:カーネル5系と4系のAMI名エイリアス
４系: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
5系: /aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2
```

### AWSコンソールから目的のAMI名を確認
以下の手順でAMI IDを取得します。
![ec2_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756249/e4c43e63-418e-9bfa-10f5-d30335f5f7de.png)
![ec2_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756249/d2d904a4-67a3-1865-d04e-32043bb07757.png)
AMI IDでAMIを検索し、AMI名を取得します。
![ec2_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756249/7ab2c6d7-fb96-700a-4508-423816450393.png)
取得したAMI名から日付ベースのバージョン識別子を削除した文字列がAMI名エイリアスとなります。
（上記の場合は`amzn2-ami-kernel-5.10-hvm-x86_64-gp2`となります。）
AMI名エイリアスが正しいかはAWS CLIの`ssm get-parameters-by-path`を利用することで確認できます。

```bash:AWS&nbsp;CLI
$ aws ssm get-parameters-by-path
    --path "/aws/service/ami-amazon-linux-latest"
    --query 'reverse(sort_by(Parameters,&LastModifiedDate))[:20].Name'
[
    "/aws/service/ami-amazon-linux-latest/amzn-ami-pv-x86_64-s3",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-pv-x86_64-ebs",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-pv-x86_64-s3",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-pv-x86_64-ebs",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-hvm-x86_64-s3",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-hvm-x86_64-ebs",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-s3",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2",
    "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-ebs",
    "/aws/service/ami-amazon-linux-latest/al2022-ami-minimal-kernel-5.10-x86_64",
    "/aws/service/ami-amazon-linux-latest/al2022-ami-minimal-kernel-5.10-arm64",
    "/aws/service/ami-amazon-linux-latest/al2022-ami-kernel-5.10-x86_64",
    "/aws/service/ami-amazon-linux-latest/al2022-ami-kernel-5.10-arm64",
    "/aws/service/ami-amazon-linux-latest/amzn2-ami-minimal-hvm-x86_64-ebs",
    "/aws/service/ami-amazon-linux-latest/amzn2-ami-minimal-hvm-arm64-ebs",
    "/aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2",　<- こちらと一致
    "/aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-ebs",
    "/aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-arm64-gp2",
    "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
    "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-ebs"
]
```
### 補足
AWSコンソールでなくてもAWS CLIを利用できる場合は以下のコマンドで最新のAMIを確認できます。
検索後は、上記と同様の手順でAMI名エイリアスを導出します。

```bash:
$ aws ec2 describe-images
    --owners amazon
    --filters "Name=name,Values=amzn2*-gp2"
    --query 'reverse(sort_by(Images, &CreationDate))[:5].Name'
[
    "amzn2-ami-minimal-selinux-enforcing-hvm-2.0.20211201.0-x86_64-gp2",
    "amzn2-ami-kernel-5.10-hvm-2.0.20211201.0-x86_64-gp2",
    "amzn2-ami-minimal-selinux-enforcing-hvm-2.0.20211201.0-arm64-gp2",
    "amzn2-ami-hvm-2.0.20211201.0-x86_64-gp2",
    "amzn2-ami-kernel-5.10-hvm-2.0.20211201.0-arm64-gp2"
]

```

# 3. 参考

- [AWS Systems Manager Parameter Store を使用して最新の Amazon Linux AMI IDを取得する](https://aws.amazon.com/jp/blogs/news/query-for-the-latest-amazon-linux-ami-ids-using-aws-systems-manager-parameter-store/)
- [AWS CLI 出力をフィルタリングする](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-filter.html#cli-usage-filter-client-side-advanced)