IAMロールを使用してS3上の公開鍵を新規EC2インスタンスに配布する

# はじめに
前回の記事「[AnsibleでTomcatコンテナをデプロイしてみる](https://qiita.com/okoge1031/items/1d9c26fcff7f72bc1aa1)」で、自動化できていなかった公開鍵の配布について、今回自動化を検討してみました。

# 今回構成する環境
![Untitled(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/991082/13427e3b-7537-f06a-1281-053d37d830fd.png)

大まかな流れは以下の流れで行います。
①キーペアの作成
②S3バケットの作成
③IAMポリシーの作成
④IAMロールの作成
⑤IAMロールのアタッチ
⑥公開鍵のアップロード
⑦EC2インスタンスの作成と公開鍵のダウンロード
⑧動作確認

# キーペアの作成
SSH接続を行う側のEC2インスタンスでキーペアを作成します。

```
$ ssh-keygen -t rsa
```

```
$ ls -l /home/ec2-user/.ssh/
total 12
-rw------- 1 ec2-user ec2-user  388 Feb 28 01:07 authorized_keys
-rw------- 1 ec2-user ec2-user 1675 Feb 28 01:08 id_rsa
-rw-r--r-- 1 ec2-user ec2-user  438 Feb 28 01:08 id_rsa.pub
$ 
```

id_rsa(秘密鍵)とid_rsa.pub(公開鍵)が作成されました。

# S3バケットの作成
S3のサービス画面で「バケットを作成」をクリックします。
今回はバケット名は「pubkey20210228」とし、サーバ暗号化(SSE-S3)を有効にします。
バケットのARNは「arn:aws:s3:::pubkey20210228」となります。
アクセス許可などの設定はデフォルトとします。(パブリックアクセスをすべてブロック)

# IAMポリシーの作成
このままではEC2インスタンスからS3のアクセスはできません。
EC2インスタンスからS3へのファイルアップロードを行おうとすると以下のようなエラーメッセージが出力されます。

```
$ aws s3 cp /home/ec2-user/.ssh/id_rsa.pub s3://pubkey20210228/
upload failed: .ssh/id_rsa.pub to s3://pubkey20210228/id_rsa.pub Unable to locate credentials
$
```

EC2インスタンスからS3へのアップロードを許可するためIAMロールを作成します。
IAMロールを使用することで、EC2インスタンスなどのサービスに対してIAMユーザと同じようなアクセス権限を付与することができます。

今回は、SSH接続元サーバに「S3バケットへのファイルアップロード権限」、SSH接続先サーバに「S3バケットからのファイルダウンロード権限」を付与します。
IAMロールの流れは以下のような流れになります。

・IAMポリシーの作成
・IAMロールの作成
・EC2インスタンスに対するIAMロールのアタッチ

IAMポリシーは複数の権限の集合ですが、IAMポリシーを直接EC2インスタンスに割り当てることはできません。
IAMポリシーをIAMロールに紐づけし、IAMロールをEC2インスタンスにアタッチすることで権限の付与を行います。

まずはIAMポリシーを作成します。

IAMのサービス画面のダッシュボードで「ポリシー」を選択し、「ポリシーの作成」をクリックします。
ポリシーはビジュアルエディタで設定を作成するか、直接JSONを編集できます。

今回は以下のような2つのポリシーを作成します。

■S3アップロード用ポリシー

|項目|値|
|:--|:--|
|サービス|S3|
|アクション|PutObject|
|リソース|arn:aws:s3:::pubkey20210228/*|
|ポリシー名|putobject_pubkey20210228|

JSON形式では以下の通り。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::pubkey20210228/*"
        }
    ]
}
```

■S3ダウンロード用ポリシー

|項目|値|
|:--|:--|
|サービス|S3|
|アクション|GetObject|
|リソース|arn:aws:s3:::pubkey20210228/*|
|ポリシー名|getobject_pubkey20210228|

JSON形式では以下の通り。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::pubkey20210228/*"
        }
    ]
}
```

# IAMロールの作成
次にIAMロールの作成を行います。
IAMのサービス画面のダッシュボードで「ロール」を選択し、「ロールの作成」をクリックします。

今回は以下のような2つのロールを作成します。

■S3アップロード用ロール

|項目|値|
|:--|:--|
|信頼されたエンティティの種類|AWSサービス|
|ユースケースの選択|EC2|
|ポリシー|putobject_pubkey20210228|
|ロール名|putobject_pubkey20210228_role|

■S3ダウンロード用ロール

|項目|値|
|:--|:--|
|信頼されたエンティティの種類|AWSサービス|
|ユースケースの選択|EC2|
|ポリシー|putobject_getkey20210228|
|ロール名|putobject_getkey20210228_role|

# IAMロールのアタッチ
作成したIAMロールをEC2インスタンスにアタッチします。
EC2サービス画面で先ほどキーペアを作成したEC2インスタンスを選択し、「アクション」->「セキュリティ」->「IAMロールを変更」の順に選択します。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/991082/059c8009-f55d-2edc-1c66-a02a50440295.png)

IAMロールに「putobject_pubkey20210228_role」を設定します。

# 公開鍵のアップロード
先ほどと同じように公開鍵をアップロードします。

```
$ aws s3 cp /home/ec2-user/.ssh/id_rsa.pub s3://pubkey20210228/
upload: .ssh/id_rsa.pub to s3://pubkey20210228/id_rsa.pub
$
```

成功すれば、S3のバケット内に新しいオブジェクトが作成できているのが確認できます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/991082/da3af3a1-c4c5-faec-1b9c-4f9718675748.png)

# EC2インスタンスの作成と公開鍵のダウンロード
続いて、アップロードした公開鍵がダウンロードされるようにEC2インスタンスを作成します。

基本的な流れは通常のEC2インスタンス作成と同じですが、インスタンス作成時にIAMロールに「getobject_pubkey20210228_role」を指定します。
そして、ユーザーデータに以下のスクリプトを指定します。

```
#!/bin/bash
aws s3 cp s3://pubkey20210228/id_rsa.pub /home/ec2-user/.ssh/id_rsa.pub_manager
cat /home/ec2-user/.ssh/id_rsa.pub_manager >> /home/ec2-user/.ssh/authorized_keys
```

# 動作確認
SSH接続元サーバから、新しく作成したEC2インスタンス(SSH接続先サーバ)に対してsshコマンドを実行します。

```
$ ssh <SSH接続先のIPアドレス>
```

OSユーザのパスワードなしで接続できれば成功です。