mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-23 00:56:20 +00:00
control/controlclient, ipn: add client audit logging (#14950)
updates tailscale/corp#26435 Adds client support for sending audit logs to control via /machine/audit-log. Specifically implements audit logging for user initiated disconnections. This will require further work to optimize the peristant storage and exclusion via build tags for mobile: tailscale/corp#27011 tailscale/corp#27012 Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
This commit is contained in:
@@ -156,6 +156,11 @@ type Options struct {
|
||||
// If we receive a new DialPlan from the server, this value will be
|
||||
// updated.
|
||||
DialPlan ControlDialPlanner
|
||||
|
||||
// Shutdown is an optional function that will be called before client shutdown is
|
||||
// attempted. It is used to allow the client to clean up any resources or complete any
|
||||
// tasks that are dependent on a live client.
|
||||
Shutdown func()
|
||||
}
|
||||
|
||||
// ControlDialPlanner is the interface optionally supplied when creating a
|
||||
@@ -1662,11 +1667,11 @@ func (c *Auto) SetDeviceAttrs(ctx context.Context, attrs tailcfg.AttrUpdate) err
|
||||
func (c *Direct) SetDeviceAttrs(ctx context.Context, attrs tailcfg.AttrUpdate) error {
|
||||
nc, err := c.getNoiseClient()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%w: %w", errNoNoiseClient, err)
|
||||
}
|
||||
nodeKey, ok := c.GetPersist().PublicNodeKeyOK()
|
||||
if !ok {
|
||||
return errors.New("no node key")
|
||||
return errNoNodeKey
|
||||
}
|
||||
if c.panicOnUse {
|
||||
panic("tainted client")
|
||||
@@ -1697,6 +1702,47 @@ func (c *Direct) SetDeviceAttrs(ctx context.Context, attrs tailcfg.AttrUpdate) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendAuditLog implements [auditlog.Transport] by sending an audit log synchronously to the control plane.
|
||||
//
|
||||
// See docs on [tailcfg.AuditLogRequest] and [auditlog.Logger] for background.
|
||||
func (c *Auto) SendAuditLog(ctx context.Context, auditLog tailcfg.AuditLogRequest) (err error) {
|
||||
return c.direct.sendAuditLog(ctx, auditLog)
|
||||
}
|
||||
|
||||
func (c *Direct) sendAuditLog(ctx context.Context, auditLog tailcfg.AuditLogRequest) (err error) {
|
||||
nc, err := c.getNoiseClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %w", errNoNoiseClient, err)
|
||||
}
|
||||
|
||||
nodeKey, ok := c.GetPersist().PublicNodeKeyOK()
|
||||
if !ok {
|
||||
return errNoNodeKey
|
||||
}
|
||||
|
||||
req := &tailcfg.AuditLogRequest{
|
||||
Version: tailcfg.CurrentCapabilityVersion,
|
||||
NodeKey: nodeKey,
|
||||
Action: auditLog.Action,
|
||||
Details: auditLog.Details,
|
||||
}
|
||||
|
||||
if c.panicOnUse {
|
||||
panic("tainted client")
|
||||
}
|
||||
|
||||
res, err := nc.post(ctx, "/machine/audit-log", nodeKey, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %w", errHTTPPostFailure, err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != 200 {
|
||||
all, _ := io.ReadAll(res.Body)
|
||||
return errBadHTTPResponse(res.StatusCode, string(all))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addLBHeader(req *http.Request, nodeKey key.NodePublic) {
|
||||
if !nodeKey.IsZero() {
|
||||
req.Header.Add(tailcfg.LBHeader, nodeKey.String())
|
||||
|
||||
Reference in New Issue
Block a user