tailscale/ipn/conf.go
Irbe Krumina d86d1e7601
cmd/k8s-operator,cmd/containerboot,ipn,k8s-operator: turn off stateful filter for egress proxies. (#12075)
Turn off stateful filtering for egress proxies to allow cluster
traffic to be forwarded to tailnet.

Allow configuring stateful filter via tailscaled config file.

Deprecate EXPERIMENTAL_TS_CONFIGFILE_PATH env var and introduce a new
TS_EXPERIMENTAL_VERSIONED_CONFIG env var that can be used to provide
containerboot a directory that should contain one or more
tailscaled config files named cap-<tailscaled-cap-version>.hujson.
Containerboot will pick the one with the newest capability version
that is not newer than its current capability version.

Proxies with this change will not work with older Tailscale
Kubernetes operator versions - users must ensure that
the deployed operator is at the same version or newer (up to
4 version skew) than the proxies.

Updates tailscale/tailscale#12061

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
Co-authored-by: Maisem Ali <maisem@tailscale.com>
2024-05-10 16:32:37 +01:00

138 lines
4.2 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package ipn
import (
"net/netip"
"tailscale.com/tailcfg"
"tailscale.com/types/opt"
"tailscale.com/types/preftype"
)
// ConfigVAlpha is the config file format for the "alpha0" version.
type ConfigVAlpha struct {
Version string // "alpha0" for now
Locked opt.Bool `json:",omitempty"` // whether the config is locked from being changed by 'tailscale set'; it defaults to true
ServerURL *string `json:",omitempty"` // defaults to https://controlplane.tailscale.com
AuthKey *string `json:",omitempty"` // as needed if NeedsLogin. either key or path to a file (if prefixed with "file:")
Enabled opt.Bool `json:",omitempty"` // wantRunning; empty string defaults to true
OperatorUser *string `json:",omitempty"` // local user name who is allowed to operate tailscaled without being root or using sudo
Hostname *string `json:",omitempty"`
AcceptDNS opt.Bool `json:"acceptDNS,omitempty"` // --accept-dns
AcceptRoutes opt.Bool `json:"acceptRoutes,omitempty"` // --accept-routes defaults to true
ExitNode *string `json:"exitNode,omitempty"` // IP, StableID, or MagicDNS base name
AllowLANWhileUsingExitNode opt.Bool `json:"allowLANWhileUsingExitNode,omitempty"`
AdvertiseRoutes []netip.Prefix `json:",omitempty"`
DisableSNAT opt.Bool `json:",omitempty"`
NetfilterMode *string `json:",omitempty"` // "on", "off", "nodivert"
NoStatefulFiltering opt.Bool `json:",omitempty"`
PostureChecking opt.Bool `json:",omitempty"`
RunSSHServer opt.Bool `json:",omitempty"` // Tailscale SSH
RunWebClient opt.Bool `json:",omitempty"`
ShieldsUp opt.Bool `json:",omitempty"`
AutoUpdate *AutoUpdatePrefs `json:",omitempty"`
ServeConfigTemp *ServeConfig `json:",omitempty"` // TODO(bradfitz,maisem): make separate stable type for this
// TODO(bradfitz,maisem): future something like:
// Profile map[string]*Config // keyed by alice@gmail.com, corp.com (TailnetSID)
}
func (c *ConfigVAlpha) ToPrefs() (MaskedPrefs, error) {
var mp MaskedPrefs
if c == nil {
return mp, nil
}
mp.WantRunning = !c.Enabled.EqualBool(false)
mp.WantRunningSet = mp.WantRunning || c.Enabled != ""
if c.ServerURL != nil {
mp.ControlURL = *c.ServerURL
mp.ControlURLSet = true
}
if c.AuthKey != nil && *c.AuthKey != "" {
mp.LoggedOut = false
mp.LoggedOutSet = true
}
if c.OperatorUser != nil {
mp.OperatorUser = *c.OperatorUser
mp.OperatorUserSet = true
}
if c.Hostname != nil {
mp.Hostname = *c.Hostname
mp.HostnameSet = true
}
if c.AcceptDNS != "" {
mp.CorpDNS = c.AcceptDNS.EqualBool(true)
mp.CorpDNSSet = true
}
if c.AcceptRoutes != "" {
mp.RouteAll = c.AcceptRoutes.EqualBool(true)
mp.RouteAllSet = true
}
if c.ExitNode != nil {
ip, err := netip.ParseAddr(*c.ExitNode)
if err == nil {
mp.ExitNodeIP = ip
mp.ExitNodeIPSet = true
} else {
mp.ExitNodeID = tailcfg.StableNodeID(*c.ExitNode)
mp.ExitNodeIDSet = true
}
}
if c.AllowLANWhileUsingExitNode != "" {
mp.ExitNodeAllowLANAccess = c.AllowLANWhileUsingExitNode.EqualBool(true)
mp.ExitNodeAllowLANAccessSet = true
}
if c.AdvertiseRoutes != nil {
mp.AdvertiseRoutes = c.AdvertiseRoutes
mp.AdvertiseRoutesSet = true
}
if c.DisableSNAT != "" {
mp.NoSNAT = c.DisableSNAT.EqualBool(true)
mp.NoSNAT = true
}
if c.NoStatefulFiltering != "" {
mp.NoStatefulFiltering = c.NoStatefulFiltering
mp.NoStatefulFilteringSet = true
}
if c.NetfilterMode != nil {
m, err := preftype.ParseNetfilterMode(*c.NetfilterMode)
if err != nil {
return mp, err
}
mp.NetfilterMode = m
mp.NetfilterModeSet = true
}
if c.PostureChecking != "" {
mp.PostureChecking = c.PostureChecking.EqualBool(true)
mp.PostureCheckingSet = true
}
if c.RunSSHServer != "" {
mp.RunSSH = c.RunSSHServer.EqualBool(true)
mp.RunSSHSet = true
}
if c.RunWebClient != "" {
mp.RunWebClient = c.RunWebClient.EqualBool(true)
mp.RunWebClientSet = true
}
if c.ShieldsUp != "" {
mp.ShieldsUp = c.ShieldsUp.EqualBool(true)
mp.ShieldsUpSet = true
}
if c.AutoUpdate != nil {
mp.AutoUpdate = *c.AutoUpdate
mp.AutoUpdateSet = AutoUpdatePrefsMask{ApplySet: true, CheckSet: true}
}
return mp, nil
}