[Bug] tags and autoApprovers not working #1024

Closed
opened 2025-12-29 02:27:40 +01:00 by adam · 3 comments
Owner

Originally created by @craftyguy on GitHub (May 15, 2025).

Is this a support request?

  • This is not a support request

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

It seems like nodes are not being tagged when configured in an acl, and thus using autoApprovers with tags isn't working either.

Expected Behavior

I expect that routes are added automatically because the node belongs to the infra@ user, and that user is permitted to own tag:routers

Steps To Reproduce

Consider this simple ACL:

{
  "tagOwners": {
    "tag:routers": [
      "infra@"
    ],
  },

  "autoApprovers": {
    "routes": {
      "10.0.10.0/24": ["tag:routers"],
      "10.0.20.0/24": ["tag:routers"]
    },
    "exitNode": ["tag:routers"]
  },
}

I add a node for the infra@ user and advertise tag:routers:

$ tailscale login --login-server=https://example.com \
  --advertise-routes=10.0.10.0/24,10.0.20.0/24 \
  --advertise-tags=tag:routers \
  --advertise-exit-node=true \
  --auth-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The command succeeds, but nothing suggests that it worked:

$ headscale nodes list -t
ID | Hostname | Name   | MachineKey | NodeKey | User   | IP addresses                  | Ephemeral | Last seen           | Expiration | Connected | Expired | ForcedTags | InvalidTags | ValidTags
4  | router   | router | [xxxxx]    | [xxxxx] | infra@ | 100.64.0.1, fd7a:115c:a1e0::1 | false     | 2025-05-15 19:57:30 | N/A        | online    | no      |            |             |

$ headscale nodes list-routes
ID | Hostname | Approved | Available                                   | Serving (Primary)
4  | router   |          | 0.0.0.0/0, 10.0.10.0/24, 10.0.20.0/24, ::/0 |

Environment

- OS: Alpine Linux 3.21, headscale in the latest `stable` docker container
- Headscale version: 0.26
- Tailscale version: 1.82.5

Runtime environment

  • Headscale is behind a (reverse) proxy
  • Headscale runs in a container

Debug information

Headscale log when node is added:

2025-05-15T13:33:52-07:00 DBG Registering node machine_key=[S9eBh] node=router node_key=[1S0Z+] user=infra@
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/db/node.go:489 > Node registered with the database node=router
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > a node sending a MapRequest with Noise protocol node=router node.id=5 omitPeers=true readOnly=false stream=false
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received endpoint update node=router node.id=5 omitPeers=true readOnly=false stream=false
2025-05-15T13:33:52-07:00 TRC PeerChange received disco_key=d:57d59f277419f60a endpoints=["50.39.160.39:41641","10.0.10.1:41641","10.0.20.1:41641","10.0.30.1:41641","10.0.40.1:41641"] hostname=router last_seen=1747341232 node.id=5 online=false
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > a node sending a MapRequest with Noise protocol node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC added new channel node.id=5 open_chans=2
2025-05-15T13:33:52-07:00 INF home/runner/work/headscale/headscale/hscontrol/poll.go:602 > node has connected, mapSession: 0xc000894000, chan: 0xc0002ad5e0 node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received stream update: StateFullUpdate  node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > Sending Full MapResponse node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC finished writing mapresp to node mkey=mkey:4bd78184fcda1a0dd7eaa36aac185c17f7dcc18f03a6cb32f5d7a655fcc9cf2e node=router timeSpent=0.566373
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > update sent node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received stream update: StatePeerChanged  node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > Sending Changed MapResponse:  node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC finished writing mapresp to node mkey=mkey:4bd78184fcda1a0dd7eaa36aac185c17f7dcc18f03a6cb32f5d7a655fcc9cf2e node=router timeSpent=0.150841
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > update sent node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > a node sending a MapRequest with Noise protocol node=router node.id=5 omitPeers=true readOnly=false stream=false
2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received endpoint update node=router node.id=5 omitPeers=true readOnly=false stream=false
2025-05-15T13:33:52-07:00 TRC PeerChange received endpoints=["50.39.160.39:41641","10.0.10.1:41641","10.0.20.1:41641","10.0.30.1:41641","10.0.40.1:41641"] hostinfo_changed=true hostname=router last_seen=1747341232 node.id=5 online=true
2025-05-15T13:33:53-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received stream update: StatePeerChanged  node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:53-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > Sending Changed MapResponse:  node=router node.id=5 omitPeers=false readOnly=false stream=true
2025-05-15T13:33:53-07:00 TRC finished writing mapresp to node mkey=mkey:4bd78184fcda1a0dd7eaa36aac185c17f7dcc18f03a6cb32f5d7a655fcc9cf2e node=router timeSpent=0.10114
2025-05-15T13:33:53-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > update sent node=router node.id=5 omitPeers=false readOnly=false stream=true
Originally created by @craftyguy on GitHub (May 15, 2025). ### Is this a support request? - [x] This is not a support request ### Is there an existing issue for this? - [x] I have searched the existing issues ### Current Behavior It seems like nodes are not being tagged when configured in an acl, and thus using autoApprovers with tags isn't working either. ### Expected Behavior I expect that routes are added automatically because the node belongs to the `infra@` user, and that user is permitted to own `tag:routers` ### Steps To Reproduce Consider this simple ACL: ``` { "tagOwners": { "tag:routers": [ "infra@" ], }, "autoApprovers": { "routes": { "10.0.10.0/24": ["tag:routers"], "10.0.20.0/24": ["tag:routers"] }, "exitNode": ["tag:routers"] }, } ``` I add a node for the `infra@` user and advertise `tag:routers`: ``` $ tailscale login --login-server=https://example.com \ --advertise-routes=10.0.10.0/24,10.0.20.0/24 \ --advertise-tags=tag:routers \ --advertise-exit-node=true \ --auth-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` The command succeeds, but nothing suggests that it worked: ``` $ headscale nodes list -t ID | Hostname | Name | MachineKey | NodeKey | User | IP addresses | Ephemeral | Last seen | Expiration | Connected | Expired | ForcedTags | InvalidTags | ValidTags 4 | router | router | [xxxxx] | [xxxxx] | infra@ | 100.64.0.1, fd7a:115c:a1e0::1 | false | 2025-05-15 19:57:30 | N/A | online | no | | | $ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 4 | router | | 0.0.0.0/0, 10.0.10.0/24, 10.0.20.0/24, ::/0 | ``` ### Environment ```markdown - OS: Alpine Linux 3.21, headscale in the latest `stable` docker container - Headscale version: 0.26 - Tailscale version: 1.82.5 ``` ### Runtime environment - [x] Headscale is behind a (reverse) proxy - [x] Headscale runs in a container ### Debug information Headscale log when node is added: ``` 2025-05-15T13:33:52-07:00 DBG Registering node machine_key=[S9eBh] node=router node_key=[1S0Z+] user=infra@ 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/db/node.go:489 > Node registered with the database node=router 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > a node sending a MapRequest with Noise protocol node=router node.id=5 omitPeers=true readOnly=false stream=false 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received endpoint update node=router node.id=5 omitPeers=true readOnly=false stream=false 2025-05-15T13:33:52-07:00 TRC PeerChange received disco_key=d:57d59f277419f60a endpoints=["50.39.160.39:41641","10.0.10.1:41641","10.0.20.1:41641","10.0.30.1:41641","10.0.40.1:41641"] hostname=router last_seen=1747341232 node.id=5 online=false 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > a node sending a MapRequest with Noise protocol node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC added new channel node.id=5 open_chans=2 2025-05-15T13:33:52-07:00 INF home/runner/work/headscale/headscale/hscontrol/poll.go:602 > node has connected, mapSession: 0xc000894000, chan: 0xc0002ad5e0 node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received stream update: StateFullUpdate node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > Sending Full MapResponse node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC finished writing mapresp to node mkey=mkey:4bd78184fcda1a0dd7eaa36aac185c17f7dcc18f03a6cb32f5d7a655fcc9cf2e node=router timeSpent=0.566373 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > update sent node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received stream update: StatePeerChanged node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > Sending Changed MapResponse: node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC finished writing mapresp to node mkey=mkey:4bd78184fcda1a0dd7eaa36aac185c17f7dcc18f03a6cb32f5d7a655fcc9cf2e node=router timeSpent=0.150841 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > update sent node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > a node sending a MapRequest with Noise protocol node=router node.id=5 omitPeers=true readOnly=false stream=false 2025-05-15T13:33:52-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received endpoint update node=router node.id=5 omitPeers=true readOnly=false stream=false 2025-05-15T13:33:52-07:00 TRC PeerChange received endpoints=["50.39.160.39:41641","10.0.10.1:41641","10.0.20.1:41641","10.0.30.1:41641","10.0.40.1:41641"] hostinfo_changed=true hostname=router last_seen=1747341232 node.id=5 online=true 2025-05-15T13:33:53-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > received stream update: StatePeerChanged node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:53-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > Sending Changed MapResponse: node=router node.id=5 omitPeers=false readOnly=false stream=true 2025-05-15T13:33:53-07:00 TRC finished writing mapresp to node mkey=mkey:4bd78184fcda1a0dd7eaa36aac185c17f7dcc18f03a6cb32f5d7a655fcc9cf2e node=router timeSpent=0.10114 2025-05-15T13:33:53-07:00 TRC home/runner/work/headscale/headscale/hscontrol/poll.go:612 > update sent node=router node.id=5 omitPeers=false readOnly=false stream=true ```
adam added the bug label 2025-12-29 02:27:40 +01:00
adam closed this issue 2025-12-29 02:27:41 +01:00
Author
Owner

@nblock commented on GitHub (May 16, 2025):

I'm unable to reproduce your issue with Headscale 0.26.0 and Tailscale 1.82.5 on a new environment. Sequence of commands used:

Setup Headscale:

$ headscale policy get
{
  "tagOwners": {
    "tag:routers": [
      "infra@"
    ],
  },

  "autoApprovers": {
    "routes": {
      "10.0.10.0/24": ["tag:routers"],
      "10.0.20.0/24": ["tag:routers"]
    },
    "exitNode": ["tag:routers"]
  },
}

$ headscale user create infra

$ headscale preauthkeys create -u 1
32fc629b13c53a75c48c6afc1cfab566e751963472a05574

Register node:

sudo tailscale login --login-server https://headscale.example.com \
  --advertise-routes=10.0.10.0/24,10.0.20.0/24 \
  --advertise-tags=tag:routers \
  --advertise-exit-node=true \
  --auth-key 32fc629b13c53a75c48c6afc1cfab566e751963472a05574

Results in:

$ headscale nodes list-routes
ID | Hostname | Approved                                    | Available                                   | Serving (Primary)                          
1  | n1       | 0.0.0.0/0, 10.0.10.0/24, 10.0.20.0/24, ::/0 | 0.0.0.0/0, 10.0.10.0/24, 10.0.20.0/24, ::/0 | 10.0.10.0/24, 10.0.20.0/24, 0.0.0.0/0, ::/0

Can you please try again?

@nblock commented on GitHub (May 16, 2025): I'm unable to reproduce your issue with Headscale 0.26.0 and Tailscale 1.82.5 on a new environment. Sequence of commands used: Setup Headscale: ```console $ headscale policy get { "tagOwners": { "tag:routers": [ "infra@" ], }, "autoApprovers": { "routes": { "10.0.10.0/24": ["tag:routers"], "10.0.20.0/24": ["tag:routers"] }, "exitNode": ["tag:routers"] }, } $ headscale user create infra $ headscale preauthkeys create -u 1 32fc629b13c53a75c48c6afc1cfab566e751963472a05574 ``` Register node: ```console sudo tailscale login --login-server https://headscale.example.com \ --advertise-routes=10.0.10.0/24,10.0.20.0/24 \ --advertise-tags=tag:routers \ --advertise-exit-node=true \ --auth-key 32fc629b13c53a75c48c6afc1cfab566e751963472a05574 ``` Results in: ```console $ headscale nodes list-routes ID | Hostname | Approved | Available | Serving (Primary) 1 | n1 | 0.0.0.0/0, 10.0.10.0/24, 10.0.20.0/24, ::/0 | 0.0.0.0/0, 10.0.10.0/24, 10.0.20.0/24, ::/0 | 10.0.10.0/24, 10.0.20.0/24, 0.0.0.0/0, ::/0 ``` Can you please try again?
Author
Owner

@craftyguy commented on GitHub (May 16, 2025):

Ok, so this seems to work if I do this:

$ headscale user create infra

But doesn't work when I do this:

$ headscale user create infra@

I added the @ at the end of the username because I saw somewhere (changelog maybe?) that we have to start including a @ character for users... Does this only apply when using usernames in ACLs?

@craftyguy commented on GitHub (May 16, 2025): Ok, so this seems to work if I do this: ``` $ headscale user create infra ``` But doesn't work when I do this: ``` $ headscale user create infra@ ``` I added the `@` at the end of the username because I saw somewhere (changelog maybe?) that we have to start including a `@` character for users... Does this only apply when using usernames in ACLs?
Author
Owner

@craftyguy commented on GitHub (May 16, 2025):

Yup, I totally misunderstood the changelog for 0.26... I'm sorry for the noise :(

If its based on usernames, or other identifiers not containing an @, an @ should be appended at the end. For example, if your user is john, it must be written as john@ in the policy.
@craftyguy commented on GitHub (May 16, 2025): Yup, I totally misunderstood the changelog for 0.26... I'm sorry for the noise :( ``` If its based on usernames, or other identifiers not containing an @, an @ should be appended at the end. For example, if your user is john, it must be written as john@ in the policy. ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/headscale#1024