個人開発用に VPS を借り始めてもう7年近くになる。これまでにボードゲーム関連で作ったサービスは基本的に VPS 1台に全部載せて運用している。コンテナすら利用していないので、PHP や MySQL のバージョンを上げるだけで一苦労だ。
日々の運用が toil になってしまって放置気味なこと、得た知見を業務にそのまま生かすのが難しいことから、今後作るものは Amazon Web Services や Google Cloud などのクラウドサービス上に構築することに決めた。社会人になって資金面の余裕が生まれたという理由もある。
同人活動に近いということもあり収益化はほぼできておらず、普段から赤字を垂れ流しているわけだが、やはり自ら手を動かして得た知見に勝るものはないだろう。これは勉強代ということにしておく。
そして、VPS を Amazon EC2 に変えても、勉強としては何の意味もないだろう、ということで、マネージドなサービスにちゃんと寄せていくことにする。とはいえ、個人開発レベルで Amazon RDS や Amazon ElastiCache を使うのはコストに見合うメリットが得られないのは明らかだ。この辺り、どう折り合いをつけていくかは今後の課題とする。
クラウドシフトプロジェクトの手始めに、Github Actions 上で動かす Visual Regression Test の結果を Amazon S3 にアップロードする仕組みを作る作業に取り掛かった。完成品は以下のような感じで、Github の Checks API を利用して良い感じに表示できるようにしてみた。
まずは、Github Actions のコンテナから画像を S3 にアップロードするのに必要な IAM ロールを作ることにした。慣れない Terraform を黙々と書いていった。
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.0" } } } # Configure the AWS Provider provider "aws" { region = "ap-northeast-1" profile = "AgricolaDevJP-admin" } // ref: https://zenn.dev/yukin01/articles/github-actions-oidc-provider-terraform data "http" "github_oidc_configuration" { url = "https://token.actions.githubusercontent.com/.well-known/openid-configuration" } data "tls_certificate" "github_oidc" { url = jsondecode(data.http.github_oidc_configuration.response_body).jwks_uri } resource "aws_iam_openid_connect_provider" "github_oidc" { url = "https://token.actions.githubusercontent.com" client_id_list = ["sts.amazonaws.com"] thumbprint_list = data.tls_certificate.github_oidc.certificates[*].sha1_fingerprint } resource "aws_s3_bucket" "agricola_card_image_generator_snapshot_bucket" { bucket = "agricola-card-image-generator-snapshot" force_destroy = true } resource "aws_s3_bucket_public_access_block" "agricola_card_image_generator_snapshot_bucket" { bucket = aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.id block_public_acls = false block_public_policy = false ignore_public_acls = false restrict_public_buckets = false } resource "aws_s3_bucket_versioning" "agricola_card_image_generator_snapshot_bucket" { bucket = aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.id versioning_configuration { status = "Disabled" } } resource "aws_s3_bucket_policy" "agricola_card_image_generator_snapshot_bucket" { bucket = aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.id policy = data.aws_iam_policy_document.agricola_card_image_generator_snapshot_bucket_public_access_policy.json } data "aws_iam_policy_document" "agricola_card_image_generator_snapshot_bucket_public_access_policy" { statement { principals { type = "*" identifiers = ["*"] } actions = [ "s3:GetObject" ] resources = [ "${aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.arn}/*" ] } } resource "aws_iam_role" "agricola_card_image_generator_snapshot_github_actions_role" { name = "agricola-card-image-generator-github-actions-role" assume_role_policy = data.aws_iam_policy_document.agricola_card_image_generator_snapshot_github_actions_role_policy.json } data "aws_iam_policy_document" "agricola_card_image_generator_snapshot_github_actions_role_policy" { statement { effect = "Allow" principals { type = "Federated" identifiers = [aws_iam_openid_connect_provider.github_oidc.arn] } actions = [ "sts:AssumeRoleWithWebIdentity" ] condition { test = "StringLike" variable = "token.actions.githubusercontent.com:sub" values = [ "repo:AgricolaDevJP/agricola-card-image-generator:*" ] } } } resource "aws_iam_role_policy" "agricola_card_image_generator_snapshot_bucket_put_policy" { name = "agricola-card-image-generator-snapshot-bucket-put-policy" role = aws_iam_role.agricola_card_image_generator_snapshot_github_actions_role.id policy = data.aws_iam_policy_document.agricola_card_image_generator_snapshot_bucket_put_policy.json } data "aws_iam_policy_document" "agricola_card_image_generator_snapshot_bucket_put_policy" { statement { effect = "Allow" actions = [ "s3:PutObject" ] resources = [ "${aws_s3_bucket.agricola_card_image_generator_snapshot_bucket.arn}/*" ] } }
ググっても credential を環境変数に埋め込む方法ばかり出てくるが、セキュリティ上の問題から定期的なローテートが必要で面倒だ。そこで、GitHub の AWS アカウントから、こちら側が用意したロールに Assume Role するようにしてみた。
上記の記事を参考に、thumbprint を直書きしないようにしたのもポイントである。
AWS を扱う上では避けたくても避けられない IAM と仲良くなるための第一歩としてちょうど良いスタートになったと思う。