diff --git a/config-example.yaml b/config-example.yaml index 2579603f..6cd529c5 100644 --- a/config-example.yaml +++ b/config-example.yaml @@ -281,15 +281,15 @@ log: format: text ## Policy -# headscale supports Tailscale's ACL policies. -# Please have a look to their KB to better -# understand the concepts: https://tailscale.com/docs/features/access-control/acls +# Headscale supports a wide range of Tailscale policy features such as ACLs and +# Grants. Please have a look at their docs to better understand the concepts: +# ACLs: https://tailscale.com/docs/features/access-control/acls +# Grants: https://tailscale.com/docs/features/access-control/grants policy: # The mode can be "file" or "database" that defines - # where the ACL policies are stored and read from. + # where the policies are stored and read from. mode: file - # If the mode is set to "file", the path to a - # HuJSON file containing ACL policies. + # If the mode is set to "file", the path to a HuJSON file containing policies. path: "" ## DNS diff --git a/docs/about/faq.md b/docs/about/faq.md index faf1c4aa..a7cb8453 100644 --- a/docs/about/faq.md +++ b/docs/about/faq.md @@ -191,7 +191,7 @@ following steps can be used to migrate from unsupported IP prefixes back to the SET ipv4=concat('100.64.', id/256, '.', id%256), ipv6=concat('fd7a:115c:a1e0::', format('%x', id)); ``` -- Update the [policy](../ref/acls.md) to reflect the IP address changes (if any) +- Update the [policy](../ref/policy.md) to reflect the IP address changes (if any) - Start Headscale Nodes should reconnect within a few seconds and pickup their newly assigned IP addresses. diff --git a/docs/assets/images/headscale-acl-network.png b/docs/assets/images/headscale-acl-network.png deleted file mode 100644 index 37b64f96..00000000 Binary files a/docs/assets/images/headscale-acl-network.png and /dev/null differ diff --git a/docs/ref/acls.md b/docs/ref/acls.md deleted file mode 100644 index 76fd924d..00000000 --- a/docs/ref/acls.md +++ /dev/null @@ -1,295 +0,0 @@ -Headscale implements the same policy ACLs as Tailscale.com, adapted to the self-hosted environment. - -For instance, instead of referring to users when defining groups you must -use users (which are the equivalent to user/logins in Tailscale.com). - -Please check [manage permissions using ACLs](https://tailscale.com/docs/features/access-control/acls) for further -information. - -When using ACL's the User borders are no longer applied. All machines -whichever the User have the ability to communicate with other hosts as -long as the ACL's permits this exchange. - -## ACL Setup - -To enable and configure ACLs in Headscale, you need to specify the path to your ACL policy file in the `policy.path` key in `config.yaml`. - -Your ACL policy file must be formatted using [huJSON](https://github.com/tailscale/hujson). - -Info on how these policies are written can be found in [Tailscale's ACL -documentation](https://tailscale.com/docs/features/access-control/acls). - -Please reload or restart Headscale after updating the ACL file. Headscale may be reloaded either via its systemd service -(`sudo systemctl reload headscale`) or by sending a SIGHUP signal (`sudo kill -HUP $(pidof headscale)`) to the main -process. Headscale logs the result of ACL policy processing after each reload. - -## Simple Examples - -- [**Allow All**](https://tailscale.com/docs/reference/examples/acls#allow-all-default-acl): If you define an ACL file but completely omit the `"acls"` field from its content, Headscale will default to an "allow all" policy. This means all devices connected to your tailnet will be able to communicate freely with each other. - - ```json - {} - ``` - -- [**Deny All**](https://tailscale.com/docs/reference/examples/acls#deny-all): To prevent all communication within your tailnet, you can include an empty array for the `"acls"` field in your policy file. - - ```json - { - "acls": [] - } - ``` - -## Complex Example - -Let's build a more complex 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 implementation example](../assets/images/headscale-acl-network.png) - -When [registering the servers](../usage/getting-started.md#register-a-node) we -will need to add the flag `--advertise-tags=tag:,tag:`, and the user -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 user that is -registering it is allowed to do it. - -Here are the ACL's to implement the same permissions as above: - -```json title="acl.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/docs/features/tags) - // 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. - { - "action": "accept", - "src": ["group:dev"], - "dst": ["10.20.0.0/16:443,5432"] - }, - - // 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"] - }, - - // Allow users to access their own devices using autogroup:self (see below for more details about performance impact) - { - "action": "accept", - "src": ["autogroup:member"], - "dst": ["autogroup:self:*"] - } - ] -} -``` - -## Autogroups - -Headscale supports several autogroups that automatically include users, destinations, or devices with specific properties. Autogroups provide a convenient way to write ACL rules without manually listing individual users or devices. - -### `autogroup:internet` - -Allows access to the internet through [exit nodes](routes.md#exit-node). Can only be used in ACL destinations. - -```json -{ - "action": "accept", - "src": ["group:users"], - "dst": ["autogroup:internet:*"] -} -``` - -### `autogroup:member` - -Includes all [personal (untagged) devices](registration.md/#identity-model). - -```json -{ - "action": "accept", - "src": ["autogroup:member"], - "dst": ["tag:prod-app-servers:80,443"] -} -``` - -### `autogroup:tagged` - -Includes all devices that [have at least one tag](registration.md/#identity-model). - -```json -{ - "action": "accept", - "src": ["autogroup:tagged"], - "dst": ["tag:monitoring:9090"] -} -``` - -### `autogroup:self` - -!!! warning "The current implementation of `autogroup:self` is inefficient" - -Includes devices where the same user is authenticated on both the source and destination. Does not include tagged devices. Can only be used in ACL destinations. - -```json -{ - "action": "accept", - "src": ["autogroup:member"], - "dst": ["autogroup:self:*"] -} -``` - -*Using `autogroup:self` may cause performance degradation on the Headscale coordinator server in large deployments, as filter rules must be compiled per-node rather than globally and the current implementation is not very efficient.* - -If you experience performance issues, consider using more specific ACL rules or limiting the use of `autogroup:self`. - -```json -{ - // The following rules allow internal users to communicate with their - // own nodes in case autogroup:self is causing performance issues. - { "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@:*"] } -} -``` - -### `autogroup:nonroot` - -Used in Tailscale SSH rules to allow access to any user except root. Can only be used in the `users` field of SSH rules. - -```json -{ - "action": "accept", - "src": ["autogroup:member"], - "dst": ["autogroup:self"], - "users": ["autogroup:nonroot"] -} -``` - -### `autogroup:danger-all` - -This autogroup resolves to all IP addresses (`0.0.0.0/0` and `::/0`) which also includes all IP addresses outside the -standard Tailscale IP ranges. [This autogroup can only be used as -source](https://tailscale.com/docs/reference/targets-and-selectors#autogroupdanger-all). diff --git a/docs/ref/policy.md b/docs/ref/policy.md new file mode 100644 index 00000000..10248e76 --- /dev/null +++ b/docs/ref/policy.md @@ -0,0 +1,200 @@ +# Policy + +Headscale implements a large portion of Tailscale's [policy +features](https://tailscale.com/docs/features/tailnet-policy-file), most notably access control based on +[ACLs](https://tailscale.com/docs/features/access-control/acls) and +[Grants](https://tailscale.com/docs/features/access-control/grants) or [Tailscale +SSH](https://tailscale.com/docs/features/tailscale-ssh). See [limitations](#limitations) to learn about missing features +and notable implementation differences between Headscale and Tailscale. + +Headscale uses the same [huJSON](https://github.com/tailscale/hujson) based file format as Tailscale. By default, no +policy is loaded which means that Headscale allows all traffic between nodes. To start using a policy file[^1], specify +its path in the `policy.path` key in the [configuration file](configuration.md). + +Headscale needs to be reloaded to pick up changes to the policy file. Either reload Headscale via its systemd service +(`sudo systemctl reload headscale`) or by sending a SIGHUP signal (`sudo kill -HUP $(pidof headscale)`) to the main +process. Headscale logs the result of policy processing after each reload. + +Please have a look at Tailscale's policy related documentation to learn more: + +- [Tailscale policy file](https://tailscale.com/docs/features/tailnet-policy-file): A description of supported sections + within the policy file along with links to syntax references for each section. +- [ACLs](https://tailscale.com/docs/features/access-control/acls): How to configure access control using ACLs. +- [Grants](https://tailscale.com/docs/features/access-control/grants): Introduction to Grants with links to [syntax + reference](https://tailscale.com/docs/reference/syntax/grants), + [examples](https://tailscale.com/docs/reference/examples/grants) and a [migration guide from ACLs to + Grants](https://tailscale.com/docs/reference/migrate-acls-grants). + +## Getting started + +Headscale supports both [ACLs](https://tailscale.com/docs/features/access-control/acls) and +[Grants](https://tailscale.com/docs/features/access-control/grants) to write an access control policy. We recommend the +use of Grants since ACLs are considered legacy and will not receive new features by Tailscale. + +### Allow All + +If you define a policy file but completely omit the `"acls"` or `"grants"` section, Headscale will default to an [allow +all](https://tailscale.com/docs/reference/examples/acls#allow-all-default-acl) policy. This means all devices connected +to your tailnet will be able to communicate freely with each other. + +```json title="policy.json" +{} +``` + +### Deny All + +To [prevent all communication within your tailnet](https://tailscale.com/docs/reference/examples/acls#deny-all), you can +include an empty array for the `"grants"` section in your policy file. + +```json title="policy.json" +{ + "grants": [] +} +``` + +### More examples + +- See our documentation on [subnet routers](routes.md#subnet-router) and [exit nodes](routes.md#exit-node) to learn how + to restrict their use or how to automatically approve them. +- The Tailscale documentation provides a large collection of configuration examples: + - [ACL examples](https://tailscale.com/docs/reference/examples/acls) + - [Grants examples](https://tailscale.com/docs/reference/examples/grants) + - [SSH configuration](https://tailscale.com/docs/features/tailscale-ssh#configure-tailscale-ssh) + - [Define a tag](https://tailscale.com/docs/features/tags#define-a-tag) + +______________________________________________________________________ + +## Limitations + +- [Device postures](https://tailscale.com/docs/features/device-posture) and the related sections such as `postures` or + `srcPosture` aren't supported. +- [IP sets](https://tailscale.com/docs/features/tailnet-policy-file/ip-sets) aren't supported. +- A subset of [Autogroups](#autogroups) are available. + +## Autogroups + +Headscale supports several [Autogroups](https://tailscale.com/docs/reference/targets-and-selectors#autogroups) that +automatically include users, destinations, or devices with specific properties. Autogroups provide a convenient way to +write policy rules without manually listing individual users or devices. + +### [`autogroup:internet`](https://tailscale.com/docs/reference/targets-and-selectors#autogroupinternet) + +Allows access to the internet through [exit nodes](routes.md#exit-node). Can only be used in policy destinations. + +```json title="policy.json" +{ + "grants": [ + { + "src": ["alice@"], + "dst": ["autogroup:internet"], + "ip": ["*"] + } + ] +} +``` + +### [`autogroup:member`](https://tailscale.com/docs/reference/targets-and-selectors#autogrouprole) + +Includes all [personal (untagged) devices](registration.md/#identity-model). + +```json title="policy.json" +{ + "grants": [ + { + "src": ["autogroup:member"], + "dst": ["tag:prod-app-servers"], + "ip": ["80,443"] + } + ] +} +``` + +### [`autogroup:tagged`](https://tailscale.com/docs/reference/targets-and-selectors#autogrouptagged) + +Includes all devices that [have at least one tag](registration.md/#identity-model). + +```json title="policy.json" +{ + "grants": [ + { + "src": ["autogroup:tagged"], + "dst": ["tag:monitoring"], + "ip": ["9090"] + } + ] +} +``` + +### [`autogroup:self`](https://tailscale.com/docs/reference/targets-and-selectors#autogroupself) + +Includes devices where the same user is authenticated on both the source and destination. Does not include tagged +devices. Can only be used in policy destinations. + +```json title="policy.json" +{ + "grants": [ + { + "src": ["autogroup:member"], + "dst": ["autogroup:self"], + "ip": ["*"] + } + ] +} +``` + +!!! warning "The current implementation of `autogroup:self` is inefficient" + + Using `autogroup:self` may cause performance degradation on the Headscale coordinator server in large deployments, + as filter rules must be compiled per-node rather than globally and the current implementation is not very efficient. + + If you experience performance issues, consider using more specific policy rules or limiting the use of + `autogroup:self`. + + ```json title="policy.json" + { + "grants": [ + // The following rules allow internal users to communicate with their + // own nodes in case autogroup:self is causing performance issues. + { + "src": ["boss@"], + "dst": ["boss@"], + "ip": "*" + }, + { + "src": ["dev1@"], + "dst": ["dev1@"], + "ip": "*" + }, + { + "src": ["intern1@"], + "dst": ["intern1@"], + "ip": "*" + } + ] + } + ``` + +### [`autogroup:nonroot`](https://tailscale.com/docs/reference/targets-and-selectors#other-built-in-targets) + +Used in Tailscale SSH rules to allow access to any user except root. Can only be used in the `users` field of SSH rules. + +```json title="policy.json" +{ + "ssh": [ + { + "action": "accept", + "src": ["autogroup:member"], + "dst": ["autogroup:self"], + "users": ["autogroup:nonroot"] + } + ] +} +``` + +### [`autogroup:danger-all`](https://tailscale.com/docs/reference/targets-and-selectors#autogroupdanger-all) + +This autogroup resolves to all IP addresses (`0.0.0.0/0` and `::/0`) which also includes all IP addresses outside the +standard Tailscale IP ranges. This autogroup can only be used as source. + +[^1]: Headscale also allows to store the policy in the database. This is typically only required in case a [web + interface](integration/web-ui.md) is used. diff --git a/docs/ref/registration.md b/docs/ref/registration.md index 0cc91067..cc8fd0e7 100644 --- a/docs/ref/registration.md +++ b/docs/ref/registration.md @@ -61,8 +61,8 @@ headscale users create === "Tagged devices" Your Headscale user needs to be authorized to register tagged devices. This authorization is specified in the - [`tagOwners`](https://tailscale.com/docs/reference/syntax/policy-file#tag-owners) section of the [ACL](acls.md). A - simple example looks like this: + [`tagOwners`](https://tailscale.com/docs/reference/syntax/policy-file#tag-owners) section of the + [policy](policy.md). A simple example looks like this: ```json title="The user alice can register nodes tagged with tag:server" { diff --git a/mkdocs.yml b/mkdocs.yml index 99d48a4d..69450523 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -77,7 +77,8 @@ plugins: - social: {} - redirects: redirect_maps: - acls.md: ref/acls.md + acls.md: ref/policy.md + ref/acls.md: ref/policy.md android-client.md: usage/connect/android.md apple-client.md: usage/connect/apple.md dns-records.md: ref/dns.md @@ -184,7 +185,7 @@ nav: - OpenID Connect: ref/oidc.md - Routes: ref/routes.md - TLS: ref/tls.md - - ACLs: ref/acls.md + - Policy: ref/policy.md - DNS: ref/dns.md - DERP: ref/derp.md - API: ref/api.md