From 82f5f438e0ada551d8e93cc130bb5c8b7d47a0d4 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Thu, 6 Oct 2022 16:19:38 -0700 Subject: [PATCH] wgengine/wgcfg: plumb down audit log IDs (#5855) The node and domain audit log IDs are provided in the map response, but are ultimately going to be used in wgengine since that's the layer that manages the tstun.Wrapper. Do the plumbing work to get this field passed down the stack. Signed-off-by: Joe Tsai --- control/controlclient/map.go | 33 +++++++++++++++++++-------------- types/netmap/netmap.go | 5 +++++ wgengine/wgcfg/config.go | 8 ++++++++ wgengine/wgcfg/nmcfg/nmcfg.go | 21 +++++++++++++++++++++ wgengine/wgcfg/wgcfg_clone.go | 17 +++++++++++------ 5 files changed, 64 insertions(+), 20 deletions(-) diff --git a/control/controlclient/map.go b/control/controlclient/map.go index 1bc57fdf2..fb6d93dd9 100644 --- a/control/controlclient/map.go +++ b/control/controlclient/map.go @@ -45,6 +45,7 @@ type mapSession struct { collectServices bool previousPeers []*tailcfg.Node // for delta-purposes lastDomain string + lastDomainAuditLogID string lastHealth []string lastPopBrowserURL string stickyDebug tailcfg.Debug // accumulated opt.Bool values @@ -113,6 +114,9 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo if resp.Domain != "" { ms.lastDomain = resp.Domain } + if resp.DomainDataPlaneAuditLogID != "" { + ms.lastDomainAuditLogID = resp.DomainDataPlaneAuditLogID + } if resp.Health != nil { ms.lastHealth = resp.Health } @@ -143,20 +147,21 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo } nm := &netmap.NetworkMap{ - NodeKey: ms.privateNodeKey.Public(), - PrivateKey: ms.privateNodeKey, - MachineKey: ms.machinePubKey, - Peers: resp.Peers, - UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile), - Domain: ms.lastDomain, - DNS: *ms.lastDNSConfig, - PacketFilter: ms.lastParsedPacketFilter, - SSHPolicy: ms.lastSSHPolicy, - CollectServices: ms.collectServices, - DERPMap: ms.lastDERPMap, - Debug: debug, - ControlHealth: ms.lastHealth, - TKAEnabled: ms.lastTKAInfo != nil && !ms.lastTKAInfo.Disabled, + NodeKey: ms.privateNodeKey.Public(), + PrivateKey: ms.privateNodeKey, + MachineKey: ms.machinePubKey, + Peers: resp.Peers, + UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile), + Domain: ms.lastDomain, + DomainAuditLogID: ms.lastDomainAuditLogID, + DNS: *ms.lastDNSConfig, + PacketFilter: ms.lastParsedPacketFilter, + SSHPolicy: ms.lastSSHPolicy, + CollectServices: ms.collectServices, + DERPMap: ms.lastDERPMap, + Debug: debug, + ControlHealth: ms.lastHealth, + TKAEnabled: ms.lastTKAInfo != nil && !ms.lastTKAInfo.Disabled, } ms.netMapBuilding = nm diff --git a/types/netmap/netmap.go b/types/netmap/netmap.go index a2270870a..1961d9ce1 100644 --- a/types/netmap/netmap.go +++ b/types/netmap/netmap.go @@ -76,6 +76,11 @@ type NetworkMap struct { // Domain is the current Tailnet name. Domain string + // DomainAuditLogID is an audit log ID provided by control and + // only populated if the domain opts into data-plane audit logging. + // If this is empty, then data-plane audit logging is disabled. + DomainAuditLogID string + UserProfiles map[tailcfg.UserID]tailcfg.UserProfile } diff --git a/wgengine/wgcfg/config.go b/wgengine/wgcfg/config.go index 80acd0d20..3598856be 100644 --- a/wgengine/wgcfg/config.go +++ b/wgengine/wgcfg/config.go @@ -8,6 +8,7 @@ import ( "net/netip" + "tailscale.com/logtail" "tailscale.com/types/key" ) @@ -22,6 +23,13 @@ type Config struct { MTU uint16 DNS []netip.Addr Peers []Peer + + // NetworkLogging enables network logging. + // It is disabled if either ID is the zero value. + NetworkLogging struct { + NodeID logtail.PrivateID + DomainID logtail.PrivateID + } } type Peer struct { diff --git a/wgengine/wgcfg/nmcfg/nmcfg.go b/wgengine/wgcfg/nmcfg/nmcfg.go index e553b9148..acd02eb04 100644 --- a/wgengine/wgcfg/nmcfg/nmcfg.go +++ b/wgengine/wgcfg/nmcfg/nmcfg.go @@ -11,6 +11,8 @@ "net/netip" "strings" + "golang.org/x/exp/slices" + "tailscale.com/logtail" "tailscale.com/net/tsaddr" "tailscale.com/tailcfg" "tailscale.com/types/logger" @@ -58,6 +60,25 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags, Peers: make([]wgcfg.Peer, 0, len(nm.Peers)), } + // Setup log IDs for data plane audit logging. + if nm.SelfNode != nil { + canNetworkLog := slices.Contains(nm.SelfNode.Capabilities, tailcfg.CapabilityDataPlaneAuditLogs) + if canNetworkLog && nm.SelfNode.DataPlaneAuditLogID != "" && nm.DomainAuditLogID != "" { + nodeID, errNode := logtail.ParsePrivateID(nm.SelfNode.DataPlaneAuditLogID) + if errNode != nil { + logf("[v1] wgcfg: unable to parse node audit log ID: %v", errNode) + } + domainID, errDomain := logtail.ParsePrivateID(nm.DomainAuditLogID) + if errDomain != nil { + logf("[v1] wgcfg: unable to parse domain audit log ID: %v", errDomain) + } + if errNode == nil && errDomain == nil { + cfg.NetworkLogging.NodeID = nodeID + cfg.NetworkLogging.DomainID = domainID + } + } + } + // Logging buffers skippedUnselected := new(bytes.Buffer) skippedIPs := new(bytes.Buffer) diff --git a/wgengine/wgcfg/wgcfg_clone.go b/wgengine/wgcfg/wgcfg_clone.go index 6b4d0dbad..abf319c22 100644 --- a/wgengine/wgcfg/wgcfg_clone.go +++ b/wgengine/wgcfg/wgcfg_clone.go @@ -9,6 +9,7 @@ import ( "net/netip" + "tailscale.com/logtail" "tailscale.com/types/key" ) @@ -31,12 +32,16 @@ func (src *Config) Clone() *Config { // A compilation failure here means this code must be regenerated, with the command at the top of this file. var _ConfigCloneNeedsRegeneration = Config(struct { - Name string - PrivateKey key.NodePrivate - Addresses []netip.Prefix - MTU uint16 - DNS []netip.Addr - Peers []Peer + Name string + PrivateKey key.NodePrivate + Addresses []netip.Prefix + MTU uint16 + DNS []netip.Addr + Peers []Peer + NetworkLogging struct { + NodeID logtail.PrivateID + DomainID logtail.PrivateID + } }{}) // Clone makes a deep copy of Peer.