ipn/{ipn,ipnlocal}: add per-user policy snapshots to IPN bus (#20135)
This adds the NotifyInitialPolicy watch option and the Policy field in Notify so that clients can receive the effective policy snapshot via IPN bus. This extends policyclient.Client so ipnlocal can get and watch policy snapshots, which is used by sysPolicyChanged to notify watchers. User-scoped policy store registration, management, and cleanup will be added in a follow-up Updates tailscale/corp#42259 Signed-off-by: kari <kari@tailscale.com>
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ts_omit_syspolicy
|
||||
|
||||
package policyclient
|
||||
|
||||
import "tailscale.com/util/syspolicy/setting"
|
||||
|
||||
// PolicySnapshot is an alias for [settings.Snapshot] unless syspolicy is omitted
|
||||
// from the build.
|
||||
type policySnapshot = setting.Snapshot
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build ts_omit_syspolicy
|
||||
|
||||
package policyclient
|
||||
|
||||
// PolicySnapshot is a stub when syspolicy is omitted from the build.
|
||||
type policySnapshot struct{}
|
||||
@@ -62,11 +62,21 @@ type Client interface {
|
||||
HasAnyOf(keys ...pkey.Key) (bool, error)
|
||||
|
||||
// RegisterChangeCallback registers a callback function that will be called
|
||||
// whenever a policy change is detected. It returns a function to unregister
|
||||
// the callback and an error if the registration fails.
|
||||
RegisterChangeCallback(cb func(PolicyChange)) (unregister func(), err error)
|
||||
// whenever a policy change is detected. If uid is empty, the callback fires
|
||||
// for device-scope policy changes. If uid is non-empty, it fires for changes
|
||||
// to that user's effective policy (device + user policies merged). It returns
|
||||
// a function to unregister the callback and an error if the registration fails.
|
||||
RegisterChangeCallback(uid string, cb func(PolicyChange)) (unregister func(), err error)
|
||||
|
||||
// GetPolicySnapshot returns the effective policy snapshot for the given user ID.
|
||||
// If uid is empty, returns the default-scope policy. Returns nil, nil if policy
|
||||
// snapshots are not supported.
|
||||
GetPolicySnapshot(uid string) (*PolicySnapshot, error)
|
||||
}
|
||||
|
||||
// PolicySnapshot is an alias for [setting.Snapshot] unless syspolicy is omitted from the build.
|
||||
type PolicySnapshot = policySnapshot
|
||||
|
||||
// Get returns a non-nil [Client] implementation as a function of the
|
||||
// build tags. It returns a no-op implementation if the full syspolicy
|
||||
// package is omitted from the build, or in tests.
|
||||
@@ -140,6 +150,10 @@ func (NoPolicyClient) HasAnyOf(keys ...pkey.Key) (bool, error) {
|
||||
|
||||
func (NoPolicyClient) SetDebugLoggingEnabled(enabled bool) {}
|
||||
|
||||
func (NoPolicyClient) RegisterChangeCallback(cb func(PolicyChange)) (unregister func(), err error) {
|
||||
func (NoPolicyClient) RegisterChangeCallback(uid string, cb func(PolicyChange)) (unregister func(), err error) {
|
||||
return func() {}, nil
|
||||
}
|
||||
|
||||
func (NoPolicyClient) GetPolicySnapshot(uid string) (*PolicySnapshot, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ func (c Config) HasAnyOf(keys ...pkey.Key) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c Config) RegisterChangeCallback(callback func(policyclient.PolicyChange)) (func(), error) {
|
||||
func (c Config) RegisterChangeCallback(uid string, callback func(policyclient.PolicyChange)) (func(), error) {
|
||||
w, ok := c[watchersKey].(*watchers)
|
||||
if !ok {
|
||||
return func() {}, nil
|
||||
@@ -242,3 +242,7 @@ func (c Config) RegisterChangeCallback(callback func(policyclient.PolicyChange))
|
||||
}
|
||||
|
||||
func (sp Config) SetDebugLoggingEnabled(enabled bool) {}
|
||||
|
||||
func (c Config) GetPolicySnapshot(uid string) (*policyclient.PolicySnapshot, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -129,8 +129,12 @@ func getDuration(name pkey.Key, defaultValue time.Duration) (time.Duration, erro
|
||||
|
||||
// registerChangeCallback adds a function that will be called whenever the effective policy
|
||||
// for the default scope changes. The returned function can be used to unregister the callback.
|
||||
func registerChangeCallback(cb rsop.PolicyChangeCallback) (unregister func(), err error) {
|
||||
effective, err := rsop.PolicyFor(setting.DefaultScope())
|
||||
func registerChangeCallback(uid string, cb rsop.PolicyChangeCallback) (unregister func(), err error) {
|
||||
scope := setting.DefaultScope()
|
||||
if uid != "" {
|
||||
scope = setting.UserScopeOf(uid)
|
||||
}
|
||||
effective, err := rsop.PolicyFor(scope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -259,6 +263,18 @@ func (globalSyspolicy) HasAnyOf(keys ...pkey.Key) (bool, error) {
|
||||
return hasAnyOf(keys...)
|
||||
}
|
||||
|
||||
func (globalSyspolicy) RegisterChangeCallback(cb func(policyclient.PolicyChange)) (unregister func(), err error) {
|
||||
return registerChangeCallback(cb)
|
||||
func (globalSyspolicy) RegisterChangeCallback(uid string, cb func(policyclient.PolicyChange)) (unregister func(), err error) {
|
||||
return registerChangeCallback(uid, cb)
|
||||
}
|
||||
|
||||
func (globalSyspolicy) GetPolicySnapshot(uid string) (*policyclient.PolicySnapshot, error) {
|
||||
scope := setting.DefaultScope()
|
||||
if uid != "" {
|
||||
scope = setting.UserScopeOf(uid)
|
||||
}
|
||||
p, err := rsop.PolicyFor(scope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.Get(), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user