0e82cda02d
ci/woodpecker/push/apply Pipeline failed
## Why Creates the arrstack secrets engine itself: the mount + config and the per-scope roles that mint arrproxy API keys. **PR 3 of 3 (resources)**, stacked on #126 (policy). Final step of the register -> policy -> resources split (was #124). ## Change - Adds `config/arrstack_secret_backend/arrstack.yaml`: mounts the engine at `arrstack` and writes its config (`base_url`, timeout). The arrproxy admin token stays out of git and is read from KV by the module. - Adds `config/arrstack_secret_backend_role/arrstack/{all,sonarr,radarr,prowlarr}.yaml`: roles scoped to each arr app (plus one covering all three). Default `ttl` is **60s** (short-lived, renewed on demand); `max_ttl` 86400 mirrors the litellm sibling convention. The engine additionally caps renewal at the arrproxy admin token's fixed mint expiry. - Adds `modules/vault_cluster/modules/arrstack_secret_backend{,_role}` and wires them in: `config/config.hcl` maps, `modules/vault_cluster/main.tf`, `variables.tf`, the environment inputs, and the root provider block. - Provider source is `artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/vault-secrets-arrstack` (repo `terraform-provider-vault-secrets-arrstack`), local name `arrstack`. ## Apply order Apply **after PR #126 (policy) AND after `terraform-provider-vault-secrets-arrstack` v0.1.0 is published** to the artifactapi terraform registry. Until the provider is published, `tofu init` cannot resolve it, so **CI/plan on this PR is red by design** — that is expected, not a regression. Note **plan-green != apply-green**: the KV-sourced `admin_token` is only fetched at apply time, so a green plan does not prove the seeded token is readable. ## Stack 1. register -> #125 2. policy -> #126 3. **resources (this PR)** -> `benvin/arrstack-resources` off `benvin/arrstack-policy` Supersedes #124. --------- Co-authored-by: unkin-agent <unkin-agent@git.unkin.net> Co-authored-by: BenVincent <benvin@main.unkin.net> Reviewed-on: #127 Co-authored-by: unkin-agent <unkin-agent@unkin.net> Co-committed-by: unkin-agent <unkin-agent@unkin.net>
297 lines
13 KiB
HCL
297 lines
13 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_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/")
|
|
}
|
|
}
|
|
}
|