Terraform を使って GitHub v2 ソースアクションでコードを取得する CodePipeline を構築する

# はじめに
GitHub と AWS CodePipeline を連携させようとした際、GitHub v1 ソースアクションが非推奨となり、v2 が推奨になっている事を知りました。
v1 は GitHub から OAuth トークンを払い出し Webhook で連携させます。
v2 は CodeStar SourceConnection を使って GitHub と連携させるようになっていました。

Terraform 上で GitHub v2 ソースアクションを連携させることが出来たので記録を残しておきます。 
CodePipeline の Source ステージ に GitHub v2 ソースアクション を設定する点に絞ってこの記事を書きます。

[KensukeTakahara/terraform-codepipeline-github](https://github.com/KensukeTakahara/terraform-codepipeline-github.git) で実装したコードを公開しています。
このリポジトリでは Build, Deploy ステージまで含めて CodePipeline を構築しています。

## 実行環境

Terraform は version 1.0.5、AWS Provider は version 3.58.0 を使用しました。

# Terraform で実装

下記のリソースについて実装します。

- S3 (アーティファクト格納用)
- CodeStar Connection
- CodePipeline

## S3 (アーティファクト格納用)

```terraform:s3
resource "aws_s3_bucket" "artifact" {
  bucket = "terraform-codepipeline-github-artifact"
}
```

CodePileline がアーティファクトを格納するために必要な S3 バケットです。
CodePileline では次のステージにアーティファクトを引き渡す時、S3 バケットを経由させます。
bucket にはリージョン内でユニークになるよう値を設定します。

## CodeStar Connection

```terraform:codestarconnections
resource "aws_codestarconnections_connection" "github" {
  name          = "github-connection"
  provider_type = "GitHub"
}
```

provide_type に "GitHub" を指定します。

## CodePipeline
```terraform:codepipeline
resource "aws_codepipeline" "example" {
  name     = "example"
  role_arn = aws_iam_role.codepipeline.arn

  stage {
    name = "Source"

    action {
      name             = "Source"
      category         = "Source"
      owner            = "AWS"
      provider         = "CodeStarSourceConnection"
      version          = 1
      output_artifacts = ["Source"]

      configuration = {
        ConnectionArn        = aws_codestarconnections_connection.github.arn
        FullRepositoryId     = "KensukeTakahara/terraform-codepipeline-github"
        BranchName           = "main"
        OutputArtifactFormat = "CODEBUILD_CLONE_REF"
      }
    }
  }

  # Build, Deploy ステージの記述は省略
  # terraform apply 実行時には必須

  artifact_store {
    location = aws_s3_bucket.artifact.id
    type     = "S3"
  }
}
```

provider に "CodeStarSourceConnection" を指定します。
configuration でリポジトリ名とブランチ名を指定します。
また Build ステージに CodeBuild を使う時は OutputArtifactFormat に "CODEBUILD_CLONE_REF" を指定しましょう。
"CODE_ZIP" を指定すると CodeBuild で使用するメタデータを生成できず、Build ステージで失敗します。
[参考](https://stackoverflow.com/questions/65916627/upload-to-s3-failed-with-the-following-error-access-denied-codestarconnection)

```terraform:iam
data "aws_iam_policy_document" "codepipeline" {
  statement {
    effect    = "Allow"
    resources = ["*"]

    actions = [
      "s3:PutObject",
      "s3:GetObject",
      "s3:GetObjectVersion",
      "s3:GetBucketVersioning",
      "codestar-connections:UseConnection"
    ]
  }
}

resource "aws_iam_policy" "codepipeline" {
  name   = "example-codepipeline-s3-policy"
  policy = data.aws_iam_policy_document.codepipeline.json
}

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

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

resource "aws_iam_role" "codepipeline" {
  name               = "example-codepipeline-role"
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_role_policy_attachment" "example" {
  role       = aws_iam_role.codepipeline.name
  policy_arn = aws_iam_policy.codepipeline.arn
}
```

IAM ロールではアーティファクトバケットと CodeStar Connection へのアクセス権限を設定しましょう。
これは Source ステージに必要な権限だけなので、適宜 Build, Deploy ステージに必要な IAM ポリシーを加えてください。

# プロビジョニング

`terraform apply` で実行して AWS 環境にプロビジョニングしても CodePipeline の構築はまだ完了していません。
GitHub 側の認証が必要です。

AWS マネジメントコンソールで CodePipeline を確認してみると、いきなり失敗しています。
![スクリーンショット 2021-09-12 22.57.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/f7a4cf75-22c3-e030-3cac-83800c51a095.png)

失敗の原因は CodeStar Connection のアクセス権限がないとのこと。
![スクリーンショット 2021-09-11 12.02.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/12f46812-b729-a5c9-62dd-65d6c72fd64f.png)

なのでコンソール上から「設定」->「接続」を選択して CodeStar Connection を確認しましょう。
![スクリーンショット 2021-09-11 12.05.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/8b2b4e03-1c57-39fa-cad3-225a2227b3e9.png)

「保留中の接続を更新」を選択。
![スクリーンショット 2021-09-11 12.05.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/051cc14a-ec40-809a-0000-98a78becdf1d.png)


別ウィンドウが出てきて GitHub 接続設定画面が出てきます。
![スクリーンショット 2021-09-11 12.06.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/aa599f98-ef37-65ed-0034-01e023ef87f2.png)

AWS アカウントと GitHub アカウントを連携させます。
![スクリーンショット 2021-09-11 23.05.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/776cc403-ffc3-7b0f-3e38-e13569b6687a.png)

対象の GitHub アカウントに AWS Connector for GitHub がない場合は新しくインストールします。
![スクリーンショット 2021-09-11 23.06.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/911acfda-358a-808f-9f8e-bfc452f5b9c7.png)

連携が完了すると、CodeStar Connection も接続が確立します。
![スクリーンショット 2021-09-11 12.08.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/05f4abda-fb80-adc8-ecb1-a27ab2845141.png)

Source ステージの再試行を実施すると成功します。
![スクリーンショット 2021-09-12 22.58.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163276/563626fc-eb89-7fff-637c-cb5e444aa990.png)

# まとめ

安全な GitHub v2 ソースアクションが Terraform 上で実装できました。
リソースの設定は Terraform 上でほとんど完結し AWS マネジメントコンソールでは GitHub 側の認証を済ませるだけなので、実装も簡単で管理もしやすいです。