Fixes #16998 Updates #12614 Change-Id: Idf2b1657898111df4be31f356091b2376d0d7f0b Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>main
parent
24b8a57b1e
commit
21f21bd2a2
@ -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) |
||||
} |
||||
@ -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) |
||||
} |
||||
Loading…
Reference in new issue