Move all 8 Authentik OIDC client_secrets out of plaintext git

Completes the 'make the repo proper' cleanup from earlier this session -
these were flagged but deliberately not touched in 185e9c2 given the
blast radius (live SSO for 8 apps). User confirmed: fix all 8 now.

infrastructure/authentik/{argocd,gitlab,nextcloud,grafana,n8n,guacamole,
rancher,vault}-blueprint.yaml: converted from plain ConfigMap (client_secret
hardcoded) to ExternalSecret with a templated blueprint body
(client_secret: "{{ .clientSecret }}") pulling from Vault. Chart already
supports mounting blueprints from Secrets (blueprints.secrets, alongside
blueprints.configMaps) - infrastructure/authentik/values.yaml updated to
route these 8 there instead.

For argocd/nextcloud/n8n/guacamole/rancher: Vault already had the matching
value at secret/<app>-oauth (the APP side was already Vault-backed via its
own ExternalSecret) - the blueprint was the only remaining plaintext copy.

For gitlab/grafana/vault: Vault had no copy at all yet - created
secret/{gitlab,grafana,vault}-oauth with the EXISTING live values (not
rotated - these are the actual working credentials right now, rotating
would break login until every consumer is updated in lockstep, which is
out of scope for a cleanup pass). Also fixed the OTHER plaintext copies
that existed for these three specifically:
  - apps/gitlab/manifests/external-secret-oidc.yaml (new): replaces a
    manually kubectl-created, never-git-tracked gitlab-oidc-secret.
  - infrastructure/grafana/manifests/grafana-oauth-secret.yaml: was a
    plain Secret whose own comment said 'hardcoded from blueprint'.
  - infrastructure/vault/manifests/vault-init-{configmap,job}.yaml: this
    one COULDN'T be converted to the same ExternalSecret-from-Vault
    pattern - it's the PostSync Job that grants ESO's own Kubernetes-auth
    role in Vault, so ESO can't yet authenticate to pull anything from
    Vault at the point this script runs (genuinely circular). Sourced
    from a new vault-oidc-bootstrap Secret instead - created once
    manually (kubectl, not git, matching how Vault's own root/unseal
    material is already handled), independent of the ESO pipeline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Scooby Husky
2026-08-20 20:04:22 -05:00
co-authored by Claude Sonnet 5
parent c6d4294be6
commit d9a4c16481
13 changed files with 730 additions and 472 deletions
+117 -95
View File
@@ -1,99 +1,121 @@
---
apiVersion: v1
kind: ConfigMap
# Was a plain ConfigMap with client_secret hardcoded in plaintext - found
# and fixed 2026-08-20. Unlike argocd/nextcloud, Vault had NO copy of
# this at all - the only places it existed were here AND in
# infrastructure/grafana/manifests/grafana-oauth-secret.yaml (also fixed
# alongside this, same Vault path). Created secret/grafana-oauth with the
# existing live value (not rotated - changing it would break login until
# both sides are updated together).
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: authentik-blueprints-grafana
namespace: authentik
labels:
goauthentik.io/blueprint: "true"
data:
grafana.yaml: |-
version: 1
metadata:
name: grafana-oidc
entries:
# ============================================================================
# AUTO-CREATE GRAFANA GROUPS
# ============================================================================
# These groups control access levels in Grafana via OAuth role mapping:
# - Grafana Admins → Admin role (full access)
# - Grafana Editors → Editor role (can edit dashboards)
# - Grafana Viewers → Viewer role (read-only)
#
# AUTOMATIC ADMIN ACCESS:
# - Anyone in "authentik Admins" automatically gets Grafana Admin access
# - No manual configuration needed!
# ============================================================================
- model: authentik_core.group
id: grafana-admins-group
state: present
identifiers:
name: Grafana Admins
attrs:
name: Grafana Admins
is_superuser: false
# Note: authentik Admins are automatically granted access via role_attribute_path
# in Grafana configuration (see grafana/values.yaml)
- model: authentik_core.group
id: grafana-editors-group
state: present
identifiers:
name: Grafana Editors
attrs:
name: Grafana Editors
is_superuser: false
- model: authentik_core.group
id: grafana-viewers-group
state: present
identifiers:
name: Grafana Viewers
attrs:
name: Grafana Viewers
is_superuser: false
# ============================================================================
# GRAFANA OAUTH2 PROVIDER
# ============================================================================
- model: authentik_providers_oauth2.oauth2provider
id: grafana-provider
state: present
identifiers:
name: Grafana
attrs:
name: Grafana
client_id: bd03e9139dd2063c6c44c4d2f65f51d69de3ba0b6d6b1b9b41c255d2376d2dcc
client_secret: 6b6f2deecfe8fd56cae9c512cc71eedd463d67ff08f24c816b15b15e78ce36bc4f06a2276c5ffe3f67799d935994a32ed32cdc02ec674f279c82d7cfe3ca05d5
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://grafana.kube.huskypup.net/login/generic_oauth"
matching_mode: strict
property_mappings:
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, default]]
# ============================================================================
# GRAFANA APPLICATION
# ============================================================================
- model: authentik_core.application
id: grafana-application
state: present
identifiers:
slug: grafana
attrs:
name: Grafana
slug: grafana
policy_engine_mode: any
provider: !KeyOf grafana-provider
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: authentik-blueprints-grafana
creationPolicy: Owner
template:
metadata:
labels:
goauthentik.io/blueprint: "true"
data:
grafana.yaml: |-
version: 1
metadata:
name: grafana-oidc
entries:
# ============================================================================
# AUTO-CREATE GRAFANA GROUPS
# ============================================================================
# These groups control access levels in Grafana via OAuth role mapping:
# - Grafana Admins → Admin role (full access)
# - Grafana Editors → Editor role (can edit dashboards)
# - Grafana Viewers → Viewer role (read-only)
#
# AUTOMATIC ADMIN ACCESS:
# - Anyone in "authentik Admins" automatically gets Grafana Admin access
# - No manual configuration needed!
# ============================================================================
- model: authentik_core.group
id: grafana-admins-group
state: present
identifiers:
name: Grafana Admins
attrs:
name: Grafana Admins
is_superuser: false
# Note: authentik Admins are automatically granted access via role_attribute_path
# in Grafana configuration (see grafana/values.yaml)
- model: authentik_core.group
id: grafana-editors-group
state: present
identifiers:
name: Grafana Editors
attrs:
name: Grafana Editors
is_superuser: false
- model: authentik_core.group
id: grafana-viewers-group
state: present
identifiers:
name: Grafana Viewers
attrs:
name: Grafana Viewers
is_superuser: false
# ============================================================================
# GRAFANA OAUTH2 PROVIDER
# ============================================================================
- model: authentik_providers_oauth2.oauth2provider
id: grafana-provider
state: present
identifiers:
name: Grafana
attrs:
name: Grafana
client_id: bd03e9139dd2063c6c44c4d2f65f51d69de3ba0b6d6b1b9b41c255d2376d2dcc
client_secret: "{{ .clientSecret }}"
authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]]
authentication_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
redirect_uris:
- url: "https://grafana.kube.huskypup.net/login/generic_oauth"
matching_mode: strict
property_mappings:
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]]
- !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]]
client_type: confidential
access_code_validity: "minutes=10"
access_token_validity: "hours=1"
refresh_token_validity: "days=30"
signing_key: !Find [authentik_crypto.certificatekeypair, [name, default]]
# ============================================================================
# GRAFANA APPLICATION
# ============================================================================
- model: authentik_core.application
id: grafana-application
state: present
identifiers:
slug: grafana
attrs:
name: Grafana
slug: grafana
policy_engine_mode: any
provider: !KeyOf grafana-provider
data:
- secretKey: clientSecret
remoteRef:
key: grafana-oauth
property: client-secret