Admin stack: Authelia SSO, portal at admin.carr.pub, gated grafana.carr.pub

This commit is contained in:
Adam Carr
2026-09-19 21:56:58 -07:00
parent 282fd3db8c
commit 2bc85826f1
5 changed files with 287 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
apiVersion: v1
kind: Namespace
metadata:
name: admin
---
apiVersion: v1
kind: ConfigMap
metadata:
name: authelia-config
namespace: admin
data:
configuration.yml: |
server:
address: tcp://:9091
theme: dark
log:
level: info
authentication_backend:
file:
path: /config/users_database.yml
password_policy:
standard:
enabled: true
min_length: 12
session:
cookies:
- domain: carr.pub
authelia_url: https://auth.carr.pub
default_redirection_url: https://admin.carr.pub
same_site: lax
storage:
local:
path: /config/data/db.sqlite3
notifier:
filesystem:
filename: /config/data/notifications.txt
totp:
issuer: carr.pub
webauthn:
disable: true
access_control:
default_policy: one_factor
rules: []
---
apiVersion: v1
kind: Secret
metadata:
name: authelia-users
namespace: admin
stringData:
users_database.yml: |
users:
adamcarr:
displayname: "Adam Carr"
password: "<argon2-hash from configs/admin-password.txt via deploy script>"
groups: ["admins"]
---
apiVersion: v1
kind: Secret
metadata:
name: authelia-secrets
namespace: admin
stringData:
session-secret: <from configs/authelia-session-secret.txt>
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: authelia-data
namespace: admin
spec:
accessModes: [ReadWriteOnce]
storageClassName: local-path
resources:
requests: {storage: 2Gi}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: authelia
namespace: admin
spec:
replicas: 1
selector:
matchLabels: {app: authelia}
template:
metadata:
labels: {app: authelia}
spec:
containers:
- name: authelia
image: authelia/authelia:v4.39.28
args: ["--config", "/config/configuration.yml"]
env:
- name: AUTHELIA_SESSION_SECRET
valueFrom: {secretKeyRef: {name: authelia-secrets, key: session-secret}}
ports: [{containerPort: 9091}]
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {memory: 256Mi}
volumeMounts:
- {name: config, mountPath: /config/configuration.yml, subPath: configuration.yml}
- {name: users, mountPath: /config/users_database.yml, subPath: users_database.yml}
- {name: data, mountPath: /config/data}
volumes:
- name: config
configMap: {name: authelia-config}
- name: users
secret: {secretName: authelia-users}
- name: data
persistentVolumeClaim: {claimName: authelia-data}
---
apiVersion: v1
kind: Service
metadata:
name: authelia
namespace: admin
spec:
selector: {app: authelia}
ports:
- port: 9091
targetPort: 9091
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: authelia-auth
namespace: admin
spec:
forwardAuth:
address: "http://authelia.admin.svc:9091/api/verify?rd=https://auth.carr.pub"
trustForwardHeader: true
authResponseHeaders: [Remote-User, Remote-Groups, Remote-Email, Remote-Name]

View File

@@ -0,0 +1,61 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: auth
namespace: admin
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts: [auth.carr.pub]
secretName: auth-carr-pub-tls
rules:
- host: auth.carr.pub
http:
paths:
- path: /
pathType: Prefix
backend:
service: {name: authelia, port: {number: 9091}}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: admin-portal
namespace: admin
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.middlewares: admin-authelia-auth@kubernetescrd
spec:
tls:
- hosts: [admin.carr.pub]
secretName: admin-carr-pub-tls
rules:
- host: admin.carr.pub
http:
paths:
- path: /
pathType: Prefix
backend:
service: {name: portal, port: {number: 80}}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grafana
namespace: monitoring
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.middlewares: admin-authelia-auth@kubernetescrd
spec:
tls:
- hosts: [grafana.carr.pub]
secretName: grafana-carr-pub-tls
rules:
- host: grafana.carr.pub
http:
paths:
- path: /
pathType: Prefix
backend:
service: {name: grafana, port: {number: 3000}}

View File

@@ -0,0 +1,66 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: portal-index
namespace: admin
data:
index.html: |
<!doctype html>
<html>
<head><meta charset="utf-8"><title>planck admin</title>
<style>
body { font-family: system-ui, sans-serif; background: #111; color: #eee;
display: grid; place-items: center; min-height: 100vh; margin: 0; }
.card { text-align: center; }
h1 { font-size: 2.5rem; margin: 0 0 1.5rem; }
a { display: block; margin: 0.6rem auto; padding: 0.8rem 1.5rem;
background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
color: #8be9fd; text-decoration: none; font-size: 1.1rem; width: 260px; }
a:hover { background: #2a2a3e; }
p { color: #888; }
</style>
</head>
<body><div class="card">
<h1>planck</h1>
<a href="https://grafana.carr.pub">Grafana</a>
<a href="https://auth.carr.pub">Account &amp; 2FA settings</a>
<p>20 nodes · k3s · carr.pub</p>
</div></body>
</html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: portal
namespace: admin
spec:
replicas: 2
selector:
matchLabels: {app: portal}
template:
metadata:
labels: {app: portal}
spec:
containers:
- name: web
image: nginx:1.29-alpine
ports: [{containerPort: 80}]
resources:
requests: {cpu: 10m, memory: 16Mi}
limits: {memory: 64Mi}
volumeMounts:
- {name: html, mountPath: /usr/share/nginx/html}
volumes:
- name: html
configMap: {name: portal-index}
---
apiVersion: v1
kind: Service
metadata:
name: portal
namespace: admin
spec:
selector: {app: portal}
ports:
- port: 80
targetPort: 80