mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			177 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # ACLs use case example
 | |
| 
 | |
| Let's build an example use case for a small business (It may be the place where
 | |
| ACL's are the most useful).
 | |
| 
 | |
| We have a small company with a boss, an admin, two developers and an intern.
 | |
| 
 | |
| The boss should have access to all servers but not to the user's hosts. Admin
 | |
| should also have access to all hosts except that their permissions should be
 | |
| limited to maintaining the hosts (for example purposes). The developers can do
 | |
| anything they want on dev hosts but only watch on productions hosts. Intern
 | |
| can only interact with the development servers.
 | |
| 
 | |
| There's an additional server that acts as a router, connecting the VPN users
 | |
| to an internal network `10.20.0.0/16`. Developers must have access to those
 | |
| internal resources.
 | |
| 
 | |
| Each user have at least a device connected to the network and we have some
 | |
| servers.
 | |
| 
 | |
| - database.prod
 | |
| - database.dev
 | |
| - app-server1.prod
 | |
| - app-server1.dev
 | |
| - billing.internal
 | |
| - router.internal
 | |
| 
 | |
| 
 | |
| 
 | |
| ## ACL setup
 | |
| 
 | |
| Note: Namespaces will be created automatically when users authenticate with the
 | |
| Headscale server.
 | |
| 
 | |
| ACLs could be written either on [huJSON](https://github.com/tailscale/hujson)
 | |
| or YAML. Check the [test ACLs](../tests/acls) for further information.
 | |
| 
 | |
| When registering the servers we will need to add the flag
 | |
| `--advertise-tags=tag:<tag1>,tag:<tag2>`, and the user (namespace) that is
 | |
| registering the server should be allowed to do it. Since anyone can add tags to
 | |
| a server they can register, the check of the tags is done on headscale server
 | |
| and only valid tags are applied. A tag is valid if the namespace that is
 | |
| registering it is allowed to do it.
 | |
| 
 | |
| Here are the ACL's to implement the same permissions as above:
 | |
| 
 | |
| ```json
 | |
| {
 | |
|   // groups are collections of users having a common scope. A user can be in multiple groups
 | |
|   // groups cannot be composed of groups
 | |
|   "groups": {
 | |
|     "group:boss": ["boss"],
 | |
|     "group:dev": ["dev1", "dev2"],
 | |
|     "group:admin": ["admin1"],
 | |
|     "group:intern": ["intern1"]
 | |
|   },
 | |
|   // tagOwners in tailscale is an association between a TAG and the people allowed to set this TAG on a server.
 | |
|   // This is documented [here](https://tailscale.com/kb/1068/acl-tags#defining-a-tag)
 | |
|   // and explained [here](https://tailscale.com/blog/rbac-like-it-was-meant-to-be/)
 | |
|   "tagOwners": {
 | |
|     // the administrators can add servers in production
 | |
|     "tag:prod-databases": ["group:admin"],
 | |
|     "tag:prod-app-servers": ["group:admin"],
 | |
| 
 | |
|     // the boss can tag any server as internal
 | |
|     "tag:internal": ["group:boss"],
 | |
| 
 | |
|     // dev can add servers for dev purposes as well as admins
 | |
|     "tag:dev-databases": ["group:admin", "group:dev"],
 | |
|     "tag:dev-app-servers": ["group:admin", "group:dev"]
 | |
| 
 | |
|     // interns cannot add servers
 | |
|   },
 | |
|   // hosts should be defined using its IP addresses and a subnet mask.
 | |
|   // to define a single host, use a /32 mask. You cannot use DNS entries here,
 | |
|   // as they're prone to be hijacked by replacing their IP addresses.
 | |
|   // see https://github.com/tailscale/tailscale/issues/3800 for more information.
 | |
|   "Hosts": {
 | |
|     "postgresql.internal": "10.20.0.2/32",
 | |
|     "webservers.internal": "10.20.10.1/29"
 | |
|   },
 | |
|   "acls": [
 | |
|     // boss have access to all servers
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["group:boss"],
 | |
|       "dst": [
 | |
|         "tag:prod-databases:*",
 | |
|         "tag:prod-app-servers:*",
 | |
|         "tag:internal:*",
 | |
|         "tag:dev-databases:*",
 | |
|         "tag:dev-app-servers:*"
 | |
|       ]
 | |
|     },
 | |
| 
 | |
|     // admin have only access to administrative ports of the servers, in tcp/22
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["group:admin"],
 | |
|       "proto": "tcp",
 | |
|       "dst": [
 | |
|         "tag:prod-databases:22",
 | |
|         "tag:prod-app-servers:22",
 | |
|         "tag:internal:22",
 | |
|         "tag:dev-databases:22",
 | |
|         "tag:dev-app-servers:22"
 | |
|       ]
 | |
|     },
 | |
| 
 | |
|     // we also allow admin to ping the servers
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["group:admin"],
 | |
|       "proto": "icmp",
 | |
|       "dst": [
 | |
|         "tag:prod-databases:*",
 | |
|         "tag:prod-app-servers:*",
 | |
|         "tag:internal:*",
 | |
|         "tag:dev-databases:*",
 | |
|         "tag:dev-app-servers:*"
 | |
|       ]
 | |
|     },
 | |
| 
 | |
|     // developers have access to databases servers and application servers on all ports
 | |
|     // they can only view the applications servers in prod and have no access to databases servers in production
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["group:dev"],
 | |
|       "dst": [
 | |
|         "tag:dev-databases:*",
 | |
|         "tag:dev-app-servers:*",
 | |
|         "tag:prod-app-servers:80,443"
 | |
|       ]
 | |
|     },
 | |
|     // developers have access to the internal network through the router.
 | |
|     // the internal network is composed of HTTPS endpoints and Postgresql
 | |
|     // database servers. There's an additional rule to allow traffic to be
 | |
|     // forwarded to the internal subnet, 10.20.0.0/16. See this issue
 | |
|     // https://github.com/juanfont/headscale/issues/502
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["group:dev"],
 | |
|       "dst": ["10.20.0.0/16:443,5432", "router.internal:0"]
 | |
|     },
 | |
| 
 | |
|     // servers should be able to talk to database in tcp/5432. Database should not be able to initiate connections to
 | |
|     // applications servers
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["tag:dev-app-servers"],
 | |
|       "proto": "tcp",
 | |
|       "dst": ["tag:dev-databases:5432"]
 | |
|     },
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["tag:prod-app-servers"],
 | |
|       "dst": ["tag:prod-databases:5432"]
 | |
|     },
 | |
| 
 | |
|     // interns have access to dev-app-servers only in reading mode
 | |
|     {
 | |
|       "action": "accept",
 | |
|       "src": ["group:intern"],
 | |
|       "dst": ["tag:dev-app-servers:80,443"]
 | |
|     },
 | |
| 
 | |
|     // We still have to allow internal namespaces communications since nothing guarantees that each user have
 | |
|     // their own namespaces.
 | |
|     { "action": "accept", "src": ["boss"], "dst": ["boss:*"] },
 | |
|     { "action": "accept", "src": ["dev1"], "dst": ["dev1:*"] },
 | |
|     { "action": "accept", "src": ["dev2"], "dst": ["dev2:*"] },
 | |
|     { "action": "accept", "src": ["admin1"], "dst": ["admin1:*"] },
 | |
|     { "action": "accept", "src": ["intern1"], "dst": ["intern1:*"] }
 | |
|   ]
 | |
| }
 | |
| ```
 |