trtmn/agent-skills · Archived

tailscale-policy-manager

Expert guide for managing Tailscale tailnet policy files (ACLs). Covers the HuJSON policy file format, all policy sections (acls, groups, tags, SSH rules, autoApprovers, tests), the Tailscale API for validating and applying policies, and GitOps automation via GitHub Actions so changes are automatically validated on PRs and deployed on merge. Use this skill whenever the user is working with Tailscale ACLs or policy files, wants to set up git-based policy management, needs to write or debug acces…

First seen Mar 11, 2026

Installation

$ npx skills add trtmn/agent-skills --skill tailscale-policy-manager

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from trtmn/agent-skills · top by installs.

npx skills add trtmn/agent-skills

Browse all from trtmn/agent-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 1
License LICENSE
Default branch main
Open issues 0
Status Archived

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 7,534 B
  • docs SUMMARY.md 823 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 5 installs

SKILL.md

Tailscale Policy Manager

Tailscale controls who can talk to what on your private network through a single policy file — a HuJSON document you manage in the admin console or, better yet, in a git repository with automated deployment.

Quick orientation

When a user asks about Tailscale policy/ACL work, figure out what they need:

  • Writing or editing rules → start with the policy file structure below, then references/policy-file-reference.md for full details
  • Setting up git-based automation → references/gitops-setup.md
  • Using the API directly → references/api-reference.md
  • Debugging why something isn't allowed → check the tests block section below and the ACL rule syntax

The HuJSON format

Tailscale policy files use HuJSON — standard JSON plus two things:

  • Line comments (//) and block comments (/ /)
  • Trailing commas on the last item in any array or object

This matters because it means you can document your rules inline, which is valuable for a security-sensitive file that multiple people edit.

{
  // Engineers can reach dev servers on any port
  "acls": [
    {
      "action": "accept",
      "src":    ["group:engineering"],
      "dst":    ["tag:dev:*"],  // trailing comma is fine
    },
  ],
}

Core policy file sections

The policy file is deny-by-default. You're always writing rules that explicitly grant access.

groups

Named sets of users. Group names must start with group:.

"groups": {
  "group:engineering": ["[email protected]", "[email protected]"],
  "group:devops":      ["[email protected]"],
},

Groups can't contain other groups. Use email addresses as members.

tagOwners

Tags are labels applied to devices (not users). Tag owners control who can tag devices with that label.

"tagOwners": {
  "tag:prod":    ["autogroup:admin"],    // only admins can tag prod
  "tag:dev":     ["group:engineering"],  // engineers can tag dev machines
  "tag:ci":      ["tag:ci"],             // CI devices can self-tag
},

An empty array [] means only admins can use the tag.

acls

The main access control rules. Each rule grants access — there's no "deny" action because everything not explicitly allowed is denied.

"acls": [
  {
    "action": "accept",
    "src":    ["group:engineering"],
    "dst":    ["tag:dev:22,443"],   // SSH and HTTPS to dev-tagged devices
  },
  {
    "action": "accept",
    "proto":  "tcp",                // optional protocol filter
    "src":    ["tag:monitoring"],
    "dst":    ["tag:prod:9100"],    // Prometheus port on prod
  },
],

Common source/destination values:

  • * — everyone/everything
  • [email protected] — specific user
  • group:name — named group
  • tag:name — tagged devices
  • autogroup:member — all tailnet members
  • autogroup:self — user's own devices
  • autogroup:admin — tailnet admins
  • 100.x.x.x — specific Tailscale IP
  • Hostname defined in hosts section

Port syntax in dst: :22 (single), :80,443 (multiple), :1000-2000 (range), :* (all)

hosts (aliases)

Named shortcuts for IPs and CIDRs:

"hosts": {
  "prod-db":     "100.64.0.10",
  "aws-vpc":     "10.0.0.0/8",
},

Then use prod-db:5432 in ACL rules instead of the raw IP.

ssh

Tailscale SSH rules (requires Tailscale SSH to be enabled on the device):

"ssh": [
  {
    "action": "accept",
    "src":    ["group:engineering"],
    "dst":    ["tag:dev"],
    "users":  ["ubuntu", "autogroup:nonroot"],
  },
  {
    "action":      "check",      // allow but re-authenticate periodically
    "checkPeriod": "8h",
    "src":         ["group:devops"],
    "dst":         ["tag:prod"],
    "users":       ["root", "ubuntu"],
  },
],

action: "check" prompts for re-auth after checkPeriod. Use this for sensitive servers.

autoApprovers

Without this, admins must manually approve every subnet route advertisement. With it, matching devices are approved automatically:

"autoApprovers": {
  "routes": {
    "10.0.0.0/8":   ["tag:vpc-router"],
    "192.168.0.0/16": ["group:network-team"],
  },
  "exitNode": ["tag:exit-node"],
},

tests

Always include tests. They run every time the policy is saved and prevent accidental regressions:

"tests": [
  {
    "src":    "[email protected]",
    "accept": ["tag:dev:22", "tag:staging:443"],
    "deny":   ["tag:prod:22"],          // verify prod is still locked down
  },
  {
    "src":    "tag:ci",
    "accept": ["tag:staging:443"],
    "deny":   ["tag:prod:443"],
  },
],

Tests fail loudly if you accidentally grant too much or too little access — they're your safety net.

ACLs vs Grants

Tailscale is migrating from acls to a newer grants syntax. For new policies, consider grants — it separates the destination host from the port/protocol:

// ACL style (still works, supported forever)
"acls": [
  {"action": "accept", "src": ["group:eng"], "dst": ["tag:web:80,443"]},
]

// Grants style (recommended for new rules)
"grants": [
  {"src": ["group:eng"], "dst": ["tag:web"], "ip": ["tcp:80", "tcp:443"]},
]

You can mix acls and grants in the same file — Tailscale explicitly supports this and recommends it as an incremental migration path. Use grants for new rules while keeping existing acls; both are evaluated together. Only grants will receive new features going forward (like app-layer capabilities and posture checks), but acls are supported indefinitely.

Practical design guidance

Use tags for machines, groups for humans. Tag-based rules survive personnel changes; user-based rules become stale.

Least privilege by default. Don't open :* unless you have a good reason. Be explicit about which ports each service needs.

Document with comments. Policy files are security-critical and reviewed by multiple people. Use comments to explain the intent of non-obvious rules.

Test your denials, not just your allows. The most important tests are the ones that verify locked-down resources stay locked down.

Reference files

For detailed information, read these as needed:

  • references/policy-file-reference.md — Complete field reference, all autogroup values, protocol syntax, grants details, real-world example policies
  • references/gitops-setup.md — Step-by-step GitHub Actions setup, all three auth methods (API key, OAuth, OIDC federated), multi-tailnet patterns, pre-commit hooks
  • references/api-reference.md — Tailscale API endpoints, authentication, ETag-based safe updates, shell scripts for validation and deployment