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 <joetsai@digital-static.net>
This commit is contained in:
Joe Tsai 2022-10-06 16:19:38 -07:00 committed by GitHub
parent 92ad56ddcb
commit 82f5f438e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 64 additions and 20 deletions

View File

@ -45,6 +45,7 @@ type mapSession struct {
collectServices bool collectServices bool
previousPeers []*tailcfg.Node // for delta-purposes previousPeers []*tailcfg.Node // for delta-purposes
lastDomain string lastDomain string
lastDomainAuditLogID string
lastHealth []string lastHealth []string
lastPopBrowserURL string lastPopBrowserURL string
stickyDebug tailcfg.Debug // accumulated opt.Bool values stickyDebug tailcfg.Debug // accumulated opt.Bool values
@ -113,6 +114,9 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
if resp.Domain != "" { if resp.Domain != "" {
ms.lastDomain = resp.Domain ms.lastDomain = resp.Domain
} }
if resp.DomainDataPlaneAuditLogID != "" {
ms.lastDomainAuditLogID = resp.DomainDataPlaneAuditLogID
}
if resp.Health != nil { if resp.Health != nil {
ms.lastHealth = resp.Health ms.lastHealth = resp.Health
} }
@ -143,20 +147,21 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
} }
nm := &netmap.NetworkMap{ nm := &netmap.NetworkMap{
NodeKey: ms.privateNodeKey.Public(), NodeKey: ms.privateNodeKey.Public(),
PrivateKey: ms.privateNodeKey, PrivateKey: ms.privateNodeKey,
MachineKey: ms.machinePubKey, MachineKey: ms.machinePubKey,
Peers: resp.Peers, Peers: resp.Peers,
UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile), UserProfiles: make(map[tailcfg.UserID]tailcfg.UserProfile),
Domain: ms.lastDomain, Domain: ms.lastDomain,
DNS: *ms.lastDNSConfig, DomainAuditLogID: ms.lastDomainAuditLogID,
PacketFilter: ms.lastParsedPacketFilter, DNS: *ms.lastDNSConfig,
SSHPolicy: ms.lastSSHPolicy, PacketFilter: ms.lastParsedPacketFilter,
CollectServices: ms.collectServices, SSHPolicy: ms.lastSSHPolicy,
DERPMap: ms.lastDERPMap, CollectServices: ms.collectServices,
Debug: debug, DERPMap: ms.lastDERPMap,
ControlHealth: ms.lastHealth, Debug: debug,
TKAEnabled: ms.lastTKAInfo != nil && !ms.lastTKAInfo.Disabled, ControlHealth: ms.lastHealth,
TKAEnabled: ms.lastTKAInfo != nil && !ms.lastTKAInfo.Disabled,
} }
ms.netMapBuilding = nm ms.netMapBuilding = nm

View File

@ -76,6 +76,11 @@ type NetworkMap struct {
// Domain is the current Tailnet name. // Domain is the current Tailnet name.
Domain string 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 UserProfiles map[tailcfg.UserID]tailcfg.UserProfile
} }

View File

@ -8,6 +8,7 @@
import ( import (
"net/netip" "net/netip"
"tailscale.com/logtail"
"tailscale.com/types/key" "tailscale.com/types/key"
) )
@ -22,6 +23,13 @@ type Config struct {
MTU uint16 MTU uint16
DNS []netip.Addr DNS []netip.Addr
Peers []Peer 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 { type Peer struct {

View File

@ -11,6 +11,8 @@
"net/netip" "net/netip"
"strings" "strings"
"golang.org/x/exp/slices"
"tailscale.com/logtail"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/types/logger" "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)), 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 // Logging buffers
skippedUnselected := new(bytes.Buffer) skippedUnselected := new(bytes.Buffer)
skippedIPs := new(bytes.Buffer) skippedIPs := new(bytes.Buffer)

View File

@ -9,6 +9,7 @@
import ( import (
"net/netip" "net/netip"
"tailscale.com/logtail"
"tailscale.com/types/key" "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. // A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _ConfigCloneNeedsRegeneration = Config(struct { var _ConfigCloneNeedsRegeneration = Config(struct {
Name string Name string
PrivateKey key.NodePrivate PrivateKey key.NodePrivate
Addresses []netip.Prefix Addresses []netip.Prefix
MTU uint16 MTU uint16
DNS []netip.Addr DNS []netip.Addr
Peers []Peer Peers []Peer
NetworkLogging struct {
NodeID logtail.PrivateID
DomainID logtail.PrivateID
}
}{}) }{})
// Clone makes a deep copy of Peer. // Clone makes a deep copy of Peer.