Admin stack: Authelia SSO, portal at admin.carr.pub, gated grafana.carr.pub
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
|||||||
configs/node-password.txt
|
configs/node-password.txt
|
||||||
.synology-password
|
.synology-password
|
||||||
|
configs/admin-password.txt
|
||||||
|
configs/authelia-session-secret.txt
|
||||||
|
configs/authelia-jwt-secret.txt
|
||||||
|
|||||||
133
manifests/admin/authelia.yaml
Normal file
133
manifests/admin/authelia.yaml
Normal 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]
|
||||||
61
manifests/admin/ingresses.yaml
Normal file
61
manifests/admin/ingresses.yaml
Normal 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}}
|
||||||
66
manifests/admin/portal.yaml
Normal file
66
manifests/admin/portal.yaml
Normal 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 & 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
|
||||||
24
scripts/deploy-admin.sh
Normal file
24
scripts/deploy-admin.sh
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Redeploy the admin stack (Authelia SSO + portal). Secrets are regenerated
|
||||||
|
# from the gitignored files in configs/ so nothing sensitive is committed.
|
||||||
|
# First-time setup: run scripts/gen-admin-secrets.sh before this.
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
HASH=$(/tmp/opencode/authelia/authelia crypto hash generate argon2 \
|
||||||
|
--password "$(cat configs/admin-password.txt)" 2>/dev/null | grep -o '\$argon2id\$.*')
|
||||||
|
SESSION=$(cat configs/authelia-session-secret.txt)
|
||||||
|
JWT=$(cat configs/authelia-jwt-secret.txt)
|
||||||
|
ENCKEY=$(openssl rand -base64 24 | tr -d "=+/" | cut -c1-32)
|
||||||
|
|
||||||
|
export HASH SESSION JWT ENCKEY
|
||||||
|
for f in manifests/admin/*.yaml; do
|
||||||
|
envsubst '\$HASH \$SESSION \$JWT \$ENCKEY' < "$f" | kubectl apply -f -
|
||||||
|
done
|
||||||
|
|
||||||
|
kubectl -n admin set env deployment/authelia \
|
||||||
|
AUTHELIA_SESSION_SECRET="$SESSION" \
|
||||||
|
AUTHELIA_STORAGE_ENCRYPTION_KEY="$ENCKEY" \
|
||||||
|
AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET="$JWT" \
|
||||||
|
>/dev/null
|
||||||
|
echo "admin stack deployed"
|
||||||
Reference in New Issue
Block a user