diff --git a/api/v1alpha2/istio_merge.go b/api/v1alpha2/istio_merge.go index a9b378abf..f77701f19 100644 --- a/api/v1alpha2/istio_merge.go +++ b/api/v1alpha2/istio_merge.go @@ -198,6 +198,18 @@ func (m *meshConfigBuilder) BuildExternalAuthorizerConfiguration(authorizers []* return m } +func (m *meshConfigBuilder) BuildTrustDomainConfig(domain *string) *meshConfigBuilder { + if domain == nil { + return m + } + + err := m.c.SetPath("trustDomain", *domain) + if err != nil { + return nil + } + return m +} + func (m *meshConfigBuilder) BuildForwardClientCertDetails(xfccStrategy *XFCCStrategy) *meshConfigBuilder { if xfccStrategy == nil { return m @@ -226,6 +238,7 @@ func (i *Istio) mergeConfig(op iopv1alpha1.IstioOperator) (iopv1alpha1.IstioOper BuildDualStackConfig(dualStackEnabled). BuildForwardClientCertDetails(i.Spec.Config.ForwardClientCertDetails). BuildAmbientConfig(ambientEnabled). + BuildTrustDomainConfig(i.Spec.Config.TrustDomain). Build() op.Spec.MeshConfig = newMeshConfig diff --git a/api/v1alpha2/istio_structs.go b/api/v1alpha2/istio_structs.go index 93702aca6..3de8e6f9c 100644 --- a/api/v1alpha2/istio_structs.go +++ b/api/v1alpha2/istio_structs.go @@ -31,6 +31,13 @@ type Config struct { // Defines the telemetry configuration of Istio. // +kubebuilder:validation:Optional Telemetry Telemetry `json:"telemetry,omitempty"` + + // Defines trust domain configuration of Istio. + // +kubebuilder:validation:Optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=255 + // +kubebuilder:validation:Pattern=`^[a-z0-9]*([a-z0-9-_]*)?(\.[a-z0-9]*([a-z0-9-_]*[a-z0-9]*)?)*$` + TrustDomain *string `json:"trustDomain,omitempty"` } // Defines how to handle the x-forwarded-client-cert (XFCC) of the HTTP header. diff --git a/api/v1alpha2/merge_test.go b/api/v1alpha2/merge_test.go index df642bd11..1da599dc1 100644 --- a/api/v1alpha2/merge_test.go +++ b/api/v1alpha2/merge_test.go @@ -789,6 +789,65 @@ var _ = Describe("Merge", func() { Expect(exists).To(BeTrue()) Expect(hbone).To(Equal("true")) }) + Context("TrustDomain", func() { + It("Should set IstioOperator TrustDomain, when Istio CR configures it", func() { + // given + m := mesh.DefaultMeshConfig() + meshConfigRaw := convert(m) + iop := iopv1alpha1.IstioOperator{ + Spec: iopv1alpha1.IstioOperatorSpec{ + MeshConfig: meshConfigRaw, + }, + } + + istioCR := istiov1alpha2.Istio{ + Spec: istiov1alpha2.IstioSpec{ + Config: istiov1alpha2.Config{ + TrustDomain: ptr.To("trusted.com"), + }, + }, + } + + // when + out, err := istioCR.MergeInto(iop) + + // then + Expect(err).ShouldNot(HaveOccurred()) + meshConfig, err := values.MapFromObject(out.Spec.MeshConfig) + Expect(err).ShouldNot(HaveOccurred()) + trustDomain, exists := meshConfig.GetPath("trustDomain") + Expect(exists).To(BeTrue()) + Expect(trustDomain).To(Equal("trusted.com")) + }) + + It("Should set IstioOperator TrustDomain, when Istio CR configures it", func() { + // given + m := mesh.DefaultMeshConfig() + meshConfigRaw := convert(m) + iop := iopv1alpha1.IstioOperator{ + Spec: iopv1alpha1.IstioOperatorSpec{ + MeshConfig: meshConfigRaw, + }, + } + + istioCR := istiov1alpha2.Istio{ + Spec: istiov1alpha2.IstioSpec{ + Config: istiov1alpha2.Config{}, + }, + } + + // when + out, err := istioCR.MergeInto(iop) + + // then + Expect(err).ShouldNot(HaveOccurred()) + meshConfig, err := values.MapFromObject(out.Spec.MeshConfig) + Expect(err).ShouldNot(HaveOccurred()) + trustDomain, exists := meshConfig.GetPath("trustDomain") + Expect(exists).To(BeTrue()) + Expect(trustDomain).To(Equal("cluster.local")) + }) + }) Context("Pilot", func() { Context("When Istio CR has 500m configured for CPU limits", func() { diff --git a/api/v1alpha2/zz_generated.deepcopy.go b/api/v1alpha2/zz_generated.deepcopy.go index 24ab160dd..e38c924b2 100644 --- a/api/v1alpha2/zz_generated.deepcopy.go +++ b/api/v1alpha2/zz_generated.deepcopy.go @@ -172,6 +172,11 @@ func (in *Config) DeepCopyInto(out *Config) { **out = **in } out.Telemetry = in.Telemetry + if in.TrustDomain != nil { + in, out := &in.TrustDomain, &out.TrustDomain + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. diff --git a/config/crd/bases/operator.kyma-project.io_istios.yaml b/config/crd/bases/operator.kyma-project.io_istios.yaml index 72a543310..373db7d62 100644 --- a/config/crd/bases/operator.kyma-project.io_istios.yaml +++ b/config/crd/bases/operator.kyma-project.io_istios.yaml @@ -1529,6 +1529,12 @@ spec: type: boolean type: object type: object + trustDomain: + description: Defines trust domain configuration of Istio. + maxLength: 255 + minLength: 1 + pattern: ^[a-z0-9]*([a-z0-9-_]*)?(\.[a-z0-9]*([a-z0-9-_]*[a-z0-9]*)?)*$ + type: string type: object experimental: description: Defines experimental configuration options. diff --git a/config/ui-extensions/istios/details b/config/ui-extensions/istios/details index 348c5f801..7b0e68e31 100644 --- a/config/ui-extensions/istios/details +++ b/config/ui-extensions/istios/details @@ -27,6 +27,9 @@ body: - source: spec.config.numTrustedProxies name: config.numTrustedProxies placeholder: '1' + - source: spec.config.trustDomain + name: config.trustDomain + visibility: '$exists($value)' - source: spec.compatibilityMode name: compatibilityMode placeholder: 'false' diff --git a/config/ui-extensions/istios/form b/config/ui-extensions/istios/form index d5a1d5d65..5e7c963f4 100644 --- a/config/ui-extensions/istios/form +++ b/config/ui-extensions/istios/form @@ -15,6 +15,12 @@ name: config.numTrustedProxies value: type: number + - path: config.trustDomain + name: config.trustDomain + simple: true + description: description.trustDomain + value: + type: string - path: compatibilityMode simple: true name: compatibilityMode diff --git a/config/ui-extensions/istios/translations b/config/ui-extensions/istios/translations index 6d1ce5d4e..34d28bd3b 100644 --- a/config/ui-extensions/istios/translations +++ b/config/ui-extensions/istios/translations @@ -1,6 +1,7 @@ en: compatibilityMode: Compatibility Mode config.numTrustedProxies: Number of trusted proxies + config.trustDomain: Trust Domain config.authorizers: Authorizers config.authorizers.name: Name @@ -38,4 +39,5 @@ en: description.requests.cpu: Total CPU requests of all Pods that are in a non-terminal state must not exceed this value description.requests.memory: Total memory requests of all Pods that are in a non-terminal state must not exceed this value description.externalTrafficPolicy: Specifies externalTrafficPolicy for the Istio Ingress Gateway Service + description.trustDomain: Defines the trust domain for the Istio service mesh. Change the value only if you have a specific requirement. Change of domain reconfiguring mTLS certificates and causes restart of all workloads in the mesh, this can lead to downtime. description.compatibilityMode: Sets Istio compatibility version the last minor version. diff --git a/docs/contributor/04-50-istio-metrics.md b/docs/contributor/04-50-istio-metrics.md index 9005d585b..75b5dfcd6 100644 --- a/docs/contributor/04-50-istio-metrics.md +++ b/docs/contributor/04-50-istio-metrics.md @@ -10,13 +10,14 @@ These metrics help monitor the health and status of Istio installations managed The operator provides metrics that are defined by the controller-runtime by default, as well as custom metrics specific to Istio CR configurations. The following custom metrics are available: -| Metric Name | Description | -|--------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| -| **istio_ext_auth_providers_total** | Specifies the total number of external authorization providers defined in the Istio CR. | -| **istio_ext_auth_timeout_configured_number_total** | Specifies the total number of external authorization providers with timeout configured in the Istio CR. | +| Metric Name | Description | +|------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------| +| **istio_ext_auth_providers_total** | Specifies the total number of external authorization providers defined in the Istio CR. | +| **istio_ext_auth_timeout_configured_number_total** | Specifies the total number of external authorization providers with timeout configured in the Istio CR. | | **istio_ext_auth_path_prefix_configured_number_total** | Specifies the total number of external authorization providers with path prefix configured in the Istio CR. | -| **istio_num_trusted_proxies_configured** | Indicates whether **numTrustedProxies** is configured in the Istio CR (`1` for configured, `0` for not configured). | -| **istio_forward_client_cert_details_configured** | Indicates whether **forwardClientCertDetails** is different from the default value of `SANITIZE` (`1` for configured, `0` for not configured). | -| **istio_prometheus_merge_enabled** | Indicates whether Prometheus merge is enabled in the Istio CR (`1` for enabled, `0` for disabled). | -| **istio_compatibility_mode_enabled** | Indicates whether compatibility mode is enabled in the Istio CR (`1` for enabled, `0` for disabled). | -| istio_egress_gateway_used | Indicates whether the egress gateway is used in the Istio CR (`1` for used, `0` for not used). | +| **istio_num_trusted_proxies_configured** | Indicates whether **numTrustedProxies** is configured in the Istio CR (`1` for configured, `0` for not configured). | +| **istio_forward_client_cert_details_configured** | Indicates whether **forwardClientCertDetails** is different from the default value of `SANITIZE` (`1` for configured, `0` for not configured). | +| **istio_trust_domain_configured** | Indicates whether **trustedDomain** is configured (`1` for configured, `0` for not configured). | +| **istio_prometheus_merge_enabled** | Indicates whether Prometheus merge is enabled in the Istio CR (`1` for enabled, `0` for disabled). | +| **istio_compatibility_mode_enabled** | Indicates whether compatibility mode is enabled in the Istio CR (`1` for enabled, `0` for disabled). | +| istio_egress_gateway_used | Indicates whether the egress gateway is used in the Istio CR (`1` for used, `0` for not used). | diff --git a/docs/contributor/adr/0012-support-for-trust-domain-configuration.md b/docs/contributor/adr/0012-support-for-trust-domain-configuration.md new file mode 100644 index 000000000..7300f7a54 --- /dev/null +++ b/docs/contributor/adr/0012-support-for-trust-domain-configuration.md @@ -0,0 +1,36 @@ +# Support for Trust Domain Configuration + +## Status + +Accepted + +## Context + +In Istio's security model, a trust domain is a fundamental concept that represents the security boundary of a service mesh. It corresponds to the trust root of a system and is used in workload identity certificates (SPIFFE certificates). The trust domain is encoded in the Subject Alternative Name (SAN) field of the X.509 certificates issued to workloads within the mesh. + +By default, Istio uses `cluster.local` as the trust domain. However, there are scenarios where users need to customize the trust domain. For example, in multi-cluster deployments, where multiple clusters need to trust each other, a shared trust domain can facilitate seamless service-to-service authentication across cluster boundaries without requiring a complex federation setup. + +The trust domain affects: +- The SPIFFE identity format: `spiffe:///ns//sa/` +- Certificate validation and authentication between services +- Authorization policies that reference identities + +Currently, the `cluster.local` trust domain is hardcoded in the Istio operator configuration, and users have no way to customize it through the Istio custom resource. + +## Decision + +We will add support for configuring the trust domain through the Istio custom resource. The implementation will include the following aspects: + +1. **Add the trustDomain field**: The field will be added to the **Config** struct in the Istio CR specification with the following properties: + - Type: `string` (optional) + - Pattern validation: must conform to the SPIFFE specification for trust domain names + - Length constraints: 1-255 characters + - Default value: `cluster.local` (when not specified) + +2. **Merge the configuration** into the IstioOperator's **trustDomain** field during reconciliation, allowing the user-specified value to override the default. + +3. **Validation**: The field will be validated by Kubernetes API server through CRD validation rules to ensure it meets the SPIFFE specification requirements for trust domain names. + +4. **Backward compatibility**: If the field is not specified, the existing default behavior (`cluster.local`) will be maintained, ensuring no breaking changes for existing deployments. + +5. **Downtime**: During the trust domain change, workloads may experience temporary authentication failures until new certificates are issued and propagated. \ No newline at end of file diff --git a/docs/release-notes/1.24.0.md b/docs/release-notes/1.24.0.md index 9cecf2aa2..9142613ad 100644 --- a/docs/release-notes/1.24.0.md +++ b/docs/release-notes/1.24.0.md @@ -12,5 +12,7 @@ See [#1710](https://github.com/kyma-project/istio/pull/1710). - We've added support for **forwardClientCertDetails**. See [#1715](https://github.com/kyma-project/istio/pull/1715) and [Istio Custom Resource](https://kyma-project.io/external-content/istio/docs/user/04-00-istio-custom-resource.html). +- We've added support for Istio trust domain configuration. + See [#1705](https://github.com/kyma-project/istio/issues/1705) - Add support for the **KYMA_FIPS_MODE_ENABLED** environment variable, which allows configuring separate Istio FIPS images. - See [#1721](https://github.com/kyma-project/istio/pull/1721). \ No newline at end of file + See [#1721](https://github.com/kyma-project/istio/pull/1721). diff --git a/docs/user/04-00-istio-custom-resource.md b/docs/user/04-00-istio-custom-resource.md index f71c49f93..81ecffee3 100644 --- a/docs/user/04-00-istio-custom-resource.md +++ b/docs/user/04-00-istio-custom-resource.md @@ -139,6 +139,7 @@ Appears in: | **authorizers**
[Authorizer](#authorizer) array | Defines a list of external authorization providers. | Optional | | **gatewayExternalTrafficPolicy**
string | Defines the external traffic policy for the Istio Ingress Gateway Service. Valid configurations are `"Local"` or `"Cluster"`. The external traffic policy set to `"Local"` preserves the client IP in the request, but also introduces the risk of unbalanced traffic distribution.
WARNING: Switching **externalTrafficPolicy** may result in a temporal increase in request delay. Make sure that this is acceptable. | Enum: [Local Cluster]
Optional
| | **telemetry**
[Telemetry](#telemetry) | Defines the telemetry configuration of Istio. | Optional
| +| **trustDomain**
string | Defines trust domain configuration of Istio. | MaxLength: 255
MinLength: 1
Optional
Pattern: `^[a-z0-9]*([a-z0-9-_]*)?(\.[a-z0-9]*([a-z0-9-_]*[a-z0-9]*)?)*$`
| ### EgressGateway diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index c0f5a4524..4c7bc5215 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -1,9 +1,10 @@ package istiocrmetrics import ( - "github.com/kyma-project/istio/operator/api/v1alpha2" "github.com/prometheus/client_golang/prometheus" ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/metrics" + + "github.com/kyma-project/istio/operator/api/v1alpha2" ) // IstioCRMetrics holds all the metrics related to the Istio CR. @@ -20,6 +21,7 @@ type configMetrics struct { prometheusMergeEnabled prometheus.Gauge compatibilityModeEnabled prometheus.Gauge forwardClientCertDetailsConfigured prometheus.Gauge + trustDomainConfigured prometheus.Gauge } type componentMetrics struct { @@ -65,6 +67,10 @@ func NewMetrics() *IstioCRMetrics { Name: "istio_forward_client_cert_details_configured", Help: "Indicates whether forwardClientCertDetails is configured in the Istio CR (1 for configured, 0 for not configured).", }), + trustDomainConfigured: prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "istio_trust_domain_configured", + Help: "Indicates whether a custom trust domain is configured in the Istio CR (1 for configured, 0 for not configured).", + }), }, componentMetrics: &componentMetrics{ egressGatewayEnabled: prometheus.NewGauge(prometheus.GaugeOpts{ @@ -124,6 +130,12 @@ func (m *IstioCRMetrics) UpdateIstioCRMetrics(cr *v1alpha2.Istio) { m.configMetrics.forwardClientCertDetailsConfigured.Set(0) } + if cr.Spec.Config.TrustDomain != nil && *cr.Spec.Config.TrustDomain != "" && *cr.Spec.Config.TrustDomain != "cluster.local" { + m.configMetrics.trustDomainConfigured.Set(1) + } else { + m.configMetrics.trustDomainConfigured.Set(0) + } + if cr.Spec.CompatibilityMode { m.configMetrics.compatibilityModeEnabled.Set(1) } else { diff --git a/internal/restarter/predicates/ingressgateway.go b/internal/restarter/predicates/ingressgateway.go index aa485eaa5..3696bed7e 100644 --- a/internal/restarter/predicates/ingressgateway.go +++ b/internal/restarter/predicates/ingressgateway.go @@ -31,6 +31,10 @@ func (i RestartPredicate) NewIngressGatewayEvaluator(_ context.Context) (Ingress NewXForwardClientCert: i.istioCR.Spec.Config.ForwardClientCertDetails, OldXForwardClientCert: lastAppliedConfig.Config.ForwardClientCertDetails, }, + TrustDomainsRestartEvaluator{ + NewTrustDomain: i.istioCR.Spec.Config.TrustDomain, + OldTrustDomain: lastAppliedConfig.Config.TrustDomain, + }, }, }, nil } @@ -71,6 +75,23 @@ func (i NumTrustedProxiesRestartEvaluator) RequiresIngressGatewayRestart() bool return false } +type TrustDomainsRestartEvaluator struct { + NewTrustDomain *string + OldTrustDomain *string +} + +func (i TrustDomainsRestartEvaluator) RequiresIngressGatewayRestart() bool { + isNewNotNil := i.NewTrustDomain != nil + isOldNotNil := i.OldTrustDomain != nil + if isNewNotNil && isOldNotNil && *i.NewTrustDomain != *i.OldTrustDomain { + return true + } + if isNewNotNil != isOldNotNil { + return true + } + return false +} + func (i XForwardClientCertRestartEvaluator) RequiresIngressGatewayRestart() bool { isNewNotNil := i.NewXForwardClientCert != nil isOldNotNil := i.OldXForwardClientCert != nil diff --git a/internal/restarter/predicates/ingressgateway_test.go b/internal/restarter/predicates/ingressgateway_test.go index ad6b71a5a..b2817c778 100644 --- a/internal/restarter/predicates/ingressgateway_test.go +++ b/internal/restarter/predicates/ingressgateway_test.go @@ -4,14 +4,14 @@ import ( "context" "fmt" - "github.com/kyma-project/istio/operator/pkg/labels" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - operatorv1alpha2 "github.com/kyma-project/istio/operator/api/v1alpha2" - predicates "github.com/kyma-project/istio/operator/internal/restarter/predicates" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" + + operatorv1alpha2 "github.com/kyma-project/istio/operator/api/v1alpha2" + "github.com/kyma-project/istio/operator/internal/restarter/predicates" + "github.com/kyma-project/istio/operator/pkg/labels" ) var _ = Describe("Ingress Gateway Predicate", func() { @@ -60,6 +60,38 @@ var _ = Describe("Ingress Gateway Predicate", func() { }) }) + Context("TrustDomainsRestartEvaluator", func() { + It("should evaluate to false if newTrustDomain is the same", func() { + evaluator := predicates.TrustDomainsRestartEvaluator{ + NewTrustDomain: ptr.To("cluster.local"), + OldTrustDomain: ptr.To("cluster.local"), + } + Expect(evaluator.RequiresIngressGatewayRestart()).To(BeFalse()) + }) + + It("should evaluate to true if newTrustDomain is different", func() { + evaluator := predicates.TrustDomainsRestartEvaluator{ + NewTrustDomain: ptr.To("cluster.local"), + OldTrustDomain: ptr.To("old.local"), + } + Expect(evaluator.RequiresIngressGatewayRestart()).To(BeTrue()) + }) + It("should evaluate to true if newTrustDomain is nil and oldTrustDomain is not nil", func() { + evaluator := predicates.TrustDomainsRestartEvaluator{ + NewTrustDomain: nil, + OldTrustDomain: ptr.To("old.local"), + } + Expect(evaluator.RequiresIngressGatewayRestart()).To(BeTrue()) + }) + It("should evaluate to true if newTrustDomain is not nil and oldTrustDomain is nil", func() { + evaluator := predicates.TrustDomainsRestartEvaluator{ + NewTrustDomain: ptr.To("cluster.local"), + OldTrustDomain: nil, + } + Expect(evaluator.RequiresIngressGatewayRestart()).To(BeTrue()) + }) + }) + Context("XForwardClientCertRestartEvaluator", func() { It("should evaluate to true if new is nil and old is not nil", func() { evaluator := predicates.XForwardClientCertRestartEvaluator{ @@ -176,7 +208,7 @@ var _ = Describe("Ingress Gateway Predicate", func() { Expect(err).NotTo(HaveOccurred()) Expect(evaluator).NotTo(BeNil()) - Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators).To(HaveLen(2)) + Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators).To(HaveLen(3)) Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[0].(predicates.NumTrustedProxiesRestartEvaluator).OldNumTrustedProxies).To(BeNil()) }) @@ -186,10 +218,11 @@ var _ = Describe("Ingress Gateway Predicate", func() { Config: operatorv1alpha2.Config{ NumTrustedProxies: ptr.To(1), ForwardClientCertDetails: ptr.To(operatorv1alpha2.AppendForward), + TrustDomain: ptr.To("trusted.cluster"), }, }, ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{lastAppliedConfiguration: fmt.Sprintf(`{"config":{"numTrustedProxies":2, "forwardClientCertDetails": "SANITIZE"},"IstioTag":"%s"}`, mockIstioTag)}, + Annotations: map[string]string{lastAppliedConfiguration: fmt.Sprintf(`{"config":{"numTrustedProxies":2, "forwardClientCertDetails": "SANITIZE", "trustDomain": "old.cluster"},"IstioTag":"%s"}`, mockIstioTag)}, }, } @@ -198,11 +231,12 @@ var _ = Describe("Ingress Gateway Predicate", func() { Expect(err).NotTo(HaveOccurred()) Expect(evaluator).NotTo(BeNil()) - Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators).To(HaveLen(2)) + Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators).To(HaveLen(3)) Expect(*evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[0].(predicates.NumTrustedProxiesRestartEvaluator).NewNumTrustedProxies).To(BeEquivalentTo(1)) - Expect(*evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[0].(predicates.NumTrustedProxiesRestartEvaluator).OldNumTrustedProxies).To(BeEquivalentTo(2)) Expect(*evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[1].(predicates.XForwardClientCertRestartEvaluator).OldXForwardClientCert).To(BeEquivalentTo(operatorv1alpha2.Sanitize)) Expect(*evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[1].(predicates.XForwardClientCertRestartEvaluator).NewXForwardClientCert).To(BeEquivalentTo(operatorv1alpha2.AppendForward)) + Expect(*evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[2].(predicates.TrustDomainsRestartEvaluator).OldTrustDomain).To(Equal("old.cluster")) + Expect(*evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[2].(predicates.TrustDomainsRestartEvaluator).NewTrustDomain).To(Equal("trusted.cluster")) }) It("should return correct nil value for new and old numTrustedProxies", func() { @@ -222,7 +256,7 @@ var _ = Describe("Ingress Gateway Predicate", func() { Expect(err).NotTo(HaveOccurred()) Expect(evaluator).NotTo(BeNil()) - Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators).To(HaveLen(2)) + Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators).To(HaveLen(3)) Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[0].(predicates.NumTrustedProxiesRestartEvaluator).NewNumTrustedProxies).To(BeNil()) Expect(evaluator.(predicates.CompositeIngressGatewayRestartEvaluator).Evaluators[0].(predicates.NumTrustedProxiesRestartEvaluator).OldNumTrustedProxies).To(BeNil()) })