feat(infra): full dezky rebrand of Authentik login (logo, favicon, bg, footer)
ci / typecheck (map[dir:services/platform-api name:platform-api]) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / typecheck (map[dir:apps/portal name:portal]) (push) Has been cancelled
ci / typecheck (map[dir:apps/website name:website]) (push) Has been cancelled
ci / typecheck (map[dir:apps/booking name:booking]) (push) Has been cancelled

Brand CSS only reaches the flow shadow DOM via CSS vars (colors), not the
logo/favicon (deeper shadow root) or the "Powered by authentik" footer (light
DOM). So, dev-style: serve real dezky assets + sed the bundle.

- web-assets/: dezky-logo.svg, dezky-favicon.svg, dezky-bg.svg (carbon).
- server-rebrand.py: patches the authentik-server Deployment with an
  initContainer that copies /web/dist to an emptyDir, drops the svgs into
  assets/icons, and seds "Powered by authentik" -> "Powered by Dezky".
- brand.yaml: branding_logo / branding_favicon / branding_default_flow_background
  point at the served svgs; auth-flow title "Welcome to Dezky"; signal-green CSS.

Verified live: login now matches dev (logo, title, carbon bg, green button,
favicon, Powered by Dezky). Durability caveat documented (reverts on helm
upgrade).
This commit is contained in:
Ronni Baslund
2026-06-08 20:36:01 +02:00
parent 99cd86cd3a
commit 326b626fc6
6 changed files with 57 additions and 20 deletions
@@ -70,6 +70,31 @@ Client secrets live in `authentik-secret` (`PORTAL_OIDC_CLIENT_SECRET`,
> post-render kustomize patch to make it durable). TODO. > post-render kustomize patch to make it durable). TODO.
## Still deferred ## Still deferred
- **Rebrand** of the "Powered by authentik" string (web-bundle `sed`, needs a
root lifecycle override) — cosmetic; the *colors* are done via the brand CSS.
- Pin the **chart version** (currently latest → app `2026.5.2`). - Pin the **chart version** (currently latest → app `2026.5.2`).
- **Durability:** the server-rebrand Deployment patch + the brand image-field
PATCH revert on a helm upgrade of Authentik — re-run them, or bake a custom
image / post-render kustomize patch.
## Full visual rebrand (logo / favicon / background / footer) — APPLIED
Brand custom CSS only reaches shadow DOM via CSS **vars** (so colors work), not
the logo/favicon (deeper shadow root) or the "Powered by authentik" footer
(light DOM). Those use dev's mechanism — real files + a bundle sed:
- `web-assets/` — `dezky-logo.svg`, `dezky-favicon.svg`, `dezky-bg.svg` (carbon).
- ConfigMap `authentik-web-assets` is built from `web-assets/`.
- `server-rebrand.py` patches the **authentik-server** Deployment: an
initContainer copies `/web/dist` into an emptyDir, drops the 3 svgs into
`/web/dist/assets/icons/`, and seds `Powered by authentik` -> `Powered by
Dezky`. The server then serves the patched bundle.
- The brand's `branding_logo` / `branding_favicon` /
`branding_default_flow_background` point at those served svgs (carried in
brand.yaml; if the blueprint leaves them default, PATCH the brand via API).
Apply:
```
kubectl -n dezky-auth create configmap authentik-web-assets --from-file=web-assets/ --dry-run=client -o yaml | kubectl apply -f -
kubectl -n dezky-auth get deploy authentik-server -o json | python3 server-rebrand.py | kubectl apply -f -
```
> CAVEAT: the server patch + brand PATCH revert on a helm upgrade of Authentik —
> re-run them (or bake a custom image) for durability.
@@ -1,8 +1,11 @@
# dezky branding for the default Authentik brand. branding_logo / # dezky branding for the default Authentik brand.
# branding_default_flow_background are FILE-PATH fields (reject data URIs), so # - branding_logo points at a dezky SVG injected into the server's web bundle
# the logo + carbon background are done via custom CSS (which allows data URIs). # by the dezky-rebrand initContainer (see authentik/README "rebrand").
# The auth-flow title is set on the flow itself. ("Powered by authentik" footer # - colors (accent, button, carbon background) via custom CSS (CSS vars cross the
# still needs the separate web-bundle patch.) # shadow boundary; selectors can't, so the logo had to be a real file).
# - "Powered by authentik" -> "Powered by Dezky" is done by the same
# initContainer sed'ing the bundle (the footer is light-DOM, unreachable by
# brand CSS).
version: 1 version: 1
metadata: metadata:
name: dezky-brand name: dezky-brand
@@ -15,6 +18,9 @@ entries:
domain: authentik-default domain: authentik-default
attrs: attrs:
branding_title: dezky branding_title: dezky
branding_logo: /static/dist/assets/icons/dezky-logo.svg
branding_favicon: /static/dist/assets/icons/dezky-favicon.svg
branding_default_flow_background: /static/dist/assets/icons/dezky-bg.svg
branding_custom_css: | branding_custom_css: |
:root, :host { :root, :host {
--ak-accent: #D4FF3A; --ak-accent: #D4FF3A;
@@ -23,19 +29,8 @@ entries:
--pf-global--link--Color: #D4FF3A; --pf-global--link--Color: #D4FF3A;
--ak-flow-background: #0A0A0A !important; --ak-flow-background: #0A0A0A !important;
} }
/* dezky logo in place of the authentik wordmark */ .pf-c-background-image, .pf-c-background-image__src { background: #0A0A0A !important; }
.pf-c-brand, img.pf-c-brand, .ak-brand img, header img { img.pf-c-background-image__src { display: none !important; }
content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxODAiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCAxODAgNDgiPjxyZWN0IHg9IjIiIHk9IjIiIHdpZHRoPSI0NCIgaGVpZ2h0PSI0NCIgcng9IjEzIiBmaWxsPSIjRjRGM0VFIi8+PHRleHQgeD0iMjQiIHk9IjM2IiBmb250LWZhbWlseT0iQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMzIiIGZvbnQtd2VpZ2h0PSI3MDAiIGZpbGw9IiMwQTBBMEEiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmQ8L3RleHQ+PGNpcmNsZSBjeD0iMzgiIGN5PSIxMiIgcj0iNC41IiBmaWxsPSIjRDRGRjNBIi8+PHRleHQgeD0iNTgiIHk9IjM0IiBmb250LWZhbWlseT0iQXJpYWwsSGVsdmV0aWNhLHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjciIGZvbnQtd2VpZ2h0PSI3MDAiIGZpbGw9IiNGNEYzRUUiPmRlemt5PC90ZXh0Pjwvc3ZnPg==") !important;
height: 48px !important;
width: auto !important;
}
/* carbon background — remove the authentik forest */
.pf-c-background-image, .pf-c-background-image__src,
ak-flow-executor, .ak-flow-card-background {
background: #0A0A0A !important;
}
img.pf-c-background-image__src, .pf-c-background-image__src { display: none !important; }
/* signal-green primary button + links */
.pf-c-button.pf-m-primary, .pf-c-button.pf-m-primary,
.pf-v5-c-button.pf-m-primary, .pf-v5-c-button.pf-m-primary,
.pf-v6-c-button.pf-m-primary { .pf-v6-c-button.pf-m-primary {
@@ -0,0 +1,14 @@
import sys,json
d=json.load(sys.stdin); spec=d["spec"]["template"]["spec"]; img=spec["containers"][0]["image"]
spec["volumes"]=[v for v in spec.get("volumes",[]) if v.get("name") not in ("webdist","webassets")]
spec["volumes"]+=[{"name":"webdist","emptyDir":{}},{"name":"webassets","configMap":{"name":"authentik-web-assets"}}]
script=("set -e\n cp -r /web/dist/. /wd/\n cp /assets/dezky-logo.svg /wd/assets/icons/dezky-logo.svg\n"
" cp /assets/dezky-bg.svg /wd/assets/icons/dezky-bg.svg\n cp /assets/dezky-favicon.svg /wd/assets/icons/dezky-favicon.svg\n"
" grep -rl 'Powered by authentik' /wd --include='*.js' | while read f; do sed -i 's/Powered by authentik/Powered by Dezky/g' \"$f\"; done\n echo rebrand-done")
ic=[c for c in spec.get("initContainers",[]) if c.get("name")!="dezky-rebrand"]
ic.append({"name":"dezky-rebrand","image":img,"command":["sh","-c",script],"volumeMounts":[{"name":"webdist","mountPath":"/wd"},{"name":"webassets","mountPath":"/assets"}]})
spec["initContainers"]=ic
c0=spec["containers"][0]
c0["volumeMounts"]=[m for m in c0.get("volumeMounts",[]) if m.get("name")!="webdist"]
c0["volumeMounts"].append({"name":"webdist","mountPath":"/web/dist"})
json.dump(d,sys.stdout)
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080"><rect width="1920" height="1080" fill="#0A0A0A"/></svg>

After

Width:  |  Height:  |  Size: 123 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><rect width="64" height="64" rx="16" fill="#F4F3EE"/><text x="31" y="48" font-family="Arial,Helvetica,sans-serif" font-size="46" font-weight="700" fill="#0A0A0A" text-anchor="middle">d</text><circle cx="50" cy="15" r="6.5" fill="#D4FF3A"/></svg>

After

Width:  |  Height:  |  Size: 329 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="190" height="52" viewBox="0 0 190 52"><rect x="2" y="2" width="48" height="48" rx="14" fill="#F4F3EE"/><text x="26" y="39" font-family="Arial,Helvetica,sans-serif" font-size="34" font-weight="700" fill="#0A0A0A" text-anchor="middle">d</text><circle cx="41" cy="13" r="5" fill="#D4FF3A"/><text x="62" y="37" font-family="Arial,Helvetica,sans-serif" font-size="30" font-weight="700" fill="#F4F3EE">dezky</text></svg>

After

Width:  |  Height:  |  Size: 462 B