Ship policy.hujson (mounted + installed on first deploy, edits preserved) and wire policy.mode=file / policy.path in config.yaml. Translate the Tailscale "grants" default into headscale's legacy "acls" format (self-access, tag:shared, Tailscale SSH), since headscale 0.28 doesn't support grants. Embed in deploy.sh and document `headscale policy check`.
50 lines
1.9 KiB
Plaintext
50 lines
1.9 KiB
Plaintext
// headscale ACL policy (HuJSON: JSON with // comments and trailing commas).
|
|
//
|
|
// IMPORTANT: headscale uses Tailscale's *legacy* policy format -- the top-level
|
|
// "acls" array -- NOT the newer "grants" syntax from the Tailscale admin
|
|
// console. This file is the grants-style default translated into "acls".
|
|
//
|
|
// Edit, then:
|
|
// headscale policy check # validate (uses the wrapper)
|
|
// docker compose restart headscale # apply (policy mode = file)
|
|
//
|
|
// A few features here (autogroup:self, the ssh block) are newer/experimental
|
|
// in headscale and may depend on your version. If headscale rejects this
|
|
// policy at start, switch to the permissive fallback at the bottom.
|
|
{
|
|
// Static user groups, e.g. "group:admins": ["alice@example.com"].
|
|
"groups": {},
|
|
|
|
// Who may apply which tags to devices.
|
|
"tagOwners": {
|
|
// tag:shared -- a device any member is allowed to reach.
|
|
"tag:shared": ["autogroup:member"],
|
|
},
|
|
|
|
// Network access rules (first match wins; default-deny otherwise).
|
|
"acls": [
|
|
// Each user can reach their own devices, on all ports.
|
|
{ "action": "accept", "src": ["autogroup:member"], "dst": ["autogroup:self:*"] },
|
|
|
|
// Anyone can reach devices tagged tag:shared, on all ports.
|
|
{ "action": "accept", "src": ["*"], "dst": ["tag:shared:*"] },
|
|
],
|
|
|
|
// Tailscale SSH rules (nodes must run `tailscale up --ssh`).
|
|
"ssh": [
|
|
// SSH into your own devices. "check" = periodic browser re-auth (the
|
|
// Tailscale default). Use "accept" if your headscale lacks check mode.
|
|
{
|
|
"action": "check",
|
|
"src": ["autogroup:member"],
|
|
"dst": ["autogroup:self"],
|
|
"users": ["autogroup:nonroot", "root"],
|
|
},
|
|
],
|
|
|
|
// ---- Permissive fallback ----------------------------------------------
|
|
// Replace the "acls" above with this (and drop "ssh") if the rules are
|
|
// rejected, to allow everything while you iterate:
|
|
// "acls": [ { "action": "accept", "src": ["*"], "dst": ["*:*"] } ],
|
|
}
|