# terraform-rancher Terraform configuration for managing Rancher (rancher.k8s.syd1.au.unkin.net) authentication via the [rancher2](https://registry.terraform.io/providers/rancher/rancher2) provider. Mirrors the `terraform-authentik` pattern. ## Managed Resources - **Keycloak(OIDC) auth config** — Authentik OIDC login for Rancher. - **Global role bindings** — Authentik group → Rancher global role. - **Users** — Rancher-local users and their global roles. - **Global roles** — custom Rancher global roles. - **Tokens** — API tokens for the identity Terraform authenticates as. - **Settings** — Rancher settings such as `server-url`. ## Configuration Every kind is discovered from YAML by `config/config.hcl`: the file name is the object's key/name and the file body holds its attributes. Adding a file is the only step needed to manage a new object; an empty directory means an empty map. `config/keycloakoidc.yaml` defines the auth provider. The OAuth client secret is read from Vault (kv-v2) — the same secret Authentik sets on its `rancher` provider — and is never committed. `access_mode: unrestricted` lets any authenticated Authentik user log in; Rancher roles are granted to users/groups separately. This avoids locking the admin out when the provider is first enabled. ### `config/global_role_bindings/.yaml` ```yaml global_role_id: admin ``` ### `config/users/.yaml` ```yaml name: Some Person # optional display name, defaults to the file name enabled: true # optional, default true must_change_password: false # optional, default false password_vault: # required — rancher2_user requires a password mount: kv path: service/rancher/users/someperson key: password # optional, default "password" global_role_bindings: # optional - user ``` The password is read from Vault **at plan time**, so seed the kv-v2 secret before adding the file, or the plan fails. The file name (the username) and every entry in `global_role_bindings` must be an RFC 1123 label — `^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`, i.e. lowercase alphanumerics and `-`, starting and ending alphanumeric. No `.`, `_`, `@` or uppercase. Rancher names each binding `akuser--` and rejects anything else, so non-compliant values fail the plan with an explicit error instead of the apply. Names that are individually valid but collapse to the same binding name (e.g. `foo-bar` + `baz` and `foo` + `bar-baz`) are rejected at plan time too. ### `config/roles/.yaml` ```yaml description: Read-only across all clusters new_user_default: false # optional, default false inherited_cluster_roles: # optional - view rules: # optional - api_groups: ["management.cattle.io"] resources: ["clusters"] verbs: ["get", "list", "watch"] # non_resource_urls and resource_names are also supported ``` ### `config/tokens/.yaml` ```yaml description: CI token # optional, defaults to the file name ttl: 7776000 # optional, seconds renew: true # optional cluster_id: c-m-abcdefgh # optional, scopes the token to one cluster ``` > **Caveat:** `rancher2_token` has no user selector — `user_id` is computed by > the provider (14.1.1), not settable. Tokens declared here are minted for the > identity the rancher2 provider authenticates as (the admin token Terraform > runs with), **not** for users in `config/users/`. A token for another user has > to be created by that user. Token values land in Terraform state. ### `config/settings/.yaml` ```yaml value: https://rancher.k8s.syd1.au.unkin.net ``` Rancher ships defaults for its settings, so an entry takes over an existing setting rather than creating a new one. ## Usage ```sh make plan # init + plan make apply # init + plan + apply make format # fmt tofu + terragrunt hcl ``` ### Authentication The rancher2 provider needs a Rancher API token, minted on demand by the Vault Rancher secrets engine at `rancher/creds/ci`. The token is ephemeral (1h lease) and Vault revokes it in Rancher when the lease expires, so nothing needs rotating. Set `VAULT_ROLEID` for local AppRole auth, or `VAULT_AUTH_METHOD=kubernetes` for CI (Woodpecker).