github.com/cilium/cilium@v1.16.2/operator/pkg/ingress/cell.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package ingress
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/cilium/hive/cell"
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/spf13/pflag"
    13  	networkingv1 "k8s.io/api/networking/v1"
    14  	ctrlRuntime "sigs.k8s.io/controller-runtime"
    15  	"sigs.k8s.io/controller-runtime/pkg/builder"
    16  	"sigs.k8s.io/controller-runtime/pkg/predicate"
    17  
    18  	operatorOption "github.com/cilium/cilium/operator/option"
    19  	"github.com/cilium/cilium/operator/pkg/model/translation"
    20  	ingressTranslation "github.com/cilium/cilium/operator/pkg/model/translation/ingress"
    21  	"github.com/cilium/cilium/operator/pkg/secretsync"
    22  	"github.com/cilium/cilium/pkg/option"
    23  )
    24  
    25  // Cell manages the Kubernetes Ingress related controllers.
    26  var Cell = cell.Module(
    27  	"ingress",
    28  	"Manages the Kubernetes Ingress controllers",
    29  
    30  	cell.Config(ingressConfig{
    31  		EnableIngressController:      false,
    32  		EnforceIngressHTTPS:          true,
    33  		EnableIngressProxyProtocol:   false,
    34  		EnableIngressSecretsSync:     true,
    35  		IngressSecretsNamespace:      "cilium-secrets",
    36  		IngressDefaultRequestTimeout: time.Duration(0),
    37  		IngressLBAnnotationPrefixes:  []string{"lbipam.cilium.io", "service.beta.kubernetes.io", "service.kubernetes.io", "cloud.google.com"},
    38  		IngressSharedLBServiceName:   "cilium-ingress",
    39  		IngressDefaultLBMode:         "dedicated",
    40  
    41  		IngressHostnetworkEnabled:            false,
    42  		IngressHostnetworkSharedListenerPort: 0,
    43  		IngressHostnetworkNodelabelselector:  "",
    44  	}),
    45  	cell.Invoke(registerReconciler),
    46  	cell.Provide(registerSecretSync),
    47  )
    48  
    49  type ingressConfig struct {
    50  	KubeProxyReplacement                 string
    51  	EnableNodePort                       bool
    52  	EnableIngressController              bool
    53  	EnforceIngressHTTPS                  bool
    54  	EnableIngressProxyProtocol           bool
    55  	EnableIngressSecretsSync             bool
    56  	IngressSecretsNamespace              string
    57  	IngressLBAnnotationPrefixes          []string
    58  	IngressSharedLBServiceName           string
    59  	IngressDefaultLBMode                 string
    60  	IngressDefaultSecretNamespace        string
    61  	IngressDefaultSecretName             string
    62  	IngressDefaultRequestTimeout         time.Duration
    63  	IngressHostnetworkEnabled            bool
    64  	IngressHostnetworkSharedListenerPort uint32
    65  	IngressHostnetworkNodelabelselector  string
    66  	IngressDefaultXffNumTrustedHops      uint32
    67  }
    68  
    69  func (r ingressConfig) Flags(flags *pflag.FlagSet) {
    70  	flags.String("kube-proxy-replacement", r.KubeProxyReplacement, "Enable only selected features (will panic if any selected feature cannot be enabled) (\"false\"), or enable all features (will panic if any feature cannot be enabled) (\"true\") (default \"false\")")
    71  	flags.Bool("enable-node-port", r.EnableNodePort, "Enable NodePort type services by Cilium")
    72  	flags.Bool("enable-ingress-controller", r.EnableIngressController, "Enables cilium ingress controller. This must be enabled along with enable-envoy-config in cilium agent.")
    73  	flags.Bool("enforce-ingress-https", r.EnforceIngressHTTPS, "Enforces https for host having matching TLS host in Ingress. Incoming traffic to http listener will return 308 http error code with respective location in header.")
    74  	flags.Bool("enable-ingress-proxy-protocol", r.EnableIngressProxyProtocol, "Enable proxy protocol for all Ingress listeners. Note that _only_ Proxy protocol traffic will be accepted once this is enabled.")
    75  	flags.Bool("enable-ingress-secrets-sync", r.EnableIngressSecretsSync, "Enables fan-in TLS secrets from multiple namespaces to singular namespace (specified by ingress-secrets-namespace flag)")
    76  	flags.String("ingress-secrets-namespace", r.IngressSecretsNamespace, "Namespace having tls secrets used by Ingress and CEC.")
    77  	flags.StringSlice("ingress-lb-annotation-prefixes", r.IngressLBAnnotationPrefixes, "Annotations and labels which are needed to propagate from Ingress to the Load Balancer.")
    78  	flags.String("ingress-shared-lb-service-name", r.IngressSharedLBServiceName, "Name of shared LB service name for Ingress.")
    79  	flags.String("ingress-default-lb-mode", r.IngressDefaultLBMode, "Default loadbalancer mode for Ingress. Applicable values: dedicated, shared")
    80  	flags.String("ingress-default-secret-namespace", r.IngressDefaultSecretNamespace, "Default secret namespace for Ingress.")
    81  	flags.String("ingress-default-secret-name", r.IngressDefaultSecretName, "Default secret name for Ingress.")
    82  	flags.Duration("ingress-default-request-timeout", r.IngressDefaultRequestTimeout, "Default request timeout for Ingress.")
    83  	flags.Bool("ingress-hostnetwork-enabled", r.IngressHostnetworkEnabled, "Exposes ingress listeners on the host network.")
    84  	flags.Uint32("ingress-hostnetwork-shared-listener-port", r.IngressHostnetworkSharedListenerPort, "Port on the host network that gets used for the shared listener (HTTP, HTTPS & TLS passthrough)")
    85  	flags.String("ingress-hostnetwork-nodelabelselector", r.IngressHostnetworkNodelabelselector, "Label selector that matches the nodes where the ingress listeners should be exposed. It's a list of comma-separated key-value label pairs. e.g. 'kubernetes.io/os=linux,kubernetes.io/hostname=kind-worker'")
    86  	flags.Uint32("ingress-default-xff-num-trusted-hops", r.IngressDefaultXffNumTrustedHops, "The number of additional ingress proxy hops from the right side of the HTTP header to trust when determining the origin client's IP address.")
    87  }
    88  
    89  type ingressParams struct {
    90  	cell.In
    91  
    92  	Logger             logrus.FieldLogger
    93  	CtrlRuntimeManager ctrlRuntime.Manager
    94  	AgentConfig        *option.DaemonConfig
    95  	OperatorConfig     *operatorOption.OperatorConfig
    96  	IngressConfig      ingressConfig
    97  }
    98  
    99  func registerReconciler(params ingressParams) error {
   100  	if !params.IngressConfig.EnableIngressController {
   101  		return nil
   102  	}
   103  
   104  	if params.IngressConfig.KubeProxyReplacement != option.KubeProxyReplacementTrue &&
   105  		!params.IngressConfig.EnableNodePort {
   106  		params.Logger.Warn("Ingress Controller support requires either kube-proxy-replacement or enable-node-port enabled")
   107  		return nil
   108  	}
   109  
   110  	cecTranslator := translation.NewCECTranslator(
   111  		params.IngressConfig.IngressSecretsNamespace,
   112  		params.IngressConfig.EnableIngressProxyProtocol,
   113  		false,
   114  		false, // hostNameSuffixMatch
   115  		params.OperatorConfig.ProxyIdleTimeoutSeconds,
   116  		params.IngressConfig.IngressHostnetworkEnabled,
   117  		translation.ParseNodeLabelSelector(params.IngressConfig.IngressHostnetworkNodelabelselector),
   118  		params.AgentConfig.EnableIPv4,
   119  		params.AgentConfig.EnableIPv6,
   120  		params.IngressConfig.IngressDefaultXffNumTrustedHops,
   121  	)
   122  
   123  	dedicatedIngressTranslator := ingressTranslation.NewDedicatedIngressTranslator(cecTranslator, params.IngressConfig.IngressHostnetworkEnabled)
   124  
   125  	reconciler := newIngressReconciler(
   126  		params.Logger,
   127  		params.CtrlRuntimeManager.GetClient(),
   128  
   129  		cecTranslator,
   130  		dedicatedIngressTranslator,
   131  
   132  		operatorOption.Config.CiliumK8sNamespace,
   133  		params.IngressConfig.IngressLBAnnotationPrefixes,
   134  		params.IngressConfig.IngressSharedLBServiceName,
   135  		params.IngressConfig.IngressDefaultLBMode,
   136  		params.IngressConfig.IngressDefaultSecretNamespace,
   137  		params.IngressConfig.IngressDefaultSecretName,
   138  		params.IngressConfig.EnforceIngressHTTPS,
   139  		params.IngressConfig.IngressDefaultRequestTimeout,
   140  
   141  		params.IngressConfig.IngressHostnetworkEnabled,
   142  		params.IngressConfig.IngressHostnetworkSharedListenerPort,
   143  	)
   144  
   145  	if err := reconciler.SetupWithManager(params.CtrlRuntimeManager); err != nil {
   146  		return fmt.Errorf("failed to setup ingress reconciler: %w", err)
   147  	}
   148  
   149  	return nil
   150  }
   151  
   152  // registerSecretSync registers the Ingress Controller for secret synchronization based on TLS secrets referenced
   153  // by a Cilium Ingress resource.
   154  func registerSecretSync(params ingressParams) secretsync.SecretSyncRegistrationOut {
   155  	if !params.IngressConfig.EnableIngressController || !params.IngressConfig.EnableIngressSecretsSync {
   156  		return secretsync.SecretSyncRegistrationOut{}
   157  	}
   158  
   159  	registration := secretsync.SecretSyncRegistrationOut{
   160  		SecretSyncRegistration: &secretsync.SecretSyncRegistration{
   161  			RefObject:            &networkingv1.Ingress{},
   162  			RefObjectEnqueueFunc: EnqueueReferencedTLSSecrets(params.CtrlRuntimeManager.GetClient(), params.Logger),
   163  			RefObjectCheckFunc:   IsReferencedByCiliumIngress,
   164  			SecretsNamespace:     params.IngressConfig.IngressSecretsNamespace,
   165  			// In addition to changed Ingresses an additional watch on IngressClass gets added.
   166  			// Its purpose is to detect any changes regarding the default IngressClass
   167  			// (that is marked via annotation).
   168  			AdditionalWatches: []secretsync.AdditionalWatch{
   169  				{
   170  					RefObject:            &networkingv1.IngressClass{},
   171  					RefObjectEnqueueFunc: enqueueAllSecrets(params.CtrlRuntimeManager.GetClient()),
   172  					RefObjectWatchOptions: []builder.WatchesOption{
   173  						builder.WithPredicates(predicate.AnnotationChangedPredicate{}),
   174  					},
   175  				},
   176  			},
   177  		},
   178  	}
   179  
   180  	if params.IngressConfig.IngressDefaultSecretName != "" && params.IngressConfig.IngressDefaultSecretNamespace != "" {
   181  		registration.SecretSyncRegistration.DefaultSecret = &secretsync.DefaultSecret{
   182  			Namespace: params.IngressConfig.IngressDefaultSecretNamespace,
   183  			Name:      params.IngressConfig.IngressDefaultSecretName,
   184  		}
   185  	}
   186  
   187  	return registration
   188  }