ipn/localapi: require root or sudo+operator access for SetServeConfig (#10142)

For an operator user, require them to be able to `sudo tailscale` to use
`tailscale serve`. This is similar to the Windows elevated token check.

Updates tailscale/corp#15405

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
Andrew Lytvynov
2023-11-07 13:31:33 -07:00
committed by GitHub
parent fc2d63bb8c
commit 9b158db2c6
3 changed files with 107 additions and 25 deletions

View File

@@ -161,14 +161,40 @@ func TestShouldDenyServeConfigForGOOSAndUserContext(t *testing.T) {
goos string
configIn *ipn.ServeConfig
h *Handler
want bool
wantErr bool
}{
{
name: "linux",
goos: "linux",
configIn: &ipn.ServeConfig{},
h: &Handler{CallerIsLocalAdmin: false},
want: false,
wantErr: false,
},
{
name: "linux-path-handler-admin",
goos: "linux",
configIn: &ipn.ServeConfig{
Web: map[ipn.HostPort]*ipn.WebServerConfig{
"foo.test.ts.net:443": {Handlers: map[string]*ipn.HTTPHandler{
"/": {Path: "/tmp"},
}},
},
},
h: &Handler{CallerIsLocalAdmin: true},
wantErr: false,
},
{
name: "linux-path-handler-not-admin",
goos: "linux",
configIn: &ipn.ServeConfig{
Web: map[ipn.HostPort]*ipn.WebServerConfig{
"foo.test.ts.net:443": {Handlers: map[string]*ipn.HTTPHandler{
"/": {Path: "/tmp"},
}},
},
},
h: &Handler{CallerIsLocalAdmin: false},
wantErr: true,
},
{
name: "windows-not-path-handler",
@@ -180,8 +206,8 @@ func TestShouldDenyServeConfigForGOOSAndUserContext(t *testing.T) {
}},
},
},
h: &Handler{CallerIsLocalAdmin: false},
want: false,
h: &Handler{CallerIsLocalAdmin: false},
wantErr: false,
},
{
name: "windows-path-handler-admin",
@@ -193,8 +219,8 @@ func TestShouldDenyServeConfigForGOOSAndUserContext(t *testing.T) {
}},
},
},
h: &Handler{CallerIsLocalAdmin: true},
want: false,
h: &Handler{CallerIsLocalAdmin: true},
wantErr: false,
},
{
name: "windows-path-handler-not-admin",
@@ -206,16 +232,17 @@ func TestShouldDenyServeConfigForGOOSAndUserContext(t *testing.T) {
}},
},
},
h: &Handler{CallerIsLocalAdmin: false},
want: true,
h: &Handler{CallerIsLocalAdmin: false},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := shouldDenyServeConfigForGOOSAndUserContext(tt.goos, tt.configIn, tt.h)
if got != tt.want {
t.Errorf("shouldDenyServeConfigForGOOSAndUserContext() got = %v, want %v", got, tt.want)
err := authorizeServeConfigForGOOSAndUserContext(tt.goos, tt.configIn, tt.h)
gotErr := err != nil
if gotErr != tt.wantErr {
t.Errorf("authorizeServeConfigForGOOSAndUserContext() got error = %v, want error %v", err, tt.wantErr)
}
})
}