Merge remote-tracking branch 'origin/main' into benvin/repospawner-oidc
# Conflicts: # config/roles/akR-global-admin.yaml
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
# Permission group akP-vault-admin (name = filename). Gates the OpenBao
|
||||||
|
# application: without a binding every Authentik user could complete an OIDC
|
||||||
|
# login, so access is restricted to this group. OpenBao's own policy mapping
|
||||||
|
# keys off the same group name in the ak_groups claim.
|
||||||
|
application: vault
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# OAuth2/OIDC provider + application for OpenBao (the estate's Vault), making
|
||||||
|
# Authentik the default *human* login. Machine auth (approle, k8s, CI) and the
|
||||||
|
# break-glass paths are untouched and stay on the OpenBao side.
|
||||||
|
#
|
||||||
|
# client_secret is generated here and written to kv/service/authentik/oidc-vault
|
||||||
|
# ({client_id, client_secret}); the companion terraform-vault change reads it to
|
||||||
|
# configure the OIDC auth mount. Nothing is seeded by hand.
|
||||||
|
name: OpenBao
|
||||||
|
authorization_flow: default-provider-authorization-implicit-consent
|
||||||
|
invalidation_flow: default-provider-invalidation-flow
|
||||||
|
client_type: confidential
|
||||||
|
client_id: vault
|
||||||
|
client_secret_vault:
|
||||||
|
mount: kv
|
||||||
|
path: service/authentik/oidc-vault
|
||||||
|
generate: true
|
||||||
|
scope_mappings:
|
||||||
|
- goauthentik.io/providers/oauth2/scope-openid
|
||||||
|
- goauthentik.io/providers/oauth2/scope-email
|
||||||
|
- goauthentik.io/providers/oauth2/scope-profile
|
||||||
|
redirect_uris:
|
||||||
|
# `bao login -method=oidc` CLI callback (local listener, fixed port 8250).
|
||||||
|
- matching_mode: strict
|
||||||
|
url: http://localhost:8250/oidc/callback
|
||||||
|
# UI SSO callback, gateway host (traefik-internal -> vault svc :8200).
|
||||||
|
- matching_mode: strict
|
||||||
|
url: https://vault.k8s.syd1.au.unkin.net/ui/vault/auth/oidc/oidc/callback
|
||||||
|
# UI SSO callback, direct Consul service address (the address the estate
|
||||||
|
# documents for Vault access; any node forwards to the active replica).
|
||||||
|
- matching_mode: strict
|
||||||
|
url: https://vault.service.consul:8200/ui/vault/auth/oidc/oidc/callback
|
||||||
|
launch_url: https://vault.k8s.syd1.au.unkin.net/ui/
|
||||||
@@ -9,6 +9,7 @@ permissions:
|
|||||||
- akP-logviewer-admin
|
- akP-logviewer-admin
|
||||||
- akP-watchstate-admin
|
- akP-watchstate-admin
|
||||||
- akP-repospawner-admin
|
- akP-repospawner-admin
|
||||||
|
- akP-vault-admin
|
||||||
# arrstack has no admin tier (it is a proxy front door); grant global admins
|
# arrstack has no admin tier (it is a proxy front door); grant global admins
|
||||||
# the front door plus every per-app entitlement so they reach all media apps.
|
# the front door plus every per-app entitlement so they reach all media apps.
|
||||||
- akP-arrstack-user
|
- akP-arrstack-user
|
||||||
|
|||||||
Generated
+23
@@ -22,6 +22,29 @@ provider "registry.opentofu.org/goauthentik/authentik" {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
provider "registry.opentofu.org/hashicorp/random" {
|
||||||
|
version = "3.9.0"
|
||||||
|
constraints = ">= 3.6.0"
|
||||||
|
hashes = [
|
||||||
|
"h1:8EQU5KSxezcjo/phRSe69rDOI0lk4pSaggj7FsskYp8=",
|
||||||
|
"zh:03f1114cc20b8913523735ab76e0f0a2b16ce13c92923a53304bf85f07fc0dbc",
|
||||||
|
"zh:105b678ee72322a3067f105d7e05e940f6143238f377f6e87ff4ec909246ac2a",
|
||||||
|
"zh:55f3bbf13ea18cbace61a706566a80f25f33fe2b1780b6f3d7b582af2a05b6d2",
|
||||||
|
"zh:63adf996db48f082f7a6351eb485e219cd88795fc71e6ec60a837263ab0d2cb1",
|
||||||
|
"zh:7e99550738a4e3cc68b8a467714b0d69371025fe95e3326d5323d026d55653e9",
|
||||||
|
"zh:8342b54af3a18a37e075eeae61be57f4de2ba71b35d95c5075d402dd2c1f289d",
|
||||||
|
"zh:83ee18e32ac9dd5fc91298554b7c4cfa4c3a1db50f4c797945637cc93c0844ae",
|
||||||
|
"zh:993ecc0adbf6bd535a59fbc9b735d8c33950e6f6eb5e621d750da9b71d65d80a",
|
||||||
|
"zh:ad722bc59d4edbf1415e827fc007c0efe6e0e9462d5568bae20b34be1058a261",
|
||||||
|
"zh:ae9448e1f87b2f9a6c5197a0e9862162ec6b137cb3a3835e11522995d8939e7c",
|
||||||
|
"zh:bc9cdd3aac784f759125c6627f6f6416e8726a1c184eb9cf3e55b9edbc94c627",
|
||||||
|
"zh:c8e35b89572ba1c40a9b20022e033a3395fb8d42e7604d50c900f193ba10382e",
|
||||||
|
"zh:e2deaa8a9975ef81d9f62baed12c41286918b0a10908e0e031f13f69a3b730a1",
|
||||||
|
"zh:ee39707557210a0ab1098aa357d2cdfe502e5a312d0dbdffb09d08facc4d3fc5",
|
||||||
|
"zh:f81afe4eb63e8aa9e0ea71be6c990f0dc69cb360e7191c0742a991f4a5081b64",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
provider "registry.opentofu.org/hashicorp/vault" {
|
provider "registry.opentofu.org/hashicorp/vault" {
|
||||||
version = "5.10.1"
|
version = "5.10.1"
|
||||||
constraints = ">= 4.0.0"
|
constraints = ">= 4.0.0"
|
||||||
|
|||||||
@@ -136,12 +136,53 @@ data "authentik_property_mapping_provider_scope" "oauth2" {
|
|||||||
managed_list = each.value.scope_mappings
|
managed_list = each.value.scope_mappings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
# Providers whose client secret is pre-seeded in Vault and only read here.
|
||||||
|
oauth2_secret_read = {
|
||||||
|
for k, v in var.providers_oauth2 : k => v
|
||||||
|
if v.client_secret_vault != null && !v.client_secret_vault.generate
|
||||||
|
}
|
||||||
|
# Providers whose client secret is generated here and published to Vault, so
|
||||||
|
# onboarding needs no operator seeding the path first.
|
||||||
|
oauth2_secret_generate = {
|
||||||
|
for k, v in var.providers_oauth2 : k => v
|
||||||
|
if v.client_secret_vault != null && v.client_secret_vault.generate
|
||||||
|
}
|
||||||
|
|
||||||
|
oauth2_client_secret = merge(
|
||||||
|
{ for k, v in local.oauth2_secret_read : k => data.vault_kv_secret_v2.oauth2[k].data["client_secret"] },
|
||||||
|
{ for k, v in local.oauth2_secret_generate : k => random_password.oauth2_client_secret[k].result },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
data "vault_kv_secret_v2" "oauth2" {
|
data "vault_kv_secret_v2" "oauth2" {
|
||||||
for_each = { for k, v in var.providers_oauth2 : k => v if v.client_secret_vault != null }
|
for_each = local.oauth2_secret_read
|
||||||
mount = each.value.client_secret_vault.mount
|
mount = each.value.client_secret_vault.mount
|
||||||
name = each.value.client_secret_vault.path
|
name = each.value.client_secret_vault.path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Alphanumeric only: the secret is pasted into consumer configs and CLI flags,
|
||||||
|
# where punctuation is an easy way to hit shell/URL escaping bugs.
|
||||||
|
resource "random_password" "oauth2_client_secret" {
|
||||||
|
for_each = local.oauth2_secret_generate
|
||||||
|
|
||||||
|
length = 64
|
||||||
|
special = false
|
||||||
|
}
|
||||||
|
|
||||||
|
# Publish the generated credential so consumers (terraform-vault, app configs)
|
||||||
|
# read it from Vault instead of an operator copying it out of Authentik.
|
||||||
|
resource "vault_kv_secret_v2" "oauth2_client_secret" {
|
||||||
|
for_each = local.oauth2_secret_generate
|
||||||
|
|
||||||
|
mount = each.value.client_secret_vault.mount
|
||||||
|
name = each.value.client_secret_vault.path
|
||||||
|
data_json = jsonencode({
|
||||||
|
client_id = each.value.client_id
|
||||||
|
client_secret = random_password.oauth2_client_secret[each.key].result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
# Default JWT signing key for OAuth2 providers. Without a signing_key Authentik
|
# Default JWT signing key for OAuth2 providers. Without a signing_key Authentik
|
||||||
# signs ID tokens with HS256, which RS256-only RP clients (argocd, grafana, ...)
|
# signs ID tokens with HS256, which RS256-only RP clients (argocd, grafana, ...)
|
||||||
# reject. Look up the estate's RSA keypair by name so providers default to RS256.
|
# reject. Look up the estate's RSA keypair by name so providers default to RS256.
|
||||||
@@ -157,7 +198,7 @@ resource "authentik_provider_oauth2" "this" {
|
|||||||
invalidation_flow = data.authentik_flow.oauth2_invalidation[each.key].id
|
invalidation_flow = data.authentik_flow.oauth2_invalidation[each.key].id
|
||||||
client_type = each.value.client_type
|
client_type = each.value.client_type
|
||||||
client_id = each.value.client_id
|
client_id = each.value.client_id
|
||||||
client_secret = each.value.client_secret_vault != null ? data.vault_kv_secret_v2.oauth2[each.key].data["client_secret"] : null
|
client_secret = lookup(local.oauth2_client_secret, each.key, null)
|
||||||
property_mappings = concat(
|
property_mappings = concat(
|
||||||
try(data.authentik_property_mapping_provider_scope.oauth2[each.key].ids, []),
|
try(data.authentik_property_mapping_provider_scope.oauth2[each.key].ids, []),
|
||||||
[authentik_property_mapping_provider_scope.groups_hierarchical.id],
|
[authentik_property_mapping_provider_scope.groups_hierarchical.id],
|
||||||
|
|||||||
@@ -60,9 +60,13 @@ variable "providers_oauth2" {
|
|||||||
client_id = string
|
client_id = string
|
||||||
# client_secret is never committed. Point at a Vault kv-v2 secret whose
|
# client_secret is never committed. Point at a Vault kv-v2 secret whose
|
||||||
# `client_secret` key holds the value (seeded out of band); TF reads it.
|
# `client_secret` key holds the value (seeded out of band); TF reads it.
|
||||||
|
# generate = true flips that around: the secret is created here and written
|
||||||
|
# to that path as {client_id, client_secret}, so onboarding needs no manual
|
||||||
|
# seed. Requires write access to the kv path.
|
||||||
client_secret_vault = optional(object({
|
client_secret_vault = optional(object({
|
||||||
mount = string
|
mount = string
|
||||||
path = string
|
path = string
|
||||||
|
generate = optional(bool, false)
|
||||||
}), null)
|
}), null)
|
||||||
# Managed identifiers of scope property mappings (e.g.
|
# Managed identifiers of scope property mappings (e.g.
|
||||||
# goauthentik.io/providers/oauth2/scope-openid). Resolved to ids.
|
# goauthentik.io/providers/oauth2/scope-openid). Resolved to ids.
|
||||||
|
|||||||
@@ -9,5 +9,9 @@ terraform {
|
|||||||
source = "hashicorp/vault"
|
source = "hashicorp/vault"
|
||||||
version = ">= 4.0.0"
|
version = ">= 4.0.0"
|
||||||
}
|
}
|
||||||
|
random = {
|
||||||
|
source = "hashicorp/random"
|
||||||
|
version = ">= 3.6.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user