Skip to content

Refactor client auth to init container and add policy hot reloading#7

Open
tekulvw wants to merge 15 commits intoKapernikov:mainfrom
tekulvw:tekulvw/improvements
Open

Refactor client auth to init container and add policy hot reloading#7
tekulvw wants to merge 15 commits intoKapernikov:mainfrom
tekulvw:tekulvw/improvements

Conversation

@tekulvw
Copy link
Copy Markdown

@tekulvw tekulvw commented Feb 4, 2026

Summary

  • Replaced Helm hook Job for client authkey creation with an init container in the client deployment, eliminating race conditions and simplifying the deployment lifecycle
  • Added k8s-sidecar for watching policy ConfigMap changes, enabling hot reloading of ACL policies without pod restarts
  • Made ACL policy always deployed and fully configurable via values.yaml with sensible defaults (SSH blocked by default)

Changes

Client Deployment

  • Moved authkey generation from a post-install/post-upgrade Job into an init container
  • Authkey is now written to an emptyDir volume shared with the main container
  • Removed secrets RBAC permissions (no longer storing authkey as a Secret)

Policy Management

  • Added kiwigrid/k8s-sidecar as a restartable init container to watch for policy ConfigMap updates
  • Policy ConfigMap is now always created (previously only when advertiseRoutes was configured)
  • Policy path changed to /etc/headscale/policy/policy.json to support sidecar volume mounting
  • Added policy section to values.yaml with configurable tagOwners, autoApprovers, and ssh settings
  • SSH access is blocked by default for security

Service Account

  • Simplified serviceAccountName helper template
  • Added Role/RoleBinding for main deployment to read ConfigMaps (required for policy sidecar)

@kervel
Copy link
Copy Markdown
Contributor

kervel commented Feb 10, 2026

Hello,

Thanks for your changes! I noticed a couple of things however.

  • Seems the option to disable service account creation and rely on an existing service account ({{- if .Values.serviceAccount.create -}} ) is gone. It is not uncommon for service account creation to be blocked.

  • when client.enabled is false, i don't think it makes sense to create the policy configmap (policy.path is also not set in that case). and you don't need the watch job enabled (and the RBAC to make the job run). or do you use the policy for other things besides configuration for the in-cluster client ?

  • The version of kiwigrid/k8s-sidecar must be pinned to a specific version to avoid backwards incompatible changes from sneaking in.

Thanks!
Frank

@kervel
Copy link
Copy Markdown
Contributor

kervel commented Feb 17, 2026

hey @tekulvw ! are you still planning to work on this or should i try incorporating the changes myself ..

@kervel
Copy link
Copy Markdown
Contributor

kervel commented Feb 26, 2026

hello!
the init container is now part of main. the policy hot reloading not yet. if you feel like rebasing or creating a smaller pr that would be great

kervel pushed a commit that referenced this pull request Mar 5, 2026
When policy.hotReload.enabled is true, a kiwigrid/k8s-sidecar runs as a
native sidecar (restartable init container) that watches for ConfigMap
changes labeled headscale-policy=true, syncing policy updates into the
pod without requiring a restart. Disabled by default so users with
Stakater Reloader or similar can continue using their existing setup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kervel kervel mentioned this pull request Mar 5, 2026
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants