github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/tunnel_strategy.go (about) 1 /* 2 Copyright 2022 Gravitational, Inc. 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 types 18 19 import ( 20 "encoding/json" 21 22 "github.com/gravitational/trace" 23 24 "github.com/gravitational/teleport/api/utils" 25 ) 26 27 const ( 28 tunnelStrategyTypeParam = "type" 29 defaultAgentConnectionCount = 1 30 ) 31 32 // DefaultAgentMeshTunnelStrategy sets default values for a agent mesh 33 // tunnel strategy. 34 func DefaultAgentMeshTunnelStrategy() *AgentMeshTunnelStrategy { 35 return &AgentMeshTunnelStrategy{} 36 } 37 38 // DefaultProxyPeeringTunnelStrategy sets default values for a proxy peering 39 // tunnel strategy. 40 func DefaultProxyPeeringTunnelStrategy() *ProxyPeeringTunnelStrategy { 41 return &ProxyPeeringTunnelStrategy{ 42 AgentConnectionCount: defaultAgentConnectionCount, 43 } 44 } 45 46 // DefaultTunnelStrategy is the default tunnel strategy used when one is not 47 // specified. 48 func DefaultTunnelStrategy() TunnelStrategy { 49 return &TunnelStrategyV1_AgentMesh{ 50 AgentMesh: DefaultAgentMeshTunnelStrategy(), 51 } 52 } 53 54 // TunnelStrategy defines methods to be implemented by any TunnelStrategy. 55 type TunnelStrategy interface { 56 isTunnelStrategyV1_Strategy 57 CheckAndSetDefaults() error 58 } 59 60 // tunnelStrategyConfig represents a unparsed tunnel strategy configuration. 61 type tunnelStrategyConfig struct { 62 Type TunnelStrategyType `yaml:"type"` 63 Params map[string]interface{} `yaml:",inline"` 64 } 65 66 // newTunnelStrategyConfig creates a new tunnelStrategyConfig instance. 67 func newTunnelStrategyConfig() *tunnelStrategyConfig { 68 return &tunnelStrategyConfig{} 69 } 70 71 // setFromMap sets a TunnelStrategyConfig from a map. 72 func (c *tunnelStrategyConfig) setFromMap(m map[string]interface{}) error { 73 rawStrategy, ok := m[tunnelStrategyTypeParam] 74 if !ok { 75 return trace.BadParameter("missing type parameter") 76 } 77 78 // The map representation of TunnelStrategyType is expected to be a string. 79 strategyType, ok := rawStrategy.(string) 80 if !ok { 81 return trace.BadParameter("invalid type parameter") 82 } 83 c.Type = TunnelStrategyType(strategyType) 84 85 c.Params = make(map[string]interface{}, len(m)-1) 86 for k, v := range m { 87 if k == tunnelStrategyTypeParam { 88 continue 89 } 90 c.Params[k] = v 91 } 92 return nil 93 } 94 95 // getMapCopy returns a TunnelStrategyConfig as a map. 96 func (c *tunnelStrategyConfig) getMapCopy() map[string]interface{} { 97 mCopy := make(map[string]interface{}, len(c.Params)+1) 98 for k, v := range c.Params { 99 mCopy[k] = v 100 } 101 102 // The map representation of TunnelStrategyType is expected to be a string. 103 mCopy[tunnelStrategyTypeParam] = string(c.Type) 104 return mCopy 105 } 106 107 // MarshalYAML converts a TunnelStrategyV1 to yaml. 108 func (s *TunnelStrategyV1) MarshalYAML() (interface{}, error) { 109 var config *tunnelStrategyConfig 110 err := s.marshal(func(c *tunnelStrategyConfig) error { 111 config = c 112 return nil 113 }) 114 if err != nil { 115 return nil, trace.Wrap(err) 116 } 117 return config.getMapCopy(), nil 118 } 119 120 // UnmarshalYAML converts yaml to a TunnelStrategyV1 using a strict policy to 121 // disallow unknown fields. 122 func (s *TunnelStrategyV1) UnmarshalYAML(unmarshal func(interface{}) error) error { 123 err := s.unmarshal(utils.StrictObjectToStruct, func(c *tunnelStrategyConfig) error { 124 return trace.Wrap(unmarshal(c)) 125 }) 126 return trace.Wrap(err) 127 } 128 129 // MarshalJSON converts a TunnelStrategyV1 to json. 130 func (s *TunnelStrategyV1) MarshalJSON() ([]byte, error) { 131 var data []byte 132 err := s.marshal(func(c *tunnelStrategyConfig) error { 133 var err error 134 data, err = json.Marshal(c.getMapCopy()) 135 return trace.Wrap(err) 136 }) 137 if err != nil { 138 return nil, trace.Wrap(err) 139 } 140 return data, nil 141 } 142 143 // UnmarshalJSON converts json to a TunnelStrategyV1. Unknown fields are allowed 144 // to prevent rollbacks causing issues decoding this data from the backend. 145 func (s *TunnelStrategyV1) UnmarshalJSON(data []byte) error { 146 err := s.unmarshal(utils.ObjectToStruct, func(c *tunnelStrategyConfig) error { 147 params := make(map[string]interface{}) 148 err := json.Unmarshal(data, ¶ms) 149 if err != nil { 150 return trace.Wrap(err) 151 } 152 return trace.Wrap(c.setFromMap(params)) 153 }) 154 return trace.Wrap(err) 155 } 156 157 // marshal converts a TunnelStrategyV1 to a TunnelStrategyConfig before calling 158 // the given marshal function. 159 func (s *TunnelStrategyV1) marshal(marshal func(*tunnelStrategyConfig) error) error { 160 config := newTunnelStrategyConfig() 161 switch strategy := s.Strategy.(type) { 162 case *TunnelStrategyV1_AgentMesh: 163 config.Type = AgentMesh 164 err := utils.ObjectToStruct(strategy.AgentMesh, &config.Params) 165 if err != nil { 166 return trace.Wrap(err) 167 } 168 case *TunnelStrategyV1_ProxyPeering: 169 config.Type = ProxyPeering 170 err := utils.ObjectToStruct(strategy.ProxyPeering, &config.Params) 171 if err != nil { 172 return trace.Wrap(err) 173 } 174 default: 175 return trace.BadParameter("unknown tunnel strategy: \"%s\"", config.Type) 176 } 177 178 return trace.Wrap(marshal(config)) 179 } 180 181 // objectToStructFunc is a function that converts one struct to another. 182 type objectToStructFunc func(interface{}, interface{}) error 183 184 func (s *TunnelStrategyV1) unmarshal(ots objectToStructFunc, unmarshal func(*tunnelStrategyConfig) error) error { 185 config := newTunnelStrategyConfig() 186 err := unmarshal(config) 187 if err != nil { 188 return trace.Wrap(err) 189 } 190 191 switch config.Type { 192 case AgentMesh: 193 strategy := &TunnelStrategyV1_AgentMesh{ 194 AgentMesh: &AgentMeshTunnelStrategy{}, 195 } 196 197 err = ots(&config.Params, strategy.AgentMesh) 198 if err != nil { 199 return trace.Wrap(err) 200 } 201 s.Strategy = strategy 202 case ProxyPeering: 203 strategy := &TunnelStrategyV1_ProxyPeering{ 204 ProxyPeering: &ProxyPeeringTunnelStrategy{}, 205 } 206 207 err = ots(&config.Params, strategy.ProxyPeering) 208 if err != nil { 209 return trace.Wrap(err) 210 } 211 s.Strategy = strategy 212 default: 213 return trace.BadParameter("unknown tunnel strategy: \"%s\"", config.Type) 214 } 215 216 return nil 217 } 218 219 // CheckAndSetDefaults validates and sets default values for a tunnel strategy. 220 func (s *TunnelStrategyV1) CheckAndSetDefaults() error { 221 if s.Strategy == nil { 222 s.Strategy = DefaultTunnelStrategy() 223 } 224 225 switch strategy := s.Strategy.(type) { 226 case TunnelStrategy: 227 err := strategy.CheckAndSetDefaults() 228 if err != nil { 229 return trace.Wrap(err) 230 } 231 default: 232 return trace.BadParameter("unknown tunnel strategy: %T", strategy) 233 } 234 235 return nil 236 } 237 238 // CheckAndSetDefaults validates an agent mesh tunnel strategy. 239 func (s *TunnelStrategyV1_AgentMesh) CheckAndSetDefaults() error { 240 if s.AgentMesh == nil { 241 s.AgentMesh = DefaultAgentMeshTunnelStrategy() 242 } 243 244 return nil 245 } 246 247 // CheckAndSetDefaults validates a proxy peering tunnel strategy. 248 func (s *TunnelStrategyV1_ProxyPeering) CheckAndSetDefaults() error { 249 if s.ProxyPeering == nil { 250 s.ProxyPeering = DefaultProxyPeeringTunnelStrategy() 251 } 252 if s.ProxyPeering.AgentConnectionCount == 0 { 253 s.ProxyPeering.AgentConnectionCount = defaultAgentConnectionCount 254 } 255 256 return nil 257 }