ipn/ipn{auth,server}: update ipnauth.Actor to carry a context

The context carries additional information about the actor, such as the
request reason, and is canceled when the actor is done.

Additionally, we implement three new ipn.Actor types that wrap other actors
to modify their behavior:
 - WithRequestReason, which adds a request reason to the actor;
 - WithoutClose, which narrows the actor's interface to prevent it from being
   closed;
 - WithPolicyChecks, which adds policy checks to the actor's CheckProfileAccess
   method.

Updates #14823

Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
Nick Khyl
2025-02-07 10:47:14 -06:00
committed by Nick Khyl
parent 5a082fccec
commit e9e2bc5bd7
5 changed files with 77 additions and 6 deletions
+26
View File
@@ -7,10 +7,36 @@ import (
"errors"
"fmt"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/ipn"
"tailscale.com/util/syspolicy"
)
type actorWithPolicyChecks struct{ Actor }
// WithPolicyChecks returns an [Actor] that wraps the given actor and
// performs additional policy checks on top of the access checks
// implemented by the wrapped actor.
func WithPolicyChecks(actor Actor) Actor {
// TODO(nickkhyl): We should probably exclude the Windows Local System
// account from policy checks as well.
switch actor.(type) {
case unrestricted:
return actor
default:
return &actorWithPolicyChecks{Actor: actor}
}
}
// CheckProfileAccess implements [Actor].
func (a actorWithPolicyChecks) CheckProfileAccess(profile ipn.LoginProfileView, requestedAccess ProfileAccess, auditLogger AuditLogFunc) error {
if err := a.Actor.CheckProfileAccess(profile, requestedAccess, auditLogger); err != nil {
return err
}
requestReason := apitype.RequestReasonKey.Value(a.Context())
return CheckDisconnectPolicy(a.Actor, profile, requestReason, auditLogger)
}
// CheckDisconnectPolicy checks if the policy allows the specified actor to disconnect
// Tailscale with the given optional reason. It returns nil if the operation is allowed,
// or an error if it is not. If auditLogger is non-nil, it is called to log the action