variable "groups" { type = map(object({ name = string is_superuser = optional(bool, false) # PKs of existing parent groups. These must be literal group PKs, not keys # into this map: authentik_group cannot reference itself. parents = optional(list(string), null) attributes = optional(map(string), {}) })) default = {} } # Two-tier RBAC. Permission groups (akP-*) are the atomic units mapped to app # roles and bound to applications for access. Role groups (akR-*) are what users # are assigned to; each nests permission groups via `parents`, so a member of a # role is an effective member of every permission it grants (Authentik membership # propagates child -> parent). Split into two variables/resources so roles can # reference permission group ids without the authentik_group self-reference error. # The group name is the map key (the config filename); no `name` field needed. variable "permission_groups" { type = map(object({ # slug of the oauth2 application this permission grants *access* to; when set, # a policy binding is created gating that app to this group (and its children). application = optional(string, null) attributes = optional(map(string), {}) })) default = {} } variable "role_groups" { type = map(object({ # keys into var.permission_groups that this role nests (becomes its parents). permissions = optional(list(string), []) is_superuser = optional(bool, false) attributes = optional(map(string), {}) })) default = {} } variable "providers_saml" { type = map(object({ name = string authorization_flow = string invalidation_flow = string acs_url = string sp_binding = optional(string, "redirect") audience = optional(string, "") name_id_mapping = optional(string, null) signing_kp = optional(string, null) })) default = {} } variable "providers_oauth2" { type = map(object({ name = string authorization_flow = string # flow slug, resolved to id via data.authentik_flow invalidation_flow = string # flow slug, resolved to id via data.authentik_flow client_type = optional(string, "confidential") client_id = string # 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({ mount = string path = string }), null) # Managed identifiers of scope property mappings (e.g. # goauthentik.io/providers/oauth2/scope-openid). Resolved to ids. scope_mappings = optional(list(string), []) # OAuth2 grant types the provider permits. Authentik 2026.5 added this as an # explicit allow-list on the provider (models default = empty); an empty list # rejects every authorize request with "invalid_request / The request is # otherwise malformed". Default to the standard confidential web-app set so # authorization_code (login) and refresh_token (offline access) work. grant_types = optional(list(string), ["authorization_code", "refresh_token"]) # allowed_redirect_uris is list(map(string)); the API always stores a # redirect_uri_type key, so it must be set here or every plan drifts. redirect_uris = optional(list(object({ matching_mode = optional(string, "strict") url = string redirect_uri_type = optional(string, "authorization") })), []) signing_key = optional(string, null) access_token_validity = optional(string, "minutes=10") # Explicit launch URL for the app tile on the user dashboard ("My # applications"). Null lets Authentik derive it from the first redirect_uri; # set it to the app's UI to make the tile deterministic and to force an # application re-save (which invalidates Authentik's cached access policy). launch_url = optional(string, null) # Optional app-role claim computed from (hierarchical) group membership: emit # `claim` = the first matching rule's role, else `default`. The app requests # `claim` as a scope and reads it (e.g. LiteLLM GENERIC_USER_ROLE_ATTRIBUTE). # rules are evaluated in order, so list highest privilege first. role_mappings = optional(object({ claim = string default = string rules = list(object({ group = string # permission group name (akP-*) role = string # app role value })) }), null) })) default = {} } # Name of the RSA certificate keypair used to sign OAuth2 ID tokens (RS256) for # every provider that does not set its own signing_key. Defaults to Authentik's # built-in self-signed RSA keypair. variable "oauth2_signing_key_name" { type = string default = "authentik Self-signed Certificate" } variable "providers_ldap" { type = map(object({ name = string bind_flow = string unbind_flow = string base_dn = string certificate = optional(string, null) tls_server_name = optional(string, null) uid_start_number = optional(number, 2000) gid_start_number = optional(number, 4000) search_mode = optional(string, "direct") bind_mode = optional(string, "direct") mfa_support = optional(bool, true) })) default = {} } # Machine identities for automation (agents, CI). Each entry creates a service # account user, an RBAC role carrying its global permissions, and any API tokens # it needs. The username is the map key (the config filename). variable "service_accounts" { type = map(object({ name = optional(string, null) # display name; defaults to the key description = optional(string, "") # Global RBAC permissions granted via a dedicated role, in # `.` form (e.g. authentik_outposts.view_outpost). permissions = optional(list(string), []) # API tokens keyed by identifier. Set `vault` to publish the generated key # into kv-v2 so consumers read it from Vault instead of an operator pasting it. tokens = optional(map(object({ description = optional(string, "") expiring = optional(bool, false) vault = optional(object({ mount = string path = string key = optional(string, "token") }), null) })), {}) })) default = {} }