Update Tailscale ACLs
How to modify Tailscale access control policies for the tailnet.
Prerequisites
- Pulumi (installed and pinned by
mise— seemise.toml) - Pulumi ESC: the tasks run against stack
tail8d86e, whoseblumeops/tailnetenvironment fetches the Tailscale OAuth credentials from thepulumi-esc1Password vault at run time (seepulumi/esc/)
Edit the Policy
The ACL policy lives in pulumi/tailscale/policy.hujson (HuJSON, so
comments are allowed). Its top-level sections are groups, grants
(L4 firewall rules), ssh, sshTests (SSH access rules),
autoApprovers, tagOwners, and tests. The policy uses the modern
grants schema — not the legacy top-level acls key.
pulumi/tailscale/__main__.py feeds the file into a tailscale.Acl
resource, which completely overwrites the tailnet’s ACL on every apply
— there is no second source of truth.
Add a new grant (firewall rule)
{
"grants": [
// ... existing grants ...
{
"src": ["autogroup:admin"],
"dst": ["tag:newservice"],
"ip": ["tcp:443"]
}
]
}"ip": ["*"] means all ports; otherwise list tcp:PORT / udp:PORT
entries.
Add a new tag
A new tag must be claimable by someone, so add it to tagOwners too
(admins, plus the operator tag if the k8s operator provisions it):
{
"tagOwners": {
// ... existing tags ...
"tag:newservice": ["autogroup:admin", "tag:blumeops"]
}
}Add a new group
{
"groups": {
// ... existing groups ...
"group:newgroup": ["user1@example.com", "user2@example.com"]
}
}Extend the Tests
The tests and sshTests sections encode the invariants that make this
policy safe to apply blindly — e.g. the agent pod reaching nothing except
forge and the heph hub, and homelab→homelab SSH for ansible. When you change a grant
or SSH rule, add or update the matching test entry so a future
regression fails the preview instead of the tailnet.
Preview and Apply
# Preview changes (always do this first)
mise run tailnet-preview
# Apply changes (auto-confirms via --yes)
mise run tailnet-upBoth tasks read the Pulumi access token from 1Password and select the
tail8d86e stack before running pulumi preview / pulumi up; the OAuth
credentials arrive via the stack’s Pulumi ESC environment, which fetches them
from 1Password at run time.
Verify
Check the Tailscale admin console at https://login.tailscale.com/ to
confirm the access rules, then exercise a new grant from a device in the
source group (or from the tests results in the console).
Troubleshooting
“Credential expired” error: The Tailscale OAuth token has lapsed. Re-run the task; the credentials come fresh from 1Password each run.
Changes not taking effect:
ACL changes apply immediately on tailnet-up. If a device isn’t following
new rules, try tailscale down && tailscale up on that device.