GitHubActionsを用いたS3へのコンテンツデプロイ


社内で行っている活動の中で、GitHubActionsを用いてGitHubのリポジトリにマージされたことをトリガーにS3へファイルをアップロードするワークフローを作成しました。
個人の経験として初めてGitHubActionsを利用したので記事にします。

S3上の静的ウェブサイトホスティング機能を利用してWebページを公開していると想定し、
Webページ用のHTMLとCSSがGitHubのブランチにマージされたらそれをS3にアップロードするという動きを作ります。
Actionsを実行するランナーはGitHubホステッドランナーを利用します。

https://docs.github.com/ja/actions

## 事前準備
### AWS設定
S3に対して静的ウェブサイトホスティングの設定を行い、Webページとして見られる状態にしておきます。
S3の静的ウェブサイトホスティングの設定自体はGitHubActionsとは関係がないため割愛します。
初期状態として以下のイメージのようなWebページを作成しました。
![actions_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561546/8f1d93d6-3677-f1f9-0bed-33b4eedd165e.jpeg)


GitHubActionsのワークフローの中でAWS CLIコマンドを実行するため、ワークフロー実行用のIAMユーザーとアクセスキーを作成し、S3アップロードに必要なIAMポリシーを作成してアタッチしておきます。
アップロードは`aws s3 sync`コマンドで特定ディレクトリ内のファイルを同期する形で行うため、`s3:DeleteObject`も付与しておきます。

```json:IMAポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "S3Access",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::<アップロード先バケット名>/*",
                "arn:aws:s3:::<アップロード先バケット名>"
            ]
        }
    ]
}
```
### GitHub設定
GitHubActions用に作成したIAMユーザーのアクセスキーとシークレットキーを
GitHubリポジトリの`Settings > Actions secrets and variables > Secrets`
に変数として設定しておきます。変数名は以下としました。
- DEV_AWS_ACCESS_KEY_ID: Actions用IAMユーザーのアクセスキー
- DEV_AWS_SECRET_ACCESS_KEY: Actions用IAMユーザーのシークレットキー

![actions_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561546/880d71da-686f-3b3d-8928-355adf2b1df0.jpeg)

`Settings > Actions secrets and variables > variables`
には変数としてAWSリージョンとアップロード先のバケットを設定しておきます。変数名は以下としました。
- AWS_DEFAULT_REGION: AWS CLIのリージョン定義
- DEV_AWS_S3_BUCKET: アップロード先S3バケット名

![actions_03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561546/81babb17-6e94-176c-751c-3dd6e8dd7e57.jpeg)

## Actionsワークフロー
### 動作の流れ
以下の動作となるよう、ワークフローを作成します。

1. developブランチにpushされた場合にワークフローを実行する
1. リポジトリからS3にアップロードするコンテンツを取得する
1. 取得されたファイル確認(Actionsのログに記録する目的)
1. AWS CLIコマンド設定
1. aws s3 syncコマンドでS3へアップロード
1. aws s3 lsコマンドでS3バケット内のファイル確認

### 作成したワークフロー定義
作成したワークフロー定義は以下の通り。`.github/workflows/`に配置してリモートリポジトリにpushしておきます。

```
リポジトリ構造
/
├─.github
│  └─workflows
│          github-actions-s3upload.yml
│
└─web-contents
        error.html
        index.html
        styles.css
```

```yaml:github-actions-s3upload.yml
name: Upload to S3 bucket
on:
  push:
      branches:
        - develop

env:
  SOURCE_DIR: web-contents

jobs:
  uploadjob:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v4
      
      - name: list checkoutfiles
        run: | 
          pwd
          ls -al ./${{env.SOURCE_DIR}}
      
      - name: setup awscli
        uses: aws-actions/configure-aws-credentials@v4
        with: 
          aws-access-key-id: ${{ secrets.DEV_AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.DEV_AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{vars.AWS_DEFAULT_REGION}}

      - name: deploy S3
        run: aws s3 sync ${{env.SOURCE_DIR}} s3://${{vars.DEV_AWS_S3_BUCKET}} --exact-timestamps --delete

      - name: check S3 objects
        run: aws s3 ls s3://${{vars.DEV_AWS_S3_BUCKET}} 
```

## 動作確認
実際に動作確認を行います。
index.html内の「テストページ」部分を「Actionsワークフローテストページ」に変えてpushします。

```diff_html
- <p>テストページ</p>
+ <p>Actionsワークフローテストページ</p>
```
GitHubリポジトリの「Actions」タブから実行履歴を確認します。
![actions_04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561546/8f59777a-46b3-691c-a1ac-16c99a637fdb.jpeg)

ログの一部抜粋。Secretsとして指定した環境変数はActionsのログ上でマスクされて表示される。
![actions_05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561546/ef4d6ac0-0cee-7238-e544-ba0a7318b397.jpeg)

Webページの確認

![actions_06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561546/c3ecbae2-ad0c-6e12-1d3a-c550f4c2f491.jpeg)


## まとめ
AWS上でCodeCommitがまだ利用できればCodeCommitでソースコードの管理、CodePiplineでS3へアップロードという流れをAWS上だけで実行できたのですが、CodeCommitの新規利用ができなくなったため、GitHubActionsを使ってみました。

セキュリティ面で、IAMユーザーのアクセスキーを発行するのではなく、IAMのIDプロバイダ機能を利用してIAMロールでワークフローを動かす方がより良い方法とされています。
今回はシンプルに動かすことを目的としたため、アクセスキーによる認証を行いましたが、IDプロバイダによる認証パターンでも試してみたいと思います。