@ -14,6 +14,7 @@ import (
"os"
"path"
"strconv"
"strings"
"tailscale.com/ipn/conffile"
"tailscale.com/kube/kubeclient"
@ -62,11 +63,67 @@ type settings struct {
// PodIP is the IP of the Pod if running in Kubernetes. This is used
// when setting up rules to proxy cluster traffic to cluster ingress
// target.
// Deprecated: use PodIPv4, PodIPv6 instead to support dual stack clusters
PodIP string
PodIPv4 string
PodIPv6 string
HealthCheckAddrPort string
EgressSvcsCfgPath string
}
func configFromEnv ( ) ( * settings , error ) {
cfg := & settings {
AuthKey : defaultEnvs ( [ ] string { "TS_AUTHKEY" , "TS_AUTH_KEY" } , "" ) ,
Hostname : defaultEnv ( "TS_HOSTNAME" , "" ) ,
Routes : defaultEnvStringPointer ( "TS_ROUTES" ) ,
ServeConfigPath : defaultEnv ( "TS_SERVE_CONFIG" , "" ) ,
ProxyTargetIP : defaultEnv ( "TS_DEST_IP" , "" ) ,
ProxyTargetDNSName : defaultEnv ( "TS_EXPERIMENTAL_DEST_DNS_NAME" , "" ) ,
TailnetTargetIP : defaultEnv ( "TS_TAILNET_TARGET_IP" , "" ) ,
TailnetTargetFQDN : defaultEnv ( "TS_TAILNET_TARGET_FQDN" , "" ) ,
DaemonExtraArgs : defaultEnv ( "TS_TAILSCALED_EXTRA_ARGS" , "" ) ,
ExtraArgs : defaultEnv ( "TS_EXTRA_ARGS" , "" ) ,
InKubernetes : os . Getenv ( "KUBERNETES_SERVICE_HOST" ) != "" ,
UserspaceMode : defaultBool ( "TS_USERSPACE" , true ) ,
StateDir : defaultEnv ( "TS_STATE_DIR" , "" ) ,
AcceptDNS : defaultEnvBoolPointer ( "TS_ACCEPT_DNS" ) ,
KubeSecret : defaultEnv ( "TS_KUBE_SECRET" , "tailscale" ) ,
SOCKSProxyAddr : defaultEnv ( "TS_SOCKS5_SERVER" , "" ) ,
HTTPProxyAddr : defaultEnv ( "TS_OUTBOUND_HTTP_PROXY_LISTEN" , "" ) ,
Socket : defaultEnv ( "TS_SOCKET" , "/tmp/tailscaled.sock" ) ,
AuthOnce : defaultBool ( "TS_AUTH_ONCE" , false ) ,
Root : defaultEnv ( "TS_TEST_ONLY_ROOT" , "/" ) ,
TailscaledConfigFilePath : tailscaledConfigFilePath ( ) ,
AllowProxyingClusterTrafficViaIngress : defaultBool ( "EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS" , false ) ,
PodIP : defaultEnv ( "POD_IP" , "" ) ,
EnableForwardingOptimizations : defaultBool ( "TS_EXPERIMENTAL_ENABLE_FORWARDING_OPTIMIZATIONS" , false ) ,
HealthCheckAddrPort : defaultEnv ( "TS_HEALTHCHECK_ADDR_PORT" , "" ) ,
EgressSvcsCfgPath : defaultEnv ( "TS_EGRESS_SERVICES_CONFIG_PATH" , "" ) ,
}
podIPs , ok := os . LookupEnv ( "POD_IPS" )
if ok {
ips := strings . Split ( podIPs , "," )
if len ( ips ) > 2 {
return nil , fmt . Errorf ( "POD_IPs can contain at most 2 IPs, got %d (%v)" , len ( ips ) , ips )
}
for _ , ip := range ips {
parsed , err := netip . ParseAddr ( ip )
if err != nil {
return nil , fmt . Errorf ( "error parsing IP address %s: %w" , ip , err )
}
if parsed . Is4 ( ) {
cfg . PodIPv4 = parsed . String ( )
continue
}
cfg . PodIPv6 = parsed . String ( )
}
}
if err := cfg . validate ( ) ; err != nil {
return nil , fmt . Errorf ( "invalid configuration: %v" , err )
}
return cfg , nil
}
func ( s * settings ) validate ( ) error {
if s . TailscaledConfigFilePath != "" {
dir , file := path . Split ( s . TailscaledConfigFilePath )