b225ef6344
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.
318 lines
14 KiB
HCL
318 lines
14 KiB
HCL
# =============================================================================
|
|
# VAULT MODULE CONFIGURATION SYSTEM
|
|
# =============================================================================
|
|
#
|
|
# This file automatically discovers and organizes YAML configuration files
|
|
# for Vault modules, creating structured configuration maps for Terraform.
|
|
#
|
|
# HOW IT WORKS:
|
|
# 1. Scans all subdirectories for *.yaml files
|
|
# 2. Groups files by module type based on directory structure
|
|
# 3. Creates unique resource keys to prevent naming conflicts
|
|
# 4. Adds computed fields like name, backend, etc. from file paths
|
|
#
|
|
# DIRECTORY STRUCTURE:
|
|
# config/
|
|
# ├── auth_approle_role/
|
|
# │ └── approle/
|
|
# │ ├── certmanager.yaml # Creates key: "approle/certmanager"
|
|
# │ └── myapp.yaml # Creates key: "approle/myapp"
|
|
# ├── auth_kubernetes_role/
|
|
# │ └── k8s/au/syd1/
|
|
# │ ├── default.yaml # Creates key: "k8s/au/syd1/default"
|
|
# │ └── myapp.yaml # Creates key: "k8s/au/syd1/myapp"
|
|
# └── kv_secret_backend/
|
|
# ├── kv.yaml # Creates key: "kv"
|
|
# └── secrets.yaml # Creates key: "secrets"
|
|
#
|
|
# EXAMPLE YAML FILE (config/auth_approle_role/approle/myapp.yaml):
|
|
# ```yaml
|
|
# token_ttl: 3600
|
|
# token_max_ttl: 7200
|
|
# bind_secret_id: true
|
|
# token_bound_cidrs:
|
|
# - "10.0.0.0/8"
|
|
# ```
|
|
#
|
|
# This becomes:
|
|
# ```hcl
|
|
# auth_approle_role = {
|
|
# "approle/myapp" = {
|
|
# approle_name = "myapp" # Auto-computed from filename
|
|
# mount_path = "approle" # Auto-computed from directory
|
|
# token_ttl = 3600 # From YAML content
|
|
# token_max_ttl = 7200 # From YAML content
|
|
# bind_secret_id = true # From YAML content
|
|
# token_bound_cidrs = ["10.0.0.0/8"]
|
|
# }
|
|
# }
|
|
# ```
|
|
#
|
|
# KEY NAMING PATTERNS:
|
|
# - Simple backends: filename only (e.g., "kv", "transit")
|
|
# - Role-based resources: full path without extension (e.g., "approle/myapp")
|
|
# - This ensures uniqueness when multiple backends have similar role names
|
|
#
|
|
# GENERATED OUTPUTS:
|
|
# - config.auth_approle_backend, config.auth_approle_role, etc.
|
|
# - Each module gets its own map with properly structured configuration
|
|
#
|
|
# =============================================================================
|
|
|
|
locals {
|
|
# Find all YAML files in subdirectories
|
|
config_files = fileset(".", "**/*.yaml")
|
|
|
|
# Create a flat map of all files with their content
|
|
all_configs = {
|
|
for file_path in local.config_files :
|
|
file_path => yamldecode(file(file_path))
|
|
}
|
|
|
|
# Group by module directory (first part of path)
|
|
config = {
|
|
auth_approle_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "auth_approle_backend/")
|
|
}
|
|
auth_approle_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "auth_approle_role/", ""), ".yaml") => merge(content, {
|
|
approle_name = trimsuffix(basename(file_path), ".yaml")
|
|
mount_path = split("/", replace(file_path, "auth_approle_role/", ""))[0]
|
|
})
|
|
if startswith(file_path, "auth_approle_role/")
|
|
}
|
|
auth_ldap_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "auth_ldap_backend/")
|
|
}
|
|
auth_ldap_group = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "auth_ldap_group/", ""), ".yaml") => merge(content, {
|
|
groupname = trimsuffix(basename(file_path), ".yaml")
|
|
backend = split("/", replace(file_path, "auth_ldap_group/", ""))[0]
|
|
})
|
|
if startswith(file_path, "auth_ldap_group/")
|
|
}
|
|
auth_oidc_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "auth_oidc_backend/")
|
|
}
|
|
auth_oidc_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "auth_oidc_role/", ""), ".yaml") => merge(content, {
|
|
role_name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "auth_oidc_role/", ""))
|
|
})
|
|
if startswith(file_path, "auth_oidc_role/")
|
|
}
|
|
auth_oidc_group = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "auth_oidc_group/", ""), ".yaml") => merge(content, {
|
|
groupname = trimsuffix(basename(file_path), ".yaml")
|
|
backend = split("/", replace(file_path, "auth_oidc_group/", ""))[0]
|
|
})
|
|
if startswith(file_path, "auth_oidc_group/")
|
|
}
|
|
auth_kubernetes_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "auth_kubernetes_backend/", ""), ".yaml") => content
|
|
if startswith(file_path, "auth_kubernetes_backend/")
|
|
}
|
|
auth_kubernetes_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "auth_kubernetes_role/", ""), ".yaml") => merge(content, {
|
|
role_name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "auth_kubernetes_role/", ""))
|
|
})
|
|
if startswith(file_path, "auth_kubernetes_role/")
|
|
}
|
|
kv_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "kv_secret_backend/")
|
|
}
|
|
transit_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "transit_secret_backend/")
|
|
}
|
|
transit_secret_backend_key = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "transit_secret_backend_key/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "transit_secret_backend_key/", ""))
|
|
})
|
|
if startswith(file_path, "transit_secret_backend_key/")
|
|
}
|
|
ssh_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "ssh_secret_backend/")
|
|
}
|
|
ssh_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "ssh_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "ssh_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "ssh_secret_backend_role/")
|
|
}
|
|
pki_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "pki_secret_backend/", ""), ".yaml") => content
|
|
if startswith(file_path, "pki_secret_backend/")
|
|
}
|
|
pki_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "pki_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "pki_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "pki_secret_backend_role/")
|
|
}
|
|
kubernetes_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "kubernetes_secret_backend/", ""), ".yaml") => content
|
|
if startswith(file_path, "kubernetes_secret_backend/")
|
|
}
|
|
kubernetes_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "kubernetes_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "kubernetes_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "kubernetes_secret_backend_role/")
|
|
}
|
|
consul_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "consul_secret_backend/", ""), ".yaml") => content
|
|
if startswith(file_path, "consul_secret_backend/")
|
|
}
|
|
consul_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "consul_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "consul_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "consul_secret_backend_role/")
|
|
}
|
|
pki_mount_only = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "pki_mount_only/")
|
|
}
|
|
litellm_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "litellm_secret_backend/")
|
|
}
|
|
litellm_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "litellm_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "litellm_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "litellm_secret_backend_role/")
|
|
}
|
|
arrstack_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "arrstack_secret_backend/")
|
|
}
|
|
arrstack_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "arrstack_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "arrstack_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "arrstack_secret_backend_role/")
|
|
}
|
|
plugins = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
})
|
|
if startswith(file_path, "plugins/")
|
|
}
|
|
gpg_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "gpg_secret_backend/")
|
|
}
|
|
gpg_key = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "gpg_key/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "gpg_key/", ""))
|
|
})
|
|
if startswith(file_path, "gpg_key/")
|
|
}
|
|
rancher_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "rancher_secret_backend/")
|
|
}
|
|
rancher_secret_backend_service_account = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "rancher_secret_backend_service_account/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "rancher_secret_backend_service_account/", ""))
|
|
})
|
|
if startswith(file_path, "rancher_secret_backend_service_account/")
|
|
}
|
|
rancher_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "rancher_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "rancher_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "rancher_secret_backend_role/")
|
|
}
|
|
gitea_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "gitea_secret_backend/")
|
|
}
|
|
gitea_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "gitea_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "gitea_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "gitea_secret_backend_role/")
|
|
}
|
|
netbox_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "netbox_secret_backend/")
|
|
}
|
|
netbox_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "netbox_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
netbox_username = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "netbox_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "netbox_secret_backend_role/")
|
|
}
|
|
ghp_secret_backend = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(basename(file_path), ".yaml") => content
|
|
if startswith(file_path, "ghp_secret_backend/")
|
|
}
|
|
ghp_secret_backend_role = {
|
|
for file_path, content in local.all_configs :
|
|
trimsuffix(replace(file_path, "ghp_secret_backend_role/", ""), ".yaml") => merge(content, {
|
|
name = trimsuffix(basename(file_path), ".yaml")
|
|
backend = dirname(replace(file_path, "ghp_secret_backend_role/", ""))
|
|
})
|
|
if startswith(file_path, "ghp_secret_backend_role/")
|
|
}
|
|
}
|
|
}
|