github.com/webmeshproj/webmesh-cni@v0.0.27/internal/host/config.go (about) 1 /* 2 Copyright 2023 Avi Zimmerman <avi.zimmerman@gmail.com>. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package host 18 19 import ( 20 "errors" 21 "fmt" 22 "net/netip" 23 "os" 24 "strings" 25 "time" 26 27 "github.com/spf13/pflag" 28 "github.com/webmeshproj/webmesh/pkg/config" 29 "github.com/webmeshproj/webmesh/pkg/meshnet/endpoints" 30 31 "github.com/webmeshproj/webmesh-cni/internal/types" 32 ) 33 34 // Config contains the options for the host node. 35 type Config struct { 36 // NodeID is the ID of the node. 37 NodeID string `koanf:"node-id"` 38 // Namespace is the namespace of the node. 39 Namespace string `koanf:"namespace,omitempty"` 40 // LockDuration is the duration to hold locks for when allocating addresses. 41 LockDuration time.Duration `koanf:"lock-duration,omitempty"` 42 // LockAcquireTimeout is the timeout for acquiring locks when allocating addresses. 43 LockAcquireTimeout time.Duration `koanf:"lock-acquire-timeout,omitempty"` 44 // ConnectTimeout is the timeout for connecting the host webmesh node to the network. 45 ConnectTimeout time.Duration `koanf:"connect-timeout,omitempty"` 46 // Auth are configuration options for authenticating with other nodes. 47 Auth config.AuthOptions `koanf:"auth,omitempty"` 48 // WireGuard are configurations for the WireGuard interface. 49 WireGuard config.WireGuardOptions `koanf:"wireguard,omitempty"` 50 // Services is the service options for the host webmesh node. 51 Services config.ServiceOptions `koanf:"services,omitempty"` 52 // Plugins is the plugin options for the host webmesh node. 53 Plugins config.PluginOptions `koanf:"plugins,omitempty"` 54 // Network is the network options for the host webmesh node. 55 Network NetworkConfig `koanf:"network,omitempty"` 56 // LogLevel is the log level for the host webmesh node. 57 LogLevel string `koanf:"log-level,omitempty"` 58 } 59 60 // NewDefaultConfig returns a new default configuration for the host webmesh node. 61 func NewDefaultConfig() Config { 62 c := Config{ 63 NodeID: os.Getenv(types.NodeNameEnvVar), 64 Namespace: os.Getenv(types.PodNamespaceEnvVar), 65 LockDuration: time.Second * 10, 66 LockAcquireTimeout: time.Second * 5, 67 ConnectTimeout: time.Second * 30, 68 Auth: config.NewAuthOptions(), 69 WireGuard: config.NewWireGuardOptions(), 70 Services: config.NewServiceOptions(true), 71 Plugins: config.NewPluginOptions(), 72 Network: NewNetworkConfig(), 73 LogLevel: "info", 74 } 75 // Make full-tunnel opt-in on the host node. It would almost certainly 76 // break things if it were enabled by default. 77 c.WireGuard.DisableFullTunnel = true 78 return c 79 } 80 81 func (o *Config) BindFlags(prefix string, fs *pflag.FlagSet) { 82 fs.StringVar(&o.NodeID, prefix+"node-id", o.NodeID, "The ID of the node") 83 fs.StringVar(&o.Namespace, prefix+"namespace", o.Namespace, "The namespace of the node") 84 fs.DurationVar(&o.LockDuration, prefix+"lock-duration", o.LockDuration, "The duration to hold locks for when allocating addresses") 85 fs.DurationVar(&o.LockAcquireTimeout, prefix+"lock-acquire-timeout", o.LockAcquireTimeout, "The timeout for acquiring locks when allocating addresses") 86 fs.DurationVar(&o.ConnectTimeout, prefix+"connect-timeout", o.ConnectTimeout, "The timeout for connecting the host webmesh node to the network") 87 fs.StringVar(&o.LogLevel, prefix+"log-level", o.LogLevel, "The log level for the host webmesh node") 88 o.Auth.BindFlags(prefix+"auth.", fs) 89 o.WireGuard.BindFlags(prefix+"wireguard.", fs) 90 o.Network.BindFlags(prefix+"network.", fs) 91 o.Services.BindFlags(prefix+"services.", fs) 92 o.Plugins.BindFlags(prefix+"plugins.", fs) 93 } 94 95 func (o *Config) Validate() error { 96 if o.NodeID == "" { 97 return errors.New("node-id must be set") 98 } 99 if o.Namespace == "" { 100 return errors.New("namespace must be set") 101 } 102 if o.ConnectTimeout <= 0 { 103 return errors.New("connect-timeout must be positive") 104 } 105 if o.LockDuration <= 0 { 106 return errors.New("lock-duration must be positive") 107 } 108 if o.LockAcquireTimeout <= 0 { 109 return errors.New("lock-acquire-timeout must be positive") 110 } 111 if err := o.Network.Validate(); err != nil { 112 return err 113 } 114 if err := o.Services.Validate(); err != nil { 115 return err 116 } 117 if err := o.WireGuard.Validate(); err != nil { 118 return err 119 } 120 return nil 121 } 122 123 // NetworkConfig contains the options for the network. 124 type NetworkConfig struct { 125 // RemoteEndpointDetection enables remote endpoint detection for wireguard endpoints. 126 RemoteEndpointDetection bool `koanf:"remote-endpoint-detection,omitempty"` 127 // PodCIDR is a comma separated list of CIDRs to use for the pod network. 128 // If no IPv6 CIDR is provided, one will be generated. 129 PodCIDR string `koanf:"pod-cidr,omitempty"` 130 // ServiceCIDR is a comma-separated list of CIDRs to use for the service network. 131 ServiceCIDR string `koanf:"service-cidr,omitempty"` 132 // ClusterDomain is the cluster domain to use for the network. 133 ClusterDomain string `koanf:"cluster-domain,omitempty"` 134 // Routes to allow for container and other connected node traffic. 135 Routes []string `koanf:"routes,omitempty"` 136 // WriteResolvConf will add any MeshDNS servers to the system resolv.conf. 137 WriteResolvConf bool `koanf:"write-resolv-conf,omitempty"` 138 // DisableIPv4 disables IPv4 on the host webmesh node. 139 DisableIPv4 bool `koanf:"disable-ipv4,omitempty"` 140 // DisableIPv6 disables IPv6 on the host webmesh node. 141 DisableIPv6 bool `koanf:"disable-ipv6,omitempty"` 142 // DisableRBAC disables RBAC controls on the webmesh network. 143 // This only takes during initial cluster bootstrap. 144 DisableRBAC bool `koanf:"disable-rbac,omitempty"` 145 } 146 147 // PodCIDRs returns the pod CIDRs. 148 func (n *NetworkConfig) PodCIDRs() endpoints.PrefixList { 149 var cidrs []netip.Prefix 150 if n.PodCIDR == "" { 151 return cidrs 152 } 153 for _, cidr := range strings.Split(n.PodCIDR, ",") { 154 cidrs = append(cidrs, netip.MustParsePrefix(cidr)) 155 } 156 return cidrs 157 } 158 159 // ServiceCIDRs returns the service CIDRs. 160 func (n *NetworkConfig) ServiceCIDRs() endpoints.PrefixList { 161 var cidrs []netip.Prefix 162 if n.ServiceCIDR == "" { 163 return cidrs 164 } 165 for _, cidr := range strings.Split(n.ServiceCIDR, ",") { 166 cidrs = append(cidrs, netip.MustParsePrefix(cidr)) 167 } 168 return cidrs 169 } 170 171 // CIDRs returns all CIDRs. 172 func (n *NetworkConfig) CIDRs() endpoints.PrefixList { 173 return append(n.PodCIDRs(), n.ServiceCIDRs()...) 174 } 175 176 // CIDRsContain checks if the local CIDRs contain the given prefix. 177 func (n *NetworkConfig) CIDRsContain(prefix netip.Prefix) bool { 178 for _, cidr := range n.PodCIDRs() { 179 if cidr.Contains(prefix.Addr()) && prefix.Bits() >= cidr.Bits() { 180 return true 181 } 182 } 183 for _, cidr := range n.ServiceCIDRs() { 184 if cidr.Contains(prefix.Addr()) && prefix.Bits() >= cidr.Bits() { 185 return true 186 } 187 } 188 return false 189 } 190 191 func NewNetworkConfig() NetworkConfig { 192 return NetworkConfig{ 193 RemoteEndpointDetection: false, 194 PodCIDR: os.Getenv(types.PodCIDREnvVar), 195 ServiceCIDR: os.Getenv(types.ServiceCIDREnvVar), 196 ClusterDomain: os.Getenv(types.ClusterDomainEnvVar), 197 Routes: []string{"0.0.0.0/0", "::/0"}, 198 DisableIPv4: false, 199 DisableIPv6: false, 200 DisableRBAC: true, 201 } 202 } 203 204 func (n *NetworkConfig) BindFlags(prefix string, fs *pflag.FlagSet) { 205 fs.BoolVar(&n.RemoteEndpointDetection, prefix+"remote-endpoint-detection", n.RemoteEndpointDetection, "Enable remote endpoint detection for wireguard endpoints") 206 fs.StringVar(&n.PodCIDR, prefix+"pod-cidr", n.PodCIDR, "The CIDR(s) to use for the pod network") 207 fs.StringVar(&n.ServiceCIDR, prefix+"service-cidr", n.ServiceCIDR, "The CIDR(s) to use for the service network") 208 fs.StringVar(&n.ClusterDomain, prefix+"cluster-domain", n.ClusterDomain, "The cluster domain to use for the network") 209 fs.StringSliceVar(&n.Routes, prefix+"routes", n.Routes, "Routes to allow for container and other connected node traffic") 210 fs.BoolVar(&n.WriteResolvConf, prefix+"write-resolv-conf", n.WriteResolvConf, "Write MeshDNS servers to the local resolv.conf") 211 fs.BoolVar(&n.DisableIPv4, prefix+"disable-ipv4", n.DisableIPv4, "Disable IPv4 on the host webmesh node") 212 fs.BoolVar(&n.DisableIPv6, prefix+"disable-ipv6", n.DisableIPv6, "Disable IPv6 on the host webmesh node") 213 fs.BoolVar(&n.DisableRBAC, prefix+"disable-rbac", n.DisableRBAC, "Disable RBAC controls on the webmesh network") 214 } 215 216 func (n *NetworkConfig) Validate() error { 217 if n.PodCIDR == "" { 218 return errors.New("pod-cidr must be set") 219 } 220 for _, addr := range strings.Split(n.PodCIDR, ",") { 221 _, err := netip.ParsePrefix(addr) 222 if err != nil { 223 return fmt.Errorf("invalid pod-cidr: %w", err) 224 } 225 } 226 if n.ServiceCIDR != "" { 227 for _, addr := range strings.Split(n.ServiceCIDR, ",") { 228 _, err := netip.ParsePrefix(addr) 229 if err != nil { 230 return fmt.Errorf("invalid service-cidr: %w", err) 231 } 232 } 233 } 234 if n.ClusterDomain == "" { 235 return errors.New("cluster-domain must be set") 236 } 237 if len(n.Routes) == 0 { 238 return errors.New("at least one route must be set") 239 } 240 for _, rt := range n.Routes { 241 _, err := netip.ParsePrefix(rt) 242 if err != nil { 243 return fmt.Errorf("invalid route: %w", err) 244 } 245 } 246 if n.DisableIPv4 && n.DisableIPv6 { 247 return errors.New("cannot disable both IPv4 and IPv6") 248 } 249 return nil 250 }