The apiserver rejects the email username-claim when email_verified is false (invalid bearer token 401). Authentik external/social users are unverified, so the default scope-email mapping fails. Mirror the proven kubernetes provider: use the custom 'Kubernetes Email (verified)' mapping (hardcodes email_verified=true) + 'Kubernetes Groups'. Drop the now-unneeded dual-aud mapping (apiserver trusts the k8s-dashboard issuer w/ audience=client_id) and align oauth2-proxy scope to 'openid email profile groups'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
151 lines
4.9 KiB
HCL
151 lines
4.9 KiB
HCL
# -----------------------------------------------------------------------------
|
|
# oauth2-proxy: runs the Authentik OIDC code-flow and injects the user's
|
|
# id_token as `Authorization: Bearer` upstream to kong-proxy, so the dashboard
|
|
# talks to the apiserver AS THE USER (per-user RBAC applies).
|
|
# -----------------------------------------------------------------------------
|
|
|
|
resource "kubernetes_manifest" "oauth2_proxy_externalsecret" {
|
|
manifest = {
|
|
apiVersion = "external-secrets.io/v1beta1"
|
|
kind = "ExternalSecret"
|
|
metadata = {
|
|
name = "oauth2-proxy"
|
|
namespace = kubernetes_namespace.k8s-dashboard.metadata[0].name
|
|
}
|
|
spec = {
|
|
refreshInterval = "1h"
|
|
secretStoreRef = { name = "vault-kv", kind = "ClusterSecretStore" }
|
|
target = { name = "oauth2-proxy", creationPolicy = "Owner" }
|
|
data = [
|
|
{ secretKey = "client-id", remoteRef = { key = "k8s-dashboard", property = "oauth2_proxy_client_id" } },
|
|
{ secretKey = "client-secret", remoteRef = { key = "k8s-dashboard", property = "oauth2_proxy_client_secret" } },
|
|
{ secretKey = "cookie-secret", remoteRef = { key = "k8s-dashboard", property = "oauth2_proxy_cookie_secret" } },
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
locals {
|
|
oauth2_proxy_upstream = "https://kubernetes-dashboard-kong-proxy.kubernetes-dashboard.svc.cluster.local:443"
|
|
}
|
|
|
|
resource "kubernetes_deployment" "oauth2_proxy" {
|
|
metadata {
|
|
name = "oauth2-proxy"
|
|
namespace = kubernetes_namespace.k8s-dashboard.metadata[0].name
|
|
labels = { app = "oauth2-proxy" }
|
|
}
|
|
|
|
spec {
|
|
replicas = 2
|
|
selector { match_labels = { app = "oauth2-proxy" } }
|
|
|
|
template {
|
|
metadata { labels = { app = "oauth2-proxy" } }
|
|
spec {
|
|
container {
|
|
name = "oauth2-proxy"
|
|
image = "quay.io/oauth2-proxy/oauth2-proxy:v7.7.1"
|
|
args = [
|
|
"--http-address=0.0.0.0:4180",
|
|
"--provider=oidc",
|
|
"--oidc-issuer-url=https://authentik.viktorbarzin.me/application/o/k8s-dashboard/",
|
|
"--redirect-url=https://k8s.viktorbarzin.me/oauth2/callback",
|
|
"--upstream=${local.oauth2_proxy_upstream}",
|
|
"--ssl-upstream-insecure-skip-verify=true",
|
|
"--scope=openid email profile groups",
|
|
"--pass-authorization-header=true",
|
|
"--set-authorization-header=true",
|
|
"--pass-access-token=true",
|
|
"--email-domain=*",
|
|
"--insecure-oidc-allow-unverified-email=true",
|
|
"--cookie-secure=true",
|
|
"--cookie-domain=k8s.viktorbarzin.me",
|
|
"--whitelist-domain=k8s.viktorbarzin.me",
|
|
"--cookie-refresh=30m",
|
|
"--cookie-expire=168h",
|
|
"--code-challenge-method=S256",
|
|
"--reverse-proxy=true",
|
|
"--skip-provider-button=true",
|
|
]
|
|
env {
|
|
name = "OAUTH2_PROXY_CLIENT_ID"
|
|
value_from {
|
|
secret_key_ref {
|
|
name = "oauth2-proxy"
|
|
key = "client-id"
|
|
}
|
|
}
|
|
}
|
|
env {
|
|
name = "OAUTH2_PROXY_CLIENT_SECRET"
|
|
value_from {
|
|
secret_key_ref {
|
|
name = "oauth2-proxy"
|
|
key = "client-secret"
|
|
}
|
|
}
|
|
}
|
|
env {
|
|
name = "OAUTH2_PROXY_COOKIE_SECRET"
|
|
value_from {
|
|
secret_key_ref {
|
|
name = "oauth2-proxy"
|
|
key = "cookie-secret"
|
|
}
|
|
}
|
|
}
|
|
port { container_port = 4180 }
|
|
readiness_probe {
|
|
http_get {
|
|
path = "/ping"
|
|
port = 4180
|
|
}
|
|
initial_delay_seconds = 5
|
|
period_seconds = 10
|
|
}
|
|
resources {
|
|
requests = {
|
|
cpu = "25m"
|
|
memory = "64Mi"
|
|
}
|
|
limits = {
|
|
memory = "128Mi"
|
|
}
|
|
}
|
|
}
|
|
dns_config {
|
|
option {
|
|
name = "ndots"
|
|
value = "2"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
lifecycle {
|
|
ignore_changes = [
|
|
spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1
|
|
spec[0].template[0].spec[0].container[0].image, # KEEL_IGNORE_IMAGE — Keel manages tag updates
|
|
metadata[0].annotations["keel.sh/policy"],
|
|
metadata[0].annotations["keel.sh/trigger"],
|
|
metadata[0].annotations["keel.sh/pollSchedule"], # KYVERNO_LIFECYCLE_V2
|
|
metadata[0].annotations["keel.sh/match-tag"],
|
|
metadata[0].labels["tier"], # stamped from namespace tier label
|
|
]
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_service" "oauth2_proxy" {
|
|
metadata {
|
|
name = "oauth2-proxy"
|
|
namespace = kubernetes_namespace.k8s-dashboard.metadata[0].name
|
|
}
|
|
spec {
|
|
selector = { app = "oauth2-proxy" }
|
|
port {
|
|
port = 4180
|
|
target_port = 4180
|
|
}
|
|
}
|
|
}
|