Files
homelab/adguardhome/k8s/cert-sync-rbac.yaml
T
forust 1e8479b853
ci / lint-prettier (push) Successful in 3s
ci / lint-ruff (push) Successful in 1s
ci / lint-yaml (push) Successful in 2s
ci / lint-dockerfiles (push) Successful in 1s
ci / validate (push) Successful in 2s
ci / build (push) Skipped
ci / deploy-userbot-panel (push) Skipped
feat(adguard): sync Traefik prod cert for dns.forust.xyz into adguard-certs
CronJob adguard-cert-sync (daily 03:17) copies the public cert/key for
dns.forust.xyz from Traefik acme.json into Secret adguard-certs, which
AdGuard mounts for DNS-over-TLS on :853.

- least-privilege RBAC: read pods/exec in ns traefik, get/update/patch
  Secret adguard-certs and get/patch adguard-deployment in ns adguard
- script selects the PROD resolver entry only, matches main domain or
  SANs, compares sha256 hashes, patches the secret and restarts the
  deployment ONLY on change; exits non-zero and touches nothing when
  Traefik holds no cert yet (HTTP-01 currently cannot complete)
2026-09-23 13:39:38 +02:00

85 lines
2.2 KiB
YAML

# Least-privilege RBAC for the adguard TLS cert sync CronJob (see cert-sync.yaml).
#
# The job runs as ServiceAccount `adguard-cert-sync` (namespace adguard) and needs:
# * namespace traefik: list/get pods (locate the running Traefik pod by label)
# and create pods/exec (read-only `cat` of /data/letsencrypt/acme.json).
# It never writes anything in namespace traefik.
# * namespace adguard: get/update/patch Secret `adguard-certs` (the only
# secret it may touch) and get/patch Deployment `adguard-deployment`
# (`kubectl rollout restart` issues a patch; `rollout status` reads).
apiVersion: v1
kind: ServiceAccount
metadata:
name: adguard-cert-sync
namespace: adguard
labels:
app: adguard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: adguard-cert-sync
namespace: adguard
labels:
app: adguard
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["adguard-certs"]
verbs: ["get", "update", "patch"]
- apiGroups: ["apps"]
resources: ["deployments"]
resourceNames: ["adguard-deployment"]
verbs: ["get", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: adguard-cert-sync
namespace: adguard
labels:
app: adguard
subjects:
- kind: ServiceAccount
name: adguard-cert-sync
namespace: adguard
roleRef:
kind: Role
name: adguard-cert-sync
apiGroup: rbac.authorization.k8s.io
---
# Read-only access to the Traefik pod (acme.json lives on its /data volume).
# The RoleBinding references a ServiceAccount from namespace adguard,
# which is allowed: the binding lives in namespace traefik and only
# grants rights inside namespace traefik.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: adguard-cert-sync
namespace: traefik
labels:
app: adguard
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: adguard-cert-sync
namespace: traefik
labels:
app: adguard
subjects:
- kind: ServiceAccount
name: adguard-cert-sync
namespace: adguard
roleRef:
kind: Role
name: adguard-cert-sync
apiGroup: rbac.authorization.k8s.io