Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5567bd6dac |
@@ -22,7 +22,7 @@ init:
|
||||
|
||||
plan: init
|
||||
@$(call vault_env) && \
|
||||
terragrunt run --all --parallelism 4 --non-interactive plan -- -lock=false
|
||||
terragrunt run --all --parallelism 4 --non-interactive plan
|
||||
|
||||
apply: init
|
||||
@$(call vault_env) && \
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
# Mints an arrproxy API key scoped to all three arr apps.
|
||||
apps:
|
||||
- prowlarr
|
||||
- radarr
|
||||
- sonarr
|
||||
ttl: 60 # seconds (1m); short-lived by design, renewed on demand
|
||||
- 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.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
# Mints an arrproxy API key for the mediamark kids-content marking UI, scoped to
|
||||
# Sonarr and Radarr only (no Prowlarr: mediamark never touches indexers).
|
||||
#
|
||||
# mediamark only lists series/movies and reads metadata + artwork, so its key is
|
||||
# read-only in intent. The engine role cannot express that today: an
|
||||
# arrstack_secret_backend_role carries apps/ttl/max_ttl only, and arrproxy scopes
|
||||
# machine tokens by app, not by HTTP method (the GET/HEAD restriction on the
|
||||
# cheeztv/kids tier is a grant on an OIDC *group*, not on a minted token). Until
|
||||
# the engine and arrproxy grow per-token method scoping, mediamark's read-only
|
||||
# posture is enforced by the app itself and by the arrproxy tier it routes to.
|
||||
apps:
|
||||
- radarr
|
||||
- sonarr
|
||||
ttl: 60 # seconds (1m); short-lived by design, renewed on demand
|
||||
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||
# arrproxy admin token's fixed mint expiry.
|
||||
@@ -2,6 +2,6 @@
|
||||
# Mints an arrproxy API key scoped to Prowlarr only.
|
||||
apps:
|
||||
- prowlarr
|
||||
ttl: 60 # seconds (1m); short-lived by design, renewed on demand
|
||||
ttl: 3600 # seconds (1h)
|
||||
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||
# arrproxy admin token's fixed mint expiry.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
# Mints an arrproxy API key scoped to Radarr only.
|
||||
apps:
|
||||
- radarr
|
||||
ttl: 60 # seconds (1m); short-lived by design, renewed on demand
|
||||
ttl: 3600 # seconds (1h)
|
||||
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||
# arrproxy admin token's fixed mint expiry.
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
# Mints an arrproxy API key scoped to Sonarr only.
|
||||
apps:
|
||||
- sonarr
|
||||
ttl: 60 # seconds (1m); short-lived by design, renewed on demand
|
||||
ttl: 3600 # seconds (1h)
|
||||
max_ttl: 86400 # seconds (24h); the engine additionally caps renewal at the
|
||||
# arrproxy admin token's fixed mint expiry.
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
# Kubernetes auth role for the mediamark app: the default service account in the
|
||||
# mediamark namespace, used by VaultDynamicSecret to read arrstack/creds/mediamark.
|
||||
bound_service_account_names:
|
||||
- default
|
||||
bound_service_account_namespaces:
|
||||
- mediamark
|
||||
token_ttl: 600
|
||||
token_max_ttl: 600
|
||||
audience: vault
|
||||
@@ -1,7 +0,0 @@
|
||||
bound_service_account_names:
|
||||
- repospawner
|
||||
bound_service_account_namespaces:
|
||||
- repospawner
|
||||
token_ttl: 600
|
||||
token_max_ttl: 600
|
||||
audience: vault
|
||||
@@ -1,17 +0,0 @@
|
||||
# Authentik (OIDC) human SSO. The mount path is the filename and MUST stay
|
||||
# "oidc": the Authentik provider registers strict redirect URIs containing
|
||||
# /ui/vault/auth/oidc/oidc/callback, which encode the mount path.
|
||||
#
|
||||
# identity.unkin.net serves the public LetsEncrypt wildcard, so the OpenBao VMs
|
||||
# validate discovery against the system roots with no CA bundle work. Do not
|
||||
# swap it for identity.k8s.syd1.au.unkin.net (internal CA).
|
||||
#
|
||||
# listing_visibility unauth makes OIDC the offered default on the UI login page.
|
||||
# client_id/client_secret are read from kv/service/authentik/oidc-vault.
|
||||
---
|
||||
oidc_discovery_url: "https://identity.unkin.net/application/o/vault/"
|
||||
default_role: "default"
|
||||
description: "Authentik SSO - default human login"
|
||||
listing_visibility: "unauth"
|
||||
default_lease_ttl: 24h
|
||||
max_lease_ttl: 168h
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
# this file doesnt need anything in it, so this data is just to make sure yamlencode reads some yaml data
|
||||
# The filename is the Authentik group name asserted in the ak_groups claim.
|
||||
# Only akP-* permission groups may appear here; akR-* roles are grouping-only.
|
||||
description: foo
|
||||
@@ -1,25 +0,0 @@
|
||||
# Default OIDC login role (the mount's default_role), used by both the web UI
|
||||
# and `bao login -method=oidc`.
|
||||
#
|
||||
# The role grants no policies of its own: authorization comes from the external
|
||||
# identity groups under config/auth_oidc_group, matched on the ak_groups claim.
|
||||
# ak_groups is Authentik's hierarchy-expanding claim (plain `groups` only carries
|
||||
# direct memberships), so nested akP-* permission groups resolve.
|
||||
#
|
||||
# allowed_redirect_uris must match the provider's strict URIs exactly.
|
||||
---
|
||||
user_claim: "email"
|
||||
groups_claim: "ak_groups"
|
||||
oidc_scopes:
|
||||
- openid
|
||||
- profile
|
||||
- email
|
||||
- ak_groups
|
||||
bound_audiences:
|
||||
- vault
|
||||
allowed_redirect_uris:
|
||||
- "http://localhost:8250/oidc/callback"
|
||||
- "https://vault.k8s.syd1.au.unkin.net/ui/vault/auth/oidc/oidc/callback"
|
||||
- "https://vault.service.consul:8200/ui/vault/auth/oidc/oidc/callback"
|
||||
token_ttl: 3600
|
||||
token_max_ttl: 28800
|
||||
@@ -97,27 +97,6 @@ locals {
|
||||
})
|
||||
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
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Role minting ephemeral, scoped ghp agent tokens. Reading ghp/creds/agent mints
|
||||
# a lease-bound token deleted from ghp on revoke/expiry. token_type "agent" binds
|
||||
# the minted token to a ghp App installation, so installation_id is REQUIRED.
|
||||
#
|
||||
# installation_id below is a PLACEHOLDER (0) and MUST be set to the real ghp App
|
||||
# installation id before this role can mint usable tokens. scopes are ghp
|
||||
# permission:level pairs; contents:read is the least-privilege default.
|
||||
---
|
||||
token_type: agent
|
||||
installation_id: 0 # PLACEHOLDER - set to the real ghp App installation id
|
||||
scopes:
|
||||
- contents:read
|
||||
session_prefix: vault
|
||||
ttl: 3600 # 1h
|
||||
max_ttl: 86400 # 24h
|
||||
@@ -1,19 +0,0 @@
|
||||
# Role minting ephemeral tokens for the repospawner service user. repospawner
|
||||
# creates and seeds Gitea repositories on demand, so it gets write on
|
||||
# repositories (create + push) and write on issues (issue/PR comments). Read is
|
||||
# implied by write. No admin/org/user-write scopes.
|
||||
# read:user is required because most API clients validate the login via
|
||||
# GET /api/v1/user, which 403s without it.
|
||||
# Reading gitea/creds/repospawner mints a lease-bound token deleted from Gitea
|
||||
# on revoke/expiry. Consumed by the repospawner pods via Kubernetes auth (see
|
||||
# policies/gitea/creds/repospawner.yaml) -- the agents AppRole is CIDR-bound to
|
||||
# Ben's workstation and cannot be used from in-cluster.
|
||||
---
|
||||
username: repospawner
|
||||
scopes:
|
||||
- write:repository
|
||||
- write:issue
|
||||
- read:user
|
||||
token_name_prefix: vault-repospawner
|
||||
ttl: 3600 # 1h
|
||||
max_ttl: 14400 # 4h
|
||||
@@ -4,10 +4,10 @@
|
||||
# Puppet (openbao-plugin-secrets-arrstack RPM ->
|
||||
# /opt/openbao-plugins/vault-plugin-secrets-arrstack).
|
||||
#
|
||||
# sha256 pins the released v0.2.0 binary; bump it in lockstep with any RPM
|
||||
# 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.2.0"
|
||||
sha256: "9ea7f16013b3bcbadfcb15b08fd1545f8069893cf864bfdaa57e7e7e72612fa1"
|
||||
version: "0.1.0"
|
||||
sha256: "f8ee60ca7ba14819976acb7dc4cfb6799e3e8da8f871d0bb2bd18d1d9e537972"
|
||||
|
||||
@@ -60,9 +60,6 @@ inputs = {
|
||||
auth_approle_role = local.config.auth_approle_role
|
||||
auth_ldap_backend = local.config.auth_ldap_backend
|
||||
auth_ldap_group = local.config.auth_ldap_group
|
||||
auth_oidc_backend = local.config.auth_oidc_backend
|
||||
auth_oidc_role = local.config.auth_oidc_role
|
||||
auth_oidc_group = local.config.auth_oidc_group
|
||||
auth_kubernetes_backend = local.config.auth_kubernetes_backend
|
||||
auth_kubernetes_role = local.config.auth_kubernetes_role
|
||||
kv_secret_backend = local.config.kv_secret_backend
|
||||
|
||||
@@ -66,8 +66,8 @@ terraform {
|
||||
version = "0.1.0"
|
||||
}
|
||||
arrstack = {
|
||||
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/vault-secrets-arrstack"
|
||||
version = "0.2.0"
|
||||
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/arrstackvaultsecret"
|
||||
version = "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,55 +64,6 @@ module "auth_ldap_group" {
|
||||
depends_on = [module.auth_ldap_backend]
|
||||
}
|
||||
|
||||
module "auth_oidc_backend" {
|
||||
source = "./modules/auth_oidc_backend"
|
||||
|
||||
for_each = var.auth_oidc_backend
|
||||
|
||||
path = each.key
|
||||
description = each.value.description
|
||||
oidc_discovery_url = each.value.oidc_discovery_url
|
||||
client_secret_mount = each.value.client_secret_mount
|
||||
client_secret_path = each.value.client_secret_path
|
||||
default_role = each.value.default_role
|
||||
listing_visibility = each.value.listing_visibility
|
||||
default_lease_ttl = each.value.default_lease_ttl
|
||||
max_lease_ttl = each.value.max_lease_ttl
|
||||
}
|
||||
|
||||
module "auth_oidc_role" {
|
||||
source = "./modules/auth_oidc_role"
|
||||
|
||||
for_each = var.auth_oidc_role
|
||||
|
||||
backend = each.value.backend
|
||||
role_name = each.value.role_name
|
||||
user_claim = each.value.user_claim
|
||||
groups_claim = each.value.groups_claim
|
||||
oidc_scopes = each.value.oidc_scopes
|
||||
bound_audiences = each.value.bound_audiences
|
||||
allowed_redirect_uris = each.value.allowed_redirect_uris
|
||||
token_ttl = each.value.token_ttl
|
||||
token_max_ttl = each.value.token_max_ttl
|
||||
# Human authorization comes from the external identity groups below, so a
|
||||
# login role carrying no policies is the normal case.
|
||||
token_policies = try(var.policy_auth_map[each.value.backend][each.value.role_name], [])
|
||||
|
||||
depends_on = [module.auth_oidc_backend]
|
||||
}
|
||||
|
||||
module "auth_oidc_group" {
|
||||
source = "./modules/auth_oidc_group"
|
||||
|
||||
for_each = var.auth_oidc_group
|
||||
|
||||
groupname = each.value.groupname
|
||||
policies = var.policy_auth_map[each.value.backend][each.value.groupname]
|
||||
mount_accessor = module.auth_oidc_backend[each.value.backend].accessor
|
||||
|
||||
depends_on = [module.auth_oidc_backend]
|
||||
}
|
||||
|
||||
module "auth_kubernetes_backend" {
|
||||
source = "./modules/auth_kubernetes_backend"
|
||||
|
||||
@@ -419,7 +370,6 @@ module "arrstack_secret_backend_role" {
|
||||
name = each.value.name
|
||||
backend = each.value.backend
|
||||
apps = each.value.apps
|
||||
methods = each.value.methods
|
||||
ttl = each.value.ttl
|
||||
max_ttl = each.value.max_ttl
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Mounts the arrstack dynamic secrets engine and writes its config via the
|
||||
# vault-secrets-arrstack provider. The plugin is registered in the catalog
|
||||
# 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"
|
||||
|
||||
@@ -6,8 +6,8 @@ terraform {
|
||||
version = "5.6.0"
|
||||
}
|
||||
arrstack = {
|
||||
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/vault-secrets-arrstack"
|
||||
version = "0.2.0"
|
||||
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/arrstackvaultsecret"
|
||||
version = "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ resource "arrstack_secret_backend_role" "this" {
|
||||
backend = var.backend
|
||||
name = var.name
|
||||
apps = var.apps
|
||||
methods = var.methods
|
||||
ttl = var.ttl
|
||||
max_ttl = var.max_ttl
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ terraform {
|
||||
required_version = ">= 1.10"
|
||||
required_providers {
|
||||
arrstack = {
|
||||
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/vault-secrets-arrstack"
|
||||
version = "0.2.0"
|
||||
source = "artifactapi.k8s.syd1.au.unkin.net/terraform-unkin/arrstackvaultsecret"
|
||||
version = "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,6 @@ variable "apps" {
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "methods" {
|
||||
description = "HTTP methods a generated key is limited to (subset of GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS). Null leaves the role unrestricted"
|
||||
type = set(string)
|
||||
# null, not [], so a role yaml that omits methods matches the provider's null read-back and shows no drift.
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "ttl" {
|
||||
description = "Default lease TTL in seconds for keys generated from this role"
|
||||
type = number
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# Expected keys in KV secret: client_id, client_secret (generated and written by
|
||||
# terraform-authentik's oauth2 provider module, never seeded by hand).
|
||||
data "vault_kv_secret_v2" "oidc_client" {
|
||||
mount = var.client_secret_mount
|
||||
name = var.client_secret_path
|
||||
}
|
||||
|
||||
resource "vault_jwt_auth_backend" "oidc" {
|
||||
path = var.path
|
||||
type = "oidc"
|
||||
description = var.description
|
||||
oidc_discovery_url = var.oidc_discovery_url
|
||||
oidc_client_id = data.vault_kv_secret_v2.oidc_client.data["client_id"]
|
||||
oidc_client_secret = data.vault_kv_secret_v2.oidc_client.data["client_secret"]
|
||||
default_role = var.default_role
|
||||
|
||||
tune {
|
||||
default_lease_ttl = var.default_lease_ttl
|
||||
max_lease_ttl = var.max_lease_ttl
|
||||
listing_visibility = var.listing_visibility
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
output "accessor" {
|
||||
description = "Accessor of the OIDC auth mount, used to bind identity group aliases"
|
||||
value = vault_jwt_auth_backend.oidc.accessor
|
||||
}
|
||||
|
||||
output "path" {
|
||||
description = "Mount path of the OIDC auth backend"
|
||||
value = vault_jwt_auth_backend.oidc.path
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
terraform {
|
||||
required_version = ">= 1.10"
|
||||
required_providers {
|
||||
vault = {
|
||||
source = "hashicorp/vault"
|
||||
version = "5.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
variable "path" {
|
||||
description = "Mount path of the OIDC auth backend"
|
||||
type = string
|
||||
default = "oidc"
|
||||
}
|
||||
|
||||
variable "description" {
|
||||
description = "Human-readable description of the auth mount"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "oidc_discovery_url" {
|
||||
description = "OIDC issuer discovery URL of the identity provider"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "client_secret_mount" {
|
||||
description = "KV-v2 mount holding the OIDC client credentials"
|
||||
type = string
|
||||
default = "kv"
|
||||
}
|
||||
|
||||
variable "client_secret_path" {
|
||||
description = "Path within the KV-v2 mount holding client_id and client_secret"
|
||||
type = string
|
||||
default = "service/authentik/oidc-vault"
|
||||
}
|
||||
|
||||
variable "default_role" {
|
||||
description = "Role used when none is supplied at login (the UI/CLI default)"
|
||||
type = string
|
||||
default = "default"
|
||||
}
|
||||
|
||||
variable "listing_visibility" {
|
||||
description = "Specifies whether to show this mount in the UI-specific listing endpoint. Valid values are 'unauth' or 'hidden'"
|
||||
type = string
|
||||
default = null
|
||||
validation {
|
||||
condition = var.listing_visibility == null || contains(["unauth", "hidden"], var.listing_visibility)
|
||||
error_message = "listing_visibility must be either 'unauth' or 'hidden'."
|
||||
}
|
||||
}
|
||||
|
||||
variable "default_lease_ttl" {
|
||||
description = "Specifies the default time-to-live. If set, this overrides the global default. Must be a valid duration string"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "max_lease_ttl" {
|
||||
description = "Specifies the maximum time-to-live. If set, this overrides the global default. Must be a valid duration string"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
# External identity group: membership is asserted by the IdP through the role's
|
||||
# groups_claim, matched by the alias name below.
|
||||
resource "vault_identity_group" "group" {
|
||||
name = var.groupname
|
||||
type = "external"
|
||||
policies = var.policies
|
||||
}
|
||||
|
||||
resource "vault_identity_group_alias" "alias" {
|
||||
name = var.groupname
|
||||
mount_accessor = var.mount_accessor
|
||||
canonical_id = vault_identity_group.group.id
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
terraform {
|
||||
required_version = ">= 1.10"
|
||||
required_providers {
|
||||
vault = {
|
||||
source = "hashicorp/vault"
|
||||
version = "5.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
variable "groupname" {
|
||||
description = "Name of the IdP group, as it appears in the groups claim"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "policies" {
|
||||
description = "List of policies to assign to the identity group"
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "mount_accessor" {
|
||||
description = "Accessor of the OIDC auth mount the alias is bound to"
|
||||
type = string
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
resource "vault_jwt_auth_backend_role" "role" {
|
||||
backend = var.backend
|
||||
role_name = var.role_name
|
||||
role_type = "oidc"
|
||||
user_claim = var.user_claim
|
||||
groups_claim = var.groups_claim
|
||||
oidc_scopes = var.oidc_scopes
|
||||
bound_audiences = var.bound_audiences
|
||||
allowed_redirect_uris = var.allowed_redirect_uris
|
||||
token_ttl = var.token_ttl
|
||||
token_max_ttl = var.token_max_ttl
|
||||
token_policies = var.token_policies
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
terraform {
|
||||
required_version = ">= 1.10"
|
||||
required_providers {
|
||||
vault = {
|
||||
source = "hashicorp/vault"
|
||||
version = "5.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
variable "backend" {
|
||||
description = "The unique path of the OIDC auth backend to configure"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "role_name" {
|
||||
description = "The name of the role"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "user_claim" {
|
||||
description = "Claim used as the entity alias name (the Vault identity of the human)"
|
||||
type = string
|
||||
default = "email"
|
||||
}
|
||||
|
||||
variable "groups_claim" {
|
||||
description = "Claim holding the caller's group memberships, matched against identity group aliases"
|
||||
type = string
|
||||
default = "ak_groups"
|
||||
}
|
||||
|
||||
variable "oidc_scopes" {
|
||||
description = "Scopes requested from the identity provider during the authorization request"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "bound_audiences" {
|
||||
description = "List of audiences (aud claim) accepted in the ID token"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "allowed_redirect_uris" {
|
||||
description = "Redirect URIs accepted for this role. Must match the provider's registered URIs exactly"
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "token_ttl" {
|
||||
description = "The TTL period of tokens issued using this role, in seconds"
|
||||
type = number
|
||||
default = 3600
|
||||
}
|
||||
|
||||
variable "token_max_ttl" {
|
||||
description = "The maximum lifetime for generated tokens in number of seconds. Its current value will be referenced at renewal time."
|
||||
type = number
|
||||
default = 28800
|
||||
}
|
||||
|
||||
variable "token_policies" {
|
||||
description = "List of policies to assign to the role (passed from policy_auth_map). Human authorization normally comes from external identity groups instead"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
@@ -62,46 +62,6 @@ variable "auth_ldap_group" {
|
||||
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({
|
||||
@@ -374,7 +334,6 @@ variable "arrstack_secret_backend_role" {
|
||||
name = string
|
||||
backend = string
|
||||
apps = list(string)
|
||||
methods = optional(set(string))
|
||||
ttl = optional(number)
|
||||
max_ttl = optional(number)
|
||||
}))
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Allow the mediamark app to mint its own Sonarr/Radarr-scoped arrproxy key.
|
||||
# Bound to the dedicated "mediamark" k8s role only, never the shared "default"
|
||||
# role, so no other namespace can read these creds.
|
||||
---
|
||||
rules:
|
||||
- path: "arrstack/creds/mediamark"
|
||||
capabilities:
|
||||
- read
|
||||
|
||||
auth:
|
||||
k8s/au/syd1:
|
||||
- mediamark
|
||||
@@ -1,19 +0,0 @@
|
||||
# Allow full administration of the OIDC auth backend (mount config and login
|
||||
# roles), mirroring policies/auth/ldap/admin.yaml. sys/auth/* already covers
|
||||
# enabling the mount itself; this covers writing auth/oidc/config and
|
||||
# auth/oidc/role/*.
|
||||
---
|
||||
rules:
|
||||
- path: "auth/oidc/*"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- read
|
||||
- delete
|
||||
- list
|
||||
|
||||
auth:
|
||||
approle:
|
||||
- tf_vault
|
||||
k8s/au/syd1:
|
||||
- woodpecker_terraform_vault
|
||||
@@ -1,16 +0,0 @@
|
||||
# Lets the repospawner pods mint ephemeral Gitea tokens for the repospawner
|
||||
# service user, so the service authenticates to git.unkin.net as its own
|
||||
# least-privilege identity. Reading gitea/creds/repospawner returns a
|
||||
# lease-bound token scoped by the role (write:repository, write:issue,
|
||||
# read:user -- never merge/admin).
|
||||
# Kubernetes auth only: repospawner runs in-cluster and the agents AppRole is
|
||||
# CIDR-bound to Ben's workstation.
|
||||
---
|
||||
rules:
|
||||
- path: "gitea/creds/repospawner"
|
||||
capabilities:
|
||||
- read
|
||||
|
||||
auth:
|
||||
k8s/au/syd1:
|
||||
- repospawner
|
||||
@@ -10,12 +10,6 @@ rules:
|
||||
- list
|
||||
- sudo
|
||||
|
||||
# The oidc entry is an Authentik akP-* permission group, not an LDAP group name:
|
||||
# it names the external identity group under config/auth_oidc_group, so a human
|
||||
# who logs in via Authentik SSO lands on exactly the policy the LDAP vault_admin
|
||||
# group already carries. akR-* roles are grouping-only and never named here.
|
||||
auth:
|
||||
ldap:
|
||||
- vault_admin
|
||||
oidc:
|
||||
- akP-vault-admin
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# Allow the deployer to manage external identity groups and their aliases, which
|
||||
# is how OIDC group membership (the ak_groups claim) maps onto Vault policies.
|
||||
# Both the collection endpoints and the per-id endpoints are needed: create posts
|
||||
# to identity/group, subsequent reads and updates address identity/group/id/<id>.
|
||||
---
|
||||
rules:
|
||||
- path: "identity/group"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- path: "identity/group/*"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- read
|
||||
- delete
|
||||
- list
|
||||
- path: "identity/group-alias"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- path: "identity/group-alias/*"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- read
|
||||
- delete
|
||||
- list
|
||||
- path: "identity/lookup/group"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
|
||||
auth:
|
||||
approle:
|
||||
- tf_vault
|
||||
k8s/au/syd1:
|
||||
- woodpecker_terraform_vault
|
||||
@@ -1,14 +0,0 @@
|
||||
# Lets the agents AppRole read a dedicated, scoped Authentik API token seeded by
|
||||
# the operator. Automation seeds OAuth2 client secrets and LDAP outpost tokens as
|
||||
# part of normal IaC workflows; fetching an outpost token requires calling the
|
||||
# Authentik API, so a scoped token (not the CI admin credential) is read here.
|
||||
# Mirrors the gitea/creds/unkin-agent agents-approle read grant pattern.
|
||||
---
|
||||
rules:
|
||||
- path: "kv/data/service/authentik/agent-api-token"
|
||||
capabilities:
|
||||
- read
|
||||
|
||||
auth:
|
||||
approle:
|
||||
- agents
|
||||
@@ -1,21 +0,0 @@
|
||||
# Let the terraform-vault deployer read the OpenBao OIDC client credentials that
|
||||
# Authentik's provider module generates and writes here (terraform_authentik owns
|
||||
# kv/service/authentik/* — see policies/kv/service/authentik/write.yaml). The
|
||||
# deployer consumes client_id/client_secret to configure the auth/oidc backend.
|
||||
#
|
||||
# OIDC becomes the default human auth path; approle and k8s (CI and agents) plus
|
||||
# the break-glass root path are unchanged.
|
||||
#
|
||||
# AppRole capabilities are fixed at login, so this grant must be applied before
|
||||
# the PR that adds the auth/oidc modules.
|
||||
---
|
||||
rules:
|
||||
- path: "kv/data/service/authentik/oidc-vault"
|
||||
capabilities:
|
||||
- read
|
||||
|
||||
auth:
|
||||
approle:
|
||||
- tf_vault
|
||||
k8s/au/syd1:
|
||||
- woodpecker_terraform_vault
|
||||
@@ -1,32 +0,0 @@
|
||||
# Let the terraform-authentik runner manage the Authentik service KV subtree as
|
||||
# IaC (vault_kv_secret_v2), starting with kv/service/authentik/agent-api-token,
|
||||
# which is currently seeded by hand.
|
||||
#
|
||||
# Scoping: the ask was to grant only *-token paths, but Vault ACL paths support
|
||||
# a trailing glob only (no infix/suffix wildcards), so the grant is the whole
|
||||
# kv/service/authentik/ subtree. That is acceptable because terraform-authentik
|
||||
# is the owner of every secret under kv/service/authentik/.
|
||||
#
|
||||
# delete is included (unlike the agents kv/kubernetes grant) so `terraform
|
||||
# destroy` and resource replacement can remove a secret and its metadata
|
||||
# cleanly; vault_kv_secret_v2 also reads the kv-v2 metadata path on every
|
||||
# plan/apply, so metadata read/list is required for the plan to succeed.
|
||||
---
|
||||
rules:
|
||||
- path: "kv/data/service/authentik/*"
|
||||
capabilities:
|
||||
- create
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
- path: "kv/metadata/service/authentik/*"
|
||||
capabilities:
|
||||
- read
|
||||
- list
|
||||
- delete
|
||||
|
||||
auth:
|
||||
approle:
|
||||
- terraform_authentik
|
||||
k8s/au/syd1:
|
||||
- woodpecker_terraform_authentik
|
||||
@@ -1,10 +0,0 @@
|
||||
# Allow reading Ceph mediafs CSI secrets
|
||||
---
|
||||
rules:
|
||||
- path: "kv/data/service/kubernetes/au/syd1/csi/ceph-mediafs-secret"
|
||||
capabilities:
|
||||
- read
|
||||
|
||||
auth:
|
||||
k8s/au/syd1:
|
||||
- ceph-csi
|
||||
@@ -1,24 +0,0 @@
|
||||
# Allow the agents AppRole to seed the ghp secrets engine's admin credentials.
|
||||
# The ghp engine (managed by the tf_vault deployer) reads its ghpsvc_ service
|
||||
# token from admin_token at ghp/config creation time; that key is currently
|
||||
# unseeded, so the master apply aborts on the ghp data-source read. This grants
|
||||
# the agents AppRole scoped write here so an agent can seed the value. Deployer
|
||||
# read is already granted via policies/kv/service/vault/secret_backends_read.yaml,
|
||||
# so this only adds the write side for the agents identity.
|
||||
---
|
||||
rules:
|
||||
# Seed value: admin_token (a ghpsvc_ service token). create/update to seed,
|
||||
# read so the agent can verify what it wrote. No delete (least privilege).
|
||||
- path: "kv/data/service/vault/au/syd1/secret_backend/ghp/config"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- read
|
||||
# vault_kv_secret_v2 also reads the kv-v2 metadata path on every plan/apply.
|
||||
- path: "kv/metadata/service/vault/au/syd1/secret_backend/ghp/config"
|
||||
capabilities:
|
||||
- read
|
||||
|
||||
auth:
|
||||
approle:
|
||||
- agents
|
||||
@@ -1,20 +0,0 @@
|
||||
# Allow the terraform-rancher runner to mint an ephemeral Rancher API token
|
||||
# from the "ci" role, so its Makefile can swap
|
||||
# vault kv get kv/service/terraform/rancher
|
||||
# for
|
||||
# vault read -field=token rancher/creds/ci
|
||||
# and retire the static 90-day admin token. The minted token is lease-bound
|
||||
# (ttl 1h, max 8h) and deleted from Rancher on revoke; it inherits the seeded
|
||||
# admin service account's RBAC, so this is the same privilege as the static
|
||||
# token it replaces, just short-lived.
|
||||
---
|
||||
rules:
|
||||
- path: "rancher/creds/ci"
|
||||
capabilities:
|
||||
- read
|
||||
|
||||
auth:
|
||||
approle:
|
||||
- terraform_rancher
|
||||
k8s/au/syd1:
|
||||
- woodpecker_terraform_rancher
|
||||
@@ -8,24 +8,6 @@ rules:
|
||||
- delete
|
||||
- read
|
||||
- list
|
||||
# Enabling/tuning an auth mount is sudo-protected, and an exact path match
|
||||
# wins over the wildcard above, so both rules repeat the full capability set.
|
||||
- path: "sys/auth/oidc"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- read
|
||||
- list
|
||||
- sudo
|
||||
- path: "sys/auth/oidc/tune"
|
||||
capabilities:
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- read
|
||||
- list
|
||||
- sudo
|
||||
|
||||
auth:
|
||||
approle:
|
||||
|
||||
@@ -22,28 +22,6 @@ rules:
|
||||
- "elasticsearch.k8s.elastic.co"
|
||||
- "kibana.k8s.elastic.co"
|
||||
- "gateway.networking.k8s.io"
|
||||
- "apm.k8s.elastic.co"
|
||||
- "beat.k8s.elastic.co"
|
||||
- "agent.k8s.elastic.co"
|
||||
- "maps.k8s.elastic.co"
|
||||
- "enterprisesearch.k8s.elastic.co"
|
||||
- "autoscaling.k8s.elastic.co"
|
||||
- "stackconfigpolicy.k8s.elastic.co"
|
||||
- "valkey.io"
|
||||
- "ceph.unkin.net"
|
||||
- "bind.unkin.net"
|
||||
- "kea.unkin.net"
|
||||
- "k8up.io"
|
||||
- "grafana.integreatly.org"
|
||||
- "operator.victoriametrics.com"
|
||||
- "clickhouse.altinity.com"
|
||||
- "clickhouse-keeper.altinity.com"
|
||||
- "acme.cert-manager.io"
|
||||
- "deviceplugin.intel.com"
|
||||
- "fpga.intel.com"
|
||||
- "autoscaling.k8s.io"
|
||||
- "snapshot.storage.k8s.io"
|
||||
- "groupsnapshot.storage.k8s.io"
|
||||
resources:
|
||||
- "*"
|
||||
verbs:
|
||||
|
||||
Reference in New Issue
Block a user