You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The existing github-ci/ Scaleway IAM application has only ObjectStorageReadOnly permissions —
sufficient for the bucket-listing smoke test, but insufficient to run terraform apply/destroy on cluster/scaleway (K8s clusters, node pools, VPC networks, Terraform state R/W). A dedicated,
scoped identity is required as a prerequisite for the Terraform CI workflows.
In scope: new terraform-ci/ root module; IAM application + least-privilege policy; API key
with time-rotation; Infisical secret storage; mise.toml tasks; gh secret set documentation;
smoke test that confirms state bucket access.
README documents gh secret set TF_SCW_ACCESS_KEY / TF_SCW_SECRET_KEY for the scaleway GitHub Environment and as repo-level secrets (for the ungated destroy workflows)
Smoke test job authenticates with the new key and successfully lists the Terraform state bucket (confirms ObjectStorageReadWrite)
Design Notes
Why a new root instead of extending github-ci/: independent state and blast radius. Revoking
the terraform-ci key does not affect the read-only CI key, and vice versa.
Scaleway permission sets for cluster/scaleway:
Permission set
Why
ObjectStorageReadWrite
R/W the S3 state backend
KubernetesFullAccess
scaleway_k8s_cluster + scaleway_k8s_pool
VPCFullAccess
scaleway_vpc_private_network
Kubernetes/Helm providers authenticate via the cluster kubeconfig (not Scaleway IAM) — no
additional IAM permission needed for them. Infisical provider uses its own credentials
(TF_VAR_infisical_*) — no IAM coverage needed.
S3 backend env vars in CI (must be set by the consuming workflows):
AWS_ACCESS_KEY_ID = TF_SCW_ACCESS_KEY value
AWS_SECRET_ACCESS_KEY = TF_SCW_SECRET_KEY value
AWS_DEFAULT_REGION = fr-par
AWS_ENDPOINT_URL_S3 = https://s3.fr-par.scw.cloud
Secret naming:TF_SCW_ACCESS_KEY / TF_SCW_SECRET_KEY — distinct from the read-only SCW_ACCESS_KEY / SCW_SECRET_KEY to preserve permission separation.
Smoke test: add a second job to the existing scaleway-auth-check.yml, triggered on PRs
touching terraform-ci/**, reusing the scaleway/action-scw pattern.
Tasks
1. Root module scaffold
1.1 Create terraform-ci/version.tf — copy github-ci/version.tf; set workspace_key_prefix = "terraform-ci"; keep providers scaleway, infisical, time
2.5 infisical_secret_folder data source or resource (reuse /ci); infisical_secret.tf_scw_access_key + infisical_secret.tf_scw_secret_key (sensitive = true)
3. Outputs
3.1 outputs.tf — expose access_key (non-sensitive ID only; secret never output)
4. mise.toml + lock
4.1 Add terraform-ci-init, terraform-ci-plan, terraform-ci-apply tasks to mise.toml
4.2 Add terraform -chdir=terraform-ci providers lock -platform=darwin_arm64 -platform=linux_amd64 to the lock task
4.3 Run mise run lock for terraform-ci; commit .terraform.lock.hcl
4.4 Add terraform-ci to the matrix in .github/workflows/terraform-lock.yml
5. README + smoke test
5.1 Write terraform-ci/README.md — purpose, why static key, what it creates, credentials, apply steps, gh secret set commands (environment scaleway + repo-level), rotation procedure
5.2 Add list-state-bucket-terraform-ci job to .github/workflows/scaleway-auth-check.yml using TF_SCW_ACCESS_KEY / TF_SCW_SECRET_KEY; trigger on PRs touching terraform-ci/**
6. Apply + wire secrets (manual, post-merge)
6.1 mise run terraform-ci-plan → review → mise run terraform-ci-apply
6.2 gh secret set TF_SCW_ACCESS_KEY + TF_SCW_SECRET_KEY in scaleway environment and as repo-level secrets
Context / Problem
The existing
github-ci/Scaleway IAM application has onlyObjectStorageReadOnlypermissions —sufficient for the bucket-listing smoke test, but insufficient to run
terraform apply/destroyoncluster/scaleway(K8s clusters, node pools, VPC networks, Terraform state R/W). A dedicated,scoped identity is required as a prerequisite for the Terraform CI workflows.
Scope & Non-Goals
In scope: new
terraform-ci/root module; IAM application + least-privilege policy; API keywith time-rotation; Infisical secret storage;
mise.tomltasks;gh secret setdocumentation;smoke test that confirms state bucket access.
Non-goals: modifying
github-ci/, automatinggh secret set, OIDC.Acceptance Criteria
terraform-ci/root module exists (version.tf,variables.tf,main.tf,outputs.tf,README.md,.terraform.lock.hcl)terraform-ci/terraform.tfstatein the shared S3 bucket (independent fromgithub-ci/andcluster/scaleway/)scaleway_iam_application.terraform_ciprovisioned (name"terraform-ci")ObjectStorageReadWrite+KubernetesFullAccess+VPCFullAccess, all scoped tovar.project_idscaleway_iam_api_key.terraform_cidriven bytime_rotating(default 365 days,var.api_key_rotation_days)/cifolder asTF_SCW_ACCESS_KEY(ID) andTF_SCW_SECRET_KEY(secret,sensitive = true)terraform-ciadded toterraform-lock.ymlCI matrixmise.tomltasksterraform-ci-init,terraform-ci-plan,terraform-ci-applyadded;terraform-ciadded tolocktaskgh secret set TF_SCW_ACCESS_KEY/TF_SCW_SECRET_KEYfor thescalewayGitHub Environment and as repo-level secrets (for the ungated destroy workflows)ObjectStorageReadWrite)Design Notes
Why a new root instead of extending
github-ci/: independent state and blast radius. Revokingthe terraform-ci key does not affect the read-only CI key, and vice versa.
Scaleway permission sets for
cluster/scaleway:ObjectStorageReadWriteKubernetesFullAccessscaleway_k8s_cluster+scaleway_k8s_poolVPCFullAccessscaleway_vpc_private_networkKubernetes/Helm providers authenticate via the cluster kubeconfig (not Scaleway IAM) — no
additional IAM permission needed for them. Infisical provider uses its own credentials
(
TF_VAR_infisical_*) — no IAM coverage needed.S3 backend env vars in CI (must be set by the consuming workflows):
AWS_ACCESS_KEY_ID=TF_SCW_ACCESS_KEYvalueAWS_SECRET_ACCESS_KEY=TF_SCW_SECRET_KEYvalueAWS_DEFAULT_REGION=fr-parAWS_ENDPOINT_URL_S3=https://s3.fr-par.scw.cloudSecret naming:
TF_SCW_ACCESS_KEY/TF_SCW_SECRET_KEY— distinct from the read-onlySCW_ACCESS_KEY/SCW_SECRET_KEYto preserve permission separation.Smoke test: add a second job to the existing
scaleway-auth-check.yml, triggered on PRstouching
terraform-ci/**, reusing thescaleway/action-scwpattern.Tasks
1. Root module scaffold
terraform-ci/version.tf— copygithub-ci/version.tf; setworkspace_key_prefix = "terraform-ci"; keep providersscaleway,infisical,timeterraform-ci/variables.tf— copygithub-ci/variables.tf(project_id,api_key_rotation_days,infisical_*)terraform-ci/nico.auto.tfvars(gitignored, same pattern asgithub-ci/)terraform initinterraform-ci/; confirm backend initializes cleanly2. IAM resources (
main.tf)scaleway_iam_application.terraform_ci(name"terraform-ci")scaleway_iam_policy.terraform_ci— 3 rules:ObjectStorageReadWrite,KubernetesFullAccess,VPCFullAccess, allproject_ids = [var.project_id]time_rotating.api_key(rotation_days = var.api_key_rotation_days)scaleway_iam_api_key.terraform_ci(expires_at = time_rotating.api_key.rotation_rfc3339,default_project_id = var.project_id)infisical_secret_folderdata source or resource (reuse/ci);infisical_secret.tf_scw_access_key+infisical_secret.tf_scw_secret_key(sensitive = true)3. Outputs
outputs.tf— exposeaccess_key(non-sensitive ID only; secret never output)4. mise.toml + lock
terraform-ci-init,terraform-ci-plan,terraform-ci-applytasks tomise.tomlterraform -chdir=terraform-ci providers lock -platform=darwin_arm64 -platform=linux_amd64to thelocktaskmise run lockforterraform-ci; commit.terraform.lock.hclterraform-cito the matrix in.github/workflows/terraform-lock.yml5. README + smoke test
terraform-ci/README.md— purpose, why static key, what it creates, credentials, apply steps,gh secret setcommands (environmentscaleway+ repo-level), rotation procedurelist-state-bucket-terraform-cijob to.github/workflows/scaleway-auth-check.ymlusingTF_SCW_ACCESS_KEY/TF_SCW_SECRET_KEY; trigger on PRs touchingterraform-ci/**6. Apply + wire secrets (manual, post-merge)
mise run terraform-ci-plan→ review →mise run terraform-ci-applygh secret set TF_SCW_ACCESS_KEY+TF_SCW_SECRET_KEYinscalewayenvironment and as repo-level secrets