Compare commits

...

6 Commits

Author SHA1 Message Date
Julian 527283e5bd
Merge c6593a2bcb into 2bac80cfbf 2024-05-07 07:39:15 +02:00
Dan Pastusek 2bac80cfbf
[DOCS] Make linux installation instructions more clear (#1927)
* Make linux installation instructions more clear

* Update running-headscale-linux.md
2024-05-06 20:06:30 +02:00
Michael Savage 93a915c096
Update OpenBSD installation docs for 2024 (#1915) 2024-05-06 20:03:21 +02:00
Julian Mundhahs c6593a2bcb feat: add a message to the user that the session is recorded
Signed-off-by: Julian Mundhahs <julian.mundhahs@mailbox.org>
2024-03-10 14:43:31 +01:00
Julian Mundhahs 31ee9bb4a8 test: add tests for `recorder` and `enforceRecorder` SSH ACL rules
Signed-off-by: Julian Mundhahs <github@mundhahs.dev>
2024-03-10 14:43:26 +01:00
Julian Mundhahs 04c7c5b0b6 feat: add `recorder` and `enforceRecorder` support in SSH ACL
Signed-off-by: Julian Mundhahs <github@mundhahs.dev>
2024-03-10 14:24:17 +01:00
5 changed files with 152 additions and 19 deletions

View File

@ -20,17 +20,19 @@ configuration (`/etc/headscale/config.yaml`).
## Installation
1. Download the latest Headscale package for your platform (`.deb` for Ubuntu and Debian) from [Headscale's releases page](https://github.com/juanfont/headscale/releases):
1. Download the [latest Headscale package](https://github.com/juanfont/headscale/releases/latest) for your platform (`.deb` for Ubuntu and Debian).
```shell
HEADSCALE_VERSION="" # See above URL for latest version, e.g. "X.Y.Z" (NOTE: do not add the "v" prefix!)
HEADSCALE_ARCH="" # Your system architecture, e.g. "amd64"
wget --output-document=headscale.deb \
https://github.com/juanfont/headscale/releases/download/v<HEADSCALE VERSION>/headscale_<HEADSCALE VERSION>_linux_<ARCH>.deb
"https://github.com/juanfont/headscale/releases/download/v${HEADSCALE_VERSION}/headscale_${HEADSCALE_VERSION}_linux_${HEADSCALE_ARCH}.deb"
```
1. Install Headscale:
```shell
sudo apt install headscale.deb
sudo apt install ./headscale.deb
```
1. Enable Headscale service, this will start Headscale at boot:

View File

@ -9,19 +9,17 @@
## Goal
This documentation has the goal of showing a user how-to install and run `headscale` on OpenBSD 7.1.
This documentation has the goal of showing a user how-to install and run `headscale` on OpenBSD.
In additional to the "get up and running section", there is an optional [rc.d section](#running-headscale-in-the-background-with-rcd)
describing how to make `headscale` run properly in a server environment.
## Install `headscale`
1. Install from ports (not recommended)
1. Install from ports
!!! info
You can install headscale from ports by running `pkg_add headscale`.
As of OpenBSD 7.2, there's a headscale in ports collection, however, it's severely outdated(v0.12.4). You can install it via `pkg_add headscale`.
1. Install from source on OpenBSD 7.2
1. Install from source
```shell
# Install prerequistes

View File

@ -357,6 +357,31 @@ func (pol *ACLPolicy) CompileSSHPolicy(
return nil, fmt.Errorf("parsing SSH policy, unknown action %q, index: %d: %w", sshACL.Action, index, err)
}
recs := make([]netip.AddrPort, 0)
for innerIndex, rec := range sshACL.Recorder {
recSet, err := pol.ExpandAlias(append(peers, node), rec)
if err != nil {
log.Error().
Msgf("Error parsing SSH %d, Recorder %d", index, innerIndex)
return nil, err
}
// ExpandAlias has expanded possible subnets; all prefixes are single IPs
for _, rec := range recSet.Prefixes() {
recs = append(recs, netip.AddrPortFrom(rec.Addr(), 80))
}
}
if len(recs) > 0 {
action.Message = "# This session is being recorded.\n"
}
action.Recorders = recs
if sshACL.EnforceRecorder {
action.OnRecordingFailure = &tailcfg.SSHRecorderFailureAction{
RejectSessionWithMessage: "# Failed to start session recording.",
TerminateSessionWithMessage: "# Failed to start session recording.",
}
}
principals := make([]*tailcfg.SSHPrincipal, 0, len(sshACL.Sources))
for innerIndex, rawSrc := range sshACL.Sources {
if isWildcard(rawSrc) {

View File

@ -6,6 +6,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/util"
"github.com/rs/zerolog/log"
@ -3340,7 +3341,11 @@ func TestSSHRules(t *testing.T) {
SSHUsers: map[string]string{
"autogroup:nonroot": "=",
},
Action: &tailcfg.SSHAction{Accept: true, AllowLocalPortForwarding: true},
Action: &tailcfg.SSHAction{
Accept: true,
AllowLocalPortForwarding: true,
Recorders: []netip.AddrPort{},
},
},
{
SSHUsers: map[string]string{
@ -3351,7 +3356,11 @@ func TestSSHRules(t *testing.T) {
Any: true,
},
},
Action: &tailcfg.SSHAction{Accept: true, AllowLocalPortForwarding: true},
Action: &tailcfg.SSHAction{
Accept: true,
AllowLocalPortForwarding: true,
Recorders: []netip.AddrPort{},
},
},
{
Principals: []*tailcfg.SSHPrincipal{
@ -3362,7 +3371,11 @@ func TestSSHRules(t *testing.T) {
SSHUsers: map[string]string{
"autogroup:nonroot": "=",
},
Action: &tailcfg.SSHAction{Accept: true, AllowLocalPortForwarding: true},
Action: &tailcfg.SSHAction{
Accept: true,
AllowLocalPortForwarding: true,
Recorders: []netip.AddrPort{},
},
},
{
SSHUsers: map[string]string{
@ -3373,7 +3386,100 @@ func TestSSHRules(t *testing.T) {
Any: true,
},
},
Action: &tailcfg.SSHAction{Accept: true, AllowLocalPortForwarding: true},
Action: &tailcfg.SSHAction{
Accept: true,
AllowLocalPortForwarding: true,
Recorders: []netip.AddrPort{},
},
},
},
},
{
name: "ssh-session-recording",
node: types.Node{
Hostname: "testnodes",
IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.99.42")},
UserID: 0,
User: types.User{
Name: "user1",
},
},
peers: types.Nodes{
&types.Node{
Hostname: "testnodes2",
IPAddresses: types.NodeAddresses{netip.MustParseAddr("100.64.0.1")},
UserID: 0,
User: types.User{
Name: "user1",
},
},
},
pol: ACLPolicy{
Groups: Groups{
"group:test": []string{"user1"},
},
Hosts: Hosts{
"client": netip.PrefixFrom(netip.MustParseAddr("100.64.99.42"), 32),
},
ACLs: []ACL{
{
Action: "accept",
Sources: []string{"*"},
Destinations: []string{"*:*"},
},
},
SSHs: []SSH{
{
Action: "accept",
Sources: []string{"group:test"},
Destinations: []string{"client"},
Users: []string{"autogroup:nonroot"},
Recorder: []string{"group:test"},
},
{
Action: "accept",
Sources: []string{"*"},
Destinations: []string{"client"},
Users: []string{"autogroup:nonroot"},
Recorder: []string{"client"},
EnforceRecorder: true,
},
},
},
want: []*tailcfg.SSHRule{
{
Principals: []*tailcfg.SSHPrincipal{
{
UserLogin: "user1",
},
},
SSHUsers: map[string]string{
"autogroup:nonroot": "=",
},
Action: &tailcfg.SSHAction{
Accept: true,
AllowLocalPortForwarding: true,
Recorders: []netip.AddrPort{netip.MustParseAddrPort("100.64.0.1:80"), netip.MustParseAddrPort("100.64.99.42:80")},
},
},
{
SSHUsers: map[string]string{
"autogroup:nonroot": "=",
},
Principals: []*tailcfg.SSHPrincipal{
{
Any: true,
},
},
Action: &tailcfg.SSHAction{
Accept: true,
AllowLocalPortForwarding: true,
Recorders: []netip.AddrPort{netip.MustParseAddrPort("100.64.99.42:80")},
OnRecordingFailure: &tailcfg.SSHRecorderFailureAction{
RejectSessionWithMessage: "# Failed to start session recording.",
TerminateSessionWithMessage: "# Failed to start session recording.",
},
},
},
}},
},
@ -3435,7 +3541,7 @@ func TestSSHRules(t *testing.T) {
got, err := tt.pol.CompileSSHPolicy(&tt.node, tt.peers)
assert.NoError(t, err)
if diff := cmp.Diff(tt.want, got); diff != "" {
if diff := cmp.Diff(tt.want, got, cmpopts.EquateComparable(netip.AddrPort{})); diff != "" {
t.Errorf("TestSSHRules() unexpected result (-want +got):\n%s", diff)
}
})

View File

@ -53,11 +53,13 @@ type AutoApprovers struct {
// SSH controls who can ssh into which machines.
type SSH struct {
Action string `json:"action" yaml:"action"`
Sources []string `json:"src" yaml:"src"`
Destinations []string `json:"dst" yaml:"dst"`
Users []string `json:"users" yaml:"users"`
CheckPeriod string `json:"checkPeriod,omitempty" yaml:"checkPeriod,omitempty"`
Action string `json:"action" yaml:"action"`
Sources []string `json:"src" yaml:"src"`
Destinations []string `json:"dst" yaml:"dst"`
Users []string `json:"users" yaml:"users"`
CheckPeriod string `json:"checkPeriod,omitempty" yaml:"checkPeriod,omitempty"`
Recorder []string `json:"recorder,omitempty" yaml:"recorder,omitempty"`
EnforceRecorder bool `json:"enforceRecorder,omitempty" yaml:"enforceRecorder,omitempty"`
}
// UnmarshalJSON allows to parse the Hosts directly into netip objects.