Files
terraform-vault/modules/vault_cluster/variables.tf
T
unkin-agent b225ef6344
ci/woodpecker/pr/plan Pipeline failed
ci/woodpecker/pr/pre-commit Pipeline was successful
Add Authentik OIDC SSO as the default human login for OpenBao
Human access to OpenBao is LDAP-only today, so operators carry a second set of
credentials outside Authentik and group membership is maintained twice. This
makes Authentik SSO the offered default on the UI login page and gives
`bao login -method=oidc` a working CLI path, while approle and kubernetes (CI
and agents) plus the break-glass root path are untouched.

Add three modules mirroring the auth_ldap_* structure: auth_oidc_backend mounts
a vault_jwt_auth_backend of type oidc, auth_oidc_role creates the default login
role, and auth_oidc_group creates an external vault_identity_group plus its
group alias so IdP groups map onto policies.

Mount the backend at the literal path "oidc". The Authentik provider registers
strict redirect URIs containing /ui/vault/auth/oidc/oidc/callback, so the path
is load-bearing and must not be renamed.

Read client_id and client_secret from kv/service/authentik/oidc-vault, which
terraform-authentik generates and writes; nothing is seeded by hand.

Match groups on the ak_groups claim rather than groups, because Authentik's
default profile mapping only emits direct memberships and the estate nests
akP-* permission groups under akR-* roles.

Bind akP-vault-admin to global-root, the same policy the LDAP vault_admin group
already carries. Only akP-* permission groups are named in config or policy;
akR-* roles stay grouping-only.

Grant the deployer auth/oidc/* and identity group management, both of which it
currently lacks. AppRole capabilities are fixed at login, so these land in an
apply before the resources that need them.
2026-08-30 21:49:14 +10:00

581 lines
19 KiB
Terraform

variable "country" {
description = "Country identifier"
type = string
}
variable "region" {
description = "Region identifier"
type = string
}
variable "auth_approle_backend" {
description = "Map of AppRole auth backends to create"
type = map(object({
listing_visibility = optional(string)
default_lease_ttl = optional(string)
max_lease_ttl = optional(string)
}))
default = {}
}
variable "auth_approle_role" {
description = "Map of AppRole roles to create"
type = map(object({
approle_name = string
mount_path = string
token_ttl = optional(number)
token_max_ttl = optional(number)
bind_secret_id = optional(bool, false)
secret_id_ttl = optional(number)
token_bound_cidrs = optional(list(string), [])
alias_metadata = optional(map(string))
use_deterministic_role_id = optional(bool, true)
}))
default = {}
}
variable "auth_ldap_backend" {
description = "Map of LDAP auth backends to create"
type = map(object({
userdn = string
userattr = optional(string, "uid")
upndomain = optional(string)
discoverdn = optional(bool, false)
groupdn = optional(string)
groupfilter = optional(string)
groupattr = optional(string, "cn")
alias_metadata = optional(map(string))
username_as_alias = optional(bool, true)
listing_visibility = optional(string)
default_lease_ttl = optional(string)
max_lease_ttl = optional(string)
}))
default = {}
}
variable "auth_ldap_group" {
description = "Map of LDAP groups to create"
type = map(object({
groupname = string
backend = string
}))
default = {}
}
variable "auth_oidc_backend" {
description = "Map of OIDC (JWT) auth backends to create"
type = map(object({
oidc_discovery_url = string
description = optional(string)
client_secret_mount = optional(string, "kv")
client_secret_path = optional(string, "service/authentik/oidc-vault")
default_role = optional(string, "default")
listing_visibility = optional(string)
default_lease_ttl = optional(string)
max_lease_ttl = optional(string)
}))
default = {}
}
variable "auth_oidc_role" {
description = "Map of OIDC auth roles to create"
type = map(object({
role_name = string
backend = string
allowed_redirect_uris = list(string)
user_claim = optional(string, "email")
groups_claim = optional(string, "ak_groups")
oidc_scopes = optional(list(string), [])
bound_audiences = optional(list(string), [])
token_ttl = optional(number, 3600)
token_max_ttl = optional(number, 28800)
}))
default = {}
}
variable "auth_oidc_group" {
description = "Map of external identity groups bound to an OIDC auth mount"
type = map(object({
groupname = string
backend = string
}))
default = {}
}
variable "auth_kubernetes_backend" {
description = "Map of Kubernetes auth backends to create"
type = map(object({
kubernetes_host = string
disable_iss_validation = optional(bool, true)
use_annotations_as_alias_metadata = optional(bool, true)
listing_visibility = optional(string)
default_lease_ttl = optional(string)
max_lease_ttl = optional(string)
}))
default = {}
}
variable "auth_kubernetes_role" {
description = "Map of Kubernetes auth roles to create"
type = map(object({
role_name = string
backend = string
bound_service_account_names = list(string)
bound_service_account_namespaces = list(string)
token_ttl = optional(number, 3600)
token_max_ttl = optional(number, 86400)
audience = optional(string, "vault")
}))
default = {}
}
variable "kv_secret_backend" {
description = "Map of KV secret engines to create"
type = map(object({
type = optional(string, "kv-v2")
description = optional(string)
version = optional(string, "2")
max_versions = optional(number)
}))
default = {}
}
variable "transit_secret_backend" {
description = "Map of Transit secret engines to create"
type = map(object({
description = optional(string)
default_lease_ttl_seconds = optional(number, 3600)
max_lease_ttl_seconds = optional(number, 86400)
}))
default = {}
}
variable "transit_secret_backend_key" {
description = "Map of Transit keys to create"
type = map(object({
name = string
backend = string
type = optional(string, "aes256-gcm96")
deletion_allowed = optional(bool, false)
derived = optional(bool, false)
exportable = optional(bool, false)
allow_plaintext_backup = optional(bool, false)
auto_rotate_period = optional(string)
}))
default = {}
}
variable "ssh_secret_backend" {
description = "Map of SSH secret engines to create"
type = map(object({
description = optional(string)
max_lease_ttl_seconds = optional(number, 315360000)
generate_signing_key = optional(bool)
key_type = optional(string, "ssh-rsa")
}))
default = {}
}
variable "ssh_secret_backend_role" {
description = "Map of SSH roles to create"
type = map(object({
name = string
backend = string
key_type = optional(string, "ca")
algorithm_signer = optional(string, "rsa-sha2-256")
ttl = optional(number, 315360000)
allow_host_certificates = optional(bool, false)
allow_user_certificates = optional(bool, false)
allowed_domains = optional(string)
allow_subdomains = optional(bool, false)
allow_bare_domains = optional(bool, false)
}))
default = {}
}
variable "pki_secret_backend" {
description = "Map of PKI secret engines to create"
type = map(object({
description = optional(string)
max_lease_ttl_seconds = optional(number, 315360000)
common_name = string
issuer_name = string
ttl = optional(number, 315360000)
format = optional(string, "pem")
issuing_certificates = optional(list(string), [])
crl_distribution_points = optional(list(string), [])
ocsp_servers = optional(list(string), [])
enable_templating = optional(bool, false)
default_follows_latest_issuer = optional(bool, false)
crl_expiry = optional(string, "72h")
crl_disable = optional(bool, false)
ocsp_disable = optional(bool, false)
auto_rebuild = optional(bool, false)
enable_delta = optional(bool, false)
delta_rebuild_interval = optional(string)
}))
default = {}
}
variable "pki_secret_backend_role" {
description = "Map of PKI roles to create"
type = map(object({
name = string
backend = string
allow_ip_sans = optional(bool, false)
allowed_domains = optional(list(string), [])
allow_subdomains = optional(bool, false)
allow_glob_domains = optional(bool, false)
allow_bare_domains = optional(bool, false)
enforce_hostnames = optional(bool, false)
allow_any_name = optional(bool, false)
max_ttl = optional(number)
key_bits = optional(number, 4096)
country = optional(list(string), [])
use_csr_common_name = optional(bool, false)
use_csr_sans = optional(bool, false)
}))
default = {}
}
variable "pki_mount_only" {
description = "Map of PKI mounts to create (without certificate generation)"
type = map(object({
description = optional(string)
max_lease_ttl_seconds = optional(number, 315360000)
issuing_certificates = optional(list(string), [])
crl_distribution_points = optional(list(string), [])
ocsp_servers = optional(list(string), [])
enable_templating = optional(bool, false)
default_issuer_ref = optional(string)
default_follows_latest_issuer = optional(bool, false)
crl_expiry = optional(string, "72h")
crl_disable = optional(bool, false)
ocsp_disable = optional(bool, false)
auto_rebuild = optional(bool, false)
enable_delta = optional(bool, false)
delta_rebuild_interval = optional(string)
}))
default = {}
}
variable "consul_secret_backend" {
description = "Map of Consul secret engines to create"
type = map(object({
description = optional(string)
address = string
bootstrap = optional(bool, false)
bootstrap_token = optional(string)
scheme = optional(string, "https")
ca_cert = optional(string)
client_cert = optional(string)
client_key = optional(string)
default_lease_ttl_seconds = optional(number)
max_lease_ttl_seconds = optional(number)
}))
default = {}
}
variable "consul_secret_backend_role" {
description = "Map of Consul roles to create"
type = map(object({
name = string
backend = string
consul_roles = optional(list(string), [])
ttl = optional(number)
max_ttl = optional(number)
local = optional(bool, false)
datacenters = optional(list(string))
description = optional(string)
service_identities = optional(list(object({
service_name = string
datacenters = optional(list(string))
})))
node_identities = optional(list(object({
node_name = string
datacenter = string
})))
}))
default = {}
}
variable "consul_backend_aliases" {
description = "Map of consul backend names to sanitized provider aliases"
type = map(string)
default = {}
}
variable "kubernetes_secret_backend" {
description = "Map of Kubernetes secret engines to create"
type = map(object({
description = optional(string)
default_lease_ttl_seconds = optional(number, 600)
max_lease_ttl_seconds = optional(number, 86400)
kubernetes_host = string
disable_local_ca_jwt = optional(bool, false)
}))
default = {}
}
variable "kubernetes_secret_backend_role" {
description = "Map of Kubernetes secret backend roles to create"
type = map(object({
name = string
backend = string
allowed_kubernetes_namespaces = optional(list(string), ["*"])
kubernetes_role_type = optional(string, "Role")
extra_labels = optional(map(string), {})
service_account_name = optional(string)
}))
default = {}
}
variable "litellm_secret_backend" {
description = "Map of LiteLLM secret engines to create (mount + config). The master key is read from KV"
type = map(object({
plugin = optional(string, "vault-plugin-secrets-litellm")
description = optional(string)
base_url = string
request_timeout_seconds = optional(number, 30)
}))
default = {}
}
variable "litellm_secret_backend_role" {
description = "Map of LiteLLM roles to create"
type = map(object({
name = string
backend = string
models = optional(list(string))
max_budget = optional(number)
key_alias_prefix = optional(string)
ttl = optional(number)
max_ttl = optional(number)
metadata = optional(map(string))
}))
default = {}
}
variable "arrstack_secret_backend" {
description = "Map of arrstack secret engines to create (mount + config). The arrproxy admin token is read from KV"
type = map(object({
plugin = optional(string, "vault-plugin-secrets-arrstack")
description = optional(string)
base_url = string
ca_cert = optional(string)
request_timeout_seconds = optional(number, 30)
}))
default = {}
}
variable "arrstack_secret_backend_role" {
description = "Map of arrstack roles to create"
type = map(object({
name = string
backend = string
apps = list(string)
methods = optional(set(string))
ttl = optional(number)
max_ttl = optional(number)
}))
default = {}
}
variable "plugins" {
description = "Map of plugins to import (register) in the catalog, keyed by catalog name"
type = map(object({
name = string
type = optional(string, "secret")
command = optional(string)
sha256 = string
version = optional(string)
}))
default = {}
}
variable "gpg_secret_backend" {
description = "Map of GPG/OpenPGP secret engines to mount (path => registered plugin + description). The plugin is registered separately via config/plugins."
type = map(object({
plugin = optional(string, "vault-plugin-secrets-gpg")
description = optional(string)
}))
default = {}
}
variable "gpg_key" {
description = "Map of OpenPGP keys to manage in a gpg engine mount"
type = map(object({
name = string
backend = string
algorithm = optional(string, "rsa-3072")
identity = optional(string)
exportable = optional(bool, false)
deletion_allowed = optional(bool, false)
min_decryption_version = optional(number)
}))
default = {}
}
variable "rancher_secret_backend" {
description = "Map of rancher token secret engines to create (mount + config)"
type = map(object({
plugin = optional(string, "vault-plugin-secrets-rancher")
description = optional(string)
rancher_url = string
ca_cert = optional(string)
tls_skip_verify = optional(bool, false)
request_timeout_seconds = optional(number, 30)
}))
default = {}
}
variable "rancher_secret_backend_service_account" {
description = "Map of seeded, auto-rotated rancher service-account tokens (seed token read from KV)"
type = map(object({
name = string
backend = string
token_ttl = optional(number)
rotation_period = optional(number)
}))
default = {}
}
variable "rancher_secret_backend_role" {
description = "Map of rancher token-minting roles to create"
type = map(object({
name = string
backend = string
service_account = string
cluster_name = optional(string)
description = optional(string)
ttl = optional(number)
max_ttl = optional(number)
}))
default = {}
}
variable "gitea_secret_backend" {
description = "Map of gitea token secret engines to create (mount + config; seeded admin creds read from KV)"
type = map(object({
plugin = optional(string, "vault-plugin-secrets-gitea")
description = optional(string)
gitea_url = string
ca_cert = optional(string)
tls_skip_verify = optional(bool, false)
request_timeout_seconds = optional(number, 30)
}))
default = {}
}
variable "gitea_secret_backend_role" {
description = "Map of gitea token-minting roles to create"
type = map(object({
name = string
backend = string
username = string
scopes = list(string)
token_name_prefix = optional(string)
ttl = optional(number)
max_ttl = optional(number)
}))
default = {}
}
variable "netbox_secret_backend" {
description = "Map of netbox token secret engines to create (mount + config; seeded admin token read from KV)"
type = map(object({
plugin = optional(string, "vault-plugin-secrets-netbox")
description = optional(string)
netbox_url = string
token_version = optional(number, 2)
ca_cert = optional(string)
tls_skip_verify = optional(bool, false)
request_timeout_seconds = optional(number, 30)
# Pre-existing NetBox superuser (or add_user + add_token + grant_token) the
# engine mints an ephemeral user-admin token for, so netbox_user_management
# authenticates with a Vault-minted credential derived from the single static
# admin token instead of a second static one. Unset = use the static
# admin_token directly (bootstrap/degraded; breaks after admin-token rotation).
user_mgmt_username = optional(string)
}))
default = {}
}
variable "netbox_secret_backend_role" {
description = "Map of netbox engine roles; each role's filename-derived name is both the engine role and the NetBox username it mints tokens for, and its permissions block is the user's object-permission set"
type = map(object({
name = string
backend = string
netbox_username = optional(string)
netbox_user_id = optional(number)
write_enabled = optional(bool, false)
description = optional(string)
ttl = optional(number)
max_ttl = optional(number)
active = optional(bool, true)
staff = optional(bool, false)
email = optional(string)
permissions = optional(list(object({
name = optional(string)
object_types = list(string)
actions = optional(list(string), ["view", "add", "change", "delete"])
constraints = optional(string)
description = optional(string)
enabled = optional(bool, true)
})), [])
}))
default = {}
}
variable "netbox_backend_aliases" {
description = "Map of netbox backend names to sanitized provider aliases"
type = map(string)
default = {}
}
variable "ghp_secret_backend" {
description = "Map of ghp token secret engines to create (mount + config; seeded service token read from KV)"
type = map(object({
plugin = optional(string, "vault-plugin-secrets-ghp")
description = optional(string)
base_url = string
ca_cert = optional(string)
tls_skip_verify = optional(bool, false)
request_timeout_seconds = optional(number, 30)
}))
default = {}
}
variable "ghp_secret_backend_role" {
description = "Map of ghp engine roles; reading ghp/creds/<name> mints a short-lived scoped ghp token"
type = map(object({
name = string
backend = string
token_type = optional(string)
installation_id = optional(number)
app_record_id = optional(string)
repositories = optional(list(string))
scopes = optional(list(string))
session_prefix = optional(string)
ttl = optional(number)
max_ttl = optional(number)
}))
default = {}
}
variable "policy_auth_map" {
description = "Map of auth mounts -> auth roles -> policy names"
type = map(map(list(string)))
default = {}
}
variable "policy_rules_map" {
description = "Map of policy names to their rules"
type = map(list(object({
path = string
capabilities = list(string)
})))
default = {}
}