Skip to content
Notifications
Clear all

Anyone else find the ACL docs too abstract? Need concrete scenarios.

6 Posts
6 Users
0 Reactions
1 Views
(@annab)
Estimable Member
Joined: 1 week ago
Posts: 98
Topic starter   [#16787]

Hi everyone, I'm relatively new to Tailscale and networking in general, coming from a marketing automation background. I've been trying to set up proper access controls for our team's setup, but I keep hitting a wall with the official ACL documentation.

The concepts are explained, but I'm struggling to map them to our actual use cases. For example, I want our content writers to reach our staging CMS server, but not our production database. I also need our analytics contractor to access only the Grafana dashboard, and nothing else on that same host. The docs talk about tags and groups, but I can't quite visualize the step-by-step from defining a user to them having the right access.

Could anyone share some concrete, real-world ACL snippets for scenarios like these? Or point me to a guide that walks through common business setups? I think seeing a few complete, working examples would help me and probably others connect the abstract rules to our actual network.



   
Quote
(@carolp)
Estimable Member
Joined: 1 week ago
Posts: 89
 

The docs are thin on examples. Here's a rough translation for your staging CMS scenario.

First, tag your servers in the admin console: `tag:staging-cms`, `tag:prod-db`.
Tag your users: `tag:content-writer`.

Then your ACL file has the actual rules:

```
// Content writers to staging CMS only
{
"action": "accept",
"src": ["tag:content-writer"],
"dst": ["tag:staging-cms:80", "tag:staging-cms:443"],
},
// Explicitly deny everything else for that group
{
"action": "accept",
"src": ["tag:content-writer"],
"dst": ["tag:prod-db:*"],
},
```

The contractor-only-to-Grafana one is trickier if Grafana is on a general app host. You'll need to use port specifications in the `dst` field like `"host:3000"` and a deny-all-other-ports rule for that contractor tag. The order of rules matters, put the specific port allow before a broader deny.

Try it in the policy simulator first.


—cp


   
ReplyQuote
(@darrenk)
Estimable Member
Joined: 1 week ago
Posts: 103
 

Totally agree, the leap from concepts to config is tough. For your Grafana example, you need two rules: one allowing the contractor tag to `your-host:3000`, and another explicitly denying that same tag to `your-host:*`. The deny rule must come AFTER the allow rule in the ACL file, because Tailscale processes them in order. That's the key part the docs don't stress enough.

Also, remember to assign the tags to the actual machines and users in the admin console before the ACL file works. The tags in the file are just references; they need to exist in your Tailscale setup first. I've been bitten by that before.

Hope that makes it a bit more concrete


dk


   
ReplyQuote
(@charlesb)
Estimable Member
Joined: 6 days ago
Posts: 50
 

Careful, your deny rule for the prod database is set to "accept". That'll have the opposite effect you want.

Also, tagging each server individually for every new service sounds like the kind of lock-in Tailscale would warn you about if they weren't selling it. You're building a dependency graph in their console that's non-trivial to export. For something like a contractor on Grafana, I'd be more inclined to stick them on an isolated subnet with a cheap cloud bastion host. Less elegant, but you own the exit strategy.


Beware of free tiers


   
ReplyQuote
(@code_reviewer_anna)
Estimable Member
Joined: 3 months ago
Posts: 122
 

Good catch on the "accept" typo - that's exactly the kind of subtle mistake that ACLs don't forgive. 😅

You've got a fair point about tag sprawl becoming its own maintenance burden. For the contractor scenario, maybe a compromise is tagging the host itself (`tag:grafana-host`) but then using a *port* in the ACL rule as `user800` mentioned, rather than creating a new tag per service. That keeps the tag list manageable while still using Tailscale's strengths for the access control.

The bastion host approach is solid for pure isolation, though you'd lose Tailscale's native auth and audit logging, which for some compliance needs is a bigger downside than the lock-in.


Clean code is not an option, it's a sanity measure.


   
ReplyQuote
(@cipher_blue)
Estimable Member
Joined: 3 months ago
Posts: 132
 

The docs are abstract because they're describing a fundamentally abstract system. What you're asking for - a concrete step-by-step from user to access - is where ACLs get messy in practice.

You don't just define a user. You define a user, tag them, tag the relevant machines, ensure those tags are auto-approved in your ACL policy, and then write rules that correctly sequence port-specific allows before broader denies. And that's before you troubleshoot why a machine didn't inherit its tag.

For your contractor-only-to-Grafana case, the snippet you'd actually need isn't a neat two-liner. You need rules for the contractor tag allowing port 3000, denying all other ports to that host, and also likely denying all other hosts entirely. Then you need to ensure no broader group rule (like `"autogroup:members"`) overrides your careful denies.

The guide you want probably doesn't exist because everyone's "common business setup" is a unique snowflake of technical debt and access panic.



   
ReplyQuote