Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae5de9bc84 | ||
|
|
ad152d2d16 | ||
|
|
0cfc4dc486 | ||
|
|
50c62da2f4 | ||
|
|
476c48c0af | ||
|
|
8200ce1898 |
@@ -976,6 +976,66 @@ data:
|
||||
kubernetes_ingress_secret_name: "authentik-outpost-tls"
|
||||
kubernetes_json_patches: null
|
||||
|
||||
# wiki-gate: the wiki service (ns ai) behind the same passkey flows as
|
||||
# llama-gate. The service trusts X-Authentik-Username only from pod
|
||||
# addresses, and its CNP admits only this outpost, so the gate is the
|
||||
# whole access control for wiki.renner.uno.
|
||||
- id: wiki-gate-provider
|
||||
model: authentik_providers_proxy.proxyprovider
|
||||
identifiers:
|
||||
name: wiki-gate
|
||||
state: present
|
||||
attrs:
|
||||
authentication_flow: !Find [authentik_flows.flow, [slug, passkey-passwordless-authentication]]
|
||||
authorization_flow: !Find [authentik_flows.flow, [slug, passkey-stepup-authorization]]
|
||||
invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]]
|
||||
mode: proxy
|
||||
internal_host: http://wiki.ai.svc.cluster.local:8080
|
||||
internal_host_ssl_validation: false
|
||||
external_host: https://wiki.renner.uno
|
||||
cookie_domain: renner.uno
|
||||
access_token_validity: hours=24
|
||||
refresh_token_validity: days=30
|
||||
intercept_header_auth: true
|
||||
|
||||
- model: authentik_core.application
|
||||
identifiers:
|
||||
slug: wiki-gate
|
||||
state: present
|
||||
attrs:
|
||||
name: Wiki
|
||||
slug: wiki-gate
|
||||
provider: !KeyOf wiki-gate-provider
|
||||
meta_launch_url: https://wiki.renner.uno
|
||||
meta_description: "Notes wiki: search, notes, answers, maintenance"
|
||||
|
||||
- model: authentik_outposts.outpost
|
||||
identifiers:
|
||||
name: wiki-gate
|
||||
state: present
|
||||
attrs:
|
||||
type: proxy
|
||||
service_connection: !KeyOf k8s-conn
|
||||
providers:
|
||||
- !KeyOf wiki-gate-provider
|
||||
config:
|
||||
log_level: info
|
||||
authentik_host: "http://authentik-server.authentik.svc.cluster.local"
|
||||
authentik_host_insecure: false
|
||||
authentik_host_browser: "https://auth.renner.uno/"
|
||||
refresh_interval: "minutes=5"
|
||||
container_image: null
|
||||
object_naming_template: "ak-outpost-%(name)s"
|
||||
kubernetes_namespace: authentik
|
||||
kubernetes_replicas: 1
|
||||
kubernetes_service_type: ClusterIP
|
||||
kubernetes_disabled_components: ["ingress"]
|
||||
kubernetes_image_pull_secrets: []
|
||||
kubernetes_ingress_annotations: {}
|
||||
kubernetes_ingress_class_name: null
|
||||
kubernetes_ingress_secret_name: "authentik-outpost-tls"
|
||||
kubernetes_json_patches: null
|
||||
|
||||
- model: authentik_outposts.outpost
|
||||
identifiers:
|
||||
name: authentik Embedded Outpost
|
||||
|
||||
@@ -16,6 +16,7 @@ resources:
|
||||
- prometheus-gate-egress.yaml
|
||||
- wordpress-gate-egress.yaml
|
||||
- llama-gate-egress.yaml
|
||||
- wiki-gate-egress.yaml
|
||||
- ldap-outpost-cert.yaml
|
||||
- ldap-outpost-lb.yaml
|
||||
- ldap-outpost-cnp.yaml
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Lets the wiki-gate outpost reach the wiki service. The authentik namespace
|
||||
# baseline CNP otherwise stops any authentik pod from entering ai. Scoped to
|
||||
# this outpost's pod label; the matching ingress rule is in ai-ns.yaml.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: wiki-gate-egress
|
||||
namespace: authentik
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
goauthentik.io/outpost-name: wiki-gate
|
||||
egress:
|
||||
- toEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": ai
|
||||
app.kubernetes.io/name: wiki
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "8080"
|
||||
protocol: TCP
|
||||
@@ -46,7 +46,7 @@ spec:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: gatus
|
||||
image: twinproduction/gatus:v5.36.0 # {"$imagepolicy": "flux-system:gatus"}
|
||||
image: twinproduction/gatus:v5.37.0 # {"$imagepolicy": "flux-system:gatus"}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
|
||||
@@ -134,7 +134,7 @@ spec:
|
||||
# is a device-bricking class of risk. Bumps are a reviewed, manual
|
||||
# act — see kubernetes/infrastructure/image-automation/README.md.
|
||||
- name: terminus
|
||||
image: ghcr.io/usetrmnl/terminus:0.74.0 # {"$imagepolicy": "flux-system:terminus"}
|
||||
image: ghcr.io/usetrmnl/terminus:0.75.0 # {"$imagepolicy": "flux-system:terminus"}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 2345
|
||||
@@ -197,7 +197,7 @@ spec:
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
- name: sidekiq
|
||||
image: ghcr.io/usetrmnl/terminus:0.74.0 # {"$imagepolicy": "flux-system:terminus"}
|
||||
image: ghcr.io/usetrmnl/terminus:0.75.0 # {"$imagepolicy": "flux-system:terminus"}
|
||||
command: ["bundle", "exec", "sidekiq", "-r", "./config/sidekiq.rb"]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
# Index snapshots per embedding model and the document catalog. A lost volume
|
||||
# costs one full sync from Gitea (~10 min).
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: wiki-data
|
||||
namespace: ai
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: ceph-block
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
# Wiki service (konairius/Wiki): mirrors the Notes repo from Gitea, embeds
|
||||
# wiki/ via wiki-embed, serves /rank, /api/v1 and the MudBlazor UI. Adapters
|
||||
# are selected in appsettings (Wiki__* env overrides); secrets arrive as env
|
||||
# from ExternalSecrets, the pod has no OpenBao access.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: wiki
|
||||
namespace: ai
|
||||
labels:
|
||||
app.kubernetes.io/name: wiki
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: wiki
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: wiki
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
runAsGroup: 65534
|
||||
fsGroup: 65534
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: wiki
|
||||
# build.<unix-ts> tags from the Wiki repo's release pipeline (commit c4e193b).
|
||||
image: gitea.renner.uno/konairius/wiki:build.1790245544
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
env:
|
||||
- name: HOME
|
||||
value: /tmp
|
||||
- name: Wiki__Index__File__Directory
|
||||
value: /data
|
||||
- name: Wiki__NoteStore__Gitea__BaseUrl
|
||||
value: https://gitea.renner.uno
|
||||
- name: Wiki__NoteStore__Gitea__Repository
|
||||
value: k.renner/notes
|
||||
- name: Wiki__NoteStore__Gitea__Branch
|
||||
value: main
|
||||
- name: Wiki__Embeddings__Models__bge-m3__Url
|
||||
value: http://wiki-embed.ai.svc.cluster.local:8080
|
||||
# Pod networks: the CNP admits only the wiki-gate outpost and Gitea.
|
||||
- name: Auth__ReverseProxy__TrustedProxies__0
|
||||
value: fd10:244::/48
|
||||
- name: Auth__ReverseProxy__TrustedProxies__1
|
||||
value: 10.244.0.0/16
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: wiki-gitea
|
||||
- secretRef:
|
||||
name: wiki-api-keys
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
# /health: the process serves (liveness). /ready: catalog synced once and the
|
||||
# active index loaded; a cold start syncs the whole vault first (~10 min).
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: http
|
||||
periodSeconds: 10
|
||||
failureThreshold: 120
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: http
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
periodSeconds: 60
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 3
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: wiki-data
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: wiki
|
||||
namespace: ai
|
||||
labels:
|
||||
app.kubernetes.io/name: wiki
|
||||
spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: wiki
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: http
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
# Gitea read token and webhook secret, shared with the Python wiki-index until
|
||||
# that is retired. Secret keys are the configuration paths the host reads.
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: wiki-gitea
|
||||
namespace: ai
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
kind: ClusterSecretStore
|
||||
name: openbao
|
||||
target:
|
||||
name: wiki-gitea
|
||||
data:
|
||||
- secretKey: Wiki__NoteStore__Gitea__Token
|
||||
remoteRef:
|
||||
key: apps/ai/wiki-index
|
||||
property: gitea_token
|
||||
- secretKey: Wiki__Webhook__Secret
|
||||
remoteRef:
|
||||
key: apps/ai/wiki-index
|
||||
property: webhook_secret
|
||||
---
|
||||
# One API key per machine identity: OpenBao apps/ai/wiki-api-keys, field = name.
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: wiki-api-keys
|
||||
namespace: ai
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
kind: ClusterSecretStore
|
||||
name: openbao
|
||||
target:
|
||||
name: wiki-api-keys
|
||||
data:
|
||||
- secretKey: Auth__ApiKeys__workstation
|
||||
remoteRef:
|
||||
key: apps/ai/wiki-api-keys
|
||||
property: workstation
|
||||
@@ -0,0 +1,20 @@
|
||||
# ExternalName mirror so the ai-namespace Ingress can backend to the wiki-gate
|
||||
# outpost in the authentik namespace.
|
||||
#
|
||||
# browser → traefik (wiki.renner.uno)
|
||||
# → ak-outpost-wiki-gate (ExternalName → authentik ns)
|
||||
# → outpost validates the session + passkey step-up, sets X-Authentik-Username
|
||||
# → http://wiki.ai.svc.cluster.local:8080
|
||||
#
|
||||
# In-cluster clients (CI agents, the Gitea webhook) address the Service directly.
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ak-outpost-wiki-gate
|
||||
namespace: ai
|
||||
spec:
|
||||
type: ExternalName
|
||||
externalName: ak-outpost-wiki-gate.authentik.svc.cluster.local
|
||||
ports:
|
||||
- port: 9000
|
||||
targetPort: 9000
|
||||
@@ -0,0 +1,26 @@
|
||||
# wiki.renner.uno — LAN-only (no dns.renner.uno/public label). Traefik backends
|
||||
# the wiki-gate outpost, never the Service; the ai CNP admits only that outpost.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wiki
|
||||
namespace: ai
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-cluster
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
tls:
|
||||
- hosts:
|
||||
- wiki.renner.uno
|
||||
secretName: wiki-tls
|
||||
rules:
|
||||
- host: wiki.renner.uno
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: ak-outpost-wiki-gate
|
||||
port:
|
||||
number: 9000
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- externalsecrets.yaml
|
||||
- deployment.yaml
|
||||
- gate-service.yaml
|
||||
- ingress.yaml
|
||||
@@ -0,0 +1,22 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: wiki
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
retryInterval: 1m
|
||||
# First start on an empty PVC syncs and embeds the whole vault before /ready is 200.
|
||||
timeout: 25m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./kubernetes/apps/wiki
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
- name: infrastructure
|
||||
- name: infrastructure-crds
|
||||
- name: infrastructure-ceph-cluster
|
||||
# wiki-embed (the embedding backend) lives in the llama-server app.
|
||||
- name: llama-server
|
||||
@@ -149,6 +149,32 @@ spec:
|
||||
- port: "8080"
|
||||
protocol: TCP
|
||||
---
|
||||
# wiki: only the wiki-gate outpost (humans, after Authentik) and Gitea (push
|
||||
# webhook) may reach it; Traefik is not admitted, so the X-Authentik-Username
|
||||
# header the service trusts cannot arrive from the LAN. Gitea and wiki-embed
|
||||
# are reached through the namespace egress above; no OpenBao access.
|
||||
apiVersion: cilium.io/v2
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: wiki
|
||||
namespace: ai
|
||||
spec:
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: wiki
|
||||
ingress:
|
||||
- fromEndpoints:
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": authentik
|
||||
goauthentik.io/outpost-name: wiki-gate
|
||||
- matchLabels:
|
||||
"k8s:io.kubernetes.pod.namespace": gitea
|
||||
app.kubernetes.io/name: gitea
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "8080"
|
||||
protocol: TCP
|
||||
---
|
||||
# wiki-index: Traefik (LAN clients behind BasicAuth) and Gitea (push webhook)
|
||||
# may reach it; it reaches OpenBao for its credentials. Gitea itself is reached
|
||||
# through Traefik, which the namespace egress above already allows.
|
||||
|
||||
Reference in New Issue
Block a user