WIP keycloak stack (gate probe)
This commit is contained in:
28 files changed
+776
-102
No files matched your search
@@ -305,9 +305,12 @@ spec:
|
||||
- name: platform-health.identity
|
||||
rules:
|
||||
- alert: KeycloakDown
|
||||
# Scope to the Keycloak SERVER StatefulSet pods (keycloak-0, keycloak-1). The keycloak
|
||||
# namespace also holds the operator (keycloak-operator-*) and DB (keycloak-db-*) pods, so an
|
||||
# un-scoped max() would be masked by those being ready — this must reflect the IdP itself.
|
||||
expr: |
|
||||
max(kube_pod_status_ready{namespace="keycloak", condition="true"}) == 0
|
||||
or absent(kube_pod_status_ready{namespace="keycloak"})
|
||||
max(kube_pod_status_ready{namespace="keycloak", pod=~"keycloak-[0-9]+", condition="true"}) == 0
|
||||
or absent(kube_pod_status_ready{namespace="keycloak", pod=~"keycloak-[0-9]+"})
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
@@ -316,10 +319,11 @@ spec:
|
||||
description: "No ready Keycloak pod for 5m — SSO is unavailable and dependent services cannot authenticate (docs/15)."
|
||||
runbook_url: "https://home.keithjackson.dev/runbooks/keycloak-down"
|
||||
- alert: KeycloakDatabaseDown
|
||||
# Keycloak's PostgreSQL (Longhorn-backed, DR-critical). Metric from postgres-exporter or
|
||||
# the bundled chart; confirm label set at bring-up.
|
||||
# Keycloak's PostgreSQL runs as a CloudNativePG Cluster `keycloak-db` (pods keycloak-db-N).
|
||||
# DR-critical, Longhorn-backed. (CNPG also exports cnpg_* metrics via its PodMonitor.)
|
||||
expr: |
|
||||
max(kube_pod_status_ready{namespace="keycloak", pod=~".*postgres.*", condition="true"}) == 0
|
||||
max(kube_pod_status_ready{namespace="keycloak", pod=~"keycloak-db-.*", condition="true"}) == 0
|
||||
or absent(kube_pod_status_ready{namespace="keycloak", pod=~"keycloak-db-.*"})
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# Ingress for Grafana at grafana.home.keithjackson.dev (docs/09) — the endpoint of the native-OIDC SSO
|
||||
# proof (log in once at Keycloak -> reach Grafana). CR of the Gateway API CRDs — carried by
|
||||
# platform-config. Same-namespace backend; parentRef allowed via the monitoring namespace's
|
||||
# gateway-access=shared label.
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: grafana
|
||||
namespace: monitoring
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: shared
|
||||
namespace: gateway
|
||||
sectionName: https
|
||||
hostnames:
|
||||
- grafana.home.keithjackson.dev
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: kube-prometheus-stack-grafana
|
||||
port: 80
|
||||
@@ -0,0 +1,26 @@
|
||||
# =============================================================================
|
||||
# TEMPLATE — NOT APPLIED, NOT ENCRYPTED (.yaml.example is ignored by kustomize and never
|
||||
# auto-encrypted by SOPS). Reference scaffold + OPERATOR HAND-OFF.
|
||||
#
|
||||
# WHAT THIS IS: the OIDC client SECRET Grafana uses to authenticate to the Keycloak `homelab` realm's
|
||||
# `grafana` client (kube-prometheus-stack.yaml -> grafana.envValueFrom.GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET).
|
||||
# The value MUST equal the `grafana-client-secret` placed in platform/keycloak/keycloak-realm-clients
|
||||
# (which the realm import injects into the Keycloak client). Consumed by name only (R-IDP-04).
|
||||
#
|
||||
# HAND-OFF STEPS (operator):
|
||||
# (a) Use the SAME grafana-client-secret generated for keycloak-realm-clients (openssl rand -hex 32).
|
||||
# (b) Copy to: platform/monitoring/grafana-oidc-credentials.sops.yaml
|
||||
# (c) Fill `client-secret` below; encrypt:
|
||||
# sops -e -i platform/monitoring/grafana-oidc-credentials.sops.yaml
|
||||
# (d) Add under `resources:` in platform/monitoring/kustomization.yaml:
|
||||
# - grafana-oidc-credentials.sops.yaml
|
||||
# Grafana runs with local admin login until this lands (secretKeyRef optional:true), then OIDC works.
|
||||
# =============================================================================
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: grafana-oidc-credentials
|
||||
namespace: monitoring
|
||||
type: Opaque
|
||||
stringData:
|
||||
client-secret: REPLACE-ME
|
||||
@@ -150,8 +150,36 @@ spec:
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 256Mi
|
||||
# TODO(WS-SEC/WS-C2, later): Keycloak OIDC client (auth.generic_oauth) + root_url behind the
|
||||
# Gateway; disable local login once SSO is proven. Secret referenced by name only.
|
||||
# --- Keycloak native-OIDC SSO (ADR-0014, deliverable #4 SSO proof) ---
|
||||
# Grafana is a confidential OIDC client of the Keycloak `homelab` realm. The client SECRET comes
|
||||
# from the SOPS-encrypted grafana-oidc-credentials Secret via env (referenced by name only,
|
||||
# R-IDP-04). optional:true so the RUNNING Grafana keeps starting before the operator fills the
|
||||
# secret — local admin login (below) stays available as the fallback until SSO is proven.
|
||||
envValueFrom:
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET:
|
||||
secretKeyRef:
|
||||
name: grafana-oidc-credentials
|
||||
key: client-secret
|
||||
optional: true
|
||||
grafana.ini:
|
||||
server:
|
||||
root_url: https://grafana.home.keithjackson.dev
|
||||
auth.generic_oauth:
|
||||
enabled: true
|
||||
name: Keycloak
|
||||
client_id: grafana
|
||||
scopes: "openid email profile"
|
||||
auth_url: https://keycloak.home.keithjackson.dev/realms/homelab/protocol/openid-connect/auth
|
||||
token_url: https://keycloak.home.keithjackson.dev/realms/homelab/protocol/openid-connect/token
|
||||
api_url: https://keycloak.home.keithjackson.dev/realms/homelab/protocol/openid-connect/userinfo
|
||||
login_attribute_path: preferred_username
|
||||
email_attribute_path: email
|
||||
# Map Keycloak groups (the `groups` claim) to Grafana roles (R-IDP-06): platform-admins ->
|
||||
# Admin, media-users -> Editor, everyone else -> Viewer.
|
||||
role_attribute_path: "contains(groups[*], 'platform-admins') && 'Admin' || contains(groups[*], 'media-users') && 'Editor' || 'Viewer'"
|
||||
# Keep local admin login enabled as break-glass until SSO is proven end-to-end; flip to
|
||||
# disable_login_form:true afterwards (docs/15 break-glass, R-IDP-05).
|
||||
# TODO(WS-SEC, post-proof): set auth.disable_login_form=true once SSO login is verified.
|
||||
|
||||
# --- Bundled exporters / operator: keep small ---
|
||||
prometheusOperator:
|
||||
|
||||
@@ -3,3 +3,7 @@ apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: monitoring
|
||||
labels:
|
||||
# Expose Grafana at grafana.home.keithjackson.dev via the shared Gateway (docs/09) for the
|
||||
# Keycloak native-OIDC SSO proof (grafana-httproute.yaml, WS-SEC Phase 6).
|
||||
gateway-access: "shared"
|
||||
Reference in new issue
Block a user