From f96737c5769150d07a73d17409cdc97be1300c4c Mon Sep 17 00:00:00 2001 From: hermes-bot Date: Sun, 1 Nov 2026 08:42:43 +0000 Subject: [PATCH 1/5] feat(youtrack): YouTrack Server, LAN only, login through Authentik Namespace youtrack: jetbrains/youtrack 2026.2.19728 (digest-pinned), one replica with Recreate, PVC youtrack (data/conf/logs/backups as subPaths), Velero youtrack-daily plus restore-youtrack like the other apps. The Ingress carries only dns.renner.uno/internal, so the UDM gets a record and netbird-service-sync publishes nothing: the host is not reachable from the internet until login goes through Authentik and a later PR adds the public label. Authentik blueprint: group YouTrack Users, confidential OIDC provider (client_id youtrack; YouTrack's OpenID Connect auth module requires a client secret), application slug youtrack, bound to the group. YouTrack Server has no documented unattended first install (2026.2 docs: the Configuration Wizard is mandatory, the skip flag exists for upgrades only), so the wizard and the auth module are a one-time owner step, accepted by the owner. --- .../apps/authentik/blueprints-configmap.yaml | 64 +++++++++++ kubernetes/apps/youtrack/deployment.yaml | 90 +++++++++++++++ kubernetes/apps/youtrack/ingress.yaml | 27 +++++ kubernetes/apps/youtrack/kustomization.yaml | 6 + kubernetes/apps/youtrack/pvc.yaml | 17 +++ kubernetes/clusters/homelab/restore.yaml | 28 +++++ kubernetes/clusters/homelab/youtrack.yaml | 20 ++++ .../infrastructure/namespaces/namespaces.yaml | 5 + .../network-policies/kustomization.yaml | 1 + .../network-policies/youtrack-ns.yaml | 107 ++++++++++++++++++ .../velero-schedules/schedules.yaml | 20 ++++ .../restore/youtrack/kustomization.yaml | 4 + kubernetes/restore/youtrack/restore.yaml | 7 ++ 13 files changed, 396 insertions(+) create mode 100644 kubernetes/apps/youtrack/deployment.yaml create mode 100644 kubernetes/apps/youtrack/ingress.yaml create mode 100644 kubernetes/apps/youtrack/kustomization.yaml create mode 100644 kubernetes/apps/youtrack/pvc.yaml create mode 100644 kubernetes/clusters/homelab/youtrack.yaml create mode 100644 kubernetes/infrastructure/network-policies/youtrack-ns.yaml create mode 100644 kubernetes/restore/youtrack/kustomization.yaml create mode 100644 kubernetes/restore/youtrack/restore.yaml diff --git a/kubernetes/apps/authentik/blueprints-configmap.yaml b/kubernetes/apps/authentik/blueprints-configmap.yaml index 684f6b43..3fff05fa 100644 --- a/kubernetes/apps/authentik/blueprints-configmap.yaml +++ b/kubernetes/apps/authentik/blueprints-configmap.yaml @@ -1045,6 +1045,70 @@ data: negate: false failure_result: false + # YouTrack (apps/youtrack): OpenID Connect auth module. YouTrack's module + # needs a client secret, so the client is confidential; Authentik generates + # the secret and it is pasted once into the module (owner step, like Gitea). + - id: youtrack-users-group + model: authentik_core.group + identifiers: + name: YouTrack Users + state: present + attrs: + is_superuser: false + # Members may sign in to YouTrack. Add/remove members HERE. + users: + - !Find [authentik_core.user, [username, k.renner]] + + - id: youtrack-provider + model: authentik_providers_oauth2.oauth2provider + identifiers: + name: YouTrack + state: present + attrs: + authentication_flow: null + authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] + invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] + client_type: confidential + client_id: youtrack + # See the Matrix (MAS) provider: a blueprint-made provider starts + # with no grant types. + grant_types: + - authorization_code + - refresh_token + 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-profile]] + - !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-email]] + redirect_uris: + # YouTrack generates the callback when the module is created; pin it strict once known. + - url: 'https://youtrack\.renner\.uno/.*' + matching_mode: regex + + # The slug is the issuer path: https://auth.renner.uno/application/o/youtrack/ + - model: authentik_core.application + identifiers: + slug: youtrack + state: present + attrs: + name: YouTrack + slug: youtrack + provider: !KeyOf youtrack-provider + meta_launch_url: https://youtrack.renner.uno + meta_description: "YouTrack issue tracker" + + # Only the YouTrack Users group passes. + - model: authentik_policies.policybinding + identifiers: + target: !Find [authentik_core.application, [slug, youtrack]] + group: !KeyOf youtrack-users-group + order: 0 + state: present + attrs: + enabled: true + negate: false + failure_result: false + # wiki.renner.uno signs in via OIDC application `wiki`; only this group may sign in. # Members are managed in Authentik. - id: wiki-readers-group diff --git a/kubernetes/apps/youtrack/deployment.yaml b/kubernetes/apps/youtrack/deployment.yaml new file mode 100644 index 00000000..1bed88fa --- /dev/null +++ b/kubernetes/apps/youtrack/deployment.yaml @@ -0,0 +1,90 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: youtrack + namespace: youtrack + labels: + app.kubernetes.io/name: youtrack +spec: + replicas: 1 + # One process owns the database directory. + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: youtrack + template: + metadata: + labels: + app.kubernetes.io/name: youtrack + spec: + automountServiceAccountToken: false + enableServiceLinks: false + securityContext: + runAsNonRoot: true + # The image's service account. + runAsUser: 13001 + runAsGroup: 13001 + fsGroup: 13001 + seccompProfile: + type: RuntimeDefault + containers: + - name: youtrack + image: jetbrains/youtrack:2026.2.19728@sha256:c5e9cedc6fb1d7bcc9b3b56fc3f63e563623e1cd39396161eb70957991583950 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + ports: + - name: http + containerPort: 8080 + resources: + requests: + cpu: 250m + memory: 2Gi + limits: + memory: 4Gi + startupProbe: + tcpSocket: + port: http + periodSeconds: 10 + failureThreshold: 60 + readinessProbe: + tcpSocket: + port: http + periodSeconds: 10 + livenessProbe: + tcpSocket: + port: http + periodSeconds: 30 + failureThreshold: 4 + volumeMounts: + - name: youtrack + mountPath: /opt/youtrack/data + subPath: data + - name: youtrack + mountPath: /opt/youtrack/conf + subPath: conf + - name: youtrack + mountPath: /opt/youtrack/logs + subPath: logs + - name: youtrack + mountPath: /opt/youtrack/backups + subPath: backups + volumes: + - name: youtrack + persistentVolumeClaim: + claimName: youtrack +--- +apiVersion: v1 +kind: Service +metadata: + name: youtrack + namespace: youtrack +spec: + selector: + app.kubernetes.io/name: youtrack + ports: + - name: http + port: 8080 + targetPort: http diff --git a/kubernetes/apps/youtrack/ingress.yaml b/kubernetes/apps/youtrack/ingress.yaml new file mode 100644 index 00000000..e88b6c9c --- /dev/null +++ b/kubernetes/apps/youtrack/ingress.yaml @@ -0,0 +1,27 @@ +# LAN-only (UDM record via dns.renner.uno/internal); no public label until login goes through Authentik. +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: youtrack + namespace: youtrack + labels: + dns.renner.uno/internal: "true" + annotations: + cert-manager.io/cluster-issuer: letsencrypt-cluster +spec: + ingressClassName: traefik + tls: + - hosts: + - youtrack.renner.uno + secretName: youtrack-tls + rules: + - host: youtrack.renner.uno + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: youtrack + port: + number: 8080 diff --git a/kubernetes/apps/youtrack/kustomization.yaml b/kubernetes/apps/youtrack/kustomization.yaml new file mode 100644 index 00000000..99bd7a00 --- /dev/null +++ b/kubernetes/apps/youtrack/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - pvc.yaml + - deployment.yaml + - ingress.yaml diff --git a/kubernetes/apps/youtrack/pvc.yaml b/kubernetes/apps/youtrack/pvc.yaml new file mode 100644 index 00000000..101908f4 --- /dev/null +++ b/kubernetes/apps/youtrack/pvc.yaml @@ -0,0 +1,17 @@ +# YouTrack data, conf, logs and backups (subPaths); Velero youtrack-daily. +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: youtrack + namespace: youtrack + labels: + app.kubernetes.io/name: youtrack + annotations: + kustomize.toolkit.fluxcd.io/prune: disabled +spec: + accessModes: + - ReadWriteOnce + storageClassName: ceph-block + resources: + requests: + storage: 20Gi diff --git a/kubernetes/clusters/homelab/restore.yaml b/kubernetes/clusters/homelab/restore.yaml index 33f6d1ee..a44acc80 100644 --- a/kubernetes/clusters/homelab/restore.yaml +++ b/kubernetes/clusters/homelab/restore.yaml @@ -394,3 +394,31 @@ spec: status.validationErrors.exists(e, e.startsWith('No backups found for schedule'))))) current: >- has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation') +--- +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: restore-youtrack + namespace: flux-system +spec: + interval: 10m + timeout: 1h + sourceRef: + kind: GitRepository + name: flux-system + path: ./kubernetes/restore/youtrack + prune: true + wait: true + dependsOn: + - name: restore-gitea + - name: velero-backups-synced + - name: infrastructure-ceph-cluster + healthCheckExprs: + - apiVersion: velero.io/v1 + kind: Restore + failed: >- + has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] || + (status.phase == 'FailedValidation' && !(has(status.validationErrors) && + status.validationErrors.exists(e, e.startsWith('No backups found for schedule'))))) + current: >- + has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation') diff --git a/kubernetes/clusters/homelab/youtrack.yaml b/kubernetes/clusters/homelab/youtrack.yaml new file mode 100644 index 00000000..0181dd91 --- /dev/null +++ b/kubernetes/clusters/homelab/youtrack.yaml @@ -0,0 +1,20 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: youtrack + namespace: flux-system +spec: + interval: 10m + retryInterval: 1m + timeout: 15m + sourceRef: + kind: GitRepository + name: flux-system + path: ./kubernetes/apps/youtrack + prune: true + wait: true + dependsOn: + - name: restore-youtrack + - name: infrastructure + - name: infrastructure-crds + - name: infrastructure-ceph-cluster diff --git a/kubernetes/infrastructure/namespaces/namespaces.yaml b/kubernetes/infrastructure/namespaces/namespaces.yaml index 1a22a6ef..05ba3f3a 100644 --- a/kubernetes/infrastructure/namespaces/namespaces.yaml +++ b/kubernetes/infrastructure/namespaces/namespaces.yaml @@ -83,6 +83,11 @@ metadata: --- apiVersion: v1 kind: Namespace +metadata: + name: youtrack +--- +apiVersion: v1 +kind: Namespace metadata: name: immich --- diff --git a/kubernetes/infrastructure/network-policies/kustomization.yaml b/kubernetes/infrastructure/network-policies/kustomization.yaml index ea5327db..3d27cff2 100644 --- a/kubernetes/infrastructure/network-policies/kustomization.yaml +++ b/kubernetes/infrastructure/network-policies/kustomization.yaml @@ -32,6 +32,7 @@ resources: - wordpress-ns.yaml - ai-ns.yaml - navidrome-ns.yaml + - youtrack-ns.yaml - uptime-monitor-ns.yaml - kuma-sync-ns.yaml - cloudflare-lb-sync-ns.yaml diff --git a/kubernetes/infrastructure/network-policies/youtrack-ns.yaml b/kubernetes/infrastructure/network-policies/youtrack-ns.yaml new file mode 100644 index 00000000..1b2cc7a2 --- /dev/null +++ b/kubernetes/infrastructure/network-policies/youtrack-ns.yaml @@ -0,0 +1,107 @@ +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: default-deny-ingress + namespace: youtrack +spec: + endpointSelector: {} + ingress: + - fromEndpoints: + - matchLabels: + "k8s:io.kubernetes.pod.namespace": youtrack + - fromEndpoints: + - matchLabels: + "k8s:io.kubernetes.pod.namespace": ingress + app.kubernetes.io/name: traefik + - fromEndpoints: + - matchLabels: + "k8s:io.kubernetes.pod.namespace": monitoring + - fromEntities: + - host + - remote-node + # ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See + # home-assistant-ns.yaml for the rationale (CT-RELATED path not + # passing related ICMP empirically; per-namespace shape, mirroring + # commit 3c517a0's verified-safe pattern with the 66dbe9f type set). + - fromEndpoints: + - matchExpressions: + - key: io.kubernetes.pod.namespace + operator: Exists + icmps: + - fields: + - { type: 0, family: IPv4 } + - { type: 3, family: IPv4 } + - { type: 8, family: IPv4 } + - { type: 11, family: IPv4 } + - { type: 12, family: IPv4 } + - { type: 1, family: IPv6 } + - { type: 2, family: IPv6 } + - { type: 3, family: IPv6 } + - { type: 4, family: IPv6 } + - { type: 128, family: IPv6 } + - { type: 129, family: IPv6 } + - { type: 133, family: IPv6 } + - { type: 134, family: IPv6 } + - { type: 135, family: IPv6 } + - { type: 136, family: IPv6 } + - { type: 143, family: IPv6 } + egress: + - toEndpoints: + - matchLabels: + "k8s:io.kubernetes.pod.namespace": youtrack + - toEndpoints: + - matchLabels: + "k8s:io.kubernetes.pod.namespace": ingress + app.kubernetes.io/name: traefik + - toEndpoints: + - matchLabels: + "k8s:io.kubernetes.pod.namespace": kube-system + k8s-app: kube-dns + toPorts: + - ports: + - port: "53" + protocol: UDP + # host/remote-node: kubelet probes + node-local reach (Ceph mons on host net) + - toEntities: + - host + - remote-node + # ICMP — egress mirror; see ingress block above. + - toEndpoints: + - matchExpressions: + - key: io.kubernetes.pod.namespace + operator: Exists + icmps: + - fields: + - { type: 0, family: IPv4 } + - { type: 3, family: IPv4 } + - { type: 8, family: IPv4 } + - { type: 11, family: IPv4 } + - { type: 12, family: IPv4 } + - { type: 1, family: IPv6 } + - { type: 2, family: IPv6 } + - { type: 3, family: IPv6 } + - { type: 4, family: IPv6 } + - { type: 128, family: IPv6 } + - { type: 129, family: IPv6 } + - { type: 133, family: IPv6 } + - { type: 134, family: IPv6 } + - { type: 135, family: IPv6 } + - { type: 136, family: IPv6 } + - { type: 143, family: IPv6 } +--- +# Outbound HTTPS: OIDC discovery/token/JWKS at auth.renner.uno (Traefik VIP, matched as traefik +# pods above) and JetBrains services (license, update check), mail-free. +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: youtrack-egress-https + namespace: youtrack +spec: + endpointSelector: {} + egress: + - toEntities: + - world + toPorts: + - ports: + - port: "443" + protocol: TCP diff --git a/kubernetes/infrastructure/velero-schedules/schedules.yaml b/kubernetes/infrastructure/velero-schedules/schedules.yaml index ccea8bc6..e024113f 100644 --- a/kubernetes/infrastructure/velero-schedules/schedules.yaml +++ b/kubernetes/infrastructure/velero-schedules/schedules.yaml @@ -369,3 +369,23 @@ spec: labelSelector: matchLabels: app.kubernetes.io/name: synapse +--- +apiVersion: velero.io/v1 +kind: Schedule +metadata: + name: youtrack-daily + namespace: velero + labels: + app.kubernetes.io/part-of: homelab-backup +spec: + # Daily at 10:15 local, next free stagger slot after matrix-daily at 09:45. + schedule: "15 10 * * *" + useOwnerReferencesInBackup: false + template: + includedNamespaces: + - youtrack + includedResources: + - persistentvolumeclaims + storageLocation: default + ttl: 720h0m0s + snapshotMoveData: true diff --git a/kubernetes/restore/youtrack/kustomization.yaml b/kubernetes/restore/youtrack/kustomization.yaml new file mode 100644 index 00000000..bc08b2d5 --- /dev/null +++ b/kubernetes/restore/youtrack/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - restore.yaml diff --git a/kubernetes/restore/youtrack/restore.yaml b/kubernetes/restore/youtrack/restore.yaml new file mode 100644 index 00000000..9a409297 --- /dev/null +++ b/kubernetes/restore/youtrack/restore.yaml @@ -0,0 +1,7 @@ +apiVersion: velero.io/v1 +kind: Restore +metadata: + name: youtrack + namespace: velero +spec: + scheduleName: youtrack-daily -- 2.54.0 From f50b33cadfaadbffdbcc144b39f6a88a089daa04 Mon Sep 17 00:00:00 2001 From: hermes-bot Date: Sun, 1 Nov 2026 08:45:40 +0000 Subject: [PATCH 2/5] fix(youtrack): manage YouTrack Users members in Authentik, not the blueprint Same as Wiki Readers: the blueprint only ensures the group exists, because the application's policy binding refers to it; membership is edited in Authentik. --- kubernetes/apps/authentik/blueprints-configmap.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kubernetes/apps/authentik/blueprints-configmap.yaml b/kubernetes/apps/authentik/blueprints-configmap.yaml index 3fff05fa..7513fe76 100644 --- a/kubernetes/apps/authentik/blueprints-configmap.yaml +++ b/kubernetes/apps/authentik/blueprints-configmap.yaml @@ -1048,6 +1048,7 @@ data: # YouTrack (apps/youtrack): OpenID Connect auth module. YouTrack's module # needs a client secret, so the client is confidential; Authentik generates # the secret and it is pasted once into the module (owner step, like Gitea). + # Only this group may sign in; members are managed in Authentik. - id: youtrack-users-group model: authentik_core.group identifiers: @@ -1055,9 +1056,6 @@ data: state: present attrs: is_superuser: false - # Members may sign in to YouTrack. Add/remove members HERE. - users: - - !Find [authentik_core.user, [username, k.renner]] - id: youtrack-provider model: authentik_providers_oauth2.oauth2provider -- 2.54.0 From 7efc62e2166bee88447d57b916cd1039106ebbfc Mon Sep 17 00:00:00 2001 From: hermes-bot Date: Sun, 1 Nov 2026 09:16:22 +0000 Subject: [PATCH 3/5] fix(youtrack): take the YouTrack Users group out of the blueprint Groups are managed in Authentik itself. The blueprint now only binds the application to the group by name (!Find). The YouTrack entries move to their own blueprint (youtrack.yaml). Authentik imports a blueprint atomically (importer.py apply() runs _apply_models in one transaction), so while the group does not exist the whole YouTrack blueprint rolls back: no provider, no application, login closed. In the shared OAuth2 blueprint the same miss would also have blocked every other provider. --- .../apps/authentik/blueprints-configmap.yaml | 123 +++++++++--------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/kubernetes/apps/authentik/blueprints-configmap.yaml b/kubernetes/apps/authentik/blueprints-configmap.yaml index 7513fe76..be74102f 100644 --- a/kubernetes/apps/authentik/blueprints-configmap.yaml +++ b/kubernetes/apps/authentik/blueprints-configmap.yaml @@ -1045,67 +1045,6 @@ data: negate: false failure_result: false - # YouTrack (apps/youtrack): OpenID Connect auth module. YouTrack's module - # needs a client secret, so the client is confidential; Authentik generates - # the secret and it is pasted once into the module (owner step, like Gitea). - # Only this group may sign in; members are managed in Authentik. - - id: youtrack-users-group - model: authentik_core.group - identifiers: - name: YouTrack Users - state: present - attrs: - is_superuser: false - - - id: youtrack-provider - model: authentik_providers_oauth2.oauth2provider - identifiers: - name: YouTrack - state: present - attrs: - authentication_flow: null - authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] - invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] - client_type: confidential - client_id: youtrack - # See the Matrix (MAS) provider: a blueprint-made provider starts - # with no grant types. - grant_types: - - authorization_code - - refresh_token - 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-profile]] - - !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-email]] - redirect_uris: - # YouTrack generates the callback when the module is created; pin it strict once known. - - url: 'https://youtrack\.renner\.uno/.*' - matching_mode: regex - - # The slug is the issuer path: https://auth.renner.uno/application/o/youtrack/ - - model: authentik_core.application - identifiers: - slug: youtrack - state: present - attrs: - name: YouTrack - slug: youtrack - provider: !KeyOf youtrack-provider - meta_launch_url: https://youtrack.renner.uno - meta_description: "YouTrack issue tracker" - - # Only the YouTrack Users group passes. - - model: authentik_policies.policybinding - identifiers: - target: !Find [authentik_core.application, [slug, youtrack]] - group: !KeyOf youtrack-users-group - order: 0 - state: present - attrs: - enabled: true - negate: false - failure_result: false # wiki.renner.uno signs in via OIDC application `wiki`; only this group may sign in. # Members are managed in Authentik. @@ -1288,6 +1227,68 @@ data: name: passkey-passwordless-webauthn-validation state: absent + # YouTrack (apps/youtrack). Own blueprint so a missing YouTrack Users group + # only holds back YouTrack, not the other OAuth2 providers. + youtrack.yaml: | + version: 1 + metadata: + name: YouTrack (homelab) + entries: + # YouTrack (apps/youtrack): OpenID Connect auth module. YouTrack's module + # needs a client secret, so the client is confidential; Authentik generates + # the secret and it is pasted once into the module (owner step, like Gitea). + - id: youtrack-provider + model: authentik_providers_oauth2.oauth2provider + identifiers: + name: YouTrack + state: present + attrs: + authentication_flow: null + authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] + invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] + client_type: confidential + client_id: youtrack + # See the Matrix (MAS) provider: a blueprint-made provider starts + # with no grant types. + grant_types: + - authorization_code + - refresh_token + 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-profile]] + - !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-email]] + redirect_uris: + # YouTrack generates the callback when the module is created; pin it strict once known. + - url: 'https://youtrack\.renner\.uno/.*' + matching_mode: regex + + # The slug is the issuer path: https://auth.renner.uno/application/o/youtrack/ + - model: authentik_core.application + identifiers: + slug: youtrack + state: present + attrs: + name: YouTrack + slug: youtrack + provider: !KeyOf youtrack-provider + meta_launch_url: https://youtrack.renner.uno + meta_description: "YouTrack issue tracker" + + # Only the YouTrack Users group passes. The group and its members live in + # Authentik; until it exists this blueprint fails as a whole (atomic + # import), so YouTrack login stays closed rather than open. + - model: authentik_policies.policybinding + identifiers: + target: !Find [authentik_core.application, [slug, youtrack]] + group: !Find [authentik_core.group, [name, YouTrack Users]] + order: 0 + state: present + attrs: + enabled: true + negate: false + failure_result: false + # Service account of authentik-gate-sync (gate-sync.yaml), the controller # behind the authentik-gate ingress class. Its role covers exactly the # objects a gate consists of, plus reading the groups, flows and service -- 2.54.0 From 68d1a174dbb88894a743ba21dd11a296cdf2203b Mon Sep 17 00:00:00 2001 From: hermes-bot Date: Sun, 1 Nov 2026 09:22:40 +0000 Subject: [PATCH 4/5] fix(youtrack): OIDC client from authentik-gate-sync, no blueprint The provider, application and group policy are now created by authentik-gate-sync from the Ingress annotations auth.renner.uno/oidc-client and auth.renner.uno/group (#1535); the youtrack.yaml blueprint is gone. The group YouTrack Users stays managed in Authentik. --- .../apps/authentik/blueprints-configmap.yaml | 63 ------------------- kubernetes/apps/youtrack/ingress.yaml | 3 + 2 files changed, 3 insertions(+), 63 deletions(-) diff --git a/kubernetes/apps/authentik/blueprints-configmap.yaml b/kubernetes/apps/authentik/blueprints-configmap.yaml index be74102f..684f6b43 100644 --- a/kubernetes/apps/authentik/blueprints-configmap.yaml +++ b/kubernetes/apps/authentik/blueprints-configmap.yaml @@ -1045,7 +1045,6 @@ data: negate: false failure_result: false - # wiki.renner.uno signs in via OIDC application `wiki`; only this group may sign in. # Members are managed in Authentik. - id: wiki-readers-group @@ -1227,68 +1226,6 @@ data: name: passkey-passwordless-webauthn-validation state: absent - # YouTrack (apps/youtrack). Own blueprint so a missing YouTrack Users group - # only holds back YouTrack, not the other OAuth2 providers. - youtrack.yaml: | - version: 1 - metadata: - name: YouTrack (homelab) - entries: - # YouTrack (apps/youtrack): OpenID Connect auth module. YouTrack's module - # needs a client secret, so the client is confidential; Authentik generates - # the secret and it is pasted once into the module (owner step, like Gitea). - - id: youtrack-provider - model: authentik_providers_oauth2.oauth2provider - identifiers: - name: YouTrack - state: present - attrs: - authentication_flow: null - authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] - invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] - client_type: confidential - client_id: youtrack - # See the Matrix (MAS) provider: a blueprint-made provider starts - # with no grant types. - grant_types: - - authorization_code - - refresh_token - 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-profile]] - - !Find [authentik_providers_oauth2.scopemapping, [managed, goauthentik.io/providers/oauth2/scope-email]] - redirect_uris: - # YouTrack generates the callback when the module is created; pin it strict once known. - - url: 'https://youtrack\.renner\.uno/.*' - matching_mode: regex - - # The slug is the issuer path: https://auth.renner.uno/application/o/youtrack/ - - model: authentik_core.application - identifiers: - slug: youtrack - state: present - attrs: - name: YouTrack - slug: youtrack - provider: !KeyOf youtrack-provider - meta_launch_url: https://youtrack.renner.uno - meta_description: "YouTrack issue tracker" - - # Only the YouTrack Users group passes. The group and its members live in - # Authentik; until it exists this blueprint fails as a whole (atomic - # import), so YouTrack login stays closed rather than open. - - model: authentik_policies.policybinding - identifiers: - target: !Find [authentik_core.application, [slug, youtrack]] - group: !Find [authentik_core.group, [name, YouTrack Users]] - order: 0 - state: present - attrs: - enabled: true - negate: false - failure_result: false - # Service account of authentik-gate-sync (gate-sync.yaml), the controller # behind the authentik-gate ingress class. Its role covers exactly the # objects a gate consists of, plus reading the groups, flows and service diff --git a/kubernetes/apps/youtrack/ingress.yaml b/kubernetes/apps/youtrack/ingress.yaml index e88b6c9c..e74fd000 100644 --- a/kubernetes/apps/youtrack/ingress.yaml +++ b/kubernetes/apps/youtrack/ingress.yaml @@ -8,6 +8,9 @@ metadata: dns.renner.uno/internal: "true" annotations: cert-manager.io/cluster-issuer: letsencrypt-cluster + # authentik-gate-sync: OIDC client youtrack (issuer auth.renner.uno/application/o/youtrack/). + auth.renner.uno/oidc-client: youtrack + auth.renner.uno/group: YouTrack Users spec: ingressClassName: traefik tls: -- 2.54.0 From 14dc5247b79523da60e1f3d001dd098872e5e04c Mon Sep 17 00:00:00 2001 From: hermes-bot Date: Sun, 1 Nov 2026 09:31:45 +0000 Subject: [PATCH 5/5] fix(youtrack): OIDC client as an OIDCClient resource, not Ingress annotations Uses the OIDCClient CRD from #1535; the Ingress carries only routing and DNS again. The Flux Kustomization treats OIDCClient as current on apply, since its Ready reflects Authentik state (the group), as with KumaMonitor. --- kubernetes/apps/youtrack/ingress.yaml | 3 --- kubernetes/apps/youtrack/kustomization.yaml | 1 + kubernetes/apps/youtrack/oidcclient.yaml | 13 +++++++++++++ kubernetes/clusters/homelab/youtrack.yaml | 5 +++++ 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 kubernetes/apps/youtrack/oidcclient.yaml diff --git a/kubernetes/apps/youtrack/ingress.yaml b/kubernetes/apps/youtrack/ingress.yaml index e74fd000..e88b6c9c 100644 --- a/kubernetes/apps/youtrack/ingress.yaml +++ b/kubernetes/apps/youtrack/ingress.yaml @@ -8,9 +8,6 @@ metadata: dns.renner.uno/internal: "true" annotations: cert-manager.io/cluster-issuer: letsencrypt-cluster - # authentik-gate-sync: OIDC client youtrack (issuer auth.renner.uno/application/o/youtrack/). - auth.renner.uno/oidc-client: youtrack - auth.renner.uno/group: YouTrack Users spec: ingressClassName: traefik tls: diff --git a/kubernetes/apps/youtrack/kustomization.yaml b/kubernetes/apps/youtrack/kustomization.yaml index 99bd7a00..ad23ae39 100644 --- a/kubernetes/apps/youtrack/kustomization.yaml +++ b/kubernetes/apps/youtrack/kustomization.yaml @@ -4,3 +4,4 @@ resources: - pvc.yaml - deployment.yaml - ingress.yaml + - oidcclient.yaml diff --git a/kubernetes/apps/youtrack/oidcclient.yaml b/kubernetes/apps/youtrack/oidcclient.yaml new file mode 100644 index 00000000..b3160f03 --- /dev/null +++ b/kubernetes/apps/youtrack/oidcclient.yaml @@ -0,0 +1,13 @@ +# Authentik OIDC client, created by authentik-gate-sync; issuer https://auth.renner.uno/application/o/youtrack/. +apiVersion: auth.renner.uno/v1alpha1 +kind: OIDCClient +metadata: + name: youtrack + namespace: youtrack +spec: + launchURL: https://youtrack.renner.uno + group: YouTrack Users + redirectURIs: + # YouTrack generates the callback when the auth module is created; pin it strict once known. + - matchingMode: regex + url: ^https://youtrack\.renner\.uno/.*$ diff --git a/kubernetes/clusters/homelab/youtrack.yaml b/kubernetes/clusters/homelab/youtrack.yaml index 0181dd91..cc11ca1d 100644 --- a/kubernetes/clusters/homelab/youtrack.yaml +++ b/kubernetes/clusters/homelab/youtrack.yaml @@ -13,6 +13,11 @@ spec: path: ./kubernetes/apps/youtrack prune: true wait: true + # OIDCClient Ready tracks Authentik (e.g. the group exists), not this apply. + healthCheckExprs: + - apiVersion: auth.renner.uno/v1alpha1 + kind: OIDCClient + current: "true" dependsOn: - name: restore-youtrack - name: infrastructure -- 2.54.0