SSMでEC2にアクセス

## 背景

[前回](https://qiita.com/class2glass/items/6a55f6a1627780bbbb35)、初めてTerraformでAWS EC2にインスタンスを構築することができました。
構築できたことはManagement Consoleで確認できましたし、インスタンスにへの接続はSSH接続で確認しました。
しかし、業務で構築するEC2はSSH接続は禁止、Session Manager(以下SSM)での接続が条件となっていました。
知識としては知っていたSSMですが使ったことはありませんでしたので、これを機に試してみようと思います。

## 目標

TerraformでSSM接続可能なEC2インスタンスを構築する。

## 環境

[前回](https://qiita.com/class2glass/items/6a55f6a1627780bbbb35)Terraformを実行したDockerコンテナ環境を使用します。

ただし、今回はSSMを使用するためPluginのインストールが必要になります。
Dockerfileに以下を追記し、コンテナを起動しています。

```
# install session-manager-plusin
RUN curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb" -o "session-manager-plugin.deb"
RUN dpkg -i session-manager-plugin.deb
```

## 参考

[Terraformで、Systems Manager（Session Manager）でアクセスできるようにしたEC2インスタンスを構築する](https://qiita.com/charon/items/58c3ad20232c74a6dc01)
[(オプション) AWS CLI 用の Session Manager プラグインをインストールする](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)

## ファイル構成

terraform
  └terraform.tfvars
  └variables.tf
  └ec2.tf
  └role.tf

## 手順

基本的なTerraformファイルの構造は変わっていません。
ポイントはSSMロールの作成と、インスタンスに作成したロールを関連付けること。

### role.tf

```
data "aws_iam_policy_document" "assume_role" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "role" {
  name               = "xxxxx_ssm_MyRole"
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

data "aws_iam_policy" "systems_manager" {
  arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_iam_role_policy_attachment" "default" {
  role       = aws_iam_role.role.name
  policy_arn = data.aws_iam_policy.systems_manager.arn
}

resource "aws_iam_instance_profile" "systems_manager" {
  name = "xxxxx_MyInstanceProfile"
  role = aws_iam_role.role.name
}
```

### ec2.tf

前回のTerraformファイルに「iam_instance_profile」の設定を追加しただけです。

```
resource "aws_instance" "c069544_tf-ec2" {
  count         = 1
  ami           = "ami-03d5c68bab01f3496" # Ubuntu 20.04 LTS official ami
  instance_type = "t2.micro"
  iam_instance_profile = aws_iam_instance_profile.systems_manager.name
  tags = {
    Name = "${format("xxxxx_tf-ec2-%02d", count.index + 1)}"
  }
}
```

### 構築

#### plan

```
# terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:
    :
    :
        }
    }

Plan: 4 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if
you run "terraform apply" now.
```

#### apply

今回は手動での構築確認を自動で行う「-auto-approve」オプションも試してみます。

```
# terraform apply -auto-approve

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:
    :
    :

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
```

#### show

terraform showコマンドを実行して確認してみましたが正常に構築されているようです。
(実行結果割愛)

## 接続確認

無事に構築できたようなので、早速SSM接続を行ってみます。

まずはおまじないのaws configureを実行。

```
# aws configure
AWS Access Key ID []:
AWS Secret Access Key []:
Default region name []:
Default output format []:
```

次に、EC2インスタンスの一覧を取得してみます。

```
# aws ec2 describe-instances --output=table --query 'Reservations[].Instances[].{InstanceId: InstanceId, PrivateIp: join(`, `, NetworkInterfaces[].PrivateIpAddress), GlobalIP: join(`, `, NetworkInterfaces[].Association.PublicIp), Platform:Platform, State: State.Name, SecurityGroupId: join(`, `, SecurityGroups[].GroupId) ,Name: Tags[?Key==`Name`].Value|[0]}'
----------------------------------------------------------------------------------------------------------------------------
|                                                     DescribeInstances                                                    |
+-------------+----------------------+--------------------+-----------+---------------+------------------------+-----------+
|  GlobalIP   |     InstanceId       |       Name         | Platform  |   PrivateIp   |    SecurityGroupId     |   State   |
+-------------+----------------------+--------------------+-----------+---------------+------------------------+-----------+
|  xx.xx.xx.xx|  xxxxxxxxxx          |  xxxxx_tf-ec2-01   |  None     |   xx.xx.xx.xx |  xxxxxxxxxx            |  running  |
+-------------+----------------------+--------------------+-----------+---------------+------------------------+-----------+

```

無事に構築できていることが確認できましたので、InstanceIdを指定してSSM接続します。

```
# aws ssm start-session --target xxxxx

Starting session with SessionId: xxxxx_xxxxx-xxxxx
$ ls -al
total 8
drwxr-xr-x 2 root root 4096 Apr 30 23:36 .
drwxr-xr-x 4 root root 4096 Apr 30 23:36 ..
$ uname -a
Linux ip-172-31-14-64 5.4.0-1045-aws #47-Ubuntu SMP Tue Apr 13 07:02:25 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
```

無事にSSM接続できていることが確認できました。

## おわりに

今回の検証では一度もManagemant Consoleにアクセスすることなく構築を行いました。
もちろん構築検証後はterraform destroyを実行し、環境を破棄してあります。

前回使用したTerraformを流用・加工し今回の検証に活かせたことも発展性のあることで良かったと感じております。

現在、一緒に活動している同士とともにCICD環境の構築を進めています。
今回検証したTerraformをCICDに統合させ、CICDの流れの中でAWS環境の構築ができないかと検討しております。

まさに「小さいことからコツコツと」なのですが、ディスカッションしながらお互いの検証結果を共有し、メンバーそれぞれが実際に手を動かし、検証、体感することでスキルアップできる活動を今後とも継続していく予定です。