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  }