【AWS】エンタープライズレベル ECS CI/CD の作り方②（GitHub Actions）

## 1. **はじめに**
ECSのCICD構成について、エンタープライズレベルでの構築方法をご紹介します。
単にコンテナをデプロイするだけでなく、セキュリティ、運用保守性などエンタープライズレベルの要件を満たすための構成を目指します。

本記事は2回目/全3回です。

初回/3回目記事はこちらです。
[【AWS】エンタープライズレベル ECS CI/CD の作り方①（GitHub Actions）](https://qiita.com/tatsufumi_haneda/items/4834ac0f413779dce638)
[【AWS】エンタープライズレベル ECS CI/CD の作り方③（GitHub Actions）](https://qiita.com/tatsufumi_haneda/items/db472c5529973dda267a)

Github Actionsワークフローファイルのコードは、初回記事に記載しています。

## 2. **設計ポイント**
2回目の記事で紹介する設計ポイントは以下の（★）の項目です。

* セキュリティ対策
    * （初回記事参照）ウィルススキャンの実施
    * （★）脆弱性スキャンの実施　
    * （★）S3上の環境変数ファイルからECSタスクへの機微情報の注入
        * Github上に機微情報を配置しない
    * （★）アクセスキーではなく、IAMロールでのAssumeRoleを利用
    * （★）IAMポリシーの最小限の権限付与
* 運用保守性
    * 単一のワークフローのみで複数環境へ選択的にデプロイ
    * 単一のワークフローのみで複数のイメージをまとめてビルドしてデプロイ
    * デプロイ実行後のCodeDeploy URL等を表示し、デプロイ結果を迅速に確認
    * コンテナイメージのタグにコミットハッシュを使用、アプリケーションのデプロイバージョンを一意に識別

## 3. **セキュリティ対策**
### 3-1. **脆弱性スキャンの実施**
脆弱性スキャンを実施することで、セキュリティホールを事前に発見し、対策を講じることができます。

ただし、脆弱性スキャンを実施した結果をどのように活用するかが重要です。
皆様も不定期かつ、大量に出力される脆弱性スキャン結果、そしてそれを読み解くのに苦労した経験があるのではないでしょうか。

つまり、脆弱性スキャンは結果に対応する運用フローと合わせて設計することが重要です。
具体的には、スキャン結果のトリアージ、SOCとの連携などが考えられます。

* 案①：CDパイプライン内でAmazon Inspectorを用いて脆弱性スキャンを実施し、脅威度の高いものを抽出してSNSに通知する
* 案②：Amazon Inspectorで脆弱性スキャン結果をFutureVulsに連携し、脅威度の高いものを抽出する

FutureVulsは、脆弱性スキャン結果を取り込み、脆弱性のトリアージを支援するツールです。具体的なトリアージの流れはクラスメソッド様の記事が参考になります。

* [【運用者向け】FutureVulsではじめる脆弱性管理](https://dev.classmethod.jp/articles/futurevuls-vulnerability-manegement/)

自チームだけで脆弱性スキャン結果をトリアージする場合は、案①で十分です。
一方で、社内のSOCとの連携を考えると、案②の方がより精度の高いトリアージと対策が可能になります。

案②で実施しているCDパイプラインとFutureVuls、SOCとの連携について図示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336189/3d8628a1-0183-56fb-2936-0a6e0be1623c.png)

ポイントは、スキャン結果をFutureVulsで自動トリアージさせる点とインフラメンバ、SOCメンバーが同じFutureVulsの画面を見て脆弱性に対する対策を相談・検討できる点になります。
これで対応を省力化しつつも、精度の高い対策を行うことができます。

### 3-2. **S3上の環境変数ファイルからECSタスクへの機微情報の注入**
Githubリポジトリに機微情報を配置しないで環境変数をECSタスクに注入する方法はいくつかあります。

* 案①：AWS Secrets Managerを利用し、ECSタスクに注入
* 案②：S3に環境変数ファイルを配置し、ECSタスクに注入

私は以下の構成図の通り、案②を採用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336189/78457a5f-bc5e-36e0-2f10-db269411da62.png)

一般的なベストプラクティスは、案①のAWS Secrets Managerを利用する方法です。
AWS Secrets Managerの優位な点は、Secretsへの利用履歴を保持できる点です。
S3でもCloudTrailでデータイベントを取得することで同様の機能を実現できます。

また、案②の場合、開発者の操作が容易である点がメリットです。
S3へのファイル配置は、AWSコンソールから開発者自身にて直感的な操作で容易に行うことができます。

s3にアップロードしたenvファイルをECSタスクに注入する方法がいかに楽か以下の記事が参考になります。

[Fargateの環境変数をs3においたenvファイルから取得する方法](https://qiita.com/GoogIeSensei/items/2b16b06c59ac202639e5)

なお、S3に環境変数ファイルを配置する場合、.envという拡張子のファイルを配置する必要があります。
対象のS3と環境変数ファイルを以下のようにECSタスク定義の`environmentFiles`句で指定します。

```json
{
    "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxxxx:task-definition/task:208",
    "containerDefinitions": [
        {
            "name": "tomcat",
            "image": "xxxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/tomcat:latest",
            ～省略～
            "environmentFiles": [
                {
                    "value": "arn:aws:s3:::sample-project-env/application.env",
                    "type": "s3"
                }
            ],
～省略～
}
```

### 3-3. **アクセスキーではなく、IAMロールでのAssumeRoleを利用**
これはもはや一般的なお話なので、詳細はクラスメソッド様の記事に譲ります。
[GitHub ActionsにAWSクレデンシャルを直接設定したくないのでIAMロールを利用したい](https://dev.classmethod.jp/articles/github-actions-aws-sts-credentials-iamrole/)

以下の3ステップで設定可能です。

1. OIDCプロバイダ追加
2. IAMロール作成
3. GitHub Actionsワークフロー修正

### 3-4. **IAMポリシーの最小限の権限付与**
こちらも同じく一般的なお話なので、詳細はクラスメソッド様の記事に譲ります。

[GitHub ActionsからECSとECRへのCI/CDを最小権限で実行したい](https://dev.classmethod.jp/articles/github-actions-ecs-ecr-minimum-iam-policy/)

今回紹介した、CICDのワークフロー(※)内でCodeDeployを利用していますので上記記事だけだと権限不足になります。ワークフローによるデプロイが失敗した場合は、詳細なエラーメッセージが出力されるため、トライ&エラーを繰り返して必要な権限を追加し、最小限の権限を付与を実現します。

※Github Actionsワークフローファイルのコードは、初回記事に記載しています。
初回記事はこちらです。
[【AWS】エンタープライズレベル ECS CI/CD の作り方①（GitHub Actions）](https://qiita.com/tatsufumi_haneda/items/4834ac0f413779dce638)

## おわりに
初回に続き、エンタープライズレベルのECS CICD構成について、セキュリティ対策についてご紹介しました。
次回は、以下の運用保守性の各項目についてご紹介予定です。

* 運用保守性
    * 単一のワークフローのみで複数環境へ選択的にデプロイ
    * 単一のワークフローのみで複数のイメージをまとめてビルドしてデプロイ
    * デプロイ実行後のCodeDeploy URL等を表示し、デプロイ結果を迅速に確認
    * コンテナイメージのタグにコミットハッシュを使用、アプリケーションのデプロイバージョンを一意に識別

ワークフローをなるべく統一し保守性を向上し、かつアプリケーションチームが使いやすいCICD環境を目指します。
次回の記事もどうぞお楽しみに。