Skip to content

feat: authenticate GitHub Actions to Scaleway via a scoped IAM key#22

Merged
nbrieussel merged 6 commits into
mainfrom
feature/github-ci-scaleway-iam-key
Jun 11, 2026
Merged

feat: authenticate GitHub Actions to Scaleway via a scoped IAM key#22
nbrieussel merged 6 commits into
mainfrom
feature/github-ci-scaleway-iam-key

Conversation

@nbrieussel

Copy link
Copy Markdown
Contributor

Context

Implements #21. GitHub Actions needs to authenticate to Scaleway. Keyless GitHub-OIDC → Scaleway is not possible (Scaleway IAM is not an OIDC relying party — feature request still open), so this uses Scaleway's supported pattern: a dedicated, least-privilege API key consumed from GitHub Actions secrets, stood up as versioned Terraform.

Changes

  • New github-ci/ root (org-wide S3 backend, Scaleway + Infisical providers):
    • scaleway_iam_application — the CI identity
    • scaleway_iam_policypermission_set_names = ["ObjectStorageReadOnly"], scoped to a single project (no broader set)
    • scaleway_iam_api_key — with default_project_id baked in
    • infisical_secret × 2 — writes SCW_ACCESS_KEY / SCW_SECRET_KEY to Infisical (staging env, /ci folder); secret half is sensitive, state-only
  • .github/workflows/scaleway-auth-check.ymlworkflow_dispatch that authenticates with the key and runs scw object bucket list region=fr-par; asserts the secrets are present so it fails clearly on missing/invalid creds
  • Wired into mise run lock, the terraform-lock CI matrix, convenience github-ci-* mise tasks, and CLAUDE.md
  • github-ci/README.md documents the manual gh secret set step + the OIDC-to-Scaleway non-goal

Verification done locally

  • terraform init (backend connects), validate ✅, plan → 5 to add, policy scoped to ObjectStorageReadOnly on the one project, secret values (sensitive value)
  • .terraform.lock.hcl covers darwin_arm64 + linux_amd64
  • terraform fmt clean, actionlint clean
  • No terraform apply run — left for explicit approval

Remaining (needs approval / can't be done from here)

These are the post-apply steps from #21, requiring a human:

  • mise run github-ci-apply (billable: creates the IAM key)
  • gh secret set SCW_ACCESS_KEY / SCW_SECRET_KEY (exact commands in github-ci/README.md)
  • Trigger Scaleway Auth Check and confirm it lists fr-par buckets, job green

Open questions from the issue — decisions taken

  • Infisical destination: staging env, new /ci folder (keeps CI secrets separate from cluster-bootstrap secrets). Overridable via vars.
  • Project scope: the default project (6283c05b-…), where the state bucket lives. Overridable via var.project_id.
  • Workflow tooling: official scaleway/action-scw pinned to a commit SHA.

🤖 Generated with Claude Code

New `github-ci/` Terraform root that stands up the Scaleway identity
GitHub Actions uses to authenticate to Scaleway:

- `scaleway_iam_application` + `scaleway_iam_policy`
  (`ObjectStorageReadOnly`, project-scoped) + `scaleway_iam_api_key`
- key written into Infisical (`staging` env, `/ci` folder); secret half
  is sensitive, state-only
- `workflow_dispatch` smoke test that authenticates with
  SCW_ACCESS_KEY/SCW_SECRET_KEY and lists fr-par buckets, failing
  clearly when the secrets are absent

Keyless GitHub-OIDC -> Scaleway is a non-goal: blocked upstream
(Scaleway IAM is not an OIDC relying party). Static least-privilege key
is Scaleway's supported pattern; mitigated with a dedicated,
independently-revocable identity.

Wires the new root into `mise run lock`, the terraform-lock CI matrix,
convenience mise tasks, and CLAUDE.md.

Closes #21
Comment thread .github/workflows/scaleway-auth-check.yml Fixed
Comment thread .github/workflows/scaleway-auth-check.yml Fixed
Comment thread .github/workflows/scaleway-auth-check.yml Fixed
Comment thread .github/workflows/scaleway-auth-check.yml Fixed
Comment thread .github/workflows/scaleway-auth-check.yml Outdated
- Add a `pull_request` trigger (paths: github-ci/**, the workflow file) so
  the Scaleway auth check can be validated before merge — workflow_dispatch
  can't be triggered from a branch, only once on the default branch.
- Run the job in a dedicated `scaleway` GitHub Environment, scoping secret
  usage (resolves zizmor's secrets-outside-env finding).
- Document both triggers + the validation order in the README.
The org enforces an expiration date on every Scaleway API key, so a key
with no expires_at fails at create ("expiration date required"). Drive
expires_at from a time_rotating resource (default 365d,
var.api_key_rotation_days): the timestamp holds steady until the window
lapses, then the next apply rotates the key (expires_at is ForceNew).

Adds the hashicorp/time provider (lock re-generated for both platforms)
and documents the rotation behaviour in the README.
infisical_secret doesn't create missing folders, so writing to /ci 404'd
("Folder with path '/ci' ... not found"). Add an infisical_secret_folder
resource for the CI folder and point the secrets at its computed path so
the folder is created first.
scw object bucket list needs a default organization ID even for a
project-scoped key ("organization ID is required"). Pass it (and the
project ID) as action inputs — public identifiers, not secrets (same
UUID already committed in github-ci/variables.tf).
Comment thread .github/workflows/scaleway-auth-check.yml Outdated
Comment thread .github/workflows/scaleway-auth-check.yml Outdated
…vars

- Trigger the auth check on pull_request only (workflow_dispatch was
  un-triggerable from a branch anyway).
- Read default-organization-id / default-project-id from repo variables
  (vars.SCW_DEFAULT_ORGANIZATION_ID / SCW_DEFAULT_PROJECT_ID) instead of
  hardcoding the UUID — public identifiers, not secrets.
- Document the two repo variables in the README.
@nbrieussel
nbrieussel marked this pull request as ready for review June 11, 2026 12:39
@nbrieussel
nbrieussel merged commit 8bb3e76 into main Jun 11, 2026
8 checks passed
@nbrieussel
nbrieussel deleted the feature/github-ci-scaleway-iam-key branch June 11, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants