はじめに
個人開発のサイトをホスティングするにあたり、普段の業務で使っているTerraformをそのまま活かしつつ、Amplifyのインフラ構築とCI/CDの仕組みを整えたのでその備忘です。
対象読者
- AmplifyやHCP Terraform未経験
- HCP Terraformのワークスペースは作成済み
やったこと
- AWS AmplifyをTerraformで構築
- HCP TerraformをBackendに設定
- GitHubへのpushをトリガーにAmplifyが自動デプロイされるCI/CDを構築
- OIDCを使ってアクセスキーなしでHCP TerraformからAWSを操作
- index.htmlの表示
構成図
ローカル
↓ git push
GitHub(インフラ用リポジトリ)
↓ VCS連携(pushを検知)
HCP Terraform
↓ OIDC認証(アクセスキー不要)
AWS IAM Role
↓ AssumeRoleWithWebIdentity
AWS Amplify(サイトをホスティング)
↑ GitHub(サイト用リポジトリ)と連携
↓ mainへのpushで自動ビルド・デプロイ
リポジトリは2つに分けています。
-
your-infra:TerraformでAWSインフラを管理 -
your-site:サイトのソースコード(HTML/CSS/JS)
ディレクトリ構成
tool-site-infra/
├── infra/
│ ├── modules/
│ │ └── amplify-site/ # 再利用可能なAmplifyモジュール
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── sites/
│ └── my-site/ # サイトごとの設定(モジュールを呼び出すだけ)
│ └── main.tf
モジュール化しておくことで、2つ目以降のサイトを追加する際はsites/配下に新しいフォルダを作ってモジュールを呼び出すだけで同じ構成が再現できます。
HCP TerraformをBackendに設定する
# infra/sites/my-site/main.tf
terraform {
cloud {
organization = "your-org-name"
workspaces {
name = "your-workspace"
}
}
}
OIDCでアクセスキーなしにする
HCP TerraformからAWSを操作する際、アクセスキーをHCP Terraformに渡したくなかったのでOIDCを使いました。
1. AWS側にOIDC Identity Providerを登録
AWSコンソール → IAM → Identity providers → Add provider
| 項目 | 値 |
|---|---|
| Provider type | OpenID Connect |
| Provider URL | https://app.terraform.io |
| Audience(対象者) | aws.workload.identity |
2. IAMロールの信頼関係にHCP Terraform用の設定を追加
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/app.terraform.io"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"app.terraform.io:aud": "aws.workload.identity"
},
"StringLike": {
"app.terraform.io:sub": "organization:YOUR_ORG:project:*:workspace:YOUR_WORKSPACE:run_phase:*"
}
}
}
]
}
3. HCP TerraformのWorkspace変数に登録
| Key | Value | Category |
|---|---|---|
TFC_AWS_PROVIDER_AUTH |
true |
Environment variable |
TFC_AWS_RUN_ROLE_ARN |
IAMロールのARN | Environment variable |
これだけでアクセスキーなしでHCP TerraformからAWSを操作できます。
AmplifyモジュールのTerraformコード
# infra/modules/amplify-site/main.tf
resource "aws_amplify_app" "this" {
name = var.app_name
repository = var.repository
access_token = var.github_access_token
build_spec = var.build_spec
enable_branch_auto_deletion = true
basic_auth_credentials = var.basic_auth_username != null ? base64encode("${var.basic_auth_username}:${var.basic_auth_password}") : null
enable_basic_auth = var.basic_auth_username != null
}
resource "aws_amplify_branch" "main" {
app_id = aws_amplify_app.this.id
branch_name = var.branch_name
stage = "PRODUCTION"
enable_auto_build = true
}
enable_auto_build = trueでGitHubのmainブランチへのpushを検知して自動ビルドが走ります。Basic認証も最初から組み込んでいます(開発中の不正アクセス防止)。
build_specの注意点
AmplifyはデフォルトでReact向けのbuild_specを想定しています。シンプルなHTML構成の場合はビルド不要なので以下にします。
version: 1
frontend:
phases:
build:
commands:
- echo "No build required"
artifacts:
baseDirectory: /
files:
- '**/*'
Reactプロジェクトでない場合はここを変更しないとビルドが失敗します(自分はここでハマりました)。
HCP TerraformのVCS連携設定
GitHubにpushしたらHCP Terraformが自動でplan/applyする設定です。
HCP TerraformのWorkspace → Settings → Version Control から設定します。
| 項目 | 値 |
|---|---|
| リポジトリ | yourname/tool-site-infra |
| Terraform Working Directory | infra/sites/my-site |
Terraform Working Directoryの注意点:リポジトリルートからの相対パスで、実際に.tfファイルが置いてある場所を指定します。モジュールの定義ファイルがある場所ではなく、モジュールを呼び出しているmain.tfがある場所を指定するのが正しいです。
ハマったポイントまとめ
1. .terraform/をgitignoreし忘れた
terraform init後に.terraform/ディレクトリが生成されますが、中にAWSプロバイダーのバイナリ(648MB)が入っておりGitHubの100MB制限を超えてpushが失敗しました。
# 履歴ごと削除
git filter-branch --force --index-filter \
'git rm -rf --cached --ignore-unmatch .terraform' \
--prune-empty --tag-name-filter cat -- --all
git push origin main --force
.terraform/
*.tfstate
*.tfstate.backup
2. HCP TerraformのTerraformバージョンが古かった
HCP TerraformのデフォルトバージョンはTerraform 1.5.7でしたが、コードが>= 1.6を要求していてエラーになりました。Workspace Settings → General → Terraform Versionから1.9.x以上に変更して解決しました。
3. Workspace変数のCategoryをHCLにしてしまった
文字列変数をHCP TerraformのWorkspace変数に登録する際、CategoryをHCLにするとTerraformのコードとして解釈されてエラーになります。文字列を渡す場合はHCLのチェックボックスをOFFにする必要があります。
結果
サイト用リポジトリにindex.htmlを追加してpushするだけで、Amplifyが自動でビルド・デプロイされ、ブラウザでHello Worldが表示されるところまで確認できました。
Amplifyは「AWSのサービス」というイメージでとっつきにくかったですが、実態はS3+CloudFront+CodePipelineをマネージドにまとめたものです。Terraformで管理してしまえば、2つ目以降のサイトを追加するのがモジュールの呼び出しだけで済むのが気に入っています。
