github.com/cilium/cilium@v1.16.2/operator/pkg/model/model.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package model 5 6 import ( 7 "sort" 8 "strconv" 9 "strings" 10 "time" 11 ) 12 13 // Model holds an abstracted data model representing the translation 14 // of various types of Kubernetes config to Cilium config. 15 type Model struct { 16 HTTP []HTTPListener 17 TLSPassthrough []TLSPassthroughListener 18 } 19 20 func (m *Model) GetListeners() []Listener { 21 var listeners []Listener 22 23 for i := range m.HTTP { 24 listeners = append(listeners, &m.HTTP[i]) 25 } 26 27 for i := range m.TLSPassthrough { 28 listeners = append(listeners, &m.TLSPassthrough[i]) 29 } 30 31 return listeners 32 } 33 34 type Listener interface { 35 GetSources() []FullyQualifiedResource 36 GetPort() uint32 37 GetAnnotations() map[string]string 38 GetLabels() map[string]string 39 } 40 41 // HTTPListener holds configuration for any listener that terminates and proxies HTTP 42 // including HTTP and HTTPS. 43 // Each holds the configuration info for one distinct HTTP listener, by 44 // - Hostname 45 // - TLS 46 // - Address 47 // - Port 48 type HTTPListener struct { 49 // Name of the HTTPListener 50 Name string 51 // Sources is a slice of fully qualified resources this HTTPListener is sourced 52 // from. 53 Sources []FullyQualifiedResource 54 // IPAddress that the listener should listen on. 55 // The string must be parseable as an IP address. 56 Address string 57 // Port on which the service can be expected to be accessed by clients. 58 Port uint32 59 // Hostname that the listener should match. 60 // Wildcards are supported in prefix or suffix forms, or the special wildcard `*`. 61 // An empty list means that the Listener should match all hostnames. 62 Hostname string 63 // TLS Certificate information. If omitted, then the listener is a cleartext HTTP listener. 64 TLS []TLSSecret 65 // Routes associated with HTTP traffic to the service. 66 // An empty list means that traffic will not be routed. 67 Routes []HTTPRoute 68 // Service configuration 69 Service *Service 70 // Infrastructure configuration 71 Infrastructure *Infrastructure 72 // ForceHTTPtoHTTPSRedirect enforces that, for HTTPListeners that have a 73 // TLS field set and create a HTTPS listener, an equivalent plaintext HTTP 74 // listener will be created that redirects requests from HTTP to HTTPS. 75 // 76 // This plaintext listener will override any other plaintext HTTP config in 77 // the final rendered Envoy Config. 78 ForceHTTPtoHTTPSRedirect bool 79 } 80 81 func (l HTTPListener) GetSources() []FullyQualifiedResource { 82 return l.Sources 83 } 84 85 func (l HTTPListener) GetPort() uint32 { 86 return l.Port 87 } 88 89 func (l HTTPListener) GetAnnotations() map[string]string { 90 if l.Infrastructure != nil { 91 return l.Infrastructure.Annotations 92 } 93 return nil 94 } 95 96 func (l HTTPListener) GetLabels() map[string]string { 97 if l.Infrastructure != nil { 98 return l.Infrastructure.Labels 99 } 100 return nil 101 } 102 103 // TLSPassthroughListener holds configuration for any listener that proxies TLS 104 // based on the SNI value. 105 // Each holds the configuration info for one distinct TLS listener, by 106 // - Hostname 107 // - Address 108 // - Port 109 type TLSPassthroughListener struct { 110 // Name of the TLSListener 111 Name string 112 // Sources is a slice of fully qualified resources this TLSListener is sourced 113 // from. 114 Sources []FullyQualifiedResource 115 // IPAddress that the listener should listen on. 116 // The string must be parseable as an IP address. 117 Address string 118 // Port on which the service can be expected to be accessed by clients. 119 Port uint32 120 // Hostname that the listener should match. 121 // Wildcards are supported in prefix or suffix forms, or the special wildcard `*`. 122 // An empty list means that the Listener should match all hostnames. 123 Hostname string 124 // Routes associated with traffic to the service. 125 // An empty list means that traffic will not be routed. 126 Routes []TLSPassthroughRoute 127 // Service configuration 128 Service *Service 129 // Infrastructure configuration 130 Infrastructure *Infrastructure 131 } 132 133 func (l TLSPassthroughListener) GetAnnotations() map[string]string { 134 if l.Infrastructure != nil { 135 return l.Infrastructure.Annotations 136 } 137 return nil 138 } 139 140 func (l TLSPassthroughListener) GetLabels() map[string]string { 141 if l.Infrastructure != nil { 142 return l.Infrastructure.Labels 143 } 144 return nil 145 } 146 147 func (l TLSPassthroughListener) GetSources() []FullyQualifiedResource { 148 return l.Sources 149 } 150 151 func (l TLSPassthroughListener) GetPort() uint32 { 152 return l.Port 153 } 154 155 // Service holds the configuration for desired Service details 156 type Service struct { 157 // Type is the type of service that is being used for Listener (e.g. Load Balancer or Node port) 158 // Defaults to Load Balancer type 159 Type string 160 // InsecureNodePort is the back-end port of the service that is being used for HTTP Listener 161 // Applicable only if Type is Node NodePort 162 InsecureNodePort *uint32 163 // SecureNodePort is the back-end port of the service that is being used for HTTPS Listener 164 // Applicable only if Type is Node NodePort 165 SecureNodePort *uint32 166 } 167 168 // FullyQualifiedResource stores the full details of a Kubernetes resource, including 169 // the Group, Version, and Kind. 170 // Namespace must be set to the empty string for cluster-scoped resources. 171 type FullyQualifiedResource struct { 172 Name string 173 Namespace string 174 Group string 175 Version string 176 Kind string 177 UID string 178 } 179 180 // TLSSecret holds a reference to a secret containing a TLS keypair. 181 type TLSSecret struct { 182 Name string 183 Namespace string 184 } 185 186 // DirectResponse holds configuration for a direct response. 187 type DirectResponse struct { 188 StatusCode int 189 Body string 190 } 191 192 // Header is a key-value pair. 193 type Header struct { 194 Name string 195 Value string 196 } 197 198 // HTTPHeaderFilter holds configuration for a request header filter. 199 type HTTPHeaderFilter struct { 200 // HeadersToAdd is a list of headers to add to the request. 201 // Existing headers with the same name will be appended to. 202 HeadersToAdd []Header 203 // HeadersToSet is a list of headers to set in the request. 204 // Existing headers will be overwritten. 205 HeadersToSet []Header 206 // HeadersToRemove is a list of headers to remove from the request. 207 HeadersToRemove []string 208 } 209 210 // HTTPRequestRedirectFilter holds configuration for a request redirect. 211 type HTTPRequestRedirectFilter struct { 212 // Scheme is the scheme to be used in the value of the `Location` header in 213 // the response. When empty, the scheme of the request is used. 214 Scheme *string 215 216 // Hostname is the hostname to be used in the value of the `Location` 217 // header in the response. 218 // When empty, the hostname of the request is used. 219 Hostname *string 220 221 // Path defines parameters used to modify the path of the incoming request. 222 // The modified path is then used to construct the `Location` header. When 223 // empty, the request path is used as-is. 224 Path *StringMatch 225 226 // Port is the port to be used in the value of the `Location` 227 // header in the response. 228 // When empty, port (if specified) of the request is used. 229 Port *int32 230 231 // StatusCode is the HTTP status code to be used in response. 232 // 233 // Note that values may be added to this enum, implementations 234 // must ensure that unknown values will not cause a crash. 235 StatusCode *int 236 } 237 238 // HTTPURLRewriteFilter defines a filter that modifies a request during 239 // forwarding. At most one of these filters may be used on a Route rule. This 240 // MUST NOT be used on the same Route rule as a HTTPRequestRedirect filter. 241 type HTTPURLRewriteFilter struct { 242 // Hostname is the value to be used to replace the Host header value during 243 // forwarding. 244 HostName *string 245 246 // Path is the values to be used to replace the path 247 Path *StringMatch 248 } 249 250 // HTTPRequestMirror defines configuration for the RequestMirror filter. 251 type HTTPRequestMirror struct { 252 // Backend is the backend handling the requests 253 Backend *Backend 254 } 255 256 // HTTPRoute holds all the details needed to route HTTP traffic to a backend. 257 type HTTPRoute struct { 258 Name string 259 // Hostnames that the route should match 260 Hostnames []string 261 // PathMatch specifies that the HTTPRoute should match a path. 262 PathMatch StringMatch 263 // HeadersMatch specifies that the HTTPRoute should match a set of headers. 264 HeadersMatch []KeyValueMatch 265 // QueryParamsMatch specifies that the HTTPRoute should match a set of query parameters. 266 QueryParamsMatch []KeyValueMatch 267 Method *string 268 // Backend is the backend handling the requests 269 Backends []Backend 270 // BackendHTTPFilters can be used to add or remove HTTP 271 BackendHTTPFilters []*BackendHTTPFilter 272 // DirectResponse instructs the proxy to respond directly to the client. 273 DirectResponse *DirectResponse 274 275 // RequestHeaderFilter can be used to add or remove an HTTP 276 // header from an HTTP request before it is sent to the upstream target. 277 RequestHeaderFilter *HTTPHeaderFilter 278 279 // ResponseHeaderModifier can be used to add or remove an HTTP 280 // header from an HTTP response before it is sent to the client. 281 ResponseHeaderModifier *HTTPHeaderFilter 282 283 // RequestRedirect defines a schema for a filter that responds to the 284 // request with an HTTP redirection. 285 RequestRedirect *HTTPRequestRedirectFilter 286 287 // Rewrite defines a schema for a filter that modifies the URL of the request. 288 Rewrite *HTTPURLRewriteFilter 289 290 // RequestMirrors defines a schema for a filter that mirrors HTTP requests 291 // Unlike other filter, multiple request mirrors are supported 292 RequestMirrors []*HTTPRequestMirror 293 294 // IsGRPC is an indicator if this route is related to GRPC 295 IsGRPC bool 296 297 // Timeout holds the timeout configuration for a route. 298 Timeout Timeout 299 } 300 301 type BackendHTTPFilter struct { 302 // Name is the name of the Backend, the name is having the format of "namespace:name:port" 303 Name string 304 // RequestHeaderFilter can be used to add or remove an HTTP 305 // header from an HTTP request before it is sent to the upstream target. 306 RequestHeaderFilter *HTTPHeaderFilter 307 308 // ResponseHeaderModifier can be used to add or remove an HTTP 309 // header from an HTTP response before it is sent to the client. 310 ResponseHeaderModifier *HTTPHeaderFilter 311 } 312 313 // Infrastructure holds the labels and annotations configuration, 314 // which will be propagated to LB service. 315 type Infrastructure struct { 316 // Labels is a map of labels to be propagated to LB service. 317 Labels map[string]string 318 319 // Annotations is a map of annotations to be propagated to LB service. 320 Annotations map[string]string 321 } 322 323 // GetMatchKey returns the key to be used for matching the backend. 324 func (r *HTTPRoute) GetMatchKey() string { 325 sb := strings.Builder{} 326 327 if r.Method != nil { 328 sb.WriteString("method:") 329 sb.WriteString(*r.Method) 330 sb.WriteString("|") 331 } 332 333 sb.WriteString("path:") 334 sb.WriteString(r.PathMatch.String()) 335 sb.WriteString("|") 336 337 sort.Slice(r.HeadersMatch, func(i, j int) bool { 338 return r.HeadersMatch[i].String() < r.HeadersMatch[j].String() 339 }) 340 for _, hm := range r.HeadersMatch { 341 sb.WriteString("header:") 342 sb.WriteString(hm.String()) 343 sb.WriteString("|") 344 } 345 346 sort.Slice(r.QueryParamsMatch, func(i, j int) bool { 347 return r.QueryParamsMatch[i].String() < r.QueryParamsMatch[j].String() 348 }) 349 for _, qm := range r.QueryParamsMatch { 350 sb.WriteString("query:") 351 sb.WriteString(qm.String()) 352 sb.WriteString("|") 353 } 354 355 return sb.String() 356 } 357 358 // TLSPassthroughRoute holds all the details needed to route TLS traffic to a backend. 359 type TLSPassthroughRoute struct { 360 Name string 361 // Hostnames that the route should match 362 Hostnames []string 363 // Backend is the backend handling the requests 364 Backends []Backend 365 } 366 367 // StringMatch describes various types of string matching. 368 // Only one field may be set. 369 // If no fields are set, all paths should match (no path match criteria should 370 // be generated for Envoy.) 371 type StringMatch struct { 372 Prefix string 373 Exact string 374 Regex string 375 } 376 377 func (sm StringMatch) String() string { 378 sb := strings.Builder{} 379 if sm.Prefix != "" { 380 sb.WriteString("prefix:") 381 sb.WriteString(sm.Prefix) 382 } else if sm.Exact != "" { 383 sb.WriteString("exact:") 384 sb.WriteString(sm.Exact) 385 } else if sm.Regex != "" { 386 sb.WriteString("regex:") 387 sb.WriteString(sm.Regex) 388 } 389 return sb.String() 390 } 391 392 type KeyValueMatch struct { 393 Key string 394 Match StringMatch 395 } 396 397 func (kv KeyValueMatch) String() string { 398 sb := strings.Builder{} 399 sb.WriteString("kv:") 400 sb.WriteString(kv.Key) 401 sb.WriteString(":") 402 sb.WriteString(kv.Match.String()) 403 return sb.String() 404 } 405 406 // Backend holds a Kubernetes Service that points to a backend for traffic. 407 type Backend struct { 408 // Name of the Service. 409 Name string 410 // Namespace of the Service. 411 Namespace string 412 // Port contains the details of the port on the Service to connect to 413 // If unset, the same port as the top-level Listener will be used. 414 Port *BackendPort 415 // AppProtocol contains the application protocol as per KEP-3726 416 // for the port of the Service. 417 AppProtocol *string 418 419 // Weight specifies the percentage of traffic to send to this backend. 420 // This is computed as weight/(sum of all weights in backends) * 100. 421 Weight *int32 422 } 423 424 // BackendPort holds the details of what port on the Service to connect to. 425 // Only one of Port or Name can be set. 426 type BackendPort struct { 427 // Port holds the numeric port to connect to. 428 Port uint32 429 // Name holds a string which will be used to connect to the port with a 430 // matching spec.ports[].name in the target Service. 431 Name string 432 } 433 434 // GetPort return the string representation of the port (either the port number or the port name) 435 func (be *BackendPort) GetPort() string { 436 if be.Port != 0 { 437 return strconv.Itoa(int(be.Port)) 438 } 439 return be.Name 440 } 441 442 // Timeout holds the timeout configuration for a route. 443 type Timeout struct { 444 // Request is the timeout for the request. 445 Request *time.Duration 446 // Backend is the timeout for the backend. 447 Backend *time.Duration 448 }