diff --git a/apps/templates/authentik-helm.yaml b/apps/templates/authentik-helm.yaml index 90b75ce..d252efa 100644 --- a/apps/templates/authentik-helm.yaml +++ b/apps/templates/authentik-helm.yaml @@ -86,6 +86,11 @@ spec: secretKeyRef: name: actualbudget-oidc-client-secret key: client_secret + - name: LONGHORN_OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: longhorn-oidc-client-secret + key: client_secret # Point OpenSSL and requests (which uses certifi otherwise) at # patched-ca-bundle, mounted below until the image drops the # compromised eMudhra intermediates. @@ -119,6 +124,9 @@ spec: - name: blueprint-session configMap: name: authentik-blueprint-session + - name: blueprint-longhorn + configMap: + name: authentik-blueprint-longhorn volumeMounts: - name: blueprint-vault mountPath: /blueprints/custom/vault-oidc.yaml @@ -141,6 +149,9 @@ spec: - name: blueprint-session mountPath: /blueprints/custom/session-duration.yaml subPath: session-duration.yaml + - name: blueprint-longhorn + mountPath: /blueprints/custom/longhorn-oidc.yaml + subPath: longhorn-oidc.yaml - name: patched-ca-bundle mountPath: /etc/ssl/certs readOnly: true @@ -181,6 +192,9 @@ spec: - name: blueprint-session configMap: name: authentik-blueprint-session + - name: blueprint-longhorn + configMap: + name: authentik-blueprint-longhorn volumeMounts: - name: blueprint-vault mountPath: /blueprints/custom/vault-oidc.yaml @@ -203,6 +217,9 @@ spec: - name: blueprint-session mountPath: /blueprints/custom/session-duration.yaml subPath: session-duration.yaml + - name: blueprint-longhorn + mountPath: /blueprints/custom/longhorn-oidc.yaml + subPath: longhorn-oidc.yaml - name: patched-ca-bundle mountPath: /etc/ssl/certs readOnly: true diff --git a/authentik/blueprint-longhorn-oidc.yaml b/authentik/blueprint-longhorn-oidc.yaml new file mode 100644 index 0000000..ffe15b8 --- /dev/null +++ b/authentik/blueprint-longhorn-oidc.yaml @@ -0,0 +1,53 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: authentik-blueprint-longhorn +data: + longhorn-oidc.yaml: | + version: 1 + metadata: + name: Longhorn OIDC + entries: + # Envoy Gateway does the login for Longhorn, which has no users of its + # own (see longhorn/httproute.yaml). + - model: authentik_providers_oauth2.oauth2provider + id: longhorn-provider + state: present + identifiers: + name: Longhorn + attrs: + name: Longhorn + 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]] + client_type: confidential + client_id: longhorn + client_secret: !Env [LONGHORN_OIDC_CLIENT_SECRET, ""] + redirect_uris: + - matching_mode: strict + url: https://longhorn.rubenhensen.nl/oauth2/callback + # Envoy's test port until the switch from ingress-nginx + - matching_mode: strict + url: https://longhorn.rubenhensen.nl:10443/oauth2/callback + signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]] + property_mappings: + - !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-openid]] + - !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-email]] + - !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-profile]] + - model: authentik_core.application + id: longhorn-app + state: present + identifiers: + slug: longhorn + attrs: + name: Longhorn + provider: !KeyOf longhorn-provider + meta_launch_url: https://longhorn.rubenhensen.nl + # Longhorn can delete volumes, so only admins get in. + - model: authentik_policies.policybinding + state: present + identifiers: + order: 0 + target: !KeyOf longhorn-app + attrs: + group: !Find [authentik_core.group, [name, "authentik Admins"]] diff --git a/authentik/external-secret.yaml b/authentik/external-secret.yaml index 996edde..d4e10ec 100644 --- a/authentik/external-secret.yaml +++ b/authentik/external-secret.yaml @@ -135,3 +135,21 @@ spec: remoteRef: key: kv/actualbudget-oidc property: client_secret +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: longhorn-oidc-client-secret +spec: + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + refreshInterval: 15m + target: + name: longhorn-oidc-client-secret + creationPolicy: Owner + data: + - secretKey: client_secret + remoteRef: + key: kv/longhorn-oidc + property: client_secret diff --git a/gateway/gateway.yaml b/gateway/gateway.yaml index 49085b7..cd3321c 100644 --- a/gateway/gateway.yaml +++ b/gateway/gateway.yaml @@ -212,3 +212,17 @@ spec: selector: matchLabels: kubernetes.io/metadata.name: argocd + - name: https-longhorn + protocol: HTTPS + port: 443 + hostname: longhorn.rubenhensen.nl + tls: + certificateRefs: + - name: letsencrypt-prod + namespace: longhorn-system + allowedRoutes: + namespaces: + from: Selector + selector: + matchLabels: + kubernetes.io/metadata.name: longhorn-system diff --git a/longhorn/httproute.yaml b/longhorn/httproute.yaml new file mode 100644 index 0000000..8779fd0 --- /dev/null +++ b/longhorn/httproute.yaml @@ -0,0 +1,76 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: longhorn +spec: + parentRefs: + - name: homelab + namespace: envoy-gateway-system + sectionName: https-longhorn + hostnames: + - longhorn.rubenhensen.nl + rules: + - backendRefs: + - name: longhorn-frontend + port: 80 + # No limit on the whole request, as with nginx. Envoy's default of 15s + # cuts off uploads and long-lived connections. + timeouts: + request: 0s +--- +# Longhorn has no login of its own. Envoy sends visitors through authentik +# first; the authentik application only lets admins in. +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: SecurityPolicy +metadata: + name: longhorn-oidc +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: longhorn + oidc: + provider: + issuer: https://authentik.rubenhensen.nl/application/o/longhorn/ + clientID: longhorn + clientSecret: + name: longhorn-oidc-client-secret + scopes: + - openid + - email + - profile + logoutPath: /logout +--- +# Same client secret as authentik's, under the key Envoy Gateway expects. +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: longhorn-oidc-client-secret +spec: + secretStoreRef: + name: vault-backend + kind: ClusterSecretStore + refreshInterval: 15m + target: + name: longhorn-oidc-client-secret + creationPolicy: Owner + data: + - secretKey: client-secret + remoteRef: + key: kv/longhorn-oidc + property: client_secret +--- +# Lets the Gateway serve the certificate cert-manager keeps in this namespace. +apiVersion: gateway.networking.k8s.io/v1 +kind: ReferenceGrant +metadata: + name: gateway-tls +spec: + from: + - group: gateway.networking.k8s.io + kind: Gateway + namespace: envoy-gateway-system + to: + - group: "" + kind: Secret + name: letsencrypt-prod diff --git a/longhorn/kustomization.yaml b/longhorn/kustomization.yaml index 77548f5..b86c55b 100644 --- a/longhorn/kustomization.yaml +++ b/longhorn/kustomization.yaml @@ -5,5 +5,6 @@ namespace: longhorn-system resources: - ingress.yaml +- httproute.yaml - volume-snapshot.yaml - https://github.com/kubernetes-csi/external-snapshotter/client/config/crd