diff --git a/DEPLOY.md b/DEPLOY.md index 2fbe9ab..6cc6daf 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -314,12 +314,13 @@ tailnet's policy is allow-all, so this is the step that makes "Tailscale identity is the access control" true rather than aspirational. Tailscale has no `deny`, so a restriction is expressed by removing the blanket -`accept` and enumerating what is left. That only works if the browser machine -can be *excluded* from a selector that still covers your own devices — which is +grant and enumerating what is left. That only works if the browser machine can +be *excluded* from a selector that still covers your own devices — which is what tagging buys: a tagged device has no user, so `autogroup:member` and `autogroup:self` stop matching it. Tagging is the mechanism, not decoration. -In the admin console, under **Access controls**, replace the default rule: +In the admin console, under **Access controls**, the shipped policy grants +`{"src": ["*"], "dst": ["*"], "ip": ["*"]}`. Replace it: ```jsonc { @@ -329,24 +330,44 @@ In the admin console, under **Access controls**, replace the default rule: "tag:bookmark-browser": [], }, - "acls": [ + "grants": [ // The only thing on the tailnet that may drive the browser. { - "action": "accept", - "src": ["tag:bookmark-api"], - "proto": "tcp", - "dst": ["tag:bookmark-browser:9222"], + "src": ["tag:bookmark-api"], + "dst": ["tag:bookmark-browser"], + "ip": ["tcp:9222"], }, - // Your own devices: everything of yours, both servers — but not CDP. - // Drop the `:22` and you have locked yourself out of the browser machine. + // Your own devices reach your own devices, and the VPS, in full. { - "action": "accept", + "src": ["autogroup:member"], + "dst": ["autogroup:self", "tag:bookmark-api"], + "ip": ["*"], + }, + // On the browser machine you get SSH and nothing else. Widen this to `*` + // and the restriction above is void; delete it and you are locked out. + { + "src": ["autogroup:member"], + "dst": ["tag:bookmark-browser"], + "ip": ["tcp:22"], + }, + // Uncomment if you route traffic through an exit node — dropping the + // blanket grant takes exit-node access with it. + // {"src": ["autogroup:member"], "dst": ["autogroup:internet"], "ip": ["*"]}, + ], + + // Tagged devices left `autogroup:self`, so Tailscale SSH needs them named. + // Irrelevant if you reach these boxes with ordinary sshd over the tailnet — + // that is the `tcp:22` grant above. + "ssh": [ + { + "action": "check", "src": ["autogroup:member"], - "dst": ["autogroup:self:*", "tag:bookmark-api:*", "tag:bookmark-browser:22"], + "dst": ["autogroup:self", "tag:bookmark-api", "tag:bookmark-browser"], + "users": ["autogroup:nonroot", "root"], }, ], - // Saved policies are rejected if these fail, so the rule cannot rot silently. + // Run on every save, so a later edit that reopens 9222 is rejected outright. "tests": [ { "src": "tag:bookmark-api", "accept": ["tag:bookmark-browser:9222"] }, {