diff --git a/modules/rancher/main.tf b/modules/rancher/main.tf index 77a74d7..93b861b 100644 --- a/modules/rancher/main.tf +++ b/modules/rancher/main.tf @@ -5,6 +5,16 @@ data "vault_kv_secret_v2" "keycloakoidc" { name = var.keycloakoidc.client_secret_vault.path } +# Read the internal PKI CA chain (intermediate + root) from Vault. Rancher makes +# its OIDC discovery call to https://identity.unkin.net server-side; without the +# internal CA it fails with x509 "certificate signed by unknown authority". The +# ca_chain field is public/non-sensitive. Sourced from Vault (not hardcoded) so +# the trust never goes stale on rotation. +data "vault_generic_secret" "internal_ca" { + count = var.keycloakoidc != null ? 1 : 0 + path = "pki_int/cert/ca_chain" +} + # Rancher's Keycloak(OIDC) auth provider, pointed at Authentik. access_mode # "unrestricted" means any authenticated Authentik user can log in; Rancher # roles are granted to users/groups separately (avoids admin lockout on enable). @@ -20,6 +30,10 @@ resource "rancher2_auth_config_keycloak_oidc" "this" { groups_field = var.keycloakoidc.groups_field access_mode = var.keycloakoidc.access_mode enabled = var.keycloakoidc.enabled + + # CA cert Rancher uses to trust the IdP's TLS during OIDC discovery. Defaults + # to the internal PKI chain from Vault; an explicit config value overrides it. + certificate = coalesce(var.keycloakoidc.certificate, data.vault_generic_secret.internal_ca[0].data["ca_chain"]) } # Grant Rancher global roles to Authentik permission groups. The keycloak_oidc diff --git a/modules/rancher/variables.tf b/modules/rancher/variables.tf index 8340ee4..19c56ac 100644 --- a/modules/rancher/variables.tf +++ b/modules/rancher/variables.tf @@ -10,6 +10,9 @@ variable "keycloakoidc" { groups_field = optional(string, "groups") access_mode = optional(string, "unrestricted") enabled = optional(bool, true) + # PEM CA cert Rancher trusts for the IdP's TLS on OIDC discovery. Leave null + # to default to the internal PKI ca_chain read from Vault. + certificate = optional(string, null) # client_secret is never committed. Point at a Vault kv-v2 secret whose # `client_secret` key holds the value (seeded out of band); TF reads it. client_secret_vault = optional(object({