diff --git a/charts/gardener/operator/files/crd-gardens.yaml b/charts/gardener/operator/files/crd-gardens.yaml
index c4f4fc15bedf..9b418ff7ffc3 100644
--- a/charts/gardener/operator/files/crd-gardens.yaml
+++ b/charts/gardener/operator/files/crd-gardens.yaml
@@ -1881,6 +1881,11 @@ spec:
- configMapName
- kubeconfigs
type: object
+ tlsMinVersion:
+ description: |-
+ TLSMinVersion is the minimum TLS version accepted by the kube-apiserver.
+ Supported values: VersionTLS12, VersionTLS13.
+ type: string
watchCacheSizes:
description: |-
WatchCacheSizes contains configuration of the API server's watch cache sizes.
diff --git a/docs/api-reference/core.md b/docs/api-reference/core.md
index a81ba38c0c75..21ee31770968 100644
--- a/docs/api-reference/core.md
+++ b/docs/api-reference/core.md
@@ -5572,6 +5572,18 @@ integer
Autoscaling contains auto-scaling configuration options for the kube-apiserver.
+
+
+tlsMinVersion
+
+string
+
+ |
+
+(Optional)
+ TLSMinVersion is the minimum TLS version accepted by the kube-apiserver. Supported values: VersionTLS12, VersionTLS13.
+ |
+
diff --git a/example/90-shoot.yaml b/example/90-shoot.yaml
index b9b871b0a1d5..0f6f22a56bdf 100644
--- a/example/90-shoot.yaml
+++ b/example/90-shoot.yaml
@@ -249,6 +249,7 @@ spec:
# minAllowed:
# cpu: "1"
# memory: 3Gi
+ # tlsMinVersion: VersionTLS12 # Minimum TLS version accepted by the kube-apiserver. Supported values: VersionTLS12, VersionTLS13.
# kubeControllerManager:
# nodeCIDRMaskSize: 24
# nodeCIDRMaskSizeIPv6: 80
diff --git a/example/operator/10-crd-operator.gardener.cloud_gardens.yaml b/example/operator/10-crd-operator.gardener.cloud_gardens.yaml
index c4f4fc15bedf..9b418ff7ffc3 100644
--- a/example/operator/10-crd-operator.gardener.cloud_gardens.yaml
+++ b/example/operator/10-crd-operator.gardener.cloud_gardens.yaml
@@ -1881,6 +1881,11 @@ spec:
- configMapName
- kubeconfigs
type: object
+ tlsMinVersion:
+ description: |-
+ TLSMinVersion is the minimum TLS version accepted by the kube-apiserver.
+ Supported values: VersionTLS12, VersionTLS13.
+ type: string
watchCacheSizes:
description: |-
WatchCacheSizes contains configuration of the API server's watch cache sizes.
diff --git a/go.mod b/go.mod
index 9b5f0a351cdc..7161748a7f92 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
github.com/coreos/go-systemd/v22 v22.7.0
github.com/distribution/distribution/v3 v3.1.1
github.com/distribution/reference v0.6.0
- github.com/docker/cli v29.7.1+incompatible
+ github.com/docker/cli v29.7.2+incompatible
github.com/docker/docker v28.5.2+incompatible
github.com/docker/go-connections v0.8.0
github.com/elliotchance/orderedmap/v3 v3.1.1
diff --git a/go.sum b/go.sum
index 7727f0856485..5bbe343b7361 100644
--- a/go.sum
+++ b/go.sum
@@ -208,8 +208,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.12.0 h1:0j4c5qQmnC6XOWNjP3PIXURXN2gWx76rd3KvgdPkCz8=
github.com/dlclark/regexp2 v1.12.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
-github.com/docker/cli v29.7.1+incompatible h1:ILZpP6B7fedIr6ANy824QkDp1WMJuouIq0O2SrBkB2w=
-github.com/docker/cli v29.7.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v29.7.2+incompatible h1:dlkwallR8XqfeVnA2ELEhdwvb4lsSwuB4IgsG8Q9cLY=
+github.com/docker/cli v29.7.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY=
diff --git a/pkg/api/core/validation/shoot.go b/pkg/api/core/validation/shoot.go
index 17582f5f0367..3b13a913c8d2 100644
--- a/pkg/api/core/validation/shoot.go
+++ b/pkg/api/core/validation/shoot.go
@@ -1888,6 +1888,13 @@ func ValidateKubeAPIServer(kubeAPIServer *core.KubeAPIServerConfig, kubernetesVe
}
}
+ if kubeAPIServer.TLSMinVersion != nil {
+ validTLSVersions := sets.New("VersionTLS12", "VersionTLS13")
+ if !validTLSVersions.Has(*kubeAPIServer.TLSMinVersion) {
+ allErrs = append(allErrs, field.NotSupported(fldPath.Child("tlsMinVersion"), *kubeAPIServer.TLSMinVersion, sets.List(validTLSVersions)))
+ }
+ }
+
allErrs = append(allErrs, ValidateControlPlaneAutoscaling(
kubeAPIServer.Autoscaling,
corev1.ResourceList{
diff --git a/pkg/api/core/validation/shoot_test.go b/pkg/api/core/validation/shoot_test.go
index f7f4d02b3d34..020c2def6f20 100644
--- a/pkg/api/core/validation/shoot_test.go
+++ b/pkg/api/core/validation/shoot_test.go
@@ -3729,6 +3729,34 @@ var _ = Describe("Shoot Validation Tests", func() {
}))))
})
+ DescribeTable("should not allow unsupported or invalid TLS min versions",
+ func(version string) {
+ shoot.Spec.Kubernetes.KubeAPIServer.TLSMinVersion = &version
+
+ errorList := ValidateShoot(shoot)
+
+ Expect(errorList).To(ConsistOf(PointTo(MatchFields(IgnoreExtras, Fields{
+ "Type": Equal(field.ErrorTypeNotSupported),
+ "Field": Equal("spec.kubernetes.kubeAPIServer.tlsMinVersion"),
+ }))))
+ },
+ Entry("VersionTLS10", "VersionTLS10"),
+ Entry("VersionTLS11", "VersionTLS11"),
+ Entry("VersionTLS00", "VersionTLS00"),
+ )
+
+ DescribeTable("should allow all valid TLS min versions",
+ func(version string) {
+ shoot.Spec.Kubernetes.KubeAPIServer.TLSMinVersion = &version
+
+ errorList := ValidateShoot(shoot)
+
+ Expect(errorList).To(BeEmpty())
+ },
+ Entry("VersionTLS12", "VersionTLS12"),
+ Entry("VersionTLS13", "VersionTLS13"),
+ )
+
It("should not allow to specify a negative defaultNotReadyTolerationSeconds", func() {
shoot.Spec.Kubernetes.KubeAPIServer.DefaultNotReadyTolerationSeconds = new(int64(-1))
diff --git a/pkg/apis/core/types_shoot.go b/pkg/apis/core/types_shoot.go
index 8b0b72c0d453..f56c3c248625 100644
--- a/pkg/apis/core/types_shoot.go
+++ b/pkg/apis/core/types_shoot.go
@@ -784,6 +784,9 @@ type KubeAPIServerConfig struct {
StructuredAuthorization *StructuredAuthorization
// Autoscaling contains auto-scaling configuration options for the kube-apiserver.
Autoscaling *ControlPlaneAutoscaling
+ // TLSMinVersion is the minimum TLS version accepted by the kube-apiserver.
+ // Supported values: VersionTLS12, VersionTLS13.
+ TLSMinVersion *string
}
// ControlPlaneAutoscaling contains auto-scaling configuration options for control-plane components.
diff --git a/pkg/apis/core/v1beta1/generated.pb.go b/pkg/apis/core/v1beta1/generated.pb.go
index 817ba35e4ba8..eb016ccc51d3 100644
--- a/pkg/apis/core/v1beta1/generated.pb.go
+++ b/pkg/apis/core/v1beta1/generated.pb.go
@@ -5303,6 +5303,15 @@ func (m *KubeAPIServerConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
+ if m.TLSMinVersion != nil {
+ i -= len(*m.TLSMinVersion)
+ copy(dAtA[i:], *m.TLSMinVersion)
+ i = encodeVarintGenerated(dAtA, i, uint64(len(*m.TLSMinVersion)))
+ i--
+ dAtA[i] = 0x1
+ i--
+ dAtA[i] = 0xa2
+ }
if m.Autoscaling != nil {
{
size, err := m.Autoscaling.MarshalToSizedBuffer(dAtA[:i])
@@ -15481,6 +15490,10 @@ func (m *KubeAPIServerConfig) Size() (n int) {
l = m.Autoscaling.Size()
n += 2 + l + sovGenerated(uint64(l))
}
+ if m.TLSMinVersion != nil {
+ l = len(*m.TLSMinVersion)
+ n += 2 + l + sovGenerated(uint64(l))
+ }
return n
}
@@ -19792,6 +19805,7 @@ func (this *KubeAPIServerConfig) String() string {
`StructuredAuthentication:` + strings.Replace(this.StructuredAuthentication.String(), "StructuredAuthentication", "StructuredAuthentication", 1) + `,`,
`StructuredAuthorization:` + strings.Replace(this.StructuredAuthorization.String(), "StructuredAuthorization", "StructuredAuthorization", 1) + `,`,
`Autoscaling:` + strings.Replace(this.Autoscaling.String(), "ControlPlaneAutoscaling", "ControlPlaneAutoscaling", 1) + `,`,
+ `TLSMinVersion:` + valueToStringGenerated(this.TLSMinVersion) + `,`,
`}`,
}, "")
return s
@@ -36398,6 +36412,39 @@ func (m *KubeAPIServerConfig) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
+ case 20:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field TLSMinVersion", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenerated
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthGenerated
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthGenerated
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ s := string(dAtA[iNdEx:postIndex])
+ m.TLSMinVersion = &s
+ iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
diff --git a/pkg/apis/core/v1beta1/generated.proto b/pkg/apis/core/v1beta1/generated.proto
index 4592842e93dc..6cb2a81ff5e8 100644
--- a/pkg/apis/core/v1beta1/generated.proto
+++ b/pkg/apis/core/v1beta1/generated.proto
@@ -1553,6 +1553,11 @@ message KubeAPIServerConfig {
// Autoscaling contains auto-scaling configuration options for the kube-apiserver.
// +optional
optional ControlPlaneAutoscaling autoscaling = 19;
+
+ // TLSMinVersion is the minimum TLS version accepted by the kube-apiserver.
+ // Supported values: VersionTLS12, VersionTLS13.
+ // +optional
+ optional string tlsMinVersion = 20;
}
// KubeControllerManagerConfig contains configuration settings for the kube-controller-manager.
diff --git a/pkg/apis/core/v1beta1/types_shoot.go b/pkg/apis/core/v1beta1/types_shoot.go
index 1a98eb1defcd..ff83ad057c39 100644
--- a/pkg/apis/core/v1beta1/types_shoot.go
+++ b/pkg/apis/core/v1beta1/types_shoot.go
@@ -1049,6 +1049,10 @@ type KubeAPIServerConfig struct {
// Autoscaling contains auto-scaling configuration options for the kube-apiserver.
// +optional
Autoscaling *ControlPlaneAutoscaling `json:"autoscaling,omitempty" protobuf:"bytes,19,opt,name=autoscaling"`
+ // TLSMinVersion is the minimum TLS version accepted by the kube-apiserver.
+ // Supported values: VersionTLS12, VersionTLS13.
+ // +optional
+ TLSMinVersion *string `json:"tlsMinVersion,omitempty" protobuf:"bytes,20,opt,name=tlsMinVersion"`
}
// ControlPlaneAutoscaling contains auto-scaling configuration options for control-plane components.
diff --git a/pkg/apis/core/v1beta1/zz_generated.conversion.go b/pkg/apis/core/v1beta1/zz_generated.conversion.go
index a36f0151cb41..aaa6b8144cdb 100644
--- a/pkg/apis/core/v1beta1/zz_generated.conversion.go
+++ b/pkg/apis/core/v1beta1/zz_generated.conversion.go
@@ -4525,6 +4525,7 @@ func autoConvert_v1beta1_KubeAPIServerConfig_To_core_KubeAPIServerConfig(in *Kub
out.StructuredAuthentication = (*core.StructuredAuthentication)(unsafe.Pointer(in.StructuredAuthentication))
out.StructuredAuthorization = (*core.StructuredAuthorization)(unsafe.Pointer(in.StructuredAuthorization))
out.Autoscaling = (*core.ControlPlaneAutoscaling)(unsafe.Pointer(in.Autoscaling))
+ out.TLSMinVersion = (*string)(unsafe.Pointer(in.TLSMinVersion))
return nil
}
@@ -4563,6 +4564,7 @@ func autoConvert_core_KubeAPIServerConfig_To_v1beta1_KubeAPIServerConfig(in *cor
out.StructuredAuthentication = (*StructuredAuthentication)(unsafe.Pointer(in.StructuredAuthentication))
out.StructuredAuthorization = (*StructuredAuthorization)(unsafe.Pointer(in.StructuredAuthorization))
out.Autoscaling = (*ControlPlaneAutoscaling)(unsafe.Pointer(in.Autoscaling))
+ out.TLSMinVersion = (*string)(unsafe.Pointer(in.TLSMinVersion))
return nil
}
diff --git a/pkg/apis/core/v1beta1/zz_generated.deepcopy.go b/pkg/apis/core/v1beta1/zz_generated.deepcopy.go
index 1cf37a35b46e..b28e0d139d4c 100644
--- a/pkg/apis/core/v1beta1/zz_generated.deepcopy.go
+++ b/pkg/apis/core/v1beta1/zz_generated.deepcopy.go
@@ -2768,6 +2768,11 @@ func (in *KubeAPIServerConfig) DeepCopyInto(out *KubeAPIServerConfig) {
*out = new(ControlPlaneAutoscaling)
(*in).DeepCopyInto(*out)
}
+ if in.TLSMinVersion != nil {
+ in, out := &in.TLSMinVersion, &out.TLSMinVersion
+ *out = new(string)
+ **out = **in
+ }
return
}
diff --git a/pkg/apis/core/zz_generated.deepcopy.go b/pkg/apis/core/zz_generated.deepcopy.go
index 9c65f92174c7..2511274b2e79 100644
--- a/pkg/apis/core/zz_generated.deepcopy.go
+++ b/pkg/apis/core/zz_generated.deepcopy.go
@@ -2773,6 +2773,11 @@ func (in *KubeAPIServerConfig) DeepCopyInto(out *KubeAPIServerConfig) {
*out = new(ControlPlaneAutoscaling)
(*in).DeepCopyInto(*out)
}
+ if in.TLSMinVersion != nil {
+ in, out := &in.TLSMinVersion, &out.TLSMinVersion
+ *out = new(string)
+ **out = **in
+ }
return
}
diff --git a/pkg/apiserver/openapi/openapi_generated.go b/pkg/apiserver/openapi/openapi_generated.go
index c0eb0a9577c1..bde94b484ad8 100644
--- a/pkg/apiserver/openapi/openapi_generated.go
+++ b/pkg/apiserver/openapi/openapi_generated.go
@@ -5064,6 +5064,13 @@ func schema_pkg_apis_core_v1beta1_KubeAPIServerConfig(ref common.ReferenceCallba
Ref: ref(v1beta1.ControlPlaneAutoscaling{}.OpenAPIModelName()),
},
},
+ "tlsMinVersion": {
+ SchemaProps: spec.SchemaProps{
+ Description: "TLSMinVersion is the minimum TLS version accepted by the kube-apiserver. Supported values: VersionTLS12, VersionTLS13.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
},
},
},
diff --git a/pkg/component/kubernetes/apiserver/apiserver.go b/pkg/component/kubernetes/apiserver/apiserver.go
index 4b2976324a4d..152fe065e593 100644
--- a/pkg/component/kubernetes/apiserver/apiserver.go
+++ b/pkg/component/kubernetes/apiserver/apiserver.go
@@ -108,6 +108,8 @@ type Values struct {
DefaultUnreachableTolerationSeconds *int64
// EventTTL is the amount of time to retain events.
EventTTL *metav1.Duration
+ // TLSMinVersion is the minimum TLS version accepted by the kube-apiserver.
+ TLSMinVersion *string
// ExternalHostname is the external hostname which should be exposed by the kube-apiserver.
ExternalHostname string
// Images is a set of container images used for the containers of the kube-apiserver pods.
diff --git a/pkg/component/kubernetes/apiserver/apiserver_test.go b/pkg/component/kubernetes/apiserver/apiserver_test.go
index a7ad9064bcac..e8b58020877d 100644
--- a/pkg/component/kubernetes/apiserver/apiserver_test.go
+++ b/pkg/component/kubernetes/apiserver/apiserver_test.go
@@ -3124,6 +3124,7 @@ kind: AuthorizationConfiguration
},
}
eventTTL = 2 * time.Hour
+ tlsMinVersion = "VersionTLS13"
externalHostname = "api.foo.bar.com"
images = Images{KubeAPIServer: "some-kapi-image:latest"}
serviceAccountIssuer = "issuer"
@@ -3144,6 +3145,7 @@ kind: AuthorizationConfiguration
},
Autoscaling: AutoscalingConfig{APIServerResources: apiServerResources},
EventTTL: &metav1.Duration{Duration: eventTTL},
+ TLSMinVersion: &tlsMinVersion,
ExternalHostname: externalHostname,
Images: images,
IsWorkerless: true,
@@ -3193,6 +3195,7 @@ kind: AuthorizationConfiguration
"--etcd-servers-overrides=/events#https://etcd-events-client:2379",
"--encryption-provider-config=/etc/kubernetes/etcd-encryption-secret/encryption-configuration.yaml",
"--event-ttl="+eventTTL.String(),
+ "--tls-min-version="+tlsMinVersion,
"--external-hostname="+externalHostname,
"--livez-grace-period=1m",
"--shutdown-delay-duration=15s",
diff --git a/pkg/component/kubernetes/apiserver/deployment.go b/pkg/component/kubernetes/apiserver/deployment.go
index 58cb348260f6..733351a03a9a 100644
--- a/pkg/component/kubernetes/apiserver/deployment.go
+++ b/pkg/component/kubernetes/apiserver/deployment.go
@@ -425,6 +425,10 @@ func (k *kubeAPIServer) computeKubeAPIServerArgs() []string {
out = append(out, fmt.Sprintf("--event-ttl=%s", k.values.EventTTL.Duration))
}
+ if k.values.TLSMinVersion != nil {
+ out = append(out, fmt.Sprintf("--tls-min-version=%s", *k.values.TLSMinVersion))
+ }
+
out = append(out, fmt.Sprintf("--proxy-client-cert-file=%s/%s", volumeMountPathKubeAggregator, secrets.DataKeyCertificate))
out = append(out, fmt.Sprintf("--proxy-client-key-file=%s/%s", volumeMountPathKubeAggregator, secrets.DataKeyPrivateKey))
out = append(out, fmt.Sprintf("--requestheader-client-ca-file=%s/%s", volumeMountPathCAFrontProxy, secrets.DataKeyCertificateBundle))
diff --git a/pkg/component/kubernetes/apiserverexposure/sni.go b/pkg/component/kubernetes/apiserverexposure/sni.go
index f941743049f2..2c818e35b676 100644
--- a/pkg/component/kubernetes/apiserverexposure/sni.go
+++ b/pkg/component/kubernetes/apiserverexposure/sni.go
@@ -109,6 +109,7 @@ type SNIValues struct {
IstioIngressGateway IstioIngressGateway
IstioTLSTermination bool
WildcardConfiguration *WildcardConfiguration
+ TLSMinVersion *string
}
// APIServerProxy contains values for the APIServer proxy protocol configuration.
@@ -360,12 +361,23 @@ func (s *sni) Deploy(ctx context.Context) error {
gatewayMutateFn := istio.GatewayWithTLSPassthrough(configuration.gateway, getLabels(), configuration.istioIngressGateway.Labels, allHosts)
if values.IstioTLSTermination {
+ minProtocolVersion := tlsVersionToIstioProtocolVersion(values.TLSMinVersion)
var serverConfigs []istio.ServerConfig
if len(configuration.hosts) > 0 {
- serverConfigs = append(serverConfigs, istio.ServerConfig{Hosts: configuration.hosts, PortName: portNameTLS, TLSSecret: s.namespace + istioTLSSecretSuffix})
+ serverConfigs = append(serverConfigs, istio.ServerConfig{
+ Hosts: configuration.hosts,
+ PortName: portNameTLS,
+ TLSSecret: s.namespace + istioTLSSecretSuffix,
+ MinProtocolVersion: minProtocolVersion,
+ })
}
if configuration.wildcardConfiguration != nil {
- serverConfigs = append(serverConfigs, istio.ServerConfig{Hosts: configuration.wildcardConfiguration.Hosts, PortName: portNameWildcardTLS, TLSSecret: s.emptyIstioWildcardTLSSecret().Name})
+ serverConfigs = append(serverConfigs, istio.ServerConfig{
+ Hosts: configuration.wildcardConfiguration.Hosts,
+ PortName: portNameWildcardTLS,
+ TLSSecret: s.emptyIstioWildcardTLSSecret().Name,
+ MinProtocolVersion: minProtocolVersion,
+ })
}
gatewayMutateFn = istio.GatewayWithMutualTLS(configuration.gateway, getLabels(), configuration.istioIngressGateway.Labels, serverConfigs)
}
@@ -668,3 +680,18 @@ func getExportTo(istioGatewayConfigurations []istioGatewayConfiguration) []strin
return namespaces
}
+
+func tlsVersionToIstioProtocolVersion(v *string) istioapinetworkingv1beta1.ServerTLSSettings_TLSProtocol {
+ if v == nil {
+ return istioapinetworkingv1beta1.ServerTLSSettings_TLS_AUTO
+ }
+
+ switch *v {
+ case "VersionTLS13":
+ return istioapinetworkingv1beta1.ServerTLSSettings_TLSV1_3
+ case "VersionTLS12":
+ return istioapinetworkingv1beta1.ServerTLSSettings_TLSV1_2
+ default:
+ return istioapinetworkingv1beta1.ServerTLSSettings_TLS_AUTO
+ }
+}
diff --git a/pkg/component/kubernetes/apiserverexposure/sni_test.go b/pkg/component/kubernetes/apiserverexposure/sni_test.go
index 5266f884573e..3b54d688abbc 100644
--- a/pkg/component/kubernetes/apiserverexposure/sni_test.go
+++ b/pkg/component/kubernetes/apiserverexposure/sni_test.go
@@ -53,6 +53,7 @@ var _ = Describe("#SNI", func() {
istioNamespace string
istioWildcardNamespace string
istioTLSTermination bool
+ tlsMinVersion *string
hosts []string
hostName string
connectionUpgradeHostName string
@@ -95,6 +96,7 @@ var _ = Describe("#SNI", func() {
istioWildcardLabels = map[string]string{"bar": "foo"}
istioWildcardNamespace = "istio-bar"
istioTLSTermination = false
+ tlsMinVersion = nil
hosts = []string{"foo.bar"}
hostName = "kube-apiserver." + namespace + ".svc.cluster.local"
connectionUpgradeHostName = "kube-apiserver-connection-upgrade." + namespace + ".svc.cluster.local"
@@ -341,6 +343,7 @@ var _ = Describe("#SNI", func() {
},
IstioTLSTermination: istioTLSTermination,
WildcardConfiguration: wildcardConfiguration,
+ TLSMinVersion: tlsMinVersion,
}
return val
})
@@ -518,8 +521,141 @@ var _ = Describe("#SNI", func() {
expectedGateway.Spec.Servers[0].Port.Protocol = "HTTPS"
expectedGateway.Spec.Servers[0].Tls = &istioapinetworkingv1beta1.ServerTLSSettings{
- Mode: istioapinetworkingv1beta1.ServerTLSSettings_OPTIONAL_MUTUAL,
- CredentialName: namespace + "-kube-apiserver-tls",
+ Mode: istioapinetworkingv1beta1.ServerTLSSettings_OPTIONAL_MUTUAL,
+ CredentialName: namespace + "-kube-apiserver-tls",
+ MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLS_AUTO,
+ }
+
+ expectedVirtualService.Spec.Tls = nil
+ expectedVirtualService.Spec.Http = []*istioapinetworkingv1beta1.HTTPRoute{
+ {
+ Name: "connection-upgrade",
+ Match: []*istioapinetworkingv1beta1.HTTPMatchRequest{
+ {
+ Headers: map[string]*istioapinetworkingv1beta1.StringMatch{
+ "Connection": {MatchType: &istioapinetworkingv1beta1.StringMatch_Exact{Exact: "Upgrade"}},
+ "Upgrade": {},
+ },
+ },
+ },
+ Route: []*istioapinetworkingv1beta1.HTTPRouteDestination{
+ {
+ Destination: &istioapinetworkingv1beta1.Destination{
+ Host: connectionUpgradeHostName,
+ Port: &istioapinetworkingv1beta1.PortSelector{Number: 443},
+ },
+ },
+ },
+ },
+ {
+ Route: []*istioapinetworkingv1beta1.HTTPRouteDestination{
+ {
+ Destination: &istioapinetworkingv1beta1.Destination{
+ Host: hostName,
+ Port: &istioapinetworkingv1beta1.PortSelector{Number: 443},
+ },
+ },
+ },
+ },
+ }
+ })
+
+ It("should succeed deploying", func() {
+ testFunc()
+ })
+ })
+
+ Context("when IstioTLSTermination feature gate is true and TLSMinVersion is VersionTLS12", func() {
+ BeforeEach(func() {
+ istioTLSTermination = true
+ tlsMinVersion = new("VersionTLS12")
+
+ expectedDestinationRule.Spec.TrafficPolicy.ConnectionPool.Http = &istioapinetworkingv1beta1.ConnectionPoolSettings_HTTPSettings{
+ UseClientProtocol: true,
+ }
+ expectedDestinationRule.Spec.TrafficPolicy.LoadBalancer = &istioapinetworkingv1beta1.LoadBalancerSettings{
+ LbPolicy: &istioapinetworkingv1beta1.LoadBalancerSettings_Simple{
+ Simple: istioapinetworkingv1beta1.LoadBalancerSettings_LEAST_REQUEST,
+ },
+ }
+ expectedDestinationRule.Spec.TrafficPolicy.OutlierDetection = nil
+ expectedDestinationRule.Spec.TrafficPolicy.Tls = &istioapinetworkingv1beta1.ClientTLSSettings{
+ Mode: istioapinetworkingv1beta1.ClientTLSSettings_SIMPLE,
+ CredentialName: namespace + "-kube-apiserver-istio-mtls",
+ Sni: "kubernetes.default.svc.cluster.local",
+ }
+
+ expectedGateway.Spec.Servers[0].Port.Protocol = "HTTPS"
+ expectedGateway.Spec.Servers[0].Tls = &istioapinetworkingv1beta1.ServerTLSSettings{
+ Mode: istioapinetworkingv1beta1.ServerTLSSettings_OPTIONAL_MUTUAL,
+ CredentialName: namespace + "-kube-apiserver-tls",
+ MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLSV1_2,
+ }
+
+ expectedVirtualService.Spec.Tls = nil
+ expectedVirtualService.Spec.Http = []*istioapinetworkingv1beta1.HTTPRoute{
+ {
+ Name: "connection-upgrade",
+ Match: []*istioapinetworkingv1beta1.HTTPMatchRequest{
+ {
+ Headers: map[string]*istioapinetworkingv1beta1.StringMatch{
+ "Connection": {MatchType: &istioapinetworkingv1beta1.StringMatch_Exact{Exact: "Upgrade"}},
+ "Upgrade": {},
+ },
+ },
+ },
+ Route: []*istioapinetworkingv1beta1.HTTPRouteDestination{
+ {
+ Destination: &istioapinetworkingv1beta1.Destination{
+ Host: connectionUpgradeHostName,
+ Port: &istioapinetworkingv1beta1.PortSelector{Number: 443},
+ },
+ },
+ },
+ },
+ {
+ Route: []*istioapinetworkingv1beta1.HTTPRouteDestination{
+ {
+ Destination: &istioapinetworkingv1beta1.Destination{
+ Host: hostName,
+ Port: &istioapinetworkingv1beta1.PortSelector{Number: 443},
+ },
+ },
+ },
+ },
+ }
+ })
+
+ It("should succeed deploying", func() {
+ testFunc()
+ })
+ })
+
+ Context("when IstioTLSTermination feature gate is true and TLSMinVersion is VersionTLS13", func() {
+ BeforeEach(func() {
+ istioTLSTermination = true
+ tlsMinVersion = new("VersionTLS13")
+
+ expectedDestinationRule.Spec.TrafficPolicy.ConnectionPool.Http = &istioapinetworkingv1beta1.ConnectionPoolSettings_HTTPSettings{
+ UseClientProtocol: true,
+ }
+ expectedDestinationRule.Spec.TrafficPolicy.LoadBalancer = &istioapinetworkingv1beta1.LoadBalancerSettings{
+ LbPolicy: &istioapinetworkingv1beta1.LoadBalancerSettings_Simple{
+ Simple: istioapinetworkingv1beta1.LoadBalancerSettings_LEAST_REQUEST,
+ },
+ }
+ expectedDestinationRule.Spec.TrafficPolicy.OutlierDetection = nil
+ expectedDestinationRule.Spec.TrafficPolicy.Tls = &istioapinetworkingv1beta1.ClientTLSSettings{
+ Mode: istioapinetworkingv1beta1.ClientTLSSettings_SIMPLE,
+ CredentialName: namespace + "-kube-apiserver-istio-mtls",
+ Sni: "kubernetes.default.svc.cluster.local",
+ }
+
+ expectedGateway.Spec.Servers[0].Port.Protocol = "HTTPS"
+ expectedGateway.Spec.Servers[0].Tls = &istioapinetworkingv1beta1.ServerTLSSettings{
+ Mode: istioapinetworkingv1beta1.ServerTLSSettings_OPTIONAL_MUTUAL,
+ CredentialName: namespace + "-kube-apiserver-tls",
+ MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLSV1_3,
}
expectedVirtualService.Spec.Tls = nil
diff --git a/pkg/component/observability/logging/victorialogs/victorialogs.go b/pkg/component/observability/logging/victorialogs/victorialogs.go
index e11d2472be3b..fe59aaa211a8 100644
--- a/pkg/component/observability/logging/victorialogs/victorialogs.go
+++ b/pkg/component/observability/logging/victorialogs/victorialogs.go
@@ -302,12 +302,18 @@ func (v *victoriaLogs) getServiceMonitor() *monitoringv1.ServiceMonitor {
return &monitoringv1.ServiceMonitor{
ObjectMeta: monitoringutils.ConfigObjectMeta("victoria-logs", v.namespace, v.getPrometheusLabel()),
Spec: monitoringv1.ServiceMonitorSpec{
- Selector: metav1.LabelSelector{MatchLabels: map[string]string{
- "app.kubernetes.io/name": "vlsingle",
- "app.kubernetes.io/instance": constants.VLSingleResourceName,
- "app.kubernetes.io/component": "monitoring",
- "managed-by": "vm-operator",
- }},
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app.kubernetes.io/name": "vlsingle",
+ "app.kubernetes.io/instance": constants.VLSingleResourceName,
+ "app.kubernetes.io/component": "monitoring",
+ "managed-by": "vm-operator",
+ },
+ MatchExpressions: []metav1.LabelSelectorRequirement{{
+ Key: "operator.victoriametrics.com/additional-service",
+ Operator: metav1.LabelSelectorOpDoesNotExist,
+ }},
+ },
Endpoints: []monitoringv1.Endpoint{{
Port: "http",
RelabelConfigs: []monitoringv1.RelabelConfig{
diff --git a/pkg/component/observability/logging/victorialogs/victorialogs_test.go b/pkg/component/observability/logging/victorialogs/victorialogs_test.go
index c3e08b46740a..9bf57254cdf9 100644
--- a/pkg/component/observability/logging/victorialogs/victorialogs_test.go
+++ b/pkg/component/observability/logging/victorialogs/victorialogs_test.go
@@ -172,12 +172,18 @@ var _ = Describe("VictoriaLogs", func() {
serviceMonitor = &monitoringv1.ServiceMonitor{
ObjectMeta: monitoringutils.ConfigObjectMeta("victoria-logs", namespace, shoot.Label),
Spec: monitoringv1.ServiceMonitorSpec{
- Selector: metav1.LabelSelector{MatchLabels: map[string]string{
- "app.kubernetes.io/name": "vlsingle",
- "app.kubernetes.io/instance": victorialogsconstants.VLSingleResourceName,
- "app.kubernetes.io/component": "monitoring",
- "managed-by": "vm-operator",
- }},
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app.kubernetes.io/name": "vlsingle",
+ "app.kubernetes.io/instance": victorialogsconstants.VLSingleResourceName,
+ "app.kubernetes.io/component": "monitoring",
+ "managed-by": "vm-operator",
+ },
+ MatchExpressions: []metav1.LabelSelectorRequirement{{
+ Key: "operator.victoriametrics.com/additional-service",
+ Operator: metav1.LabelSelectorOpDoesNotExist,
+ }},
+ },
Endpoints: []monitoringv1.Endpoint{{
Port: "http",
RelabelConfigs: []monitoringv1.RelabelConfig{
diff --git a/pkg/component/observability/opentelemetry/collector/collector.go b/pkg/component/observability/opentelemetry/collector/collector.go
index 899be301736c..b74003bd3b2a 100644
--- a/pkg/component/observability/opentelemetry/collector/collector.go
+++ b/pkg/component/observability/opentelemetry/collector/collector.go
@@ -15,10 +15,12 @@ import (
istioapiannotation "istio.io/api/annotation"
istioapinetworkingv1beta1 "istio.io/api/networking/v1beta1"
istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
+ autoscalingv1 "k8s.io/api/autoscaling/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ vpaautoscalingv1 "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants"
@@ -45,6 +47,7 @@ const (
managedResourceNameTarget = "logging-target"
managedResourceName = "opentelemetry-collector"
serviceMonitorName = "opentelemetry-collector"
+ vpaName = "opentelemetry-collector"
openTelemetryCollectorName = "gardener-opentelemetry-collector"
kubeRBACProxyName = "rbac-proxy"
@@ -201,6 +204,7 @@ func (o *otelCollector) Deploy(ctx context.Context) error {
seedObjects = append(seedObjects, o.openTelemetryCollector(o.namespace, o.values.LokiEndpoint, genericTokenKubeconfigSecretName))
seedObjects = append(seedObjects, o.serviceMonitor())
seedObjects = append(seedObjects, o.serviceAccount())
+ seedObjects = append(seedObjects, o.vpa())
seedRegistry := managedresources.NewRegistry(kubernetes.SeedScheme, kubernetes.SeedCodec, kubernetes.SeedSerializer)
serializedResources, err := seedRegistry.AddAllAndSerialize(seedObjects...)
@@ -259,6 +263,41 @@ func (o *otelCollector) WaitCleanup(ctx context.Context) error {
return managedresources.WaitUntilDeleted(timeoutCtx, o.client, o.namespace, managedResourceName)
}
+func (o *otelCollector) vpa() *vpaautoscalingv1.VerticalPodAutoscaler {
+ return &vpaautoscalingv1.VerticalPodAutoscaler{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: vpaName,
+ Namespace: o.namespace,
+ Labels: getLabels(),
+ },
+ Spec: vpaautoscalingv1.VerticalPodAutoscalerSpec{
+ TargetRef: &autoscalingv1.CrossVersionObjectReference{
+ APIVersion: otelv1beta1.GroupVersion.String(),
+ Kind: "OpenTelemetryCollector",
+ Name: collectorconstants.OpenTelemetryCollectorResourceName,
+ },
+ UpdatePolicy: &vpaautoscalingv1.PodUpdatePolicy{
+ UpdateMode: new(vpaautoscalingv1.UpdateModeInPlaceOrRecreate),
+ },
+ ResourcePolicy: &vpaautoscalingv1.PodResourcePolicy{
+ ContainerPolicies: []vpaautoscalingv1.ContainerResourcePolicy{
+ {
+ ContainerName: collectorconstants.ContainerName,
+ MinAllowed: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("64Mi"),
+ },
+ ControlledValues: new(vpaautoscalingv1.ContainerControlledValuesRequestsOnly),
+ },
+ {
+ ContainerName: vpaautoscalingv1.DefaultContainerResourcePolicy,
+ Mode: new(vpaautoscalingv1.ContainerScalingModeOff),
+ },
+ },
+ },
+ },
+ }
+}
+
func (o *otelCollector) serviceAccount() *corev1.ServiceAccount {
return &corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
@@ -358,7 +397,7 @@ func (o *otelCollector) openTelemetryCollector(namespace, lokiEndpoint, genericT
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("10m"),
- corev1.ResourceMemory: resource.MustParse("50Mi"),
+ corev1.ResourceMemory: resource.MustParse("64Mi"),
},
},
SecurityContext: &corev1.SecurityContext{
diff --git a/pkg/component/observability/opentelemetry/collector/collector_test.go b/pkg/component/observability/opentelemetry/collector/collector_test.go
index b27b299abb28..4746edac7227 100644
--- a/pkg/component/observability/opentelemetry/collector/collector_test.go
+++ b/pkg/component/observability/opentelemetry/collector/collector_test.go
@@ -17,11 +17,13 @@ import (
"google.golang.org/protobuf/types/known/wrapperspb"
istioapinetworkingv1beta1 "istio.io/api/networking/v1beta1"
istionetworkingv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
+ autoscalingv1 "k8s.io/api/autoscaling/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ vpaautoscalingv1 "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -77,6 +79,7 @@ var _ = Describe("OpenTelemetry Collector", func() {
volume corev1.Volume
volumeMount corev1.VolumeMount
+ vpa *vpaautoscalingv1.VerticalPodAutoscaler
managedResourceTarget *resourcesv1alpha1.ManagedResource
openTelemetryCollector *otelv1beta1.OpenTelemetryCollector
serviceMonitor *monitoringv1.ServiceMonitor
@@ -353,7 +356,7 @@ var _ = Describe("OpenTelemetry Collector", func() {
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("10m"),
- corev1.ResourceMemory: resource.MustParse("50Mi"),
+ corev1.ResourceMemory: resource.MustParse("64Mi"),
},
},
ServiceAccount: "opentelemetry-collector",
@@ -525,6 +528,39 @@ var _ = Describe("OpenTelemetry Collector", func() {
},
}
+ vpa = &vpaautoscalingv1.VerticalPodAutoscaler{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "opentelemetry-collector",
+ Namespace: namespace,
+ Labels: getLabels(),
+ },
+ Spec: vpaautoscalingv1.VerticalPodAutoscalerSpec{
+ TargetRef: &autoscalingv1.CrossVersionObjectReference{
+ APIVersion: otelv1beta1.GroupVersion.String(),
+ Kind: "OpenTelemetryCollector",
+ Name: "opentelemetry-collector",
+ },
+ UpdatePolicy: &vpaautoscalingv1.PodUpdatePolicy{
+ UpdateMode: new(vpaautoscalingv1.UpdateModeInPlaceOrRecreate),
+ },
+ ResourcePolicy: &vpaautoscalingv1.PodResourcePolicy{
+ ContainerPolicies: []vpaautoscalingv1.ContainerResourcePolicy{
+ {
+ ContainerName: "otc-container",
+ MinAllowed: corev1.ResourceList{
+ corev1.ResourceMemory: resource.MustParse("64Mi"),
+ },
+ ControlledValues: new(vpaautoscalingv1.ContainerControlledValuesRequestsOnly),
+ },
+ {
+ ContainerName: vpaautoscalingv1.DefaultContainerResourcePolicy,
+ Mode: new(vpaautoscalingv1.ContainerScalingModeOff),
+ },
+ },
+ },
+ },
+ }
+
openTelemetryCollector.Spec.AdditionalContainers = []corev1.Container{kubeRBACProxyValiContainer, kubeRBACProxyOTLPContainer}
openTelemetryCollector.Spec.Volumes = []corev1.Volume{volume}
openTelemetryCollector.Spec.Ports = append(openTelemetryCollector.Spec.Ports, otelv1beta1.PortsSpec{
@@ -587,6 +623,7 @@ var _ = Describe("OpenTelemetry Collector", func() {
getVirtualService(),
getDestinationRule(),
getTLSSecret(tlsSecret),
+ vpa,
serviceMonitor,
serviceAccount,
))
@@ -644,6 +681,7 @@ var _ = Describe("OpenTelemetry Collector", func() {
getVirtualService(),
getDestinationRule(),
getTLSSecret(tlsSecret),
+ vpa,
serviceMonitor,
serviceAccount,
))
@@ -733,6 +771,7 @@ var _ = Describe("OpenTelemetry Collector", func() {
getVirtualService(),
getDestinationRule(),
getTLSSecret(tlsSecret),
+ vpa,
serviceMonitor,
serviceAccount,
))
@@ -768,6 +807,7 @@ var _ = Describe("OpenTelemetry Collector", func() {
getVirtualService(),
getDestinationRule(),
getTLSSecret(tlsSecret),
+ vpa,
serviceMonitor,
serviceAccount,
))
diff --git a/pkg/component/observability/opentelemetry/collector/constants/constants.go b/pkg/component/observability/opentelemetry/collector/constants/constants.go
index 18fc8829a7b0..ed2dda4e253e 100644
--- a/pkg/component/observability/opentelemetry/collector/constants/constants.go
+++ b/pkg/component/observability/opentelemetry/collector/constants/constants.go
@@ -10,6 +10,9 @@ const (
// DeploymentName is the name that the OpenTelemetry Operator will for the Collector deployment.
// Note: Currently, the OpenTelemetry Operator hardcodes the deployment name to be the same as the resource name with a '-collector' suffix.
DeploymentName = OpenTelemetryCollectorResourceName + "-collector"
+ // ContainerName is the name of the main container in the OpenTelemetry Collector deployment.
+ // Note: Currently, the OpenTelemetry Operator hardcodes the container name to 'otc-container'.
+ ContainerName = "otc-container"
// ServiceName is the name the OpenTelemetry Operator will use for the Collector service.
// Note: Currently, the OpenTelemetry Operator hardcodes the service name to be the same as the resource name with a '-collector' suffix.
ServiceName = OpenTelemetryCollectorResourceName + "-collector"
diff --git a/pkg/component/shared/kubeapiserver.go b/pkg/component/shared/kubeapiserver.go
index 7bd5de9101b0..ae2665718043 100644
--- a/pkg/component/shared/kubeapiserver.go
+++ b/pkg/component/shared/kubeapiserver.go
@@ -109,6 +109,7 @@ func NewKubeAPIServer(
defaultNotReadyTolerationSeconds *int64
defaultUnreachableTolerationSeconds *int64
eventTTL *metav1.Duration
+ tlsMinVersion *string
featureGates map[string]bool
requests *gardencorev1beta1.APIServerRequests
runtimeConfig map[string]bool
@@ -151,6 +152,7 @@ func NewKubeAPIServer(
defaultNotReadyTolerationSeconds = apiServerConfig.DefaultNotReadyTolerationSeconds
defaultUnreachableTolerationSeconds = apiServerConfig.DefaultUnreachableTolerationSeconds
eventTTL = apiServerConfig.EventTTL
+ tlsMinVersion = apiServerConfig.TLSMinVersion
featureGates = apiServerConfig.FeatureGates
logging = apiServerConfig.Logging
requests = apiServerConfig.Requests
@@ -202,6 +204,7 @@ func NewKubeAPIServer(
DefaultNotReadyTolerationSeconds: defaultNotReadyTolerationSeconds,
DefaultUnreachableTolerationSeconds: defaultUnreachableTolerationSeconds,
EventTTL: eventTTL,
+ TLSMinVersion: tlsMinVersion,
Images: images,
IsWorkerless: isWorkerless,
NamePrefix: namePrefix,
diff --git a/pkg/component/shared/kubeapiserver_test.go b/pkg/component/shared/kubeapiserver_test.go
index 42e559b509ea..2206f2851728 100644
--- a/pkg/component/shared/kubeapiserver_test.go
+++ b/pkg/component/shared/kubeapiserver_test.go
@@ -1004,6 +1004,26 @@ authorizers:
})
})
+ Describe("TLSMinVersion", func() {
+ It("should not set the tls min version field", func() {
+ kubeAPIServer, err := NewKubeAPIServer(ctx, runtimeClientSet, resourceConfigClient, namespace, objectMeta, runtimeVersion, targetVersion, sm, namePrefix, apiServerConfig, autoscalingConfig, vpnConfig, priorityClassName, isWorkerless, runsAsStaticPod, istioTLSTerminationEnabled, auditWebhookConfig, authenticationWebhookConfig, authorizationWebhookConfigs, resourcesToStoreInETCDEvents)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(kubeAPIServer.GetValues().TLSMinVersion).To(BeNil())
+ })
+
+ It("should set the field to the configured value", func() {
+ tlsMinVersion := new("VersionTLS13")
+
+ apiServerConfig = &gardencorev1beta1.KubeAPIServerConfig{
+ TLSMinVersion: tlsMinVersion,
+ }
+
+ kubeAPIServer, err := NewKubeAPIServer(ctx, runtimeClientSet, resourceConfigClient, namespace, objectMeta, runtimeVersion, targetVersion, sm, namePrefix, apiServerConfig, autoscalingConfig, vpnConfig, priorityClassName, isWorkerless, runsAsStaticPod, istioTLSTerminationEnabled, auditWebhookConfig, authenticationWebhookConfig, authorizationWebhookConfigs, resourcesToStoreInETCDEvents)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(kubeAPIServer.GetValues().TLSMinVersion).To(Equal(tlsMinVersion))
+ })
+ })
+
Describe("FeatureGates", func() {
It("should set the field to nil by default", func() {
kubeAPIServer, err := NewKubeAPIServer(ctx, runtimeClientSet, resourceConfigClient, namespace, objectMeta, runtimeVersion, targetVersion, sm, namePrefix, apiServerConfig, autoscalingConfig, vpnConfig, priorityClassName, isWorkerless, runsAsStaticPod, istioTLSTerminationEnabled, auditWebhookConfig, authenticationWebhookConfig, authorizationWebhookConfigs, resourcesToStoreInETCDEvents)
diff --git a/pkg/gardenlet/operation/botanist/kubeapiserverexposure.go b/pkg/gardenlet/operation/botanist/kubeapiserverexposure.go
index fe87e3ed65a5..f05d8bf1890b 100644
--- a/pkg/gardenlet/operation/botanist/kubeapiserverexposure.go
+++ b/pkg/gardenlet/operation/botanist/kubeapiserverexposure.go
@@ -120,6 +120,7 @@ func (b *Botanist) DefaultKubeAPIServerSNI() component.DeployWaiter {
},
IstioTLSTermination: b.ShootUsesIstioTLSTermination(),
WildcardConfiguration: wildcardConfiguration,
+ TLSMinVersion: b.shootKubeAPIServerTLSMinVersion(),
}
},
))
@@ -186,6 +187,7 @@ func (b *Botanist) setAPIServerServiceClusterIPs(clusterIPs []string) {
},
IstioTLSTermination: b.ShootUsesIstioTLSTermination(),
WildcardConfiguration: wildcardConfiguration,
+ TLSMinVersion: b.shootKubeAPIServerTLSMinVersion(),
}
if b.Shoot.ExternalClusterDomain != nil {
@@ -197,6 +199,14 @@ func (b *Botanist) setAPIServerServiceClusterIPs(clusterIPs []string) {
)
}
+func (b *Botanist) shootKubeAPIServerTLSMinVersion() *string {
+ if cfg := b.Shoot.GetInfo().Spec.Kubernetes.KubeAPIServer; cfg != nil {
+ return cfg.TLSMinVersion
+ }
+
+ return nil
+}
+
func mapToReservedKubeApiServerRange(ip net.IP) string {
// prevent leakage of real cluster ip to shoot. we use the reserved range 240.0.0.0/8 as prefix instead.
// e.g. cluster ip in seed: 192.168.102.23 => ip in shoot: 240.168.102.23
diff --git a/pkg/utils/istio/gateway.go b/pkg/utils/istio/gateway.go
index 77683189bc67..99991920adaf 100644
--- a/pkg/utils/istio/gateway.go
+++ b/pkg/utils/istio/gateway.go
@@ -13,9 +13,10 @@ const httpsPort = 443
// ServerConfig is a configuration for a server in an Istio Gateway.
type ServerConfig struct {
- Hosts []string
- PortName string
- TLSSecret string
+ Hosts []string
+ PortName string
+ TLSSecret string
+ MinProtocolVersion istioapinetworkingv1beta1.ServerTLSSettings_TLSProtocol
}
// GatewayWithTLSPassthrough returns a function setting the given attributes to a gateway object.
@@ -81,8 +82,9 @@ func GatewayWithMutualTLS(gateway *istionetworkingv1beta1.Gateway, labels map[st
Protocol: "HTTPS",
},
Tls: &istioapinetworkingv1beta1.ServerTLSSettings{
- Mode: istioapinetworkingv1beta1.ServerTLSSettings_OPTIONAL_MUTUAL,
- CredentialName: serverConfig.TLSSecret,
+ Mode: istioapinetworkingv1beta1.ServerTLSSettings_OPTIONAL_MUTUAL,
+ CredentialName: serverConfig.TLSSecret,
+ MinProtocolVersion: serverConfig.MinProtocolVersion,
},
})
}
diff --git a/pkg/utils/istio/gateway_test.go b/pkg/utils/istio/gateway_test.go
index 17f37fb1ff42..8b5e39b73182 100644
--- a/pkg/utils/istio/gateway_test.go
+++ b/pkg/utils/istio/gateway_test.go
@@ -77,11 +77,14 @@ var _ = Describe("Gateway", func() {
Expect(gateway.Spec.Servers[i].Port.Protocol).To(Equal("HTTPS"))
Expect(gateway.Spec.Servers[i].Tls.CredentialName).To(Equal(serverConfig.TLSSecret))
Expect(gateway.Spec.Servers[i].Tls.Mode).To(Equal(istioapinetworkingv1beta1.ServerTLSSettings_OPTIONAL_MUTUAL))
+ Expect(gateway.Spec.Servers[i].Tls.MinProtocolVersion).To(Equal(serverConfig.MinProtocolVersion))
}
},
- Entry("Nil values", nil, nil, []ServerConfig{{Hosts: nil, PortName: "", TLSSecret: ""}}),
- Entry("Some values", map[string]string{"foo": "bar", "key": "value"}, map[string]string{"app": "istio", "istio": "gateway"}, []ServerConfig{{Hosts: []string{"host-1", "host-2"}, PortName: "foo", TLSSecret: "my-secret"}}),
- Entry("Multiple servers", map[string]string{"foo": "bar", "key": "value"}, map[string]string{"app": "istio", "istio": "gateway"}, []ServerConfig{{Hosts: []string{"host-1", "host-2"}, PortName: "foo", TLSSecret: "my-secret"}, {Hosts: []string{"host-3", "host-4"}, PortName: "bar", TLSSecret: "my-other-secret"}}),
+ Entry("Nil values", nil, nil, []ServerConfig{{Hosts: nil, PortName: "", TLSSecret: "", MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLS_AUTO}}),
+ Entry("Some values", map[string]string{"foo": "bar", "key": "value"}, map[string]string{"app": "istio", "istio": "gateway"}, []ServerConfig{{Hosts: []string{"host-1", "host-2"}, PortName: "foo", TLSSecret: "my-secret", MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLS_AUTO}}),
+ Entry("Multiple servers", map[string]string{"foo": "bar", "key": "value"}, map[string]string{"app": "istio", "istio": "gateway"}, []ServerConfig{{Hosts: []string{"host-1", "host-2"}, PortName: "foo", TLSSecret: "my-secret", MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLS_AUTO}, {Hosts: []string{"host-3", "host-4"}, PortName: "bar", TLSSecret: "my-other-secret", MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLS_AUTO}}),
+ Entry("TLSV1_2", map[string]string{"foo": "bar"}, map[string]string{"app": "istio"}, []ServerConfig{{Hosts: []string{"host-1"}, PortName: "tls", TLSSecret: "secret", MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLSV1_2}}),
+ Entry("TLSV1_3", map[string]string{"foo": "bar"}, map[string]string{"app": "istio"}, []ServerConfig{{Hosts: []string{"host-1"}, PortName: "tls", TLSSecret: "secret", MinProtocolVersion: istioapinetworkingv1beta1.ServerTLSSettings_TLSV1_3}}),
)
})