Add SSH support to ACLs #285

Closed
opened 2025-12-29 01:26:02 +01:00 by adam · 13 comments
Owner

Originally created by @GrigoriyMikhalkin on GitHub (Jun 23, 2022).

Feature request

Tailscale introduced Tailscale SSH feature, which allows to manage SSH connections as part of tailnet. In particular, user can control SSH access via ACLs. There's new field for that called ssh and here is an example of such config:

{
  "acls": [
    {
      "action": "accept",
      "src": ["*"],
      "dst": ["*:*"]
    }
  ],
  "ssh": [
    {
      "action": "accept",
      "src": ["autogroup:members"],
      "dst": ["autogroup:self"],
      "users": ["root", "autogroup:nonroot"]
    }
  ]
}

Would be great to see support for that in headscale. I would gladly try to help to implement this if this is ok.

Originally created by @GrigoriyMikhalkin on GitHub (Jun 23, 2022). <!-- Headscale is a multinational community across the globe. Our common language is English. Please consider raising the feature request in this language. --> **Feature request** Tailscale introduced [Tailscale SSH](https://tailscale.com/kb/1193/tailscale-ssh/) feature, which allows to manage SSH connections as part of tailnet. In particular, user can control SSH access via ACLs. There's new field for that called `ssh` and here is an example of such config: ``` { "acls": [ { "action": "accept", "src": ["*"], "dst": ["*:*"] } ], "ssh": [ { "action": "accept", "src": ["autogroup:members"], "dst": ["autogroup:self"], "users": ["root", "autogroup:nonroot"] } ] } ``` Would be great to see support for that in `headscale`. I would gladly try to help to implement this if this is ok.
adam added the enhancement label 2025-12-29 01:26:02 +01:00
adam closed this issue 2025-12-29 01:26:02 +01:00
Author
Owner

@juanfont commented on GitHub (Jun 23, 2022):

Hi @GrigoriyMikhalkin, I am looking at it already - but want to merge some big stuff before.

But feel free to try :)

@juanfont commented on GitHub (Jun 23, 2022): Hi @GrigoriyMikhalkin, I am looking at it already - but want to merge some big stuff before. But feel free to try :)
Author
Owner

@db48x commented on GitHub (Jun 26, 2022):

I started on implementing this, but have not yet had a chance to test it. It is at least good enough to let tailscale up --ssh work as long as there is an explicit ACL, so presumably tailscale ssh will work as well. I’ll see if I can make time to test it this coming week, and perhaps continue the work if nobody beats me to it.

@db48x commented on GitHub (Jun 26, 2022): I started on implementing this, but have not yet had a chance to test it. It is at least good enough to let `tailscale up --ssh` work as long as there is an explicit ACL, so presumably `tailscale ssh` will work as well. I’ll see if I can make time to test it this coming week, and perhaps continue the work if nobody beats me to it.
Author
Owner

@Zk2u commented on GitHub (Aug 17, 2022):

@db48x @juanfont any updates on this? this is a pretty important setup step for us to use - happy to sponsor it if that means it gets added faster :)

@Zk2u commented on GitHub (Aug 17, 2022): @db48x @juanfont any updates on this? this is a pretty important setup step for us to use - happy to sponsor it if that means it gets added faster :)
Author
Owner

@juanfont commented on GitHub (Aug 17, 2022):

@617a7a I'll look into it as soon as we have the new protocol fully working

@juanfont commented on GitHub (Aug 17, 2022): @617a7a I'll look into it as soon as we have the new protocol fully working
Author
Owner

@Thunderbottom commented on GitHub (Sep 16, 2022):

@db48x tried the code from your fork, and I can't seem to get it to work even with ACLs explicitly specified, for example, my ACL configuration has:

{
	"groups": {
		"group:example": [
			"example"  // Namespace
		]
	},
	"hosts": {
		"client": "100.64.0.2"
	},
	"acls": [
		{
			"action": "accept",
			"src": ["*"],
			"dst": ["*:*"]
		}
	],
	"ssh": [
		{
			"action": "accept",
			"src": ["autogroup:members"],
			"dst": ["client"],
			"users": ["autogroup:nonroot"]
		}

	]
}

and when I try to connect to the client host with tailscale ssh, I get permission denied (tailscale). Is the current implementation lacking something? If it helps, the logs show me this:

2022-09-16T17:15:16+05:30 TRC ACL rules generated ACL=[{"DstPorts":[{"Bits":null,"IP":"*","Ports
":{"First":0,"Last":65535}}],"IPProto":[1,58,6,17],"SrcIPs":["*"]}]                             
2022-09-16T17:15:16+05:30 TRC SSH rules generated SSH=[{"action":{"accept":true,"allowLocalPortF
orwarding":true},"principals":[{"userLogin":"autogroup:members"}],"sshUsers":{"autogroup:nonroot
":"="}}] 

Let me know if there's anything else you need from me to make this work. Will be more than happy to be of help. Thanks a lot.

@Thunderbottom commented on GitHub (Sep 16, 2022): @db48x tried the code from your fork, and I can't seem to get it to work even with ACLs explicitly specified, for example, my ACL configuration has: ```json { "groups": { "group:example": [ "example" // Namespace ] }, "hosts": { "client": "100.64.0.2" }, "acls": [ { "action": "accept", "src": ["*"], "dst": ["*:*"] } ], "ssh": [ { "action": "accept", "src": ["autogroup:members"], "dst": ["client"], "users": ["autogroup:nonroot"] } ] } ``` and when I try to connect to the `client` host with `tailscale ssh`, I get `permission denied (tailscale)`. Is the current implementation lacking something? If it helps, the logs show me this: ``` 2022-09-16T17:15:16+05:30 TRC ACL rules generated ACL=[{"DstPorts":[{"Bits":null,"IP":"*","Ports ":{"First":0,"Last":65535}}],"IPProto":[1,58,6,17],"SrcIPs":["*"]}] 2022-09-16T17:15:16+05:30 TRC SSH rules generated SSH=[{"action":{"accept":true,"allowLocalPortF orwarding":true},"principals":[{"userLogin":"autogroup:members"}],"sshUsers":{"autogroup:nonroot ":"="}}] ``` Let me know if there's anything else you need from me to make this work. Will be more than happy to be of help. Thanks a lot.
Author
Owner

@restanrm commented on GitHub (Sep 16, 2022):

The autogroup feature is not supported yet, so I don't think you're ACL file can work at all.

@restanrm commented on GitHub (Sep 16, 2022): The `autogroup` feature is not supported yet, so I don't think you're ACL file can work at all.
Author
Owner

@Thunderbottom commented on GitHub (Sep 17, 2022):

Ah, was unaware, the acl docs link to the tailscale website. It even does not work with * as the src. Would it only work with a specified IP/group name?

@Thunderbottom commented on GitHub (Sep 17, 2022): Ah, was unaware, the acl docs link to the tailscale website. It even does not work with `*` as the `src`. Would it only work with a specified IP/group name?
Author
Owner

@db48x commented on GitHub (Sep 17, 2022):

Yes, my implementation is marked as a WIP for a reason. :)

My commit message probably should have been more explicit though; I got just far enough along to get tailscale to connect and no further. If you look at the relevant portion of my commit, you will see that I don’t handle wildcards or any form of group or tag. It will only work with explicit source and destination addresses, as well as explicit user names.

I’ve not yet been afforded any time to continue working on it, but if all goes well then I can sneak in some work on it this coming Friday. Really, the work to support tags and group names is not that difficult; any one of you could probably do it. You just have to look up the tag/group name in Headscale’s list of such and put the corresponding list of explicit addresses or user names into the SSHRules that get built.

@db48x commented on GitHub (Sep 17, 2022): Yes, my implementation is marked as a WIP for a reason. :) My commit message probably should have been more explicit though; I got just far enough along to get tailscale to connect and no further. If you [look at the relevant portion of my commit](https://github.com/headlinevc/headscale/commit/e6c03f65c75e7f263f9bec7acaea45e96dc897bc#diff-8a958d21d2c196a668a4f4a5927eae3b74a0e9be8e483ba7ba22d456cb4fed09R227-R248), you will see that I don’t handle wildcards or any form of group or tag. It will only work with explicit source and destination addresses, as well as explicit user names. I’ve not yet been afforded any time to continue working on it, but if all goes well then I can sneak in some work on it this coming Friday. Really, the work to support tags and group names is not that difficult; any one of you could probably do it. You just have to look up the tag/group name in Headscale’s list of such and put the corresponding list of explicit addresses or user names into the `SSHRule`s that get built.
Author
Owner

@kradalby commented on GitHub (Sep 24, 2023):

SSH support is now implemented as part of the Policy packaged during the codereorg.

@kradalby commented on GitHub (Sep 24, 2023): SSH support is now implemented as part of the Policy packaged during the codereorg.
Author
Owner

@vbrandl commented on GitHub (Sep 30, 2023):

SSH support is now implemented as part of the Policy packaged during the codereorg.

Does this include autogroup?

@vbrandl commented on GitHub (Sep 30, 2023): > SSH support is now implemented as part of the Policy packaged during the codereorg. Does this include `autogroup`?
Author
Owner

@kradalby commented on GitHub (Oct 2, 2023):

No, not yet, that is tracked separately in https://github.com/juanfont/headscale/issues/657.

@kradalby commented on GitHub (Oct 2, 2023): No, not yet, that is tracked separately in https://github.com/juanfont/headscale/issues/657.
Author
Owner

@celevra commented on GitHub (Jul 10, 2025):

if i try to set my acl like this:

{
  "acls": [
    {
      "action": "accept",
      "src": ["*"],
      "dst": ["*:*"]
    }
  ],
  "ssh": [
    {
      "action": "accept",
      "src": ["group:sshusers"],
      "dst": ["hostname"],
      "users": ["root"]
    }
  ]
}

i can't see an error in the logs, but headplane gives me an error

Image

what is the correct format?

@celevra commented on GitHub (Jul 10, 2025): if i try to set my acl like this: ``` { "acls": [ { "action": "accept", "src": ["*"], "dst": ["*:*"] } ], "ssh": [ { "action": "accept", "src": ["group:sshusers"], "dst": ["hostname"], "users": ["root"] } ] } ``` i can't see an error in the logs, but headplane gives me an error <img width="1168" height="392" alt="Image" src="https://github.com/user-attachments/assets/e165b425-8965-4755-bced-2771c5178247" /> what is the correct format?
Author
Owner

@kumraa-1 commented on GitHub (Nov 7, 2025):

if i try to set my acl like this:

{
  "acls": [
    {
      "action": "accept",
      "src": ["*"],
      "dst": ["*:*"]
    }
  ],
  "ssh": [
    {
      "action": "accept",
      "src": ["group:sshusers"],
      "dst": ["hostname"],
      "users": ["root"]
    }
  ]
}

what is the correct format?

https://tailscale.com/kb/1193/tailscale-ssh
The dst can be a user, tag or autogroup. I did it like this:

{
  "groups": {
    "group:admin": ["me@"]
  },

  "tagOwners": {
    "tag:ssh": ["group:admin"]
  },

  "acls": [
    { "action": "accept", "src": ["group:admin"], "dst": ["*:*"] }
  ],

  "ssh": [
    {
      "action": "check",
      "src": ["group:admin"],
      "dst": ["tag:ssh"],
      "users": ["root"]
    }
  ]
}
@kumraa-1 commented on GitHub (Nov 7, 2025): > if i try to set my acl like this: > > ``` > { > "acls": [ > { > "action": "accept", > "src": ["*"], > "dst": ["*:*"] > } > ], > "ssh": [ > { > "action": "accept", > "src": ["group:sshusers"], > "dst": ["hostname"], > "users": ["root"] > } > ] > } > ``` > what is the correct format? https://tailscale.com/kb/1193/tailscale-ssh The dst can be a user, tag or autogroup. I did it like this: ``` { "groups": { "group:admin": ["me@"] }, "tagOwners": { "tag:ssh": ["group:admin"] }, "acls": [ { "action": "accept", "src": ["group:admin"], "dst": ["*:*"] } ], "ssh": [ { "action": "check", "src": ["group:admin"], "dst": ["tag:ssh"], "users": ["root"] } ] } ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/headscale#285