- Add 'memory' scope property mapping (memory_projects, memory_visibility, memory_role) - Add capability groups: llm-users, memory-users, memory-writers - Add service account provisioning for portfolio-agent, memory-agent - Fix sops-secrets kustomization (generatorOptions) - Add RoleBindings for portfolio, poimen, dashboard namespaces - Remove PostSync hook - IAM provisioning is now manual-only
253 lines
7.0 KiB
YAML
253 lines
7.0 KiB
YAML
# Authentik OAuth provisioning — MANUAL operation, NOT auto-run.
|
|
#
|
|
# Security-sensitive IAM changes should be reviewed and run locally:
|
|
# export AUTHENTIK_BOOTSTRAP_TOKEN=$(kubectl -n iam get secret authentik-secrets \
|
|
# -o jsonpath='{.data.AUTHENTIK_BOOTSTRAP_TOKEN}' | base64 -d)
|
|
# sed 's|http://authentik-server.iam.svc.cluster.local|https://authentik.riotpiao.com|g' \
|
|
# k8s/infra/iam/scripts/authentik-provision.py | python3
|
|
#
|
|
# What it does (see scripts/authentik-provision.py docstring): creates scope
|
|
# mappings (groups, permissions, memory, policy, immich_role), admin groups,
|
|
# the "rock" admin user, OAuth2 providers + Applications, service accounts
|
|
# (portfolio-agent, memory-agent), and binds groups to applications.
|
|
#
|
|
# This file provides the RBAC (ServiceAccount + RoleBindings) needed if you
|
|
# ever want to run the Job in-cluster manually (kubectl create -f), but the
|
|
# PostSync hook is deliberately removed — IAM is not GitOps-auto-deployed.
|
|
#
|
|
# RBAC: this Job only touches Secrets (get existing client secrets, create new
|
|
# ones) across the namespaces those services live in.
|
|
apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: ClusterRole
|
|
metadata:
|
|
name: authentik-provisioner
|
|
rules:
|
|
- apiGroups: [""]
|
|
resources: ["secrets"]
|
|
verbs: ["get", "list", "create", "update", "patch"]
|
|
---
|
|
# One RoleBinding per namespace the script touches (least-privilege: Secrets
|
|
# only, and only in these 5 namespaces — not a cluster-wide ClusterRoleBinding).
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: cicd
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: argocd
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: logging
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: storage
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: paperless
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: immich
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: llm-serving
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: portfolio
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: poimen
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
name: authentik-provisioner
|
|
namespace: dashboard
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: authentik-provisioner
|
|
namespace: iam
|
|
roleRef:
|
|
kind: ClusterRole
|
|
name: authentik-provisioner
|
|
apiGroup: rbac.authorization.k8s.io
|
|
---
|
|
apiVersion: batch/v1
|
|
kind: Job
|
|
metadata:
|
|
name: authentik-provision
|
|
namespace: iam
|
|
# No ArgoCD hook - run manually when IAM changes are needed
|
|
spec:
|
|
ttlSecondsAfterFinished: 600
|
|
backoffLimit: 3
|
|
template:
|
|
spec:
|
|
serviceAccountName: authentik-provisioner
|
|
restartPolicy: Never
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1000
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
containers:
|
|
- name: provision
|
|
image: python:3.12-alpine
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
env:
|
|
- name: AUTHENTIK_BOOTSTRAP_TOKEN
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: authentik-secrets
|
|
key: AUTHENTIK_BOOTSTRAP_TOKEN
|
|
volumeMounts:
|
|
- name: script
|
|
mountPath: /script
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
set -e
|
|
echo "waiting for authentik-server..."
|
|
until wget -q -O /dev/null http://authentik-server.iam.svc.cluster.local/-/health/ready/ 2>/dev/null; do
|
|
sleep 5
|
|
done
|
|
echo "installing kubectl (via python urllib - no apk/curl: this"
|
|
echo "container runs as non-root UID 1000 and can't write to"
|
|
echo "apk's directories or /usr/local/bin, both root-owned in"
|
|
echo "the python:3.12-alpine image; /tmp is world-writable)..."
|
|
python3 -c "
|
|
import urllib.request, os, stat
|
|
kver = urllib.request.urlopen('https://dl.k8s.io/release/stable.txt').read().decode().strip()
|
|
url = f'https://dl.k8s.io/release/{kver}/bin/linux/amd64/kubectl'
|
|
urllib.request.urlretrieve(url, '/tmp/kubectl')
|
|
st = os.stat('/tmp/kubectl')
|
|
os.chmod('/tmp/kubectl', st.st_mode | stat.S_IEXEC)
|
|
"
|
|
export PATH="/tmp:$PATH"
|
|
echo "running provisioning script..."
|
|
python3 /script/authentik-provision.py
|
|
volumes:
|
|
- name: script
|
|
configMap:
|
|
name: authentik-provision-script
|