521ef4f0f3
ci/woodpecker/push/apply Pipeline was successful
## Why - Managing NetBox from Vault needs three capabilities the repo does not yet have: mounting the netbox engine, minting scoped tokens through roles, and creating the NetBox service users those roles mint tokens for. Landing the modules and config scaffolding before any backend or role data lets each concrete identity be added as pure data later. ## How - Add three modules under `modules/vault_cluster/modules`: `netbox_secret_backend` (mount + engine config, admin token read from KV), `netbox_secret_backend_role` (mint ephemeral scoped tokens for a filename-derived NetBox username), and `netbox_user_management` (mirror consul_acl_management: read the seeded admin token, drive one e-breuninger/netbox provider per backend, and synthesize the NetBox user + object permissions from the role map's inline permissions). - Derive the `netbox_secret_backend` and `netbox_secret_backend_role` maps in `config.hcl`, deriving each role's name and netbox_username from its filename so the engine role and NetBox username match by construction. - Wire the three module blocks and their variables through `vault_cluster` and the syd1 terragrunt inputs, reusing the sanitized backend-alias pattern the Consul providers use. - Leave the backend and role maps empty: the modules stand ready and create nothing until backend and role config data are added. ## Dependency order - Stacked on the plugin registration PR (branch `benvin/netbox-plugin`); merge that first, then this, then the backend + role PR (#117). Plans clean with empty netbox maps. --------- Co-authored-by: BenVincent <benvin@main.unkin.net> Reviewed-on: #115 Co-authored-by: Ben Vincent <ben@unkin.net> Co-committed-by: Ben Vincent <ben@unkin.net>
480 lines
16 KiB
Terraform
480 lines
16 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_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 "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)
|
|
}))
|
|
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 "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 = {}
|
|
}
|
|
|