- Just 100%
|
All checks were successful
Deploy Terraform state backend / deploy (push) Successful in 26s
|
||
|---|---|---|
| .forgejo/workflows | ||
| cloudformation | ||
| .gitignore | ||
| justfile | ||
| lefthook.yml | ||
| LICENSE | ||
| README.md | ||
Terraform state bucket
This repository contains a CloudFormation template that provisions the AWS resources needed to use an S3 bucket as a Terraform remote state backend, shared by multiple projects.
- tries to solve the problem of also managing the S3 backend bucket via IaC and keeping it in a place that I can easily access and manage (and won't lose/forget easily)
- leverages Forgejo's OIDC identity provider to authenticate with AWS so no long-lived access keys are needed
Resources
The template creates:
- a KMS key used to encrypt the state files
- an S3 bucket used to store the state files
- an IAM managed policy granting the minimal permissions needed to use the backend from Terraform (attach it to the user/role that runs Terraform)
- Forgejo registered as an OIDC identity provider, plus an IAM role that Forgejo Actions assumes via OIDC — so the deploy pipeline uses short-lived credentials and there are no long-lived access keys to rotate
Bootstrap
The deploy workflow bootstraps itself. On its first run it authenticates with static AWS access keys (no OIDC role exists yet) and creates the stack — which provisions the Forgejo OIDC provider and the deployer role. From then on every run authenticates through OIDC.
It uses the AWS_DEPLOYER_ROLE_ARN repository variable as the bootstrap signal:
- unset → not bootstrapped → deploy with access keys (creates the role)
- set → bootstrapped → deploy through OIDC
-
Provide AWS access keys
In Settings → Actions → Secrets add
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYfor an IAM principal that can create everything in the stack (S3 bucket, KMS key, IAM roles/policies and the OIDC provider) — e.g. the root account or an admin user. They are only needed for the first run. -
Set the Forgejo instance host
Use
env.FORGEJO_SERVER_URLby default, overridable withMY_FORGEJO_PUBLIC_URL— the host of the Forgejo instance, without scheme or trailing slash (e.g.codeberg.org). -
Run the workflow (bootstrap)
Trigger it with a push to
masteror a manual dispatch. SinceAWS_DEPLOYER_ROLE_ARNis not set yet, it runs in bootstrap mode with the access keys and creates the stack and deployer role. -
Point the workflow at the deployer role
Copy the
DeployerRoleArnvalue fromjust outputsand set it as the repository variableAWS_DEPLOYER_ROLE_ARN. -
Done
Every subsequent run authenticates through OIDC. You can now delete the
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYsecrets.
Alternative: you can also bootstrap locally with
just deploy <host> <repo> <bucket name>using credentials configured in your AWS profile, then setAWS_DEPLOYER_ROLE_ARNand let the workflow take over.Trust boundary: the deployer role manages the whole stack, including its own permissions policy. Anyone who can push to
ForgejoBranchcan therefore change what the role is allowed to do — protect that branch accordingly.
Using the backend from Terraform
terraform {
backend "s3" {
bucket = "<bucket name>" # `just outputs | grep -A 1 BucketName` to fetch the bucket name
key = "project-name/terraform.tfstate"
region = "us-east-2"
use_lockfile = true
encrypt = true
kms_key_id = "alias/terraform-state"
}
}
Development
Prerequisites
- cfn-lint — CloudFormation template linter
- lefthook — Git hooks manager (already configured in
lefthook.yml)
Setup
Install the Git hooks so cfn-lint runs on every commit:
lefthook install
Lint manually
just lint
References
- Terraform S3 backend: https://developer.hashicorp.com/terraform/language/backend/s3
- Forgejo Actions OIDC: https://forgejo.org/docs/latest/user/actions/security-openid-connect/
- Forgejo Actions reference: https://forgejo.org/docs/next/user/actions/reference/
- AWS CloudFormation
AWS::S3::Bucket: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html