mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-24 01:26:39 +00:00
util/syspolicy: finish adding ts_omit_syspolicy build tags, tests
Fixes #16998 Updates #12614 Change-Id: Idf2b1657898111df4be31f356091b2376d0d7f0b Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
24b8a57b1e
commit
21f21bd2a2
@@ -41,7 +41,7 @@ while [ "$#" -gt 1 ]; do
|
|||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
ldflags="$ldflags -w -s"
|
ldflags="$ldflags -w -s"
|
||||||
tags="${tags:+$tags,}ts_omit_aws,ts_omit_bird,ts_omit_tap,ts_omit_kube,ts_omit_completion,ts_omit_ssh,ts_omit_wakeonlan,ts_omit_capture,ts_omit_relayserver,ts_omit_systray,ts_omit_taildrop,ts_omit_tpm"
|
tags="${tags:+$tags,}ts_omit_aws,ts_omit_bird,ts_omit_tap,ts_omit_kube,ts_omit_completion,ts_omit_ssh,ts_omit_wakeonlan,ts_omit_capture,ts_omit_relayserver,ts_omit_systray,ts_omit_taildrop,ts_omit_tpm,ts_omit_syspolicy"
|
||||||
;;
|
;;
|
||||||
--box)
|
--box)
|
||||||
if [ ! -z "${TAGS:-}" ]; then
|
if [ ! -z "${TAGS:-}" ]; then
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ import (
|
|||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/tkatype"
|
"tailscale.com/types/tkatype"
|
||||||
"tailscale.com/util/eventbus"
|
"tailscale.com/util/eventbus"
|
||||||
"tailscale.com/util/syspolicy/setting"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// defaultClient is the default Client when using the legacy
|
// defaultClient is the default Client when using the legacy
|
||||||
@@ -926,33 +925,6 @@ func (lc *Client) EditPrefs(ctx context.Context, mp *ipn.MaskedPrefs) (*ipn.Pref
|
|||||||
return decodeJSON[*ipn.Prefs](body)
|
return decodeJSON[*ipn.Prefs](body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEffectivePolicy returns the effective policy for the specified scope.
|
|
||||||
func (lc *Client) GetEffectivePolicy(ctx context.Context, scope setting.PolicyScope) (*setting.Snapshot, error) {
|
|
||||||
scopeID, err := scope.MarshalText()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
body, err := lc.get200(ctx, "/localapi/v0/policy/"+string(scopeID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return decodeJSON[*setting.Snapshot](body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReloadEffectivePolicy reloads the effective policy for the specified scope
|
|
||||||
// by reading and merging policy settings from all applicable policy sources.
|
|
||||||
func (lc *Client) ReloadEffectivePolicy(ctx context.Context, scope setting.PolicyScope) (*setting.Snapshot, error) {
|
|
||||||
scopeID, err := scope.MarshalText()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
body, err := lc.send(ctx, "POST", "/localapi/v0/policy/"+string(scopeID), 200, http.NoBody)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return decodeJSON[*setting.Snapshot](body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDNSOSConfig returns the system DNS configuration for the current device.
|
// GetDNSOSConfig returns the system DNS configuration for the current device.
|
||||||
// That is, it returns the DNS configuration that the system would use if Tailscale weren't being used.
|
// That is, it returns the DNS configuration that the system would use if Tailscale weren't being used.
|
||||||
func (lc *Client) GetDNSOSConfig(ctx context.Context) (*apitype.DNSOSConfig, error) {
|
func (lc *Client) GetDNSOSConfig(ctx context.Context) (*apitype.DNSOSConfig, error) {
|
||||||
|
|||||||
40
client/local/syspolicy.go
Normal file
40
client/local/syspolicy.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
//go:build !ts_omit_syspolicy
|
||||||
|
|
||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"tailscale.com/util/syspolicy/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEffectivePolicy returns the effective policy for the specified scope.
|
||||||
|
func (lc *Client) GetEffectivePolicy(ctx context.Context, scope setting.PolicyScope) (*setting.Snapshot, error) {
|
||||||
|
scopeID, err := scope.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body, err := lc.get200(ctx, "/localapi/v0/policy/"+string(scopeID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return decodeJSON[*setting.Snapshot](body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadEffectivePolicy reloads the effective policy for the specified scope
|
||||||
|
// by reading and merging policy settings from all applicable policy sources.
|
||||||
|
func (lc *Client) ReloadEffectivePolicy(ctx context.Context, scope setting.PolicyScope) (*setting.Snapshot, error) {
|
||||||
|
scopeID, err := scope.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body, err := lc.send(ctx, "POST", "/localapi/v0/policy/"+string(scopeID), 200, http.NoBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return decodeJSON[*setting.Snapshot](body)
|
||||||
|
}
|
||||||
@@ -209,6 +209,7 @@ func noDupFlagify(c *ffcli.Command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fileCmd func() *ffcli.Command
|
var fileCmd func() *ffcli.Command
|
||||||
|
var sysPolicyCmd func() *ffcli.Command
|
||||||
|
|
||||||
func newRootCmd() *ffcli.Command {
|
func newRootCmd() *ffcli.Command {
|
||||||
rootfs := newFlagSet("tailscale")
|
rootfs := newFlagSet("tailscale")
|
||||||
@@ -239,7 +240,7 @@ change in the future.
|
|||||||
logoutCmd,
|
logoutCmd,
|
||||||
switchCmd,
|
switchCmd,
|
||||||
configureCmd(),
|
configureCmd(),
|
||||||
syspolicyCmd,
|
nilOrCall(sysPolicyCmd),
|
||||||
netcheckCmd,
|
netcheckCmd,
|
||||||
ipCmd,
|
ipCmd,
|
||||||
dnsCmd,
|
dnsCmd,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) Tailscale Inc & AUTHORS
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
//go:build !ts_omit_syspolicy
|
||||||
|
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -20,7 +22,9 @@ var syspolicyArgs struct {
|
|||||||
json bool // JSON output mode
|
json bool // JSON output mode
|
||||||
}
|
}
|
||||||
|
|
||||||
var syspolicyCmd = &ffcli.Command{
|
func init() {
|
||||||
|
sysPolicyCmd = func() *ffcli.Command {
|
||||||
|
return &ffcli.Command{
|
||||||
Name: "syspolicy",
|
Name: "syspolicy",
|
||||||
ShortHelp: "Diagnose the MDM and system policy configuration",
|
ShortHelp: "Diagnose the MDM and system policy configuration",
|
||||||
LongHelp: "The 'tailscale syspolicy' command provides tools for diagnosing the MDM and system policy configuration.",
|
LongHelp: "The 'tailscale syspolicy' command provides tools for diagnosing the MDM and system policy configuration.",
|
||||||
@@ -53,6 +57,8 @@ var syspolicyCmd = &ffcli.Command{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func runSysPolicyList(ctx context.Context, args []string) error {
|
func runSysPolicyList(ctx context.Context, args []string) error {
|
||||||
policy, err := localClient.GetEffectivePolicy(ctx, setting.DefaultScope())
|
policy, err := localClient.GetEffectivePolicy(ctx, setting.DefaultScope())
|
||||||
@@ -61,7 +67,6 @@ func runSysPolicyList(ctx context.Context, args []string) error {
|
|||||||
}
|
}
|
||||||
printPolicySettings(policy)
|
printPolicySettings(policy)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSysPolicyReload(ctx context.Context, args []string) error {
|
func runSysPolicyReload(ctx context.Context, args []string) error {
|
||||||
|
|||||||
@@ -27,3 +27,17 @@ func TestOmitSSH(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}.Check(t)
|
}.Check(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOmitSyspolicy(t *testing.T) {
|
||||||
|
const msg = "unexpected syspolicy usage with ts_omit_syspolicy"
|
||||||
|
deptest.DepChecker{
|
||||||
|
GOOS: "linux",
|
||||||
|
GOARCH: "amd64",
|
||||||
|
Tags: "ts_omit_syspolicy,ts_include_cli",
|
||||||
|
BadDeps: map[string]string{
|
||||||
|
"tailscale.com/util/syspolicy": msg,
|
||||||
|
"tailscale.com/util/syspolicy/setting": msg,
|
||||||
|
"tailscale.com/util/syspolicy/rsop": msg,
|
||||||
|
},
|
||||||
|
}.Check(t)
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,8 +58,6 @@ import (
|
|||||||
"tailscale.com/util/mak"
|
"tailscale.com/util/mak"
|
||||||
"tailscale.com/util/osdiag"
|
"tailscale.com/util/osdiag"
|
||||||
"tailscale.com/util/rands"
|
"tailscale.com/util/rands"
|
||||||
"tailscale.com/util/syspolicy/rsop"
|
|
||||||
"tailscale.com/util/syspolicy/setting"
|
|
||||||
"tailscale.com/version"
|
"tailscale.com/version"
|
||||||
"tailscale.com/wgengine/magicsock"
|
"tailscale.com/wgengine/magicsock"
|
||||||
)
|
)
|
||||||
@@ -79,7 +77,6 @@ type LocalAPIHandler func(*Handler, http.ResponseWriter, *http.Request)
|
|||||||
var handler = map[string]LocalAPIHandler{
|
var handler = map[string]LocalAPIHandler{
|
||||||
// The prefix match handlers end with a slash:
|
// The prefix match handlers end with a slash:
|
||||||
"cert/": (*Handler).serveCert,
|
"cert/": (*Handler).serveCert,
|
||||||
"policy/": (*Handler).servePolicy,
|
|
||||||
"profiles/": (*Handler).serveProfiles,
|
"profiles/": (*Handler).serveProfiles,
|
||||||
|
|
||||||
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
|
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
|
||||||
@@ -1603,53 +1600,6 @@ func (h *Handler) servePrefs(w http.ResponseWriter, r *http.Request) {
|
|||||||
e.Encode(prefs)
|
e.Encode(prefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) servePolicy(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !h.PermitRead {
|
|
||||||
http.Error(w, "policy access denied", http.StatusForbidden)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/policy/")
|
|
||||||
if !ok {
|
|
||||||
http.Error(w, "misconfigured", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var scope setting.PolicyScope
|
|
||||||
if suffix == "" {
|
|
||||||
scope = setting.DefaultScope()
|
|
||||||
} else if err := scope.UnmarshalText([]byte(suffix)); err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("%q is not a valid scope", suffix), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
policy, err := rsop.PolicyFor(scope)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var effectivePolicy *setting.Snapshot
|
|
||||||
switch r.Method {
|
|
||||||
case httpm.GET:
|
|
||||||
effectivePolicy = policy.Get()
|
|
||||||
case httpm.POST:
|
|
||||||
effectivePolicy, err = policy.Reload()
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
e := json.NewEncoder(w)
|
|
||||||
e.SetIndent("", "\t")
|
|
||||||
e.Encode(effectivePolicy)
|
|
||||||
}
|
|
||||||
|
|
||||||
type resJSON struct {
|
type resJSON struct {
|
||||||
Error string `json:",omitempty"`
|
Error string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
68
ipn/localapi/syspolicy_api.go
Normal file
68
ipn/localapi/syspolicy_api.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
//go:build !ts_omit_syspolicy
|
||||||
|
|
||||||
|
package localapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"tailscale.com/util/httpm"
|
||||||
|
"tailscale.com/util/syspolicy/rsop"
|
||||||
|
"tailscale.com/util/syspolicy/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
handler["policy/"] = (*Handler).servePolicy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) servePolicy(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !h.PermitRead {
|
||||||
|
http.Error(w, "policy access denied", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/policy/")
|
||||||
|
if !ok {
|
||||||
|
http.Error(w, "misconfigured", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var scope setting.PolicyScope
|
||||||
|
if suffix == "" {
|
||||||
|
scope = setting.DefaultScope()
|
||||||
|
} else if err := scope.UnmarshalText([]byte(suffix)); err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("%q is not a valid scope", suffix), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
policy, err := rsop.PolicyFor(scope)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var effectivePolicy *setting.Snapshot
|
||||||
|
switch r.Method {
|
||||||
|
case httpm.GET:
|
||||||
|
effectivePolicy = policy.Get()
|
||||||
|
case httpm.POST:
|
||||||
|
effectivePolicy, err = policy.Reload()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
e := json.NewEncoder(w)
|
||||||
|
e.SetIndent("", "\t")
|
||||||
|
e.Encode(effectivePolicy)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user