<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <docs>https://blogs.law.harvard.edu/tech/rss</docs>
    <title>Envoy-Gateway on Fuchsbau</title>
    <link>https://this-is-fine.io/tags/envoy-gateway/</link>
    <description>Recent content in Envoy-Gateway on Fuchsbau</description>
    <image>
      <title>Envoy-Gateway on Fuchsbau</title>
      <link>https://this-is-fine.io/tags/envoy-gateway/</link>
      <url>https://source.unsplash.com/2000x1322/?fox</url>
    </image>
    <ttl>1440</ttl>
    <generator>Hugo 0.125.4</generator>
    <language>de-DE</language>
    <lastBuildDate>Wed, 20 May 2026 22:26:11 UT</lastBuildDate>
    <atom:link href="https://this-is-fine.io/tags/envoy-gateway/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Pocket ID as the Lab OIDC Provider (Zot Example)</title>
      <link>https://this-is-fine.io/posts/20251122-pocket-id-oidc-zot/</link>
      <pubDate>Sat, 22 Nov 2025 11:00:00 UT</pubDate>
      <dc:creator>ff0x</dc:creator>
      <guid>https://this-is-fine.io/posts/20251122-pocket-id-oidc-zot/</guid>
      <description>Pocket ID is a small OpenID Connect provider — enough for a homelab without Keycloak. The lab runs it at https://auth.this-is-fine.io with Flux and an HTTPRoute on Envoy Gateway. Below is how Zot uses native OpenID against that issuer.
If you already run a homelab IdP, the interesting part is how little application code must change when the app speaks OIDC natively. Zot is a clear example: configure issuer URL, client ID, and redirect URIs, mount a secret, and the registry UI handles login without an OAuth sidecar in front of it.
</description>
      <category domain="https://this-is-fine.io/categories/infrastructure">Infrastructure</category>
      <content:encoded><![CDATA[Pocket ID is a small OpenID Connect provider — enough for a homelab without Keycloak. The lab runs it at https://auth.this-is-fine.io with Flux and an HTTPRoute on Envoy Gateway. Below is how Zot uses native OpenID against that issuer.
If you already run a homelab IdP, the interesting part is how little application code must change when the app speaks OIDC natively. Zot is a clear example: configure issuer URL, client ID, and redirect URIs, mount a secret, and the registry UI handles login without an OAuth sidecar in front of it.
Software map Piece Link Role Pocket ID pocket-id.org Users, OAuth clients, consent UI OIDC primer OpenID Connect Issuer, client_id, redirect URIs Zot OpenID Zot auth Registry login Pocket ID on the cluster browser -&amp;gt; auth.this-is-fine.io -&amp;gt; Pocket ID (PVC-backed) -&amp;gt; /.well-known/openid-configuration Public route on shared-gateway-external; TRUST_PROXY=true behind Cloudflare. Optional VolSync backup for the PVC. Encryption key and client credentials via SOPS, same as other apps. Register each OAuth client in Pocket ID (redirect URL and scopes) before switching the app on. A mismatch on redirect URI is the most common first-login failure; fix it in Pocket ID, not in Zot’s logs alone.
Zot: native OpenID Zot at oci.this-is-fine.io reads OpenID from zot.json — no Envoy OIDC shim for the registry UI.
&amp;#34;openid&amp;#34;: { &amp;#34;providers&amp;#34;: { &amp;#34;oidc&amp;#34;: { &amp;#34;issuer&amp;#34;: &amp;#34;https://auth.this-is-fine.io&amp;#34;, &amp;#34;scopes&amp;#34;: [&amp;#34;openid&amp;#34;, &amp;#34;profile&amp;#34;, &amp;#34;email&amp;#34;] } } } A Kubernetes Secret mounts the client credentials file. htpasswd stays for robots (buildbot, CI); people use SSO. RBAC maps OIDC groups (admins, users) to registry roles.
human -&amp;gt; oci.this-is-fine.io -&amp;gt; redirect -&amp;gt; auth.this-is-fine.io &amp;lt;- authorization code / token automation -&amp;gt; htpasswd or robot account (unchanged) People through Pocket ID; automation through scoped local accounts — a useful split elsewhere too.
Headscale OIDC is on the backlog (Envoy post notes the TODO): the chart already has placeholder environment variables; enabling them means registering another client in Pocket ID and trusting the same issuer URL.
Related Zot vs Harbor Cosign enforcement Lab GitOps Pocket ID: installation, OIDC clients.
]]></content:encoded>
    </item>
    <item>
      <title>Envoy Gateway and the Move from Traefik to Gateway API</title>
      <link>https://this-is-fine.io/posts/20251122-envoy-gateway-headscale-routes/</link>
      <pubDate>Sat, 22 Nov 2025 08:00:00 UT</pubDate>
      <dc:creator>ff0x</dc:creator>
      <guid>https://this-is-fine.io/posts/20251122-envoy-gateway-headscale-routes/</guid>
      <description>The lab used to run Traefik with its own CRDs (IngressRoute, Middleware, and friends). Gateway API standardises routes; Envoy Gateway is the controller here — one Helm install, three shared Gateways, and per-app HTTPRoute resources instead of Traefik-only objects.
Traefik is excellent at the edge, but its CRDs are controller-specific. Moving to Gateway API was less about feature envy and more about portability: the same HTTPRoute can be read by another implementation if you ever switch controllers. Envoy Gateway is the implementation here; the routes stay standard Kubernetes objects.
</description>
      <category domain="https://this-is-fine.io/categories/infrastructure">Infrastructure</category>
      <content:encoded><![CDATA[The lab used to run Traefik with its own CRDs (IngressRoute, Middleware, and friends). Gateway API standardises routes; Envoy Gateway is the controller here — one Helm install, three shared Gateways, and per-app HTTPRoute resources instead of Traefik-only objects.
Traefik is excellent at the edge, but its CRDs are controller-specific. Moving to Gateway API was less about feature envy and more about portability: the same HTTPRoute can be read by another implementation if you ever switch controllers. Envoy Gateway is the implementation here; the routes stay standard Kubernetes objects.
Traefik habits vs Gateway API Traefik Gateway API IngressRoute &#43; entrypoints HTTPRoute &#43; parentRefs on a Gateway listener Per-app TLS / middleware CRDs TLS on the Gateway; filters on HTTPRoute; Envoy policies when needed Traefik host rules hostnames and matches on gateway.networking.k8s.io/v1 Routes stay portable across controllers. Envoy-specific tuning uses gateway.envoyproxy.io (BackendTrafficPolicy, ClientTrafficPolicy, &amp;hellip;).
Three shared gateways Envoy Gateway (Helm) shared-gateway-external *.this-is-fine.io, *.this-is-fine.social Let&amp;#39;s Encrypt, LB .0.1 shared-gateway-internal *.this-is-fine.internal Vault PKI, LB .0.2 shared-gateway-tailnet *.tif.internal Vault PKI, LB .0.3 Pick the gateway by who connects: the internet, lab browsers on the internal CA, or tailnet clients. Templates under k8s/templates/gateway-api/ repeat the same HTTPRoute shape for each class.
Static LoadBalancer IPs (.0.1, .0.2, .0.3) come from a small pool advertised with Cilium BGP. DNS and certificates differ per zone, but the dataplane pattern is the same: one Envoy deployment, several logical gateways, many HTTPRoutes attached to listeners.
Headscale example (public API, private UI) Headscale disables Helm ingress; exposure is all Gateway API.
Surface Hostname Gateway Backend Tailscale clients / API ts.this-is-fine.io shared-gateway-external :8080 Web UI (operators) ts.this-is-fine.internal shared-gateway-internal :8081 (UI sidecar) The external route allows CORS from https://ts.this-is-fine.internal. Control traffic needs WebSocket upgrades; a BackendTrafficPolicy on that HTTPRoute enables tailscale-control-protocol and derp.
Splitting API and UI across external and internal DNS is deliberate. Tailscale clients and the public internet need ts.this-is-fine.io with a certificate browsers and devices trust. Operators can open the same logical service on ts.this-is-fine.internal with the lab’s internal CA, without publishing the admin UI to the open internet.
Public API (lab pattern):
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: headscale-https-external spec: parentRefs: - name: shared-gateway-external namespace: envoy-gateway-system sectionName: this-is-fine-io-https hostnames: - ts.this-is-fine.io rules: - backendRefs: - name: headscale port: 8080 Internal UI — same host label on the internal zone, different listener and port:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: headscale-ui-https-internal spec: parentRefs: - name: shared-gateway-internal namespace: envoy-gateway-system sectionName: this-is-fine-internal-https hostnames: - ts.this-is-fine.internal rules: - backendRefs: - name: headscale port: 8081 Helm sets HEADSCALE_SERVER_URL=https://ts.this-is-fine.io so clients and the UI agree on the public URL while operators open the UI on the internal name.
TODO: connect Pocket ID for Headscale OIDC (HEADSCALE_OIDC_* is stubbed in chart values; not enabled yet). Same backlog as Zeroclaw UI and Vault.
Adding another app Expose the workload with a Service. Attach an HTTPRoute (or TCPRoute) to the right shared-gateway-* and hostname. Let cert-manager issue TLS via the gateway certificateRefs / ClusterIssuers. IRC on port 6697 uses TCPRoute on the public gateway — IRC post. VIPs .0.1–.0.3 are advertised with Cilium BGP. GitOps context: lab overview.
]]></content:encoded>
    </item>
    <item>
      <title>Cluster-Wide Tailscale: Headscale, Tailnet DNS, and Cross-Cluster Routes</title>
      <link>https://this-is-fine.io/posts/20251121-tailscale-headscale-mesh/</link>
      <pubDate>Fri, 21 Nov 2025 09:00:00 UT</pubDate>
      <dc:creator>ff0x</dc:creator>
      <guid>https://this-is-fine.io/posts/20251121-tailscale-headscale-mesh/</guid>
      <description>Tailscale builds a WireGuard mesh with little configuration. Headscale is an open control server for the same clients — you run policy and issue keys yourself. The lab does not use the Tailscale Kubernetes operator; a handful of Deployments and DaemonSets do the job instead.
The goal is one tailnet for laptops and nodes, with Kubernetes APIs and internal HTTP on *.tif.internal without putting those names on the public internet.
Self-hosting the control plane means you own ACL files, preauth keys, and MagicDNS base domains. The trade-off is operational work: upgrades, backups, and policy edits are yours. For a multi-cluster lab that already runs GitOps everywhere else, that trade-off is acceptable.
</description>
      <category domain="https://this-is-fine.io/categories/infrastructure">Infrastructure</category>
      <content:encoded><![CDATA[Tailscale builds a WireGuard mesh with little configuration. Headscale is an open control server for the same clients — you run policy and issue keys yourself. The lab does not use the Tailscale Kubernetes operator; a handful of Deployments and DaemonSets do the job instead.
The goal is one tailnet for laptops and nodes, with Kubernetes APIs and internal HTTP on *.tif.internal without putting those names on the public internet.
Self-hosting the control plane means you own ACL files, preauth keys, and MagicDNS base domains. The trade-off is operational work: upgrades, backups, and policy edits are yours. For a multi-cluster lab that already runs GitOps everywhere else, that trade-off is acceptable.
Read first Piece Docs Headscale headscale.net Talos Tailscale extension Talos network guide Gateway API gateway-api.sigs.k8s.io Envoy Gateway gateway.envoyproxy.io Public control plane URL: ts.this-is-fine.io. MagicDNS suffix: tif.internal.
What joins the mesh Headscale (ts.this-is-fine.io) Talos nodes (Tailscale extension) kube-apiserver-proxy per cluster (TCP 6443 on tailnet) tailnet-dns (pods resolve *.tif.internal) address space: 100.64.0.0/10 kube-apiserver-proxy runs tailscaled and socat. Tailnet clients use hydra-k8s.tif.internal:6443 (pattern: &amp;lt;cluster&amp;gt;-k8s.tif.internal) to reach the cluster API VIP. tailnet-dns forwards *.tif.internal to Headscale MagicDNS from inside the cluster.
Pods do not run a Tailscale sidecar in this design. Workloads that need the Kubernetes API or an internal service use cluster DNS first. The tailnet-dns DaemonSet patches the chain so *.tif.internal resolves the same way your laptop would on the mesh. Egress from the pod still leaves via the node’s tailnet identity, so ACLs must allow that path.
HTTP on the tailnet Attach an HTTPRoute to shared-gateway-tailnet. Example hostname: vault.tif.internal -&amp;gt; Envoy -&amp;gt; Service. TLS comes from in-cluster PKI via cert-manager.
tailnet client (HTTPS) -&amp;gt; vault.tif.internal -&amp;gt; shared-gateway-tailnet -&amp;gt; Service -&amp;gt; Pods Public sites use a different gateway (this-is-fine.io, Let&amp;rsquo;s Encrypt). Keep listeners separate so you do not accidentally expose an internal-only app.
Policy (sketch) Headscale ACLs use tags (k8s-api, fabric, per-cluster node tags) and auto-approved routes for the LoadBalancer slice that fronts the tailnet gateway. Join keys are SOPS-encrypted bootstrap secrets.
Operator UI: ts.this-is-fine.internal on port 8081 through the internal gateway.
Part of the wider GitOps lab. IRC TLS on the public gateway is covered in the IRC post.
]]></content:encoded>
    </item>
  </channel>
</rss>
