diff options
| author | Brad Fitzpatrick <bradfitz@tailscale.com> | 2025-01-21 12:34:15 -0800 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@tailscale.com> | 2025-01-21 14:34:19 -0800 |
| commit | 3116dbefacba11586b99acd1dc0891adf40d76ca (patch) | |
| tree | e04f0f450d3b8cd24e440016211f1b8174ce879a /ipn/localapi/syspolicy_api.go | |
| parent | b50d32059f1b33311dbba96a57c82d33a28f0e1f (diff) | |
| download | tailscale-bradfitz/syspolicy_key.tar.xz tailscale-bradfitz/syspolicy_key.zip | |
util/syspolicy/policyclient: add Client interface to the syspolicy universebradfitz/syspolicy_key
This removes the dependency on syspolicy/... from LocalBackend and tailscaled
when ts_omit_syspolicy is true.
Updates #12614
Change-Id: I309deb0f50f8e7d6bc11454e4210bb3b358abc77
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Diffstat (limited to 'ipn/localapi/syspolicy_api.go')
| -rw-r--r-- | ipn/localapi/syspolicy_api.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/ipn/localapi/syspolicy_api.go b/ipn/localapi/syspolicy_api.go new file mode 100644 index 000000000..366045de3 --- /dev/null +++ b/ipn/localapi/syspolicy_api.go @@ -0,0 +1,67 @@ +// 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/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 "GET": + effectivePolicy = policy.Get() + case "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) +} |
