GitHub Actionsを使ってアクセスキーなしにEC2上のサーバー内シェルを実行する方法

GitHub Actions内からEC2で作成したサーバにおいてあるシェルを実行できるのだけれども、WEB情報をみてみるとアクセスキーとシークレットアクセスキーをシークレットに設定してからEC2内のコマンドを実行する例がよく顕在される。

例えば以下のような情報
https://take-engineer.com/aws-ssm_ec2_github-actions/

```
name: AWS SSM Send-Command Example

on:
  push:
    branches: main

jobs:
  start:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: AWS SSM Send-Command
        uses: peterkimzz/aws-ssm-send-command@master
        id: ssm
        with:
          aws-region: ${{ secrets.AWS_REGION }}
  ここ ==> aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
  ここ ==> aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          instance-ids: ${{ secrets.INSTANCE_ID }}

          working-directory: /home/ubuntu
          command: hogehoge.sh
```

## もっとよい方法があるはずだ!

GitHubActions内には(正確には runs-on: ubuntu-latest で構築されるコンテナ内)AWS CLIがすでにインストールされているので、aws ssm send-command で セッションマネージャー経由にてEC2内のコマンドが実行できるはず。

#### つまり以下が発行できればよいということではないか？ 
EC2内で初期化などの実行したいシェルを作成しておき (例) 「setup.sh」

> [setup.sh]を実行するAWS CLIコマンド

```
          aws ssm send-command \
            --document-name "AWS-RunShellScript" \
            --document-version "1" \
            --targets "Key=instanceids,Values=xxxxxxxxxxxxx" \
            --parameters "commands='setup.sh'" \
            --timeout-seconds 180 \
            --max-concurrency "50" \
            --max-errors "0" \
            --region ap-northeast-1
```

### 事前準備
以下の2点のみで準備OK

:::note info
- セッションマネージャーからアクセスできるようにEC2をセッティングする。
- GitHubActions内から ssm send-command を実行できるようにするため、
IAMロールを作成する。
:::


##### セッションマネージャーからアクセスできるようにEC2をセッティングする。

- AWSコンソールからの場合
    - AmazonSSMManagedInstanceCore を追加する
![スクリーンショット 2023-07-06 14.39.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2810146/05ceacf3-b829-6aff-ff12-d25fb94f374d.png)

- CDKの場合は以下の記述を追加する

``` typescript
// セッションマネージャーから接続できるようにポリシーを設定
const role = new iam.Role(this, 'ec2Role', {
  assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com')
})
role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'))

//このあたりはいろいろ省略

//EC2インスタンスの作成
const ec2Instance = new ec2.Instance(this, 'ec2Instance', {
    vpc,
    instanceType: ec2.InstanceType.of(ec2.InstanceClass.T2, ec2.InstanceSize.NANO),
    machineImage: ami,
    securityGroup: securityGroup,
    role: role, <====== ロールを設定
});

```

##### GitHubActions内から ssm send-command を実行できるようにするため、IAMロールを作成する。

``` json
-- IAMロールの作成 arn:aws:iam::xxxxxxxxxxxx:role/deploy-role --
信頼ポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::xxxxxxxxxxxx:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:XXXXX/xxxxxxxx:ref:refs/heads/*"
                }
            }
        }
    ]
}

許可ポリシー インライン
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
              "s3:ListBucket", <== これらはおまけ、GithubActions内からS3へリソースをsyncするのに必要
              "s3:GetObject",  <== 今回はなくてもOK
              "s3:PutObject",  <== 

              "ssm:SendCommand" <== これが必要

            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}
```

### GitHubActionsの書き方

:::note info
事前に変更されるであろうパラメータを GitHub Actions 構成変数(環境変数) に設定しておく

- AWS_ROLE              
    -  (arn:aws:iam::xxxxxxxxxxxx:role/deploy-role)
- AWS_EC2_INSTANCEIDS   
    -  (i-abcdefg)
- AWS_SSM_SEND_COMMAND  
    -  (setup.sh)
:::

Actions(実際)の書き方 (actions.yml)

``` yaml

jobs:
  deploy:
    name: sample
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v3
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: ${{ vars.AWS_ROLE }}
          aws-region: ap-northeast-1

      - name: ec2 shell run
        run: |
          aws ssm send-command \
            --document-name "AWS-RunShellScript" \
            --document-version "1" \
            --targets "Key=instanceids,Values=${{ vars.AWS_EC2_INSTANCEIDS }}" \
            --parameters "commands='${{ vars.AWS_SSM_SEND_COMMAND }}'" \
            --timeout-seconds 180 \
            --max-concurrency "50" \
            --max-errors "0" \
            --region ap-northeast-1

```

### ここで注意点
:::note warn
警告
aws ssm send-command で実行されるユーザーは 「ssm-user」になるので、他(たとえばubuntu)ユーザでシェル内コマンドを実行する場合 su コマンドでユーザを変更する記述を書く必要がある。
:::

#### 記述例
``` bash
#!/bin/bash

cd /home/ubuntu

sudo su - ubuntu <<EOF
echo hogehoge
EOF
```

### 補足
:::note info
aws s3 sync コマンドを実行できるので、リポジトリ内に setup.sh を配置しておき
S3にアップロード後にダウンロードしてその内容を実行するようにシェルを書いておけば
プルリクエストで初期設定などの内容が変更されてるのでこの方法も有用。
:::