Trust internal CA for Rancher OIDC discovery
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful

Rancher's server-side OIDC discovery call to the Authentik issuer
(https://identity.unkin.net) fails with x509 "certificate signed by
unknown authority" because Rancher does not trust the internal unkin.net
PKI. The keycloak_oidc auth config never set a CA certificate.

- Read the internal PKI ca_chain (intermediate + root) from Vault via a
  vault_generic_secret data source (pki_int/cert/ca_chain).
- Set certificate on rancher2_auth_config_keycloak_oidc, defaulting to the
  Vault-sourced chain so trust cannot go stale on rotation; add an optional
  keycloakoidc.certificate override for an explicit value.

Issuer, client, scopes and role bindings are unchanged.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
This commit is contained in:
2026-07-31 20:30:55 +10:00
parent 08fbc9b8ab
commit dbd1f6db8a
2 changed files with 17 additions and 0 deletions
+14
View File
@@ -5,6 +5,16 @@ data "vault_kv_secret_v2" "keycloakoidc" {
name = var.keycloakoidc.client_secret_vault.path 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 # Rancher's Keycloak(OIDC) auth provider, pointed at Authentik. access_mode
# "unrestricted" means any authenticated Authentik user can log in; Rancher # "unrestricted" means any authenticated Authentik user can log in; Rancher
# roles are granted to users/groups separately (avoids admin lockout on enable). # 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 groups_field = var.keycloakoidc.groups_field
access_mode = var.keycloakoidc.access_mode access_mode = var.keycloakoidc.access_mode
enabled = var.keycloakoidc.enabled 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 # Grant Rancher global roles to Authentik permission groups. The keycloak_oidc
+3
View File
@@ -10,6 +10,9 @@ variable "keycloakoidc" {
groups_field = optional(string, "groups") groups_field = optional(string, "groups")
access_mode = optional(string, "unrestricted") access_mode = optional(string, "unrestricted")
enabled = optional(bool, true) 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 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` key holds the value (seeded out of band); TF reads it.
client_secret_vault = optional(object({ client_secret_vault = optional(object({