Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5567bd6dac |
@@ -0,0 +1,9 @@
|
|||||||
|
# Mounts the arrstack dynamic secrets engine at "arrstack" and writes its config.
|
||||||
|
# The arrproxy admin token is sensitive and read from KV, not stored here:
|
||||||
|
# kv/kubernetes/namespace/arrstack/default/arrproxy-admin-token -> key "token"
|
||||||
|
# (seeded by argocd-apps #384). arrstack.unkin.net terminates on traefik-external
|
||||||
|
# with an internal-CA cert the OpenBao nodes already trust, so ca_cert is omitted
|
||||||
|
# (system trust store), mirroring the gitea engine against git.unkin.net.
|
||||||
|
description: "arrstack dynamic arrproxy API keys"
|
||||||
|
base_url: "https://arrstack.unkin.net"
|
||||||
|
request_timeout_seconds: 30
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
# Mints an arrproxy API key scoped to all three arr apps.
|
||||||
|
apps:
|
||||||
|
- sonarr
|
||||||
|
- radarr
|
||||||
|
- prowlarr
|
||||||
|
ttl: 3600 # seconds (1h)
|
||||||
|
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||||
|
# arrproxy admin token's fixed mint expiry.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
# Mints an arrproxy API key scoped to Prowlarr only.
|
||||||
|
apps:
|
||||||
|
- prowlarr
|
||||||
|
ttl: 3600 # seconds (1h)
|
||||||
|
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||||
|
# arrproxy admin token's fixed mint expiry.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
# Mints an arrproxy API key scoped to Radarr only.
|
||||||
|
apps:
|
||||||
|
- radarr
|
||||||
|
ttl: 3600 # seconds (1h)
|
||||||
|
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||||
|
# arrproxy admin token's fixed mint expiry.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
# Mints an arrproxy API key scoped to Sonarr only.
|
||||||
|
apps:
|
||||||
|
- sonarr
|
||||||
|
ttl: 3600 # seconds (1h)
|
||||||
|
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||||
|
# arrproxy admin token's fixed mint expiry.
|
||||||
@@ -198,6 +198,19 @@ locals {
|
|||||||
})
|
})
|
||||||
if startswith(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 = {
|
plugins = {
|
||||||
for file_path, content in local.all_configs :
|
for file_path, content in local.all_configs :
|
||||||
trimsuffix(basename(file_path), ".yaml") => merge(content, {
|
trimsuffix(basename(file_path), ".yaml") => merge(content, {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# config/plugins/vault-plugin-secrets-arrstack.yaml
|
||||||
|
# Imports (registers) the arrstack secrets plugin in the catalog. Filename =
|
||||||
|
# catalog name = mount type. The binary is installed on the OpenBao nodes by
|
||||||
|
# Puppet (openbao-plugin-secrets-arrstack RPM ->
|
||||||
|
# /opt/openbao-plugins/vault-plugin-secrets-arrstack).
|
||||||
|
#
|
||||||
|
# sha256 pins the released v0.1.0 binary; bump it in lockstep with any RPM
|
||||||
|
# upgrade or OpenBao will refuse to launch the plugin. Registration only
|
||||||
|
# succeeds once the Puppet PR has installed the binary on the nodes.
|
||||||
|
type: secret
|
||||||
|
command: vault-plugin-secrets-arrstack
|
||||||
|
version: "0.1.0"
|
||||||
|
sha256: "f8ee60ca7ba14819976acb7dc4cfb6799e3e8da8f871d0bb2bd18d1d9e537972"
|
||||||
@@ -76,6 +76,8 @@ inputs = {
|
|||||||
pki_mount_only = local.config.pki_mount_only
|
pki_mount_only = local.config.pki_mount_only
|
||||||
litellm_secret_backend = local.config.litellm_secret_backend
|
litellm_secret_backend = local.config.litellm_secret_backend
|
||||||
litellm_secret_backend_role = local.config.litellm_secret_backend_role
|
litellm_secret_backend_role = local.config.litellm_secret_backend_role
|
||||||
|
arrstack_secret_backend = local.config.arrstack_secret_backend
|
||||||
|
arrstack_secret_backend_role = local.config.arrstack_secret_backend_role
|
||||||
plugins = local.config.plugins
|
plugins = local.config.plugins
|
||||||
gpg_secret_backend = local.config.gpg_secret_backend
|
gpg_secret_backend = local.config.gpg_secret_backend
|
||||||
gpg_key = local.config.gpg_key
|
gpg_key = local.config.gpg_key
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ provider "rancher" {
|
|||||||
address = local.vault_addr
|
address = local.vault_addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The arrstack (arrproxy API key) secrets engine is managed through its own
|
||||||
|
# provider (same Vault server; token falls back to VAULT_TOKEN).
|
||||||
|
provider "arrstack" {
|
||||||
|
address = local.vault_addr
|
||||||
|
}
|
||||||
|
|
||||||
terraform {
|
terraform {
|
||||||
backend "consul" {
|
backend "consul" {
|
||||||
address = "https://consul.service.consul"
|
address = "https://consul.service.consul"
|
||||||
@@ -59,6 +65,10 @@ terraform {
|
|||||||
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/ranchervaultsecret"
|
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/ranchervaultsecret"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
}
|
}
|
||||||
|
arrstack = {
|
||||||
|
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/arrstackvaultsecret"
|
||||||
|
version = "0.1.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -347,6 +347,35 @@ module "plugin" {
|
|||||||
plugin_version = each.value.version
|
plugin_version = each.value.version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module "arrstack_secret_backend" {
|
||||||
|
source = "./modules/arrstack_secret_backend"
|
||||||
|
|
||||||
|
for_each = var.arrstack_secret_backend
|
||||||
|
|
||||||
|
path = each.key
|
||||||
|
plugin = each.value.plugin
|
||||||
|
description = each.value.description
|
||||||
|
base_url = each.value.base_url
|
||||||
|
ca_cert = each.value.ca_cert
|
||||||
|
request_timeout_seconds = each.value.request_timeout_seconds
|
||||||
|
|
||||||
|
depends_on = [module.plugin]
|
||||||
|
}
|
||||||
|
|
||||||
|
module "arrstack_secret_backend_role" {
|
||||||
|
source = "./modules/arrstack_secret_backend_role"
|
||||||
|
|
||||||
|
for_each = var.arrstack_secret_backend_role
|
||||||
|
|
||||||
|
name = each.value.name
|
||||||
|
backend = each.value.backend
|
||||||
|
apps = each.value.apps
|
||||||
|
ttl = each.value.ttl
|
||||||
|
max_ttl = each.value.max_ttl
|
||||||
|
|
||||||
|
depends_on = [module.arrstack_secret_backend]
|
||||||
|
}
|
||||||
|
|
||||||
module "gpg_secret_backend" {
|
module "gpg_secret_backend" {
|
||||||
source = "./modules/gpg_secret_backend"
|
source = "./modules/gpg_secret_backend"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Mounts the arrstack dynamic secrets engine and writes its config via the
|
||||||
|
# arrstackvaultsecret provider. The plugin is registered in the catalog
|
||||||
|
# separately (config/plugins/vault-plugin-secrets-arrstack.yaml). The arrproxy
|
||||||
|
# admin token is sensitive and read from KV, not stored in git:
|
||||||
|
# kv/kubernetes/namespace/arrstack/default/arrproxy-admin-token -> key "token"
|
||||||
|
# (seeded by argocd-apps #384).
|
||||||
|
data "vault_kv_secret_v2" "admin_token" {
|
||||||
|
mount = "kv"
|
||||||
|
name = var.admin_token_kv_name
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "arrstack_secret_backend" "this" {
|
||||||
|
path = var.path
|
||||||
|
plugin = var.plugin
|
||||||
|
description = var.description
|
||||||
|
base_url = var.base_url
|
||||||
|
admin_token = data.vault_kv_secret_v2.admin_token.data[var.admin_token_kv_key]
|
||||||
|
ca_cert = var.ca_cert
|
||||||
|
request_timeout_seconds = var.request_timeout_seconds
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
terraform {
|
||||||
|
required_version = ">= 1.10"
|
||||||
|
required_providers {
|
||||||
|
vault = {
|
||||||
|
source = "hashicorp/vault"
|
||||||
|
version = "5.6.0"
|
||||||
|
}
|
||||||
|
arrstack = {
|
||||||
|
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/arrstackvaultsecret"
|
||||||
|
version = "0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
variable "path" {
|
||||||
|
description = "Mount path of the arrstack secrets engine (e.g. \"arrstack\")"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "plugin" {
|
||||||
|
description = "Registered plugin name/type to mount (the catalog name = mount type)"
|
||||||
|
type = string
|
||||||
|
default = "vault-plugin-secrets-arrstack"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "description" {
|
||||||
|
description = "Human-friendly description of the mount"
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "base_url" {
|
||||||
|
description = "Base URL of the arrproxy front door (e.g. https://arrstack.unkin.net)"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "admin_token_kv_name" {
|
||||||
|
description = "kv-v2 secret name (relative to the \"kv\" mount) holding the seeded arrproxy admin token"
|
||||||
|
type = string
|
||||||
|
default = "kubernetes/namespace/arrstack/default/arrproxy-admin-token"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "admin_token_kv_key" {
|
||||||
|
description = "Key within the KV secret that holds the arrproxy admin token"
|
||||||
|
type = string
|
||||||
|
default = "token"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ca_cert" {
|
||||||
|
description = "PEM CA certificate that signed the arrproxy server's TLS cert (optional; omit to use the system trust store)"
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "request_timeout_seconds" {
|
||||||
|
description = "HTTP timeout in seconds for calls from the plugin to arrproxy"
|
||||||
|
type = number
|
||||||
|
default = 30
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
resource "arrstack_secret_backend_role" "this" {
|
||||||
|
backend = var.backend
|
||||||
|
name = var.name
|
||||||
|
apps = var.apps
|
||||||
|
ttl = var.ttl
|
||||||
|
max_ttl = var.max_ttl
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
terraform {
|
||||||
|
required_version = ">= 1.10"
|
||||||
|
required_providers {
|
||||||
|
arrstack = {
|
||||||
|
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/arrstackvaultsecret"
|
||||||
|
version = "0.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
variable "name" {
|
||||||
|
description = "Name of the role"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "backend" {
|
||||||
|
description = "Mount path of the arrstack secrets engine this role belongs to"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "apps" {
|
||||||
|
description = "arr apps a generated key may access (subset of sonarr, radarr, prowlarr)"
|
||||||
|
type = list(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ttl" {
|
||||||
|
description = "Default lease TTL in seconds for keys generated from this role"
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "max_ttl" {
|
||||||
|
description = "Maximum lease TTL in seconds for keys generated from this role"
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
}
|
||||||
@@ -316,6 +316,30 @@ variable "litellm_secret_backend_role" {
|
|||||||
default = {}
|
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)
|
||||||
|
ttl = optional(number)
|
||||||
|
max_ttl = optional(number)
|
||||||
|
}))
|
||||||
|
default = {}
|
||||||
|
}
|
||||||
|
|
||||||
variable "plugins" {
|
variable "plugins" {
|
||||||
description = "Map of plugins to import (register) in the catalog, keyed by catalog name"
|
description = "Map of plugins to import (register) in the catalog, keyed by catalog name"
|
||||||
type = map(object({
|
type = map(object({
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Allow management of the arrstack secrets engine (config and roles) by the
|
||||||
|
# terraform-vault deployer.
|
||||||
|
---
|
||||||
|
rules:
|
||||||
|
- path: "arrstack/config"
|
||||||
|
capabilities:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- read
|
||||||
|
- delete
|
||||||
|
- path: "arrstack/roles/*"
|
||||||
|
capabilities:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- delete
|
||||||
|
- read
|
||||||
|
- list
|
||||||
|
- path: "arrstack/roles"
|
||||||
|
capabilities:
|
||||||
|
- read
|
||||||
|
- list
|
||||||
|
|
||||||
|
auth:
|
||||||
|
approle:
|
||||||
|
- tf_vault
|
||||||
|
k8s/au/syd1:
|
||||||
|
- woodpecker_terraform_vault
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Allow the terraform-prowlarr run to mint a Prowlarr-scoped arrproxy key.
|
||||||
|
---
|
||||||
|
rules:
|
||||||
|
- path: "arrstack/creds/prowlarr"
|
||||||
|
capabilities:
|
||||||
|
- read
|
||||||
|
|
||||||
|
auth:
|
||||||
|
approle:
|
||||||
|
- terraform_prowlarr
|
||||||
|
k8s/au/syd1:
|
||||||
|
- woodpecker_terraform_prowlarr
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Allow the terraform-radarr run to mint a Radarr-scoped arrproxy key.
|
||||||
|
---
|
||||||
|
rules:
|
||||||
|
- path: "arrstack/creds/radarr"
|
||||||
|
capabilities:
|
||||||
|
- read
|
||||||
|
|
||||||
|
auth:
|
||||||
|
approle:
|
||||||
|
- terraform_radarr
|
||||||
|
k8s/au/syd1:
|
||||||
|
- woodpecker_terraform_radarr
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Allow the terraform-sonarr run to mint a Sonarr-scoped arrproxy key.
|
||||||
|
---
|
||||||
|
rules:
|
||||||
|
- path: "arrstack/creds/sonarr"
|
||||||
|
capabilities:
|
||||||
|
- read
|
||||||
|
|
||||||
|
auth:
|
||||||
|
approle:
|
||||||
|
- terraform_sonarr
|
||||||
|
k8s/au/syd1:
|
||||||
|
- woodpecker_terraform_sonarr
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Allow the terraform-vault deployer to read the seeded arrproxy admin token so
|
||||||
|
# the arrstack engine config module can source it. The token is seeded by
|
||||||
|
# argocd-apps #384 at kv/kubernetes/namespace/arrstack/default/arrproxy-admin-token.
|
||||||
|
# The deployer's existing secret_backends_read policy only covers
|
||||||
|
# kv/data/service/vault/+/+/secret_backend/*, which does not match this
|
||||||
|
# kubernetes/namespace path, so this adds the minimal read grant rather than
|
||||||
|
# duplicating the secret into the litellm-style path. vault_kv_secret_v2 also
|
||||||
|
# reads the kv-v2 metadata path on every plan/apply, so grant that too.
|
||||||
|
---
|
||||||
|
rules:
|
||||||
|
- path: "kv/data/kubernetes/namespace/arrstack/default/arrproxy-admin-token"
|
||||||
|
capabilities:
|
||||||
|
- read
|
||||||
|
- path: "kv/metadata/kubernetes/namespace/arrstack/default/arrproxy-admin-token"
|
||||||
|
capabilities:
|
||||||
|
- read
|
||||||
|
|
||||||
|
auth:
|
||||||
|
approle:
|
||||||
|
- tf_vault
|
||||||
|
k8s/au/syd1:
|
||||||
|
- woodpecker_terraform_vault
|
||||||
Reference in New Issue
Block a user