diff --git a/Makefile.core.mk b/Makefile.core.mk index 93c6e1e49c7b..332a6965dc9b 100644 --- a/Makefile.core.mk +++ b/Makefile.core.mk @@ -362,6 +362,8 @@ copy-templates: cp manifests/charts/istio-control/istio-discovery/templates/configmap.yaml manifests/charts/istiod-remote/templates cp manifests/charts/istio-control/istio-discovery/templates/_helpers.tpl manifests/charts/istiod-remote/templates sed -e '1 i {{- if .Values.global.configCluster }}' -e '$$ a {{- end }}' manifests/charts/base/crds/crd-all.gen.yaml > manifests/charts/istiod-remote/templates/crd-all.gen.yaml + sed -e '1 i {{- if .Values.global.configCluster }}' -e '$$ a {{- end }}' manifests/charts/base/templates/validatingadmissionpolicy.yaml > manifests/charts/istiod-remote/templates/defaultrevisionvalidatingadmissionpolicy.yaml + sed -e '1 i {{- if .Values.global.configCluster }}' -e '$$ a {{- end }}' manifests/charts/istio-control/istio-discovery/templates/validatingadmissionpolicy.yaml > manifests/charts/istiod-remote/templates/validatingadmissionpolicy.yaml sed -e '1 i {{- if .Values.global.configCluster }}' -e '$$ a {{- end }}' manifests/charts/base/templates/default.yaml > manifests/charts/istiod-remote/templates/default.yaml sed -e '1 i {{- if .Values.global.configCluster }}' -e '$$ a {{- end }}' manifests/charts/istio-control/istio-discovery/templates/validatingwebhookconfiguration.yaml > manifests/charts/istiod-remote/templates/validatingwebhookconfiguration.yaml sed -e '1 i {{- if .Values.global.configCluster }}' -e '$$ a {{- end }}' manifests/charts/istio-control/istio-discovery/templates/serviceaccount.yaml > manifests/charts/istiod-remote/templates/serviceaccount.yaml diff --git a/cni/pkg/nodeagent/net.go b/cni/pkg/nodeagent/net.go index a8c27cc9b329..a37c85fea511 100644 --- a/cni/pkg/nodeagent/net.go +++ b/cni/pkg/nodeagent/net.go @@ -231,8 +231,8 @@ func (s *NetServer) RemovePodFromMesh(ctx context.Context, pod *corev1.Pod) erro openNetns := s.currentPodSnapshot.Take(string(pod.UID)) if openNetns == nil { - log.Warn("failed to find pod netns") - return fmt.Errorf("failed to find pod netns") + log.Warn("failed to find pod netns during removal") + return fmt.Errorf("failed to find pod netns during removal") } // pod is removed from the mesh, but is still running. remove iptables rules log.Debugf("calling DeleteInpodRules.") @@ -312,11 +312,17 @@ func addPodToHostNSIpset(pod *corev1.Pod, podIPs []netip.Addr, hostsideProbeSet for _, pip := range podIPs { // Add to host ipset log.Debugf("adding pod %s probe to ipset %s with ip %s", pod.Name, hostsideProbeSet.Name, pip) - // Add IP/port combo to set. Note that we set Replace to true - a pod ip/port combo already being - // in the set is perfectly fine, and something we can always safely overwrite, so we will. - if err := hostsideProbeSet.AddIP(pip, ipProto, podUID, true); err != nil { + // Add IP/port combo to set. Note that we set Replace to false here - we _did_ previously + // set it to true, but in theory that could mask weird scenarios where K8S triggers events out of order -> + // an add(sameIPreused) then delete(originalIP). + // Which will result in the new pod starting to fail healthchecks. + // + // Since we purge on restart of CNI, and remove pod IPs from the set on every pod removal/deletion, + // we _shouldn't_ get any overwrite/overlap, unless something is wrong and we are asked to add + // a pod by an IP we already have in the set (which will give an error, which we want). + if err := hostsideProbeSet.AddIP(pip, ipProto, podUID, false); err != nil { ipsetAddrErrs = append(ipsetAddrErrs, err) - log.Warnf("failed adding pod %s to ipset %s with ip %s, error was %s", + log.Errorf("failed adding pod %s to ipset %s with ip %s, error was %s", pod.Name, hostsideProbeSet.Name, pip, err) } } diff --git a/cni/pkg/nodeagent/net_test.go b/cni/pkg/nodeagent/net_test.go index d3c92be48f41..7802de1f0061 100644 --- a/cni/pkg/nodeagent/net_test.go +++ b/cni/pkg/nodeagent/net_test.go @@ -146,7 +146,7 @@ func TestServerAddPod(t *testing.T) { netip.MustParseAddr("99.9.9.9"), uint8(unix.IPPROTO_TCP), string(podMeta.UID), - true, + false, ).Return(nil) err := netServer.AddPodToMesh(ctx, &corev1.Pod{ObjectMeta: podMeta}, podIPs, "fakenetns") @@ -243,7 +243,7 @@ func expectPodAddedToIPSet(ipsetDeps *ipset.MockedIpsetDeps, podMeta metav1.Obje netip.MustParseAddr("99.9.9.9"), uint8(unix.IPPROTO_TCP), string(podMeta.UID), - true, + false, ).Return(nil) } @@ -361,7 +361,7 @@ func TestAddPodToHostNSIPSets(t *testing.T) { netip.MustParseAddr("99.9.9.9"), ipProto, podUID, - true, + false, ).Return(nil) fakeIPSetDeps.On("addIP", @@ -369,7 +369,7 @@ func TestAddPodToHostNSIPSets(t *testing.T) { netip.MustParseAddr("2.2.2.2"), ipProto, podUID, - true, + false, ).Return(nil) podIPs := []netip.Addr{netip.MustParseAddr("99.9.9.9"), netip.MustParseAddr("2.2.2.2")} @@ -392,7 +392,7 @@ func TestAddPodProbePortsToHostNSIPSetsReturnsErrorIfOneFails(t *testing.T) { netip.MustParseAddr("99.9.9.9"), ipProto, podUID, - true, + false, ).Return(nil) fakeIPSetDeps.On("addIP", @@ -400,7 +400,7 @@ func TestAddPodProbePortsToHostNSIPSetsReturnsErrorIfOneFails(t *testing.T) { netip.MustParseAddr("2.2.2.2"), ipProto, podUID, - true, + false, ).Return(errors.New("bwoah")) podIPs := []netip.Addr{netip.MustParseAddr("99.9.9.9"), netip.MustParseAddr("2.2.2.2")} @@ -450,7 +450,7 @@ func TestSyncHostIPSetsPrunesNothingIfNoExtras(t *testing.T) { netip.MustParseAddr("3.3.3.3"), ipProto, podUID, - true, + false, ).Return(nil) fixture.ipsetDeps.On("addIP", @@ -458,7 +458,7 @@ func TestSyncHostIPSetsPrunesNothingIfNoExtras(t *testing.T) { netip.MustParseAddr("2.2.2.2"), ipProto, podUID, - true, + false, ).Return(nil) fixture.ipsetDeps.On("listEntriesByIP", @@ -512,7 +512,7 @@ func TestSyncHostIPSetsPrunesIfExtras(t *testing.T) { netip.MustParseAddr("3.3.3.3"), ipProto, podUID, - true, + false, ).Return(nil) fixture.ipsetDeps.On("addIP", @@ -520,7 +520,7 @@ func TestSyncHostIPSetsPrunesIfExtras(t *testing.T) { netip.MustParseAddr("2.2.2.2"), ipProto, podUID, - true, + false, ).Return(nil) // List should return one IP not in our "pod snapshot", which means we prune diff --git a/go.mod b/go.mod index 448691e89ce0..4b301c246c68 100644 --- a/go.mod +++ b/go.mod @@ -106,8 +106,8 @@ require ( gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.14.3 - istio.io/api v1.22.0-beta.0 - istio.io/client-go v1.22.0-rc.0.0.20240511020757-412bec918d1e + istio.io/api v1.22.1-0.20240524024004-b6815be0740d + istio.io/client-go v1.22.1-0.20240524024404-e48447329f77 k8s.io/api v0.30.0 k8s.io/apiextensions-apiserver v0.30.0 k8s.io/apimachinery v0.30.0 diff --git a/go.sum b/go.sum index 4873e6104bcb..4e3b15757481 100644 --- a/go.sum +++ b/go.sum @@ -1102,10 +1102,10 @@ helm.sh/helm/v3 v3.14.3/go.mod h1:v6myVbyseSBJTzhmeE39UcPLNv6cQK6qss3dvgAySaE= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -istio.io/api v1.22.0-beta.0 h1:dlBLCqjH6/12RZEjDU5dbM3Evwl22jS6JucFn3nJyZ0= -istio.io/api v1.22.0-beta.0/go.mod h1:S3l8LWqNYS9yT+d4bH+jqzH2lMencPkW7SKM1Cu9EyM= -istio.io/client-go v1.22.0-rc.0.0.20240511020757-412bec918d1e h1:scHu9YFFfu8cj56K8kY2BxQfOV8SLywqUZDIJ1iT4w4= -istio.io/client-go v1.22.0-rc.0.0.20240511020757-412bec918d1e/go.mod h1:1lAPr0DOVBbnRQqLAQKxWbEaxFk6b1CJTm+ypnP7sMo= +istio.io/api v1.22.1-0.20240524024004-b6815be0740d h1:2GncSQ55NOr91NYPmi0jqhVM7z7/xswJsD96dQMkN38= +istio.io/api v1.22.1-0.20240524024004-b6815be0740d/go.mod h1:S3l8LWqNYS9yT+d4bH+jqzH2lMencPkW7SKM1Cu9EyM= +istio.io/client-go v1.22.1-0.20240524024404-e48447329f77 h1:RxyTd7arbmdk/E7xINxtrsC4pXtVR6piZgn25WYVqJ4= +istio.io/client-go v1.22.1-0.20240524024404-e48447329f77/go.mod h1:Z2QE9uMt6tDVyrmiLfLVhutbqtfUkPJ7A5Uw/p6gNFo= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA= diff --git a/istio.deps b/istio.deps index 1eeb908e0004..331dfd172278 100644 --- a/istio.deps +++ b/istio.deps @@ -4,13 +4,13 @@ "name": "PROXY_REPO_SHA", "repoName": "proxy", "file": "", - "lastStableSHA": "b2dd15dc498b84431c063042e7821e179d5a3c41" + "lastStableSHA": "f0254260634c0ca50a596a99e25fb2e55fe9bfb7" }, { "_comment": "", "name": "ZTUNNEL_REPO_SHA", "repoName": "ztunnel", "file": "", - "lastStableSHA": "909bf991d01edc4db51265bc633acfe303555ef5" + "lastStableSHA": "959e69db8ea156a17c556de415c53b8791312e99" } ] diff --git a/manifests/charts/istiod-remote/templates/defaultrevisionvalidatingadmissionpolicy.yaml b/manifests/charts/istiod-remote/templates/defaultrevisionvalidatingadmissionpolicy.yaml new file mode 100644 index 000000000000..4c1f856957c2 --- /dev/null +++ b/manifests/charts/istiod-remote/templates/defaultrevisionvalidatingadmissionpolicy.yaml @@ -0,0 +1,53 @@ +{{- if .Values.global.configCluster }} +{{- if and .Values.experimental.stableValidationPolicy (not (eq .Values.defaultRevision "")) }} +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: "stable-channel-default-policy.istio.io" + labels: + release: {{ .Release.Name }} + istio: istiod + istio.io/rev: {{ .Values.defaultRevision }} +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - security.istio.io + - networking.istio.io + - telemetry.istio.io + - extensions.istio.io + apiVersions: ["*"] + operations: ["CREATE", "UPDATE"] + resources: ["*"] + variables: + - name: isEnvoyFilter + expression: "object.kind == 'EnvoyFilter'" + - name: isWasmPlugin + expression: "object.kind == 'WasmPlugin'" + - name: isProxyConfig + expression: "object.kind == 'ProxyConfig'" + - name: isTelemetry + expression: "object.kind == 'Telemetry'" + validations: + - expression: "!variables.isEnvoyFilter" + - expression: "!variables.isWasmPlugin" + - expression: "!variables.isProxyConfig" + - expression: | + !( + variables.isTelemetry && ( + (has(object.spec.tracing) ? object.spec.tracing : {}).exists(t, has(t.useRequestIdForTraceSampling)) || + (has(object.spec.metrics) ? object.spec.metrics : {}).exists(m, has(m.reportingInterval)) || + (has(object.spec.accessLogging) ? object.spec.accessLogging : {}).exists(l, has(l.filter)) + ) + ) +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: "stable-channel-default-policy-binding.istio.io" +spec: + policyName: "stable-channel-default-policy.istio.io" + validationActions: [Deny] +{{- end }} +{{- end }} diff --git a/manifests/charts/istiod-remote/templates/validatingadmissionpolicy.yaml b/manifests/charts/istiod-remote/templates/validatingadmissionpolicy.yaml new file mode 100644 index 000000000000..9cdb5b075ec8 --- /dev/null +++ b/manifests/charts/istiod-remote/templates/validatingadmissionpolicy.yaml @@ -0,0 +1,59 @@ +{{- if .Values.global.configCluster }} +{{- if .Values.experimental.stableValidationPolicy }} +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: "stable-channel-policy{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}-{{ .Values.global.istioNamespace }}.istio.io" +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: + - security.istio.io + - networking.istio.io + - telemetry.istio.io + - extensions.istio.io + apiVersions: ["*"] + operations: ["CREATE", "UPDATE"] + resources: ["*"] + objectSelector: + matchExpressions: + - key: istio.io/rev + operator: In + values: + {{- if (eq .Values.revision "") }} + - "default" + {{- else }} + - "{{ .Values.revision }}" + {{- end }} + variables: + - name: isEnvoyFilter + expression: "object.kind == 'EnvoyFilter'" + - name: isWasmPlugin + expression: "object.kind == 'WasmPlugin'" + - name: isProxyConfig + expression: "object.kind == 'ProxyConfig'" + - name: isTelemetry + expression: "object.kind == 'Telemetry'" + validations: + - expression: "!variables.isEnvoyFilter" + - expression: "!variables.isWasmPlugin" + - expression: "!variables.isProxyConfig" + - expression: | + !( + variables.isTelemetry && ( + (has(object.spec.tracing) ? object.spec.tracing : {}).exists(t, has(t.useRequestIdForTraceSampling)) || + (has(object.spec.metrics) ? object.spec.metrics : {}).exists(m, has(m.reportingInterval)) || + (has(object.spec.accessLogging) ? object.spec.accessLogging : {}).exists(l, has(l.filter)) + ) + ) +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: "stable-channel-policy-binding{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}-{{ .Values.global.istioNamespace }}.istio.io" +spec: + policyName: "stable-channel-policy{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}-{{ .Values.global.istioNamespace }}.istio.io" + validationActions: [Deny] +{{- end }} +{{- end }} diff --git a/manifests/charts/ztunnel/values.yaml b/manifests/charts/ztunnel/values.yaml index bdfc0b87c66b..501c8029744f 100644 --- a/manifests/charts/ztunnel/values.yaml +++ b/manifests/charts/ztunnel/values.yaml @@ -32,8 +32,10 @@ defaults: # Pod resource configuration resources: requests: - cpu: 500m - memory: 2048Mi + cpu: 200m + # Ztunnel memory scales with the size of the cluster and traffic load + # While there are many factors, this is enough for ~200k pod cluster or 100k concurrently open connections. + memory: 512Mi # List of secret names to add to the service account as image pull secrets imagePullSecrets: [] diff --git a/operator/cmd/mesh/install.go b/operator/cmd/mesh/install.go index 6c594aa7f711..9d52c21ff698 100644 --- a/operator/cmd/mesh/install.go +++ b/operator/cmd/mesh/install.go @@ -406,8 +406,7 @@ func detectDefaultWebhookChange(p Printer, client kube.CLIClient, iop *v1alpha12 // If there is no default webhook but a revisioned default webhook exists, // and we are installing a new IOP with default semantics, the default webhook shifts. if exists && len(mwhs.Items) == 0 && iop.Spec.GetRevision() == "" { - p.Println("This installation will make default injection and validation pointing to the default revision, and " + - "originally it was pointing to the revisioned one.") + p.Println("The default revision has been updated to point to this installation.") } return nil } diff --git a/pilot/pkg/config/kube/gateway/deploymentcontroller.go b/pilot/pkg/config/kube/gateway/deploymentcontroller.go index d971fde2a106..220be4f32587 100644 --- a/pilot/pkg/config/kube/gateway/deploymentcontroller.go +++ b/pilot/pkg/config/kube/gateway/deploymentcontroller.go @@ -28,6 +28,7 @@ import ( klabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" gateway "sigs.k8s.io/gateway-api/apis/v1beta1" "sigs.k8s.io/yaml" @@ -46,6 +47,7 @@ import ( "istio.io/istio/pkg/kube/inject" "istio.io/istio/pkg/kube/kclient" istiolog "istio.io/istio/pkg/log" + "istio.io/istio/pkg/maps" "istio.io/istio/pkg/revisions" "istio.io/istio/pkg/test/util/tmpl" "istio.io/istio/pkg/test/util/yml" @@ -346,37 +348,6 @@ func (d *DeploymentController) configureIstioGateway(log *istiolog.Scope, gw gat serviceType = corev1.ServiceType(o) } - // TODO: Codify this API (i.e how to know if a specific gateway is an Istio waypoint gateway) - isWaypointGateway := strings.Contains(string(gw.Spec.GatewayClassName), "waypoint") - - // Default the network label for waypoints if not explicitly set in gateway's labels - network := d.injectConfig().Values.Struct().GetGlobal().GetNetwork() - if _, ok := gw.GetLabels()[label.TopologyNetwork.Name]; !ok && network != "" && isWaypointGateway { - if gw.Labels == nil { - gw.Labels = make(map[string]string) - } - gw.Labels[label.TopologyNetwork.Name] = d.injectConfig().Values.Struct().GetGlobal().GetNetwork() - } - - // TODO this sprays ambient annotations/labels all over EVER gateway resource (serviceaccts, services, etc) - // where they have no meaning/are not used/are ignored. We really only need them on the deployment podspec. - var hasAmbientLabel bool - if _, ok := gw.Labels[constants.DataplaneModeLabel]; ok { - hasAmbientLabel = true - } - if gw.Spec.Infrastructure != nil { - if _, ok := gw.Spec.Infrastructure.Labels[constants.DataplaneModeLabel]; ok { - hasAmbientLabel = true - } - } - // If no ambient redirection label is set explicitly, explicitly disable. - if features.EnableAmbientWaypoints && !isWaypointGateway && !hasAmbientLabel { - if gw.Labels == nil { - gw.Labels = make(map[string]string) - } - gw.Labels[constants.DataplaneModeLabel] = constants.DataplaneModeNone - } - input := TemplateInput{ Gateway: &gw, DeploymentName: model.GetOrDefault(gw.Annotations[gatewayNameOverride], defaultName), @@ -395,37 +366,11 @@ func (d *DeploymentController) configureIstioGateway(log *istiolog.Scope, gw gat } d.setGatewayNameLabel(&input) - // Default to the gateway labels/annotations and overwrite if infrastructure labels/annotations are set - gwInfra := gw.Spec.Infrastructure - if gwInfra != nil && gwInfra.Labels != nil { - infraLabels := make(map[string]string, len(gwInfra.Labels)) - for k, v := range gw.Spec.Infrastructure.Labels { - if strings.HasPrefix(string(k), "gateway.networking.k8s.io/") { - continue // ignore this prefix to avoid conflicts - } - infraLabels[string(k)] = string(v) - } - // Default the network label for waypoints if not explicitly set in infra labels - // We do this a second time here for correctness since if infra labels are set (according to the gwapi spec), - // the gateway's labels are ignored. - if _, ok := infraLabels[label.TopologyNetwork.Name]; !ok && network != "" && isWaypointGateway { - infraLabels[label.TopologyNetwork.Name] = network - } - - input.InfrastructureLabels = infraLabels - } - - if gwInfra != nil && gwInfra.Annotations != nil { - infraAnnotations := make(map[string]string, len(gwInfra.Annotations)) - for k, v := range gw.Spec.Infrastructure.Annotations { - if strings.HasPrefix(string(k), "gateway.networking.k8s.io/") { - continue // ignore this prefix to avoid conflicts - } - infraAnnotations[string(k)] = string(v) - } - input.InfrastructureAnnotations = infraAnnotations - } + // Default to the gateway labels/annotations and overwrite if infrastructure labels/annotations are set + input.InfrastructureLabels = extractInfrastructureLabels(gw) + input.InfrastructureAnnotations = extractInfrastructureAnnotations(gw) + d.setLabelOverrides(gw, input) if overwriteControllerVersion { log.Debugf("write controller version, existing=%v", existingControllerVersion) @@ -450,6 +395,66 @@ func (d *DeploymentController) configureIstioGateway(log *istiolog.Scope, gw gat return nil } +func (d *DeploymentController) setLabelOverrides(gw gateway.Gateway, input TemplateInput) { + // TODO: Codify this API (i.e how to know if a specific gateway is an Istio waypoint gateway) + isWaypointGateway := strings.Contains(string(gw.Spec.GatewayClassName), "waypoint") + + var hasAmbientLabel bool + if _, ok := gw.Labels[constants.DataplaneModeLabel]; ok { + hasAmbientLabel = true + } + if _, ok := input.InfrastructureLabels[constants.DataplaneModeLabel]; ok { + hasAmbientLabel = true + } + // If no ambient redirection label is set explicitly, explicitly disable. + // TODO this sprays ambient annotations/labels all over EVER gateway resource (serviceaccts, services, etc) + if features.EnableAmbientWaypoints && !isWaypointGateway && !hasAmbientLabel { + input.InfrastructureLabels[constants.DataplaneModeLabel] = constants.DataplaneModeNone + } + + // Default the network label for waypoints if not explicitly set in gateway's labels + network := d.injectConfig().Values.Struct().GetGlobal().GetNetwork() + if _, ok := gw.GetLabels()[label.TopologyNetwork.Name]; !ok && network != "" && isWaypointGateway { + input.InfrastructureLabels[label.TopologyNetwork.Name] = d.injectConfig().Values.Struct().GetGlobal().GetNetwork() + } +} + +func extractInfrastructureLabels(gw gateway.Gateway) map[string]string { + return extractInfrastructureMetadata(gw.Spec.Infrastructure, true, gw) +} + +func extractInfrastructureAnnotations(gw gateway.Gateway) map[string]string { + return extractInfrastructureMetadata(gw.Spec.Infrastructure, false, gw) +} + +func extractInfrastructureMetadata(gwInfra *gatewayv1.GatewayInfrastructure, isLabel bool, gw gateway.Gateway) map[string]string { + var field map[gatewayv1.AnnotationKey]gatewayv1.AnnotationValue + if gwInfra != nil && isLabel && gwInfra.Labels != nil { + field = gwInfra.Labels + } else if gwInfra != nil && !isLabel && gwInfra.Annotations != nil { + field = gwInfra.Annotations + } + if field != nil { + infra := make(map[string]string, len(field)) + for k, v := range field { + if strings.HasPrefix(string(k), "gateway.networking.k8s.io/") { + continue // ignore this prefix to avoid conflicts + } + infra[string(k)] = string(v) + } + return infra + } else if isLabel { + if gw.GetLabels() == nil { + return make(map[string]string) + } + return maps.Clone(gw.GetLabels()) + } + if gw.GetAnnotations() == nil { + return make(map[string]string) + } + return maps.Clone(gw.GetAnnotations()) +} + const ( // ControllerVersionAnnotation is an annotation added to the Gateway by the controller specifying // the "controller version". The original intent of this was to work around diff --git a/pilot/pkg/config/kube/gateway/deploymentcontroller_test.go b/pilot/pkg/config/kube/gateway/deploymentcontroller_test.go index 66aa018b9d5f..61f85303f018 100644 --- a/pilot/pkg/config/kube/gateway/deploymentcontroller_test.go +++ b/pilot/pkg/config/kube/gateway/deploymentcontroller_test.go @@ -346,7 +346,7 @@ func TestConfigureIstioGateway(t *testing.T) { kube.SetObjectFilter(client, tt.discoveryNamespaceFilter) client.Kube().Discovery().(*fakediscovery.FakeDiscovery).FakedServerVersion = &kubeVersion.Info{Major: "1", Minor: "28"} kclient.NewWriteClient[*k8sbeta.GatewayClass](client).Create(customClass) - kclient.NewWriteClient[*k8sbeta.Gateway](client).Create(&tt.gw) + kclient.NewWriteClient[*k8sbeta.Gateway](client).Create(tt.gw.DeepCopy()) stop := test.NewStop(t) env := model.NewEnvironment() env.PushContext().ProxyConfigs = tt.pcs @@ -374,6 +374,10 @@ func TestConfigureIstioGateway(t *testing.T) { resp := timestampRegex.ReplaceAll(buf.Bytes(), []byte("lastTransitionTime: fake")) util.CompareContent(t, resp, filepath.Join("testdata", "deployment", tt.name+".yaml")) } + // ensure we didn't mutate the object + if !tt.ignore { + assert.Equal(t, d.gateways.Get(tt.gw.Name, tt.gw.Namespace), &tt.gw) + } }) } } diff --git a/pilot/pkg/config/kube/gateway/testdata/deployment/infrastructure-labels-annotations.yaml b/pilot/pkg/config/kube/gateway/testdata/deployment/infrastructure-labels-annotations.yaml index d94dfa007e75..6659c44a15f4 100644 --- a/pilot/pkg/config/kube/gateway/testdata/deployment/infrastructure-labels-annotations.yaml +++ b/pilot/pkg/config/kube/gateway/testdata/deployment/infrastructure-labels-annotations.yaml @@ -13,6 +13,7 @@ metadata: foo: bar gateway.istio.io/managed: istio.io-gateway-controller gateway.networking.k8s.io/gateway-name: default + istio.io/dataplane-mode: none istio.io/gateway-name: default name: default-istio namespace: default @@ -31,6 +32,7 @@ metadata: foo: bar gateway.istio.io/managed: istio.io-gateway-controller gateway.networking.k8s.io/gateway-name: default + istio.io/dataplane-mode: none istio.io/gateway-name: default name: default-istio namespace: default @@ -54,6 +56,7 @@ spec: labels: foo: bar gateway.networking.k8s.io/gateway-name: default + istio.io/dataplane-mode: none istio.io/gateway-name: default service.istio.io/canonical-name: default-istio service.istio.io/canonical-revision: latest @@ -228,6 +231,7 @@ metadata: foo: bar gateway.istio.io/managed: istio.io-gateway-controller gateway.networking.k8s.io/gateway-name: default + istio.io/dataplane-mode: none istio.io/gateway-name: default name: default-istio namespace: default diff --git a/pilot/pkg/model/context.go b/pilot/pkg/model/context.go index 0509c1a2ca2c..1174efeedfba 100644 --- a/pilot/pkg/model/context.go +++ b/pilot/pkg/model/context.go @@ -361,6 +361,9 @@ type Proxy struct { // The merged gateways associated with the proxy if this is a Router MergedGateway *MergedGateway + // PrevMergedGateway contains information about merged gateway associated with the proxy previously + PrevMergedGateway *PrevMergedGateway + // ServiceTargets contains a list of all Services associated with the proxy, contextualized for this particular proxy. // These are unique to this proxy, as the port information is specific to it - while a ServicePort is shared with the // service, the target port may be distinct per-endpoint. So this maintains a view specific to this proxy. @@ -560,7 +563,15 @@ func (node *Proxy) SetGatewaysForProxy(ps *PushContext) { if node.Type != Router { return } + var prevMergedGateway MergedGateway + if node.MergedGateway != nil { + prevMergedGateway = *node.MergedGateway + } node.MergedGateway = ps.mergeGateways(node) + node.PrevMergedGateway = &PrevMergedGateway{ + ContainsAutoPassthroughGateways: prevMergedGateway.ContainsAutoPassthroughGateways, + AutoPassthroughSNIHosts: prevMergedGateway.GetAutoPassthrughGatewaySNIHosts(), + } } func (node *Proxy) SetServiceTargets(serviceDiscovery ServiceDiscovery) { diff --git a/pilot/pkg/model/endpointshards.go b/pilot/pkg/model/endpointshards.go index 78e5cca39f40..327990aafb8c 100644 --- a/pilot/pkg/model/endpointshards.go +++ b/pilot/pkg/model/endpointshards.go @@ -322,8 +322,9 @@ func (e *EndpointIndex) UpdateServiceEndpoints( } for _, nie := range istioEndpoints { if oie, exists := omap[nie.Address]; exists { - // If endpoint exists already, we should push if it's health status changes. - if oie.HealthStatus != nie.HealthStatus { + // If endpoint exists already, we should push if it's changed. + // Skip this check if we already decide we need to push to avoid expensive checks + if !needPush && !oie.Equals(nie) { needPush = true } newIstioEndpoints = append(newIstioEndpoints, nie) @@ -405,6 +406,8 @@ func updateShardServiceAccount(shards *EndpointShards, serviceName string) bool // EndpointIndexUpdater is an updater that will keep an EndpointIndex in sync. This is intended for tests only. type EndpointIndexUpdater struct { Index *EndpointIndex + // Optional; if set, we will trigger ConfigUpdates in response to EDS updates as appropriate + ConfigUpdateFunc func(req *PushRequest) } var _ XDSUpdater = &EndpointIndexUpdater{} @@ -416,7 +419,15 @@ func NewEndpointIndexUpdater(ei *EndpointIndex) *EndpointIndexUpdater { func (f *EndpointIndexUpdater) ConfigUpdate(*PushRequest) {} func (f *EndpointIndexUpdater) EDSUpdate(shard ShardKey, serviceName string, namespace string, eps []*IstioEndpoint) { - f.Index.UpdateServiceEndpoints(shard, serviceName, namespace, eps) + pushType := f.Index.UpdateServiceEndpoints(shard, serviceName, namespace, eps) + if f.ConfigUpdateFunc != nil && (pushType == IncrementalPush || pushType == FullPush) { + // Trigger a push + f.ConfigUpdateFunc(&PushRequest{ + Full: pushType == FullPush, + ConfigsUpdated: sets.New(ConfigKey{Kind: kind.ServiceEntry, Name: serviceName, Namespace: namespace}), + Reason: NewReasonStats(EndpointUpdate), + }) + } } func (f *EndpointIndexUpdater) EDSCacheUpdate(shard ShardKey, serviceName string, namespace string, eps []*IstioEndpoint) { diff --git a/pilot/pkg/model/gateway.go b/pilot/pkg/model/gateway.go index 5ccbef96f9d7..88ed130ee28a 100644 --- a/pilot/pkg/model/gateway.go +++ b/pilot/pkg/model/gateway.go @@ -97,6 +97,34 @@ type MergedGateway struct { VerifiedCertificateReferences sets.String } +func (g *MergedGateway) HasAutoPassthroughGateways() bool { + if g != nil { + return g.ContainsAutoPassthroughGateways + } + return false +} + +// PrevMergedGateway describes previous state of the gateway. +// Currently, it only contains information relevant for CDS. +type PrevMergedGateway struct { + ContainsAutoPassthroughGateways bool + AutoPassthroughSNIHosts sets.Set[string] +} + +func (g *PrevMergedGateway) HasAutoPassthroughGateway() bool { + if g != nil { + return g.ContainsAutoPassthroughGateways + } + return false +} + +func (g *PrevMergedGateway) GetAutoPassthroughSNIHosts() sets.Set[string] { + if g != nil { + return g.AutoPassthroughSNIHosts + } + return sets.Set[string]{} +} + var ( typeTag = monitoring.CreateLabel("type") nameTag = monitoring.CreateLabel("name") @@ -348,6 +376,23 @@ func MergeGateways(gateways []gatewayWithInstances, proxy *Proxy, ps *PushContex } } +func (g *MergedGateway) GetAutoPassthrughGatewaySNIHosts() sets.Set[string] { + hosts := sets.Set[string]{} + if g == nil { + return hosts + } + if g.ContainsAutoPassthroughGateways { + for _, tls := range g.MergedServers { + for _, s := range tls.Servers { + if s.GetTls().GetMode() == networking.ServerTLSSettings_AUTO_PASSTHROUGH { + hosts.InsertAll(s.Hosts...) + } + } + } + } + return hosts +} + func udpSupportedPort(number uint32, instances []ServiceTarget) bool { for _, w := range instances { if int(number) == w.Port.Port && w.Port.Protocol == protocol.UDP { diff --git a/pilot/pkg/model/gateway_test.go b/pilot/pkg/model/gateway_test.go index e7ea4f997f9d..c1064d50553c 100644 --- a/pilot/pkg/model/gateway_test.go +++ b/pilot/pkg/model/gateway_test.go @@ -20,6 +20,7 @@ import ( networking "istio.io/api/networking/v1alpha3" "istio.io/istio/pkg/config" + "istio.io/istio/pkg/util/sets" ) // nolint lll @@ -160,6 +161,70 @@ func TestMergeGateways(t *testing.T) { } } +func TestGetAutoPassthroughSNIHosts(t *testing.T) { + gateway := config.Config{ + Meta: config.Meta{ + Name: "gateway", + Namespace: "istio-system", + }, + Spec: &networking.Gateway{ + Selector: map[string]string{"istio": "ingressgateway"}, + Servers: []*networking.Server{ + { + Hosts: []string{"static.example.com"}, + Port: &networking.Port{Name: "http", Number: 80, Protocol: "HTTP"}, + }, + { + Hosts: []string{"www.example.com"}, + Port: &networking.Port{Name: "https", Number: 443, Protocol: "HTTPS"}, + Tls: &networking.ServerTLSSettings{Mode: networking.ServerTLSSettings_SIMPLE}, + }, + { + Hosts: []string{"a.apps.svc.cluster.local", "b.apps.svc.cluster.local"}, + Port: &networking.Port{Name: "tls", Number: 15443, Protocol: "TLS"}, + Tls: &networking.ServerTLSSettings{Mode: networking.ServerTLSSettings_AUTO_PASSTHROUGH}, + }, + }, + }, + } + svc := &Service{ + Attributes: ServiceAttributes{ + Labels: map[string]string{}, + }, + } + gatewayServiceTargets := []ServiceTarget{ + { + Service: svc, + Port: ServiceInstancePort{ + ServicePort: &Port{Port: 80}, + TargetPort: 80, + }, + }, + { + Service: svc, + Port: ServiceInstancePort{ + ServicePort: &Port{Port: 443}, + TargetPort: 443, + }, + }, + { + Service: svc, + Port: ServiceInstancePort{ + ServicePort: &Port{Port: 15443}, + TargetPort: 15443, + }, + }, + } + instances := []gatewayWithInstances{{gateway: gateway, instances: gatewayServiceTargets}} + mgw := MergeGateways(instances, &Proxy{}, nil) + hosts := mgw.GetAutoPassthrughGatewaySNIHosts() + expectedHosts := sets.Set[string]{} + expectedHosts.InsertAll("a.apps.svc.cluster.local", "b.apps.svc.cluster.local") + if !hosts.Equals(expectedHosts) { + t.Errorf("expected to get: [a.apps.svc.cluster.local,b.apps.svc.cluster.local], got: %s", hosts.String()) + } +} + func makeConfig(name, namespace, host, portName, portProtocol string, portNumber uint32, gw string, bind string, mode networking.ServerTLSSettings_TLSmode, ) config.Config { diff --git a/pilot/pkg/model/push_context.go b/pilot/pkg/model/push_context.go index 9495ea60f36b..d688a192612b 100644 --- a/pilot/pkg/model/push_context.go +++ b/pilot/pkg/model/push_context.go @@ -2075,6 +2075,23 @@ func (ps *PushContext) WasmPlugins(proxy *Proxy) map[extensions.PluginPhase][]*W return ps.WasmPluginsByListenerInfo(proxy, anyListener, WasmPluginTypeAny) } +func (ps *PushContext) WasmPluginsByName(proxy *Proxy, names []types.NamespacedName) []*WasmPluginWrapper { + res := make([]*WasmPluginWrapper, 0, len(names)) + for _, n := range names { + if n.Namespace != proxy.ConfigNamespace && n.Namespace != ps.Mesh.RootNamespace { + log.Warnf("proxy requested invalid WASM configuration: %v", n) + continue + } + for _, wsm := range ps.wasmPluginsByNamespace[n.Namespace] { + if wsm.Name == n.Name { + res = append(res, wsm) + break + } + } + } + return res +} + // WasmPluginsByListenerInfo return the WasmPluginWrappers which are matched with TrafficSelector in the given proxy. func (ps *PushContext) WasmPluginsByListenerInfo(proxy *Proxy, info WasmPluginListenerInfo, pluginType WasmPluginType, diff --git a/pilot/pkg/model/service.go b/pilot/pkg/model/service.go index 34f78aafb425..866a991e8094 100644 --- a/pilot/pkg/model/service.go +++ b/pilot/pkg/model/service.go @@ -1374,6 +1374,56 @@ func (ep *IstioEndpoint) ShallowCopy() *IstioEndpoint { return &cpy } +// Equals checks whether the attributes are equal from the passed in service. +func (ep *IstioEndpoint) Equals(other *IstioEndpoint) bool { + if ep == nil { + return other == nil + } + if other == nil { + return ep == nil + } + + // Check things we can directly compare... + eq := ep.Address == other.Address && + ep.ServicePortName == other.ServicePortName && + ep.LegacyClusterPortKey == other.LegacyClusterPortKey && + ep.ServiceAccount == other.ServiceAccount && + ep.Network == other.Network && + ep.Locality == other.Locality && + ep.EndpointPort == other.EndpointPort && + ep.LbWeight == other.LbWeight && + ep.TLSMode == other.TLSMode && + ep.Namespace == other.Namespace && + ep.WorkloadName == other.WorkloadName && + ep.HostName == other.HostName && + ep.SubDomain == other.SubDomain && + ep.HealthStatus == other.HealthStatus && + ep.NodeName == other.NodeName + if !eq { + return false + } + + // check everything else + if !maps.Equal(ep.Labels, other.Labels) { + return false + } + + // Compare discoverability by name + var epp string + if ep.DiscoverabilityPolicy != nil { + epp = ep.DiscoverabilityPolicy.String() + } + var op string + if other.DiscoverabilityPolicy != nil { + op = other.DiscoverabilityPolicy.String() + } + if epp != op { + return false + } + + return true +} + func copyInternal(v any) any { copied, err := copystructure.Copy(v) if err != nil { diff --git a/pilot/pkg/networking/core/cluster.go b/pilot/pkg/networking/core/cluster.go index b7742c75e4d8..95ad9a631dfb 100644 --- a/pilot/pkg/networking/core/cluster.go +++ b/pilot/pkg/networking/core/cluster.go @@ -321,7 +321,7 @@ func (configgen *ConfigGeneratorImpl) buildOutboundClusters(cb *ClusterBuilder, // create default cluster discoveryType := convertResolution(cb.proxyType, service) - defaultCluster := cb.buildCluster(clusterKey.clusterName, discoveryType, lbEndpoints, model.TrafficDirectionOutbound, port, service, nil) + defaultCluster := cb.buildCluster(clusterKey.clusterName, discoveryType, lbEndpoints, model.TrafficDirectionOutbound, port, service, nil, "") if defaultCluster == nil { continue } @@ -443,7 +443,7 @@ func (configgen *ConfigGeneratorImpl) buildOutboundSniDnatClusters(proxy *model. lbEndpoints = endpointBuilder.FromServiceEndpoints() } - defaultCluster := cb.buildCluster(clusterName, discoveryType, lbEndpoints, model.TrafficDirectionOutbound, port, service, nil) + defaultCluster := cb.buildCluster(clusterName, discoveryType, lbEndpoints, model.TrafficDirectionOutbound, port, service, nil, "") if defaultCluster == nil { continue } diff --git a/pilot/pkg/networking/core/cluster_builder.go b/pilot/pkg/networking/core/cluster_builder.go index 488396366063..31328a7d1906 100644 --- a/pilot/pkg/networking/core/cluster_builder.go +++ b/pilot/pkg/networking/core/cluster_builder.go @@ -181,7 +181,7 @@ func (cb *ClusterBuilder) buildSubsetCluster( lbEndpoints = endpointBuilder.WithSubset(subset.Name).FromServiceEndpoints() } - subsetCluster := cb.buildCluster(subsetClusterName, clusterType, lbEndpoints, model.TrafficDirectionOutbound, opts.port, service, nil) + subsetCluster := cb.buildCluster(subsetClusterName, clusterType, lbEndpoints, model.TrafficDirectionOutbound, opts.port, service, nil, subset.Name) if subsetCluster == nil { return nil } @@ -284,6 +284,7 @@ func (cb *ClusterBuilder) applyMetadataExchange(c *cluster.Cluster) { func (cb *ClusterBuilder) buildCluster(name string, discoveryType cluster.Cluster_DiscoveryType, localityLbEndpoints []*endpoint.LocalityLbEndpoints, direction model.TrafficDirection, port *model.Port, service *model.Service, inboundServices []model.ServiceTarget, + subset string, ) *clusterWrapper { c := &cluster.Cluster{ Name: name, @@ -342,7 +343,7 @@ func (cb *ClusterBuilder) buildCluster(name string, discoveryType cluster.Cluste // If stat name is configured, build the alternate stats name. if len(cb.req.Push.Mesh.OutboundClusterStatName) != 0 { ec.cluster.AltStatName = telemetry.BuildStatPrefix(cb.req.Push.Mesh.OutboundClusterStatName, - string(service.Hostname), "", port, 0, &service.Attributes) + string(service.Hostname), subset, port, 0, &service.Attributes) } } @@ -366,7 +367,7 @@ func (cb *ClusterBuilder) buildInboundCluster(clusterPort int, bind string, clusterType = cluster.Cluster_STATIC } localCluster := cb.buildCluster(clusterName, clusterType, localityLbEndpoints, - model.TrafficDirectionInbound, instance.Port.ServicePort, instance.Service, inboundServices) + model.TrafficDirectionInbound, instance.Port.ServicePort, instance.Service, inboundServices, "") // If stat name is configured, build the alt statname. if len(cb.req.Push.Mesh.InboundClusterStatName) != 0 { localCluster.cluster.AltStatName = telemetry.BuildStatPrefix(cb.req.Push.Mesh.InboundClusterStatName, diff --git a/pilot/pkg/networking/core/cluster_builder_test.go b/pilot/pkg/networking/core/cluster_builder_test.go index 13a1a415df8e..36870b166d2f 100644 --- a/pilot/pkg/networking/core/cluster_builder_test.go +++ b/pilot/pkg/networking/core/cluster_builder_test.go @@ -110,6 +110,7 @@ func TestApplyDestinationRule(t *testing.T) { port *model.Port proxyView model.ProxyView destRule *networking.DestinationRule + meshConfig *meshconfig.MeshConfig expectedSubsetClusters []*cluster.Cluster }{ // TODO(ramaraochavali): Add more tests to cover additional conditions. @@ -265,6 +266,56 @@ func TestApplyDestinationRule(t *testing.T) { }, }, }, + { + name: "destination rule with subset traffic policy and alt statname", + cluster: &cluster.Cluster{Name: "foo", ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_EDS}}, + clusterMode: DefaultClusterMode, + service: service, + port: servicePort[0], + proxyView: model.ProxyViewAll, + destRule: &networking.DestinationRule{ + Host: "foo.default.svc.cluster.local", + Subsets: []*networking.Subset{ + { + Name: "foobar", + Labels: map[string]string{"foo": "bar"}, + TrafficPolicy: &networking.TrafficPolicy{ + ConnectionPool: &networking.ConnectionPoolSettings{ + Http: &networking.ConnectionPoolSettings_HTTPSettings{ + MaxRetries: 10, + }, + }, + }, + }, + }, + }, + meshConfig: &meshconfig.MeshConfig{ + OutboundClusterStatName: "%SERVICE%_%SUBSET_NAME%_%SERVICE_PORT_NAME%_%SERVICE_PORT%", + InboundTrafficPolicy: &meshconfig.MeshConfig_InboundTrafficPolicy{}, + EnableAutoMtls: &wrappers.BoolValue{ + Value: false, + }, + }, + expectedSubsetClusters: []*cluster.Cluster{ + { + Name: "outbound|8080|foobar|foo.default.svc.cluster.local", + ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_EDS}, + EdsClusterConfig: &cluster.Cluster_EdsClusterConfig{ + ServiceName: "outbound|8080|foobar|foo.default.svc.cluster.local", + }, + CircuitBreakers: &cluster.CircuitBreakers{ + Thresholds: []*cluster.CircuitBreakers_Thresholds{ + { + MaxRetries: &wrappers.UInt32Value{ + Value: 10, + }, + }, + }, + }, + AltStatName: "foo.default.svc.cluster.local_foobar_default_8080", + }, + }, + }, { name: "destination rule with use client protocol traffic policy", cluster: &cluster.Cluster{Name: "foo", ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_EDS}}, @@ -735,6 +786,7 @@ func TestApplyDestinationRule(t *testing.T) { Instances: instances, ConfigPointers: []*config.Config{cfg}, Services: []*model.Service{tt.service}, + MeshConfig: tt.meshConfig, }) proxy := cg.SetupProxy(nil) cb := NewClusterBuilder(proxy, &model.PushRequest{Push: cg.PushContext()}, nil) @@ -851,6 +903,11 @@ func compareClusters(t *testing.T, ec *cluster.Cluster, gc *cluster.Cluster) { t.Errorf("Unexpected circuit breaker thresholds want %v, got %v", ec.CircuitBreakers.Thresholds[0].MaxRetries, gc.CircuitBreakers.Thresholds[0].MaxRetries) } } + if ec.AltStatName != "" { + if ec.AltStatName != gc.AltStatName { + t.Errorf("Unexpected alt stat name want %s, got %s", ec.AltStatName, gc.AltStatName) + } + } } func verifyALPNOverride(t *testing.T, md *core.Metadata, tlsMode networking.ClientTLSSettings_TLSmode) { @@ -1093,7 +1150,7 @@ func TestBuildDefaultCluster(t *testing.T) { MeshExternal: false, Attributes: model.ServiceAttributes{Name: "svc", Namespace: "default"}, } - defaultCluster := cb.buildCluster(tt.clusterName, tt.discovery, tt.endpoints, tt.direction, servicePort, service, nil) + defaultCluster := cb.buildCluster(tt.clusterName, tt.discovery, tt.endpoints, tt.direction, servicePort, service, nil, "") eb := endpoints.NewCDSEndpointBuilder(proxy, cb.req.Push, tt.clusterName, tt.direction, "", service.Hostname, servicePort.Port, service, nil) @@ -1201,7 +1258,7 @@ func TestClusterDnsLookupFamily(t *testing.T) { MeshExternal: false, Attributes: model.ServiceAttributes{Name: "svc", Namespace: "default"}, } - defaultCluster := cb.buildCluster(tt.clusterName, tt.discovery, endpoints, model.TrafficDirectionOutbound, servicePort, service, nil) + defaultCluster := cb.buildCluster(tt.clusterName, tt.discovery, endpoints, model.TrafficDirectionOutbound, servicePort, service, nil, "") if defaultCluster.build().DnsLookupFamily != tt.expectedFamily { t.Errorf("Unexpected DnsLookupFamily, got: %v, want: %v", defaultCluster.build().DnsLookupFamily, tt.expectedFamily) diff --git a/pilot/pkg/networking/core/cluster_waypoint.go b/pilot/pkg/networking/core/cluster_waypoint.go index cf1bf4eb7f88..4f85e289c4e1 100644 --- a/pilot/pkg/networking/core/cluster_waypoint.go +++ b/pilot/pkg/networking/core/cluster_waypoint.go @@ -95,7 +95,7 @@ func (cb *ClusterBuilder) buildWaypointInboundVIPCluster(svc *model.Service, por clusterType := cluster.Cluster_EDS localCluster := cb.buildCluster(clusterName, clusterType, nil, - model.TrafficDirectionInbound, &port, nil, nil) + model.TrafficDirectionInbound, &port, nil, nil, subset) // Ensure VIP cluster has services metadata for stats filter usage im := getOrCreateIstioMetadata(localCluster.cluster) diff --git a/pilot/pkg/networking/core/extension/wasmplugin.go b/pilot/pkg/networking/core/extension/wasmplugin.go index 30ef9a3ea747..1c5a3669044c 100644 --- a/pilot/pkg/networking/core/extension/wasmplugin.go +++ b/pilot/pkg/networking/core/extension/wasmplugin.go @@ -97,7 +97,7 @@ func toEnvoyNetworkFilter(wasmPlugin *model.WasmPluginWrapper) *listener.Filter // InsertedExtensionConfigurations builds added via WasmPlugin. func InsertedExtensionConfigurations( - wasmPlugins map[extensions.PluginPhase][]*model.WasmPluginWrapper, + wasmPlugins []*model.WasmPluginWrapper, names []string, pullSecrets map[string][]byte, ) []*core.TypedExtensionConfig { result := make([]*core.TypedExtensionConfig, 0) @@ -105,38 +105,35 @@ func InsertedExtensionConfigurations( return result } hasName := sets.New(names...) - for _, list := range wasmPlugins { - for _, p := range list { - if !hasName.Contains(p.ResourceName) { + for _, p := range wasmPlugins { + if !hasName.Contains(p.ResourceName) { + continue + } + switch { + case p.Type == extensions.PluginType_NETWORK: + wasmExtensionConfig := p.BuildNetworkWasmFilter() + if wasmExtensionConfig == nil { continue } - switch { - case p.Type == extensions.PluginType_NETWORK: - wasmExtensionConfig := p.BuildNetworkWasmFilter() - if wasmExtensionConfig == nil { - continue - } - updatePluginConfig(wasmExtensionConfig.GetConfig(), pullSecrets) - typedConfig := protoconv.MessageToAny(wasmExtensionConfig) - ec := &core.TypedExtensionConfig{ - Name: p.ResourceName, - TypedConfig: typedConfig, - } - result = append(result, ec) - default: - wasmExtensionConfig := p.BuildHTTPWasmFilter() - if wasmExtensionConfig == nil { - continue - } - updatePluginConfig(wasmExtensionConfig.GetConfig(), pullSecrets) - typedConfig := protoconv.MessageToAny(wasmExtensionConfig) - ec := &core.TypedExtensionConfig{ - Name: p.ResourceName, - TypedConfig: typedConfig, - } - result = append(result, ec) + updatePluginConfig(wasmExtensionConfig.GetConfig(), pullSecrets) + typedConfig := protoconv.MessageToAny(wasmExtensionConfig) + ec := &core.TypedExtensionConfig{ + Name: p.ResourceName, + TypedConfig: typedConfig, } - + result = append(result, ec) + default: + wasmExtensionConfig := p.BuildHTTPWasmFilter() + if wasmExtensionConfig == nil { + continue + } + updatePluginConfig(wasmExtensionConfig.GetConfig(), pullSecrets) + typedConfig := protoconv.MessageToAny(wasmExtensionConfig) + ec := &core.TypedExtensionConfig{ + Name: p.ResourceName, + TypedConfig: typedConfig, + } + result = append(result, ec) } } return result diff --git a/pilot/pkg/networking/core/extension/wasmplugin_test.go b/pilot/pkg/networking/core/extension/wasmplugin_test.go index 9451082b3124..582d4421c8ac 100644 --- a/pilot/pkg/networking/core/extension/wasmplugin_test.go +++ b/pilot/pkg/networking/core/extension/wasmplugin_test.go @@ -125,23 +125,21 @@ func TestInsertedExtensionConfigurations(t *testing.T) { }) testCases := []struct { name string - wasmPlugins map[extensions.PluginPhase][]*model.WasmPluginWrapper + wasmPlugins []*model.WasmPluginWrapper names []string expectedECs []*core.TypedExtensionConfig }{ { name: "empty", - wasmPlugins: map[extensions.PluginPhase][]*model.WasmPluginWrapper{}, + wasmPlugins: []*model.WasmPluginWrapper{}, names: []string{someAuthNFilter.Name}, expectedECs: []*core.TypedExtensionConfig{}, }, { name: "authn", - wasmPlugins: map[extensions.PluginPhase][]*model.WasmPluginWrapper{ - extensions.PluginPhase_AUTHN: { - someAuthNFilter, - someAuthZFilter, - }, + wasmPlugins: []*model.WasmPluginWrapper{ + someAuthNFilter, + someAuthZFilter, }, names: []string{someAuthNFilter.Namespace + "." + someAuthNFilter.Name}, expectedECs: []*core.TypedExtensionConfig{ @@ -153,10 +151,8 @@ func TestInsertedExtensionConfigurations(t *testing.T) { }, { name: "network", - wasmPlugins: map[extensions.PluginPhase][]*model.WasmPluginWrapper{ - extensions.PluginPhase_AUTHN: { - someNetworkFilter, - }, + wasmPlugins: []*model.WasmPluginWrapper{ + someNetworkFilter, }, names: []string{ someNetworkFilter.Namespace + "." + someNetworkFilter.Name, @@ -170,11 +166,9 @@ func TestInsertedExtensionConfigurations(t *testing.T) { }, { name: "combination of http and network", - wasmPlugins: map[extensions.PluginPhase][]*model.WasmPluginWrapper{ - extensions.PluginPhase_AUTHN: { - someAuthNFilter, - someNetworkFilter, - }, + wasmPlugins: []*model.WasmPluginWrapper{ + someAuthNFilter, + someNetworkFilter, }, names: []string{ someAuthNFilter.Namespace + "." + someAuthNFilter.Name, diff --git a/pilot/pkg/networking/core/extension_config_builder.go b/pilot/pkg/networking/core/extension_config_builder.go index ac972753d969..6d55371cb37c 100644 --- a/pilot/pkg/networking/core/extension_config_builder.go +++ b/pilot/pkg/networking/core/extension_config_builder.go @@ -15,11 +15,15 @@ package core import ( + "strings" + core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + "k8s.io/apimachinery/pkg/types" "istio.io/istio/pilot/pkg/model" "istio.io/istio/pilot/pkg/networking/core/envoyfilter" "istio.io/istio/pilot/pkg/networking/core/extension" + "istio.io/istio/pkg/log" ) // BuildExtensionConfiguration returns the list of extension configuration for the given proxy and list of names. @@ -29,7 +33,24 @@ func (configgen *ConfigGeneratorImpl) BuildExtensionConfiguration( ) []*core.TypedExtensionConfig { envoyFilterPatches := push.EnvoyFilters(proxy) extensions := envoyfilter.InsertedExtensionConfigurations(envoyFilterPatches, extensionConfigNames) - wasmPlugins := push.WasmPlugins(proxy) + wasmPlugins := push.WasmPluginsByName(proxy, parseExtensionName(extensionConfigNames)) extensions = append(extensions, extension.InsertedExtensionConfigurations(wasmPlugins, extensionConfigNames, pullSecrets)...) return extensions } + +func parseExtensionName(names []string) []types.NamespacedName { + res := make([]types.NamespacedName, 0, len(names)) + for _, n := range names { + if !strings.HasPrefix(n, model.WasmPluginResourceNamePrefix) { + log.Warnf("ignoring unknown ECDS: %v", n) + continue + } + ns, name, ok := strings.Cut(n[len(model.WasmPluginResourceNamePrefix):], ".") + if !ok { + log.Warnf("ignoring unknown ECDS: %v", n) + continue + } + res = append(res, types.NamespacedName{Namespace: ns, Name: name}) + } + return res +} diff --git a/pilot/pkg/serviceregistry/aggregate/controller.go b/pilot/pkg/serviceregistry/aggregate/controller.go index 89014d91c9ca..7786a0d828cb 100644 --- a/pilot/pkg/serviceregistry/aggregate/controller.go +++ b/pilot/pkg/serviceregistry/aggregate/controller.go @@ -27,6 +27,7 @@ import ( "istio.io/istio/pkg/config/mesh" "istio.io/istio/pkg/log" "istio.io/istio/pkg/maps" + "istio.io/istio/pkg/slices" "istio.io/istio/pkg/util/sets" ) @@ -139,7 +140,20 @@ func NewController(opt Options) *Controller { } func (c *Controller) addRegistry(registry serviceregistry.Instance, stop <-chan struct{}) { - c.registries = append(c.registries, ®istryEntry{Instance: registry, stop: stop}) + added := false + if registry.Provider() == provider.Kubernetes { + for i, r := range c.registries { + if r.Provider() != provider.Kubernetes { + // insert the registry in the position of the first non kubernetes registry + c.registries = slices.Insert(c.registries, i, ®istryEntry{Instance: registry, stop: stop}) + added = true + break + } + } + } + if !added { + c.registries = append(c.registries, ®istryEntry{Instance: registry, stop: stop}) + } // Observe the registry for events. registry.AppendNetworkGatewayHandler(c.NotifyGatewayHandlers) diff --git a/pilot/pkg/serviceregistry/aggregate/controller_test.go b/pilot/pkg/serviceregistry/aggregate/controller_test.go index 89d6eea0da80..85101e37b084 100644 --- a/pilot/pkg/serviceregistry/aggregate/controller_test.go +++ b/pilot/pkg/serviceregistry/aggregate/controller_test.go @@ -273,6 +273,11 @@ func TestAddRegistry(t *testing.T) { ClusterID: "cluster2", DiscoveryController: memory.NewServiceDiscovery(), }, + { + ProviderID: provider.Kubernetes, + ClusterID: "cluster3", + DiscoveryController: memory.NewServiceDiscovery(), + }, } ctrl := NewController(Options{}) @@ -280,8 +285,11 @@ func TestAddRegistry(t *testing.T) { registry2Counter := atomic.NewInt32(0) for _, r := range registries { + counter := atomic.NewInt32(0) clusterID := r.Cluster() - counter := registry1Counter + if clusterID == "cluster1" { + counter = registry1Counter + } if clusterID == "cluster2" { counter = registry2Counter } @@ -290,8 +298,13 @@ func TestAddRegistry(t *testing.T) { }) ctrl.AddRegistry(r) } - if l := len(ctrl.registries); l != 2 { - t.Fatalf("Expected length of the registries slice should be 2, got %d", l) + if l := len(ctrl.registries); l != 3 { + t.Fatalf("Expected length of the registries slice should be 3, got %d", l) + } + + if ctrl.registries[0].Instance.Provider() != provider.Kubernetes { + t.Errorf("expected first registry should be %s, but got %s", provider.Kubernetes, + ctrl.registries[0].Instance.Provider()) } registries[0].DiscoveryController.(*memory.ServiceDiscovery).AddService(mock.HelloService) diff --git a/pilot/pkg/serviceregistry/serviceregistry_test.go b/pilot/pkg/serviceregistry/serviceregistry_test.go index f7ab812cc977..f5013cc19b01 100644 --- a/pilot/pkg/serviceregistry/serviceregistry_test.go +++ b/pilot/pkg/serviceregistry/serviceregistry_test.go @@ -65,6 +65,7 @@ func setupTest(t *testing.T) (model.ConfigStoreController, kubernetes.Interface, endpoints := model.NewEndpointIndex(model.DisabledCache{}) delegate := model.NewEndpointIndexUpdater(endpoints) xdsUpdater := xdsfake.NewWithDelegate(delegate) + delegate.ConfigUpdateFunc = xdsUpdater.ConfigUpdate meshWatcher := mesh.NewFixedWatcher(&meshconfig.MeshConfig{}) kc := kubecontroller.NewController( client, @@ -241,10 +242,13 @@ func TestWorkloadInstances(t *testing.T) { makePod(t, kube, pod) createEndpoints(t, kube, service.Name, namespace, []v1.EndpointPort{{Name: "http", Port: 80}}, []string{pod.Status.PodIP}) fx.WaitOrFail(t, "eds") + // Endpoint update is triggered since its a brand new service + if ev := fx.WaitOrFail(t, "xds full"); !ev.Reason.Has(model.EndpointUpdate) { + t.Fatalf("xds push reason does not contain %v: %v", model.EndpointUpdate, ev) + } // headless service update must trigger nds push, so we trigger a full push. - ev := fx.WaitOrFail(t, "xds full") - if !ev.Reason.Has(model.HeadlessEndpointUpdate) { - t.Fatalf("xds push reason does not contain %v", model.HeadlessEndpointUpdate) + if ev := fx.WaitOrFail(t, "xds full"); !ev.Reason.Has(model.HeadlessEndpointUpdate) { + t.Fatalf("xds push reason does not contain %v: %v", model.HeadlessEndpointUpdate, ev) } // pure HTTP headless services should not need a full push since they do not @@ -263,10 +267,13 @@ func TestWorkloadInstances(t *testing.T) { makePod(t, kube, pod) createEndpoints(t, kube, service.Name, namespace, []v1.EndpointPort{{Name: "tcp", Port: 70}}, []string{pod.Status.PodIP}) fx.WaitOrFail(t, "eds") - ev := fx.WaitOrFail(t, "xds full") - // headless service update must trigger nds push. - if !ev.Reason.Has(model.HeadlessEndpointUpdate) { - t.Fatalf("xds push reason does not contain %v", model.HeadlessEndpointUpdate) + // Endpoint update is triggered since its a brand new service + if ev := fx.WaitOrFail(t, "xds full"); !ev.Reason.Has(model.EndpointUpdate) { + t.Fatalf("xds push reason does not contain %v: %v", model.EndpointUpdate, ev) + } + // headless service update must trigger nds push, so we trigger a full push. + if ev := fx.WaitOrFail(t, "xds full"); !ev.Reason.Has(model.HeadlessEndpointUpdate) { + t.Fatalf("xds push reason does not contain %v: %v", model.HeadlessEndpointUpdate, ev) } instances := []EndpointResponse{{ Address: pod.Status.PodIP, @@ -465,6 +472,53 @@ func TestWorkloadInstances(t *testing.T) { expectServiceEndpoints(t, fx, expectedSvc, 80, instances) }) + t.Run("External only: workloadEntry port is changed", func(t *testing.T) { + store, _, fx := setupTest(t) + makeIstioObject(t, store, config.Config{ + Meta: config.Meta{ + Name: "service-entry", + Namespace: namespace, + GroupVersionKind: gvk.ServiceEntry, + Domain: "cluster.local", + }, + Spec: &networking.ServiceEntry{ + Hosts: []string{"service.namespace.svc.cluster.local"}, + Ports: []*networking.ServicePort{{ + Name: "http", + Number: 80, + Protocol: "http", + }}, + WorkloadSelector: &networking.WorkloadSelector{ + Labels: labels, + }, + }, + }) + makeIstioObject(t, store, workloadEntry) + fx.WaitOrFail(t, "xds full") + + instances := []EndpointResponse{{ + Address: workloadEntry.Spec.(*networking.WorkloadEntry).Address, + Port: 80, + }} + expectServiceEndpoints(t, fx, expectedSvc, 80, instances) + + fx.Clear() + // Update the port + newWorkloadEntry := workloadEntry.DeepCopy() + spec := workloadEntry.Spec.(*networking.WorkloadEntry).DeepCopy() + spec.Ports = map[string]uint32{ + "http": 1234, + } + newWorkloadEntry.Spec = spec + makeIstioObject(t, store, newWorkloadEntry) + instances = []EndpointResponse{{ + Address: workloadEntry.Spec.(*networking.WorkloadEntry).Address, + Port: 1234, + }} + fx.WaitOrFail(t, "xds") + expectServiceEndpoints(t, fx, expectedSvc, 80, instances) + }) + t.Run("Service selects WorkloadEntry", func(t *testing.T) { store, kube, fx := setupTest(t) makeService(t, kube, service) diff --git a/pilot/pkg/xds/cds.go b/pilot/pkg/xds/cds.go index 738da908bfe7..cb84f77deb10 100644 --- a/pilot/pkg/xds/cds.go +++ b/pilot/pkg/xds/cds.go @@ -91,10 +91,18 @@ func cdsNeedsPush(req *model.PushRequest, proxy *model.Proxy) bool { if len(req.ConfigsUpdated) == 0 { return true } + + checkGateway := false for config := range req.ConfigsUpdated { - if features.FilterGatewayClusterConfig && proxy.Type == model.Router { - if _, f := pushCdsGatewayConfig[config.Kind]; f { - return true + if proxy.Type == model.Router { + if features.FilterGatewayClusterConfig { + if _, f := pushCdsGatewayConfig[config.Kind]; f { + return true + } + } + if config.Kind == kind.Gateway { + // Do the check outside of the loop since its slow; just trigger we need it + checkGateway = true } } @@ -102,6 +110,13 @@ func cdsNeedsPush(req *model.PushRequest, proxy *model.Proxy) bool { return true } } + if checkGateway { + autoPassthroughModeChanged := proxy.MergedGateway.HasAutoPassthroughGateways() != proxy.PrevMergedGateway.HasAutoPassthroughGateway() + autoPassthroughHostsChanged := !proxy.MergedGateway.GetAutoPassthrughGatewaySNIHosts().Equals(proxy.PrevMergedGateway.GetAutoPassthroughSNIHosts()) + if autoPassthroughModeChanged || autoPassthroughHostsChanged { + return true + } + } return false } diff --git a/pkg/kube/inject/inject_test.go b/pkg/kube/inject/inject_test.go index a53fb001ca98..87bcb3ac7786 100644 --- a/pkg/kube/inject/inject_test.go +++ b/pkg/kube/inject/inject_test.go @@ -284,6 +284,24 @@ func TestInjection(t *testing.T) { in: "proxy-override-args.yaml", want: "proxy-override-args.yaml.injected", }, + { + in: "proxy-override-runas.yaml", + want: "proxy-override-runas.yaml.injected", + }, + { + in: "proxy-override-runas.yaml", + want: "proxy-override-runas.yaml.cni.injected", + setFlags: []string{ + "components.cni.enabled=true", + }, + }, + { + in: "proxy-override-runas.yaml", + want: "proxy-override-runas.yaml.tproxy.injected", + mesh: func(m *meshapi.MeshConfig) { + m.DefaultConfig.InterceptionMode = meshapi.ProxyConfig_TPROXY + }, + }, { in: "proxy-override-args.yaml", want: "proxy-override-args-native.yaml.injected", diff --git a/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml new file mode 100644 index 000000000000..a6645e8cd41d --- /dev/null +++ b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml @@ -0,0 +1,22 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hello +spec: + selector: + matchLabels: + app: hello + template: + metadata: + labels: + app: hello + spec: + containers: + - name: hello + image: "fake.docker.io/google-samples/hello-go-gke:1.0" + - name: istio-proxy + image: auto + securityContext: + # iptables rules must honor this value, and must not use 1337 + runAsUser: 1234 + runAsGroup: 4321 diff --git a/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.cni.injected b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.cni.injected new file mode 100644 index 000000000000..11f2d5c22437 --- /dev/null +++ b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.cni.injected @@ -0,0 +1,234 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + name: hello +spec: + selector: + matchLabels: + app: hello + strategy: {} + template: + metadata: + annotations: + istio.io/rev: default + kubectl.kubernetes.io/default-container: hello + kubectl.kubernetes.io/default-logs-container: hello + prometheus.io/path: /stats/prometheus + prometheus.io/port: "15020" + prometheus.io/scrape: "true" + proxy.istio.io/overrides: '{"containers":[{"name":"istio-proxy","resources":{},"securityContext":{"runAsUser":1234,"runAsGroup":4321}}]}' + sidecar.istio.io/interceptionMode: REDIRECT + sidecar.istio.io/status: '{"initContainers":["istio-validation"],"containers":["istio-proxy"],"volumes":["workload-socket","credential-socket","workload-certs","istio-envoy","istio-data","istio-podinfo","istio-token","istiod-ca-cert"],"imagePullSecrets":null,"revision":"default"}' + traffic.sidecar.istio.io/excludeInboundPorts: "15020" + traffic.sidecar.istio.io/includeInboundPorts: '*' + traffic.sidecar.istio.io/includeOutboundIPRanges: '*' + creationTimestamp: null + labels: + app: hello + security.istio.io/tlsMode: istio + service.istio.io/canonical-name: hello + service.istio.io/canonical-revision: latest + spec: + containers: + - image: fake.docker.io/google-samples/hello-go-gke:1.0 + name: hello + resources: {} + - args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --proxyLogLevel=warning + - --proxyComponentLogLevel=misc:error + - --log_output_level=default:info + env: + - name: PILOT_CERT_PROVIDER + value: istiod + - name: CA_ADDR + value: istiod.istio-system.svc:15012 + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_CPU_LIMIT + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.cpu + - name: PROXY_CONFIG + value: | + {} + - name: ISTIO_META_POD_PORTS + value: |- + [ + ] + - name: ISTIO_META_APP_CONTAINERS + value: hello + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.memory + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.cpu + - name: ISTIO_META_CLUSTER_ID + value: Kubernetes + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: ISTIO_META_INTERCEPTION_MODE + value: REDIRECT + - name: ISTIO_META_WORKLOAD_NAME + value: hello + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/default/deployments/hello + - name: ISTIO_META_MESH_ID + value: cluster.local + - name: TRUST_DOMAIN + value: cluster.local + image: gcr.io/istio-testing/proxyv2:latest + name: istio-proxy + ports: + - containerPort: 15090 + name: http-envoy-prom + protocol: TCP + readinessProbe: + failureThreshold: 4 + httpGet: + path: /healthz/ready + port: 15021 + periodSeconds: 15 + timeoutSeconds: 3 + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 4321 + runAsNonRoot: true + runAsUser: 1234 + startupProbe: + failureThreshold: 600 + httpGet: + path: /healthz/ready + port: 15021 + periodSeconds: 1 + timeoutSeconds: 3 + volumeMounts: + - mountPath: /var/run/secrets/workload-spiffe-uds + name: workload-socket + - mountPath: /var/run/secrets/credential-uds + name: credential-socket + - mountPath: /var/run/secrets/workload-spiffe-credentials + name: workload-certs + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + - mountPath: /var/lib/istio/data + name: istio-data + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /var/run/secrets/tokens + name: istio-token + - mountPath: /etc/istio/pod + name: istio-podinfo + initContainers: + - args: + - istio-iptables + - -p + - "15001" + - -z + - "15006" + - -u + - "1234" + - -m + - REDIRECT + - -i + - '*' + - -x + - "" + - -b + - '*' + - -d + - 15090,15021,15020 + - --log_output_level=default:info + - --run-validation + - --skip-rule-apply + image: gcr.io/istio-testing/proxyv2:latest + name: istio-validation + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 4321 + runAsNonRoot: true + runAsUser: 1234 + volumes: + - name: workload-socket + - name: credential-socket + - name: workload-certs + - emptyDir: + medium: Memory + name: istio-envoy + - emptyDir: {} + name: istio-data + - downwardAPI: + items: + - fieldRef: + fieldPath: metadata.labels + path: labels + - fieldRef: + fieldPath: metadata.annotations + path: annotations + name: istio-podinfo + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: istio-ca + expirationSeconds: 43200 + path: istio-token + - configMap: + name: istio-ca-root-cert + name: istiod-ca-cert +status: {} +--- diff --git a/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.injected b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.injected new file mode 100644 index 000000000000..9c7c7eacc9e9 --- /dev/null +++ b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.injected @@ -0,0 +1,231 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + name: hello +spec: + selector: + matchLabels: + app: hello + strategy: {} + template: + metadata: + annotations: + istio.io/rev: default + kubectl.kubernetes.io/default-container: hello + kubectl.kubernetes.io/default-logs-container: hello + prometheus.io/path: /stats/prometheus + prometheus.io/port: "15020" + prometheus.io/scrape: "true" + proxy.istio.io/overrides: '{"containers":[{"name":"istio-proxy","resources":{},"securityContext":{"runAsUser":1234,"runAsGroup":4321}}]}' + sidecar.istio.io/status: '{"initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["workload-socket","credential-socket","workload-certs","istio-envoy","istio-data","istio-podinfo","istio-token","istiod-ca-cert"],"imagePullSecrets":null,"revision":"default"}' + creationTimestamp: null + labels: + app: hello + security.istio.io/tlsMode: istio + service.istio.io/canonical-name: hello + service.istio.io/canonical-revision: latest + spec: + containers: + - image: fake.docker.io/google-samples/hello-go-gke:1.0 + name: hello + resources: {} + - args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --proxyLogLevel=warning + - --proxyComponentLogLevel=misc:error + - --log_output_level=default:info + env: + - name: PILOT_CERT_PROVIDER + value: istiod + - name: CA_ADDR + value: istiod.istio-system.svc:15012 + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_CPU_LIMIT + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.cpu + - name: PROXY_CONFIG + value: | + {} + - name: ISTIO_META_POD_PORTS + value: |- + [ + ] + - name: ISTIO_META_APP_CONTAINERS + value: hello + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.memory + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.cpu + - name: ISTIO_META_CLUSTER_ID + value: Kubernetes + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: ISTIO_META_INTERCEPTION_MODE + value: REDIRECT + - name: ISTIO_META_WORKLOAD_NAME + value: hello + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/default/deployments/hello + - name: ISTIO_META_MESH_ID + value: cluster.local + - name: TRUST_DOMAIN + value: cluster.local + image: gcr.io/istio-testing/proxyv2:latest + name: istio-proxy + ports: + - containerPort: 15090 + name: http-envoy-prom + protocol: TCP + readinessProbe: + failureThreshold: 4 + httpGet: + path: /healthz/ready + port: 15021 + periodSeconds: 15 + timeoutSeconds: 3 + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 4321 + runAsNonRoot: true + runAsUser: 1234 + startupProbe: + failureThreshold: 600 + httpGet: + path: /healthz/ready + port: 15021 + periodSeconds: 1 + timeoutSeconds: 3 + volumeMounts: + - mountPath: /var/run/secrets/workload-spiffe-uds + name: workload-socket + - mountPath: /var/run/secrets/credential-uds + name: credential-socket + - mountPath: /var/run/secrets/workload-spiffe-credentials + name: workload-certs + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + - mountPath: /var/lib/istio/data + name: istio-data + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /var/run/secrets/tokens + name: istio-token + - mountPath: /etc/istio/pod + name: istio-podinfo + initContainers: + - args: + - istio-iptables + - -p + - "15001" + - -z + - "15006" + - -u + - "1234" + - -m + - REDIRECT + - -i + - '*' + - -x + - "" + - -b + - '*' + - -d + - 15090,15021,15020 + - --log_output_level=default:info + image: gcr.io/istio-testing/proxyv2:latest + name: istio-init + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_ADMIN + - NET_RAW + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + volumes: + - name: workload-socket + - name: credential-socket + - name: workload-certs + - emptyDir: + medium: Memory + name: istio-envoy + - emptyDir: {} + name: istio-data + - downwardAPI: + items: + - fieldRef: + fieldPath: metadata.labels + path: labels + - fieldRef: + fieldPath: metadata.annotations + path: annotations + name: istio-podinfo + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: istio-ca + expirationSeconds: 43200 + path: istio-token + - configMap: + name: istio-ca-root-cert + name: istiod-ca-cert +status: {} +--- diff --git a/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.tproxy.injected b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.tproxy.injected new file mode 100644 index 000000000000..a8aa55985d1c --- /dev/null +++ b/pkg/kube/inject/testdata/inject/proxy-override-runas.yaml.tproxy.injected @@ -0,0 +1,233 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + name: hello +spec: + selector: + matchLabels: + app: hello + strategy: {} + template: + metadata: + annotations: + istio.io/rev: default + kubectl.kubernetes.io/default-container: hello + kubectl.kubernetes.io/default-logs-container: hello + prometheus.io/path: /stats/prometheus + prometheus.io/port: "15020" + prometheus.io/scrape: "true" + proxy.istio.io/overrides: '{"containers":[{"name":"istio-proxy","resources":{},"securityContext":{"runAsUser":1234,"runAsGroup":4321}}]}' + sidecar.istio.io/status: '{"initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["workload-socket","credential-socket","workload-certs","istio-envoy","istio-data","istio-podinfo","istio-token","istiod-ca-cert"],"imagePullSecrets":null,"revision":"default"}' + creationTimestamp: null + labels: + app: hello + security.istio.io/tlsMode: istio + service.istio.io/canonical-name: hello + service.istio.io/canonical-revision: latest + spec: + containers: + - image: fake.docker.io/google-samples/hello-go-gke:1.0 + name: hello + resources: {} + - args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --proxyLogLevel=warning + - --proxyComponentLogLevel=misc:error + - --log_output_level=default:info + env: + - name: PILOT_CERT_PROVIDER + value: istiod + - name: CA_ADDR + value: istiod.istio-system.svc:15012 + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_CPU_LIMIT + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.cpu + - name: PROXY_CONFIG + value: | + {"interceptionMode":"TPROXY"} + - name: ISTIO_META_POD_PORTS + value: |- + [ + ] + - name: ISTIO_META_APP_CONTAINERS + value: hello + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.memory + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + divisor: "0" + resource: limits.cpu + - name: ISTIO_META_CLUSTER_ID + value: Kubernetes + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: ISTIO_META_INTERCEPTION_MODE + value: TPROXY + - name: ISTIO_META_WORKLOAD_NAME + value: hello + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/default/deployments/hello + - name: ISTIO_META_MESH_ID + value: cluster.local + - name: TRUST_DOMAIN + value: cluster.local + image: gcr.io/istio-testing/proxyv2:latest + name: istio-proxy + ports: + - containerPort: 15090 + name: http-envoy-prom + protocol: TCP + readinessProbe: + failureThreshold: 4 + httpGet: + path: /healthz/ready + port: 15021 + periodSeconds: 15 + timeoutSeconds: 3 + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_ADMIN + drop: + - ALL + privileged: false + readOnlyRootFilesystem: true + runAsGroup: 4321 + runAsNonRoot: false + runAsUser: 0 + startupProbe: + failureThreshold: 600 + httpGet: + path: /healthz/ready + port: 15021 + periodSeconds: 1 + timeoutSeconds: 3 + volumeMounts: + - mountPath: /var/run/secrets/workload-spiffe-uds + name: workload-socket + - mountPath: /var/run/secrets/credential-uds + name: credential-socket + - mountPath: /var/run/secrets/workload-spiffe-credentials + name: workload-certs + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + - mountPath: /var/lib/istio/data + name: istio-data + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /var/run/secrets/tokens + name: istio-token + - mountPath: /etc/istio/pod + name: istio-podinfo + initContainers: + - args: + - istio-iptables + - -p + - "15001" + - -z + - "15006" + - -u + - "1234" + - -m + - TPROXY + - -i + - '*' + - -x + - "" + - -b + - '*' + - -d + - 15090,15021,15020 + - --log_output_level=default:info + image: gcr.io/istio-testing/proxyv2:latest + name: istio-init + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - NET_ADMIN + - NET_RAW + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + volumes: + - name: workload-socket + - name: credential-socket + - name: workload-certs + - emptyDir: + medium: Memory + name: istio-envoy + - emptyDir: {} + name: istio-data + - downwardAPI: + items: + - fieldRef: + fieldPath: metadata.labels + path: labels + - fieldRef: + fieldPath: metadata.annotations + path: annotations + name: istio-podinfo + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: istio-ca + expirationSeconds: 43200 + path: istio-token + - configMap: + name: istio-ca-root-cert + name: istiod-ca-cert +status: {} +--- diff --git a/pkg/kube/inject/testdata/inputs/custom-template.yaml.37.mesh.gen.yaml b/pkg/kube/inject/testdata/inputs/custom-template.yaml.40.mesh.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/custom-template.yaml.37.mesh.gen.yaml rename to pkg/kube/inject/testdata/inputs/custom-template.yaml.40.mesh.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/custom-template.yaml.37.template.gen.yaml b/pkg/kube/inject/testdata/inputs/custom-template.yaml.40.template.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/custom-template.yaml.37.template.gen.yaml rename to pkg/kube/inject/testdata/inputs/custom-template.yaml.40.template.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/custom-template.yaml.37.values.gen.yaml b/pkg/kube/inject/testdata/inputs/custom-template.yaml.40.values.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/custom-template.yaml.37.values.gen.yaml rename to pkg/kube/inject/testdata/inputs/custom-template.yaml.40.values.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/hello-openshift.yaml.44.mesh.gen.yaml b/pkg/kube/inject/testdata/inputs/hello-openshift.yaml.47.mesh.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/hello-openshift.yaml.44.mesh.gen.yaml rename to pkg/kube/inject/testdata/inputs/hello-openshift.yaml.47.mesh.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/hello-openshift.yaml.44.template.gen.yaml b/pkg/kube/inject/testdata/inputs/hello-openshift.yaml.47.template.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/hello-openshift.yaml.44.template.gen.yaml rename to pkg/kube/inject/testdata/inputs/hello-openshift.yaml.47.template.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/hello-openshift.yaml.44.values.gen.yaml b/pkg/kube/inject/testdata/inputs/hello-openshift.yaml.47.values.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/hello-openshift.yaml.44.values.gen.yaml rename to pkg/kube/inject/testdata/inputs/hello-openshift.yaml.47.values.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/merge-probers.yaml.40.mesh.gen.yaml b/pkg/kube/inject/testdata/inputs/merge-probers.yaml.43.mesh.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/merge-probers.yaml.40.mesh.gen.yaml rename to pkg/kube/inject/testdata/inputs/merge-probers.yaml.43.mesh.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/merge-probers.yaml.40.template.gen.yaml b/pkg/kube/inject/testdata/inputs/merge-probers.yaml.43.template.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/merge-probers.yaml.40.template.gen.yaml rename to pkg/kube/inject/testdata/inputs/merge-probers.yaml.43.template.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/merge-probers.yaml.40.values.gen.yaml b/pkg/kube/inject/testdata/inputs/merge-probers.yaml.43.values.gen.yaml similarity index 100% rename from pkg/kube/inject/testdata/inputs/merge-probers.yaml.40.values.gen.yaml rename to pkg/kube/inject/testdata/inputs/merge-probers.yaml.43.values.gen.yaml diff --git a/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.mesh.gen.yaml b/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.mesh.gen.yaml new file mode 100644 index 000000000000..29e80375bc7e --- /dev/null +++ b/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.mesh.gen.yaml @@ -0,0 +1,8 @@ +defaultConfig: + discoveryAddress: istiod.istio-system.svc:15012 +defaultProviders: + metrics: + - prometheus +enablePrometheusMerge: true +rootNamespace: istio-system +trustDomain: cluster.local \ No newline at end of file diff --git a/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.template.gen.yaml b/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.template.gen.yaml new file mode 100644 index 000000000000..7f7c6623b155 --- /dev/null +++ b/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.template.gen.yaml @@ -0,0 +1,1835 @@ +# defaultTemplates defines the default template to use for pods that do not explicitly specify a template +defaultTemplates: [sidecar] +policy: enabled +alwaysInjectSelector: + [] +neverInjectSelector: + [] +injectedAnnotations: +template: "{{ Template_Version_And_Istio_Version_Mismatched_Check_Installation }}" +templates: + sidecar: | + {{- define "resources" }} + {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }} + {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) }} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end }} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{- end }} + {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }} + limits: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit` }}" + {{ end }} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit` }}" + {{ end }} + {{- end }} + {{- else }} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 6 }} + {{- end }} + {{- end }} + {{- end }} + {{ $nativeSidecar := (eq (env "ENABLE_NATIVE_SIDECARS" "false") "true") }} + {{- $containers := list }} + {{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}} + metadata: + labels: + security.istio.io/tlsMode: {{ index .ObjectMeta.Labels `security.istio.io/tlsMode` | default "istio" | quote }} + {{- if eq (index .ProxyConfig.ProxyMetadata "ISTIO_META_ENABLE_HBONE") "true" }} + networking.istio.io/tunnel: {{ index .ObjectMeta.Labels `networking.istio.io/tunnel` | default "http" | quote }} + {{- end }} + service.istio.io/canonical-name: {{ index .ObjectMeta.Labels `service.istio.io/canonical-name` | default (index .ObjectMeta.Labels `app.kubernetes.io/name`) | default (index .ObjectMeta.Labels `app`) | default .DeploymentMeta.Name | trunc 63 | trimSuffix "-" | quote }} + service.istio.io/canonical-revision: {{ index .ObjectMeta.Labels `service.istio.io/canonical-revision` | default (index .ObjectMeta.Labels `app.kubernetes.io/version`) | default (index .ObjectMeta.Labels `version`) | default "latest" | quote }} + annotations: { + istio.io/rev: {{ .Revision | default "default" | quote }}, + {{- if ge (len $containers) 1 }} + {{- if not (isset .ObjectMeta.Annotations `kubectl.kubernetes.io/default-logs-container`) }} + kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}", + {{- end }} + {{- if not (isset .ObjectMeta.Annotations `kubectl.kubernetes.io/default-container`) }} + kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}", + {{- end }} + {{- end }} + {{- if or .Values.pilot.cni.enabled .Values.istio_cni.enabled }} + {{- if or (eq .Values.pilot.cni.provider "multus") (eq .Values.istio_cni.provider "multus") (not .Values.istio_cni.chained)}} + k8s.v1.cni.cncf.io/networks: '{{ appendMultusNetwork (index .ObjectMeta.Annotations `k8s.v1.cni.cncf.io/networks`) `default/istio-cni` }}', + {{- end }} + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}", + {{ with annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}traffic.sidecar.istio.io/includeOutboundIPRanges: "{{.}}",{{ end }} + {{ with annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{.}}",{{ end }} + {{ with annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` .Values.global.proxy.includeInboundPorts }}traffic.sidecar.istio.io/includeInboundPorts: "{{.}}",{{ end }} + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}", + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/includeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.includeOutboundPorts "") "") }} + traffic.sidecar.istio.io/includeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundPorts` .Values.global.proxy.includeOutboundPorts }}", + {{- end }} + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}", + {{- end }} + {{ with index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}traffic.sidecar.istio.io/kubevirtInterfaces: "{{.}}",{{ end }} + {{ with index .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeInterfaces` }}traffic.sidecar.istio.io/excludeInterfaces: "{{.}}",{{ end }} + {{- end }} + } + spec: + {{- $holdProxy := and + (or .ProxyConfig.HoldApplicationUntilProxyStarts.GetValue .Values.global.proxy.holdApplicationUntilProxyStarts) + (not $nativeSidecar) }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{ if or .Values.pilot.cni.enabled .Values.istio_cni.enabled -}} + - name: istio-validation + {{ else -}} + - name: istio-init + {{ end -}} + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .ProxyImage }}" + {{- end }} + args: + - istio-iptables + - "-p" + - {{ .MeshConfig.ProxyListenPort | default "15001" | quote }} + - "-z" + - {{ .MeshConfig.ProxyInboundListenPort | default "15006" | quote }} + - "-u" + - {{ .ProxyUID | default "1337" | quote }} + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` .Values.global.proxy.includeInboundPorts }}" + - "-d" + {{- if excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }} + - "15090,15021,{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{- else }} + - "15090,15021" + {{- end }} + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/includeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.includeOutboundPorts "") "") -}} + - "-q" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundPorts` .Values.global.proxy.includeOutboundPorts }}" + {{ end -}} + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeInterfaces`) -}} + - "-c" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeInterfaces` }}" + {{ end -}} + - "--log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }}" + {{ if .Values.global.logAsJson -}} + - "--log_as_json" + {{ end -}} + {{ if or .Values.pilot.cni.enabled .Values.istio_cni.enabled -}} + - "--run-validation" + - "--skip-rule-apply" + {{ end -}} + {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} + {{- if .ProxyConfig.ProxyMetadata }} + env: + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + resources: + {{ template "resources" . }} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + privileged: {{ .Values.global.proxy.privileged }} + capabilities: + {{- if not (or .Values.pilot.cni.enabled .Values.istio_cni.enabled) }} + add: + - NET_ADMIN + - NET_RAW + {{- end }} + drop: + - ALL + {{- if not (or .Values.pilot.cni.enabled .Values.istio_cni.enabled) }} + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{- else }} + readOnlyRootFilesystem: true + runAsGroup: {{ .ProxyGID | default "1337" }} + runAsUser: {{ .ProxyUID | default "1337" }} + runAsNonRoot: true + {{- end }} + {{ end -}} + {{- if eq (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/data/core.proxy && ulimit -c unlimited + command: + - /bin/sh + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .ProxyImage }}" + {{- end }} + {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} + resources: + {{ template "resources" . }} + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SYS_ADMIN + drop: + - ALL + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{ end }} + {{ if not $nativeSidecar }} + containers: + {{ end }} + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .ProxyImage }}" + {{- end }} + {{ if $nativeSidecar }}restartPolicy: Always{{end}} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel }} + - --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel }} + - --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }} + {{- if .Values.global.sts.servicePort }} + - --stsPort={{ .Values.global.sts.servicePort }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + {{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{ toYaml .Values.global.proxy.lifecycle | indent 6 }} + {{- else if $holdProxy }} + lifecycle: + postStart: + exec: + command: + - pilot-agent + - wait + {{- else if $nativeSidecar }} + {{- /* preStop is called when the pod starts shutdown. Initialize drain. We will get SIGTERM once applications are torn down. */}} + lifecycle: + preStop: + exec: + command: + - pilot-agent + - request + - --debug-port={{(annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort)}} + - POST + - drain + {{- end }} + env: + {{- if eq .InboundTrafficPolicyMode "localhost" }} + - name: REWRITE_PROBE_LEGACY_LOCALHOST_DESTINATION + value: "true" + {{- end }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: CA_ADDR + {{- if .Values.global.caAddress }} + value: {{ .Values.global.caAddress }} + {{- else }} + value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_CPU_LIMIT + valueFrom: + resourceFieldRef: + resource: limits.cpu + - name: PROXY_CONFIG + value: | + {{ protoToJSON .ProxyConfig }} + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_APP_CONTAINERS + value: "{{ $containers | join "," }}" + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + resource: limits.cpu + {{- if .CompliancePolicy }} + - name: COMPLIANCE_POLICY + value: "{{ .CompliancePolicy }}" + {{- end }} + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: "{{ .DeploymentMeta.Name }}" + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: ISTIO_META_MESH_ID + value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}" + {{- end }} + {{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: TRUST_DOMAIN + value: "{{ . }}" + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "datadog") (isset .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + {{ if .Values.global.proxy.startupProbe.enabled }} + startupProbe: + httpGet: + path: /healthz/ready + port: 15021 + initialDelaySeconds: 0 + periodSeconds: 1 + timeoutSeconds: 3 + failureThreshold: {{ .Values.global.proxy.startupProbe.failureThreshold }} + {{ end }} + readinessProbe: + httpGet: + path: /healthz/ready + port: 15021 + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + timeoutSeconds: 3 + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + {{- if eq (index .ProxyConfig.ProxyMetadata "IPTABLES_TRACE_LOGGING") "true" }} + allowPrivilegeEscalation: true + capabilities: + add: + - NET_ADMIN + drop: + - ALL + privileged: true + readOnlyRootFilesystem: {{ ne (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + runAsGroup: {{ .ProxyGID | default "1337" }} + runAsNonRoot: false + runAsUser: 0 + {{- else }} + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + capabilities: + {{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}} + add: + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + - NET_ADMIN + {{- end }} + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true` -}} + - NET_BIND_SERVICE + {{- end }} + {{- end }} + drop: + - ALL + privileged: {{ .Values.global.proxy.privileged }} + readOnlyRootFilesystem: {{ ne (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + runAsGroup: {{ .ProxyGID | default "1337" }} + {{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}} + runAsNonRoot: false + runAsUser: 0 + {{- else -}} + runAsNonRoot: true + runAsUser: {{ .ProxyUID | default "1337" }} + {{- end }} + {{- end }} + resources: + {{ template "resources" . }} + volumeMounts: + - name: workload-socket + mountPath: /var/run/secrets/workload-spiffe-uds + - name: credential-socket + mountPath: /var/run/secrets/credential-uds + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + mountPath: /var/run/secrets/workload-spiffe-credentials + readOnly: true + {{- else }} + - name: workload-certs + mountPath: /var/run/secrets/workload-spiffe-credentials + {{- end }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + {{- end }} + {{- if eq .Values.global.pilotCertProvider "kubernetes" }} + - mountPath: /var/run/secrets/istio/kubernetes + name: kube-ca-cert + {{- end }} + - mountPath: /var/lib/istio/data + name: istio-data + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + # SDS channel between istioagent and Envoy + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + - name: istio-podinfo + mountPath: /etc/istio/pod + {{- if and (eq .Values.global.proxy.tracer "lightstep") .ProxyConfig.GetTracing.GetTlsSettings }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetTlsSettings.GetCaCertificates }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 6 }} + {{ end }} + {{- end }} + volumes: + - emptyDir: + name: workload-socket + - emptyDir: + name: credential-socket + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + csi: + driver: workloadcertificates.security.cloud.google.com + {{- else }} + - emptyDir: + name: workload-certs + {{- end }} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + # SDS channel between istioagent and Envoy + - emptyDir: + medium: Memory + name: istio-envoy + - name: istio-data + emptyDir: {} + - name: istio-podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + name: istio-ca-root-cert + {{- end }} + {{- if eq .Values.global.pilotCertProvider "kubernetes" }} + - name: kube-ca-cert + configMap: + name: kube-root-ca.crt + {{- end }} + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{ end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .ProxyConfig.GetTracing.GetTlsSettings }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + gateway: | + {{- $containers := list }} + {{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}} + metadata: + labels: + service.istio.io/canonical-name: {{ index .ObjectMeta.Labels `service.istio.io/canonical-name` | default (index .ObjectMeta.Labels `app.kubernetes.io/name`) | default (index .ObjectMeta.Labels `app`) | default .DeploymentMeta.Name | quote }} + service.istio.io/canonical-revision: {{ index .ObjectMeta.Labels `service.istio.io/canonical-revision` | default (index .ObjectMeta.Labels `app.kubernetes.io/version`) | default (index .ObjectMeta.Labels `version`) | default "latest" | quote }} + annotations: { + istio.io/rev: {{ .Revision | default "default" | quote }}, + {{- if eq (len $containers) 1 }} + kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}", + kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}", + {{ end }} + } + spec: + securityContext: + sysctls: + - name: net.ipv4.ip_unprivileged_port_start + value: "0" + containers: + - name: istio-proxy + {{- if contains "/" .Values.global.proxy.image }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .ProxyImage }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel }} + - --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel }} + - --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }} + {{- if .Values.global.sts.servicePort }} + - --stsPort={{ .Values.global.sts.servicePort }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + {{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{ toYaml .Values.global.proxy.lifecycle | indent 6 }} + {{- end }} + securityContext: + runAsUser: {{ .ProxyUID | default "1337" }} + runAsGroup: {{ .ProxyGID | default "1337" }} + env: + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: CA_ADDR + {{- if .Values.global.caAddress }} + value: {{ .Values.global.caAddress }} + {{- else }} + value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_CPU_LIMIT + valueFrom: + resourceFieldRef: + resource: limits.cpu + - name: PROXY_CONFIG + value: | + {{ protoToJSON .ProxyConfig }} + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + resource: limits.cpu + {{- if .CompliancePolicy }} + - name: COMPLIANCE_POLICY + value: "{{ .CompliancePolicy }}" + {{- end }} + - name: ISTIO_META_APP_CONTAINERS + value: "{{ $containers | join "," }}" + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ .ProxyConfig.InterceptionMode.String }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: "{{ .DeploymentMeta.Name }}" + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: ISTIO_META_MESH_ID + value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}" + {{- end }} + {{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: TRUST_DOMAIN + value: "{{ . }}" + {{- end }} + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} + readinessProbe: + httpGet: + path: /healthz/ready + port: 15021 + initialDelaySeconds: {{.Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ .Values.global.proxy.readinessPeriodSeconds }} + timeoutSeconds: 3 + failureThreshold: {{ .Values.global.proxy.readinessFailureThreshold }} + volumeMounts: + - name: workload-socket + mountPath: /var/run/secrets/workload-spiffe-uds + - name: credential-socket + mountPath: /var/run/secrets/credential-uds + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + mountPath: /var/run/secrets/workload-spiffe-credentials + readOnly: true + {{- else }} + - name: workload-certs + mountPath: /var/run/secrets/workload-spiffe-credentials + {{- end }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + {{- end }} + - mountPath: /var/lib/istio/data + name: istio-data + # SDS channel between istioagent and Envoy + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + - name: istio-podinfo + mountPath: /etc/istio/pod + volumes: + - emptyDir: {} + name: workload-socket + - emptyDir: {} + name: credential-socket + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + csi: + driver: workloadcertificates.security.cloud.google.com + {{- else}} + - emptyDir: {} + name: workload-certs + {{- end }} + # SDS channel between istioagent and Envoy + - emptyDir: + medium: Memory + name: istio-envoy + - name: istio-data + emptyDir: {} + - name: istio-podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + name: istio-ca-root-cert + {{- end }} + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- end }} + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + grpc-simple: | + metadata: + annotations: + sidecar.istio.io/rewriteAppHTTPProbers: "false" + spec: + initContainers: + - name: grpc-bootstrap-init + image: busybox:1.28 + volumeMounts: + - mountPath: /var/lib/grpc/data/ + name: grpc-io-proxyless-bootstrap + env: + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_NAMESPACE + value: | + {{ .Values.global.istioNamespace }} + command: + - sh + - "-c" + - |- + NODE_ID="sidecar~${INSTANCE_IP}~${POD_NAME}.${POD_NAMESPACE}~cluster.local" + SERVER_URI="dns:///istiod.${ISTIO_NAMESPACE}.svc:15010" + echo ' + { + "xds_servers": [ + { + "server_uri": "'${SERVER_URI}'", + "channel_creds": [{"type": "insecure"}], + "server_features" : ["xds_v3"] + } + ], + "node": { + "id": "'${NODE_ID}'", + "metadata": { + "GENERATOR": "grpc" + } + } + }' > /var/lib/grpc/data/bootstrap.json + containers: + {{- range $index, $container := .Spec.Containers }} + - name: {{ $container.Name }} + env: + - name: GRPC_XDS_BOOTSTRAP + value: /var/lib/grpc/data/bootstrap.json + - name: GRPC_GO_LOG_VERBOSITY_LEVEL + value: "99" + - name: GRPC_GO_LOG_SEVERITY_LEVEL + value: info + volumeMounts: + - mountPath: /var/lib/grpc/data/ + name: grpc-io-proxyless-bootstrap + {{- end }} + volumes: + - name: grpc-io-proxyless-bootstrap + emptyDir: {} + grpc-agent: | + {{- define "resources" }} + {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }} + {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) }} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end }} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{- end }} + {{- if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) }} + limits: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPULimit` }}" + {{ end }} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemoryLimit` }}" + {{ end }} + {{- end }} + {{- else }} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 6 }} + {{- end }} + {{- end }} + {{- end }} + {{- $containers := list }} + {{- range $index, $container := .Spec.Containers }}{{ if not (eq $container.Name "istio-proxy") }}{{ $containers = append $containers $container.Name }}{{end}}{{- end}} + metadata: + labels: + {{/* security.istio.io/tlsMode: istio must be set by user, if gRPC is using mTLS initialization code. We can't set it automatically. */}} + service.istio.io/canonical-name: {{ index .ObjectMeta.Labels `service.istio.io/canonical-name` | default (index .ObjectMeta.Labels `app.kubernetes.io/name`) | default (index .ObjectMeta.Labels `app`) | default .DeploymentMeta.Name | quote }} + service.istio.io/canonical-revision: {{ index .ObjectMeta.Labels `service.istio.io/canonical-revision` | default (index .ObjectMeta.Labels `app.kubernetes.io/version`) | default (index .ObjectMeta.Labels `version`) | default "latest" | quote }} + annotations: { + istio.io/rev: {{ .Revision | default "default" | quote }}, + {{- if ge (len $containers) 1 }} + {{- if not (isset .ObjectMeta.Annotations `kubectl.kubernetes.io/default-logs-container`) }} + kubectl.kubernetes.io/default-logs-container: "{{ index $containers 0 }}", + {{- end }} + {{- if not (isset .ObjectMeta.Annotations `kubectl.kubernetes.io/default-container`) }} + kubectl.kubernetes.io/default-container: "{{ index $containers 0 }}", + {{- end }} + {{- end }} + sidecar.istio.io/rewriteAppHTTPProbers: "false", + } + spec: + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .ProxyImage }}" + {{- end }} + ports: + - containerPort: 15020 + protocol: TCP + name: mesh-metrics + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel }} + - --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel }} + - --log_output_level={{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level }} + {{- if .Values.global.sts.servicePort }} + - --stsPort={{ .Values.global.sts.servicePort }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + lifecycle: + postStart: + exec: + command: + - pilot-agent + - wait + - --url=http://localhost:15020/healthz/ready + env: + - name: ISTIO_META_GENERATOR + value: grpc + - name: OUTPUT_CERTS + value: /var/lib/istio/data + {{- if eq .InboundTrafficPolicyMode "localhost" }} + - name: REWRITE_PROBE_LEGACY_LOCALHOST_DESTINATION + value: "true" + {{- end }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: CA_ADDR + {{- if .Values.global.caAddress }} + value: {{ .Values.global.caAddress }} + {{- else }} + value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: PROXY_CONFIG + value: | + {{ protoToJSON .ProxyConfig }} + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_APP_CONTAINERS + value: "{{ $containers | join "," }}" + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: "{{ .DeploymentMeta.Name }}" + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: ISTIO_META_MESH_ID + value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}" + {{- end }} + {{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: TRUST_DOMAIN + value: "{{ . }}" + {{- end }} + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + # grpc uses xds:/// to resolve – no need to resolve VIP + - name: ISTIO_META_DNS_CAPTURE + value: "false" + - name: DISABLE_ENVOY + value: "true" + {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: 15020 + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + timeoutSeconds: 3 + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + resources: + {{ template "resources" . }} + volumeMounts: + - name: workload-socket + mountPath: /var/run/secrets/workload-spiffe-uds + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + mountPath: /var/run/secrets/workload-spiffe-credentials + readOnly: true + {{- else }} + - name: workload-certs + mountPath: /var/run/secrets/workload-spiffe-credentials + {{- end }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + {{- end }} + - mountPath: /var/lib/istio/data + name: istio-data + # UDS channel between istioagent and gRPC client for XDS/SDS + - mountPath: /etc/istio/proxy + name: istio-xds + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + - name: istio-podinfo + mountPath: /etc/istio/pod + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 6 }} + {{ end }} + {{- end }} + {{- range $index, $container := .Spec.Containers }} + {{ if not (eq $container.Name "istio-proxy") }} + - name: {{ $container.Name }} + env: + - name: "GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT" + value: "true" + - name: "GRPC_XDS_BOOTSTRAP" + value: "/etc/istio/proxy/grpc-bootstrap.json" + volumeMounts: + - mountPath: /var/lib/istio/data + name: istio-data + # UDS channel between istioagent and gRPC client for XDS/SDS + - mountPath: /etc/istio/proxy + name: istio-xds + {{- if eq $.Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + mountPath: /var/run/secrets/workload-spiffe-credentials + readOnly: true + {{- else }} + - name: workload-certs + mountPath: /var/run/secrets/workload-spiffe-credentials + {{- end }} + {{- end }} + {{- end }} + volumes: + - emptyDir: + name: workload-socket + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + csi: + driver: workloadcertificates.security.cloud.google.com + {{- else }} + - emptyDir: + name: workload-certs + {{- end }} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + # SDS channel between istioagent and Envoy + - emptyDir: + medium: Memory + name: istio-xds + - name: istio-data + emptyDir: {} + - name: istio-podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + name: istio-ca-root-cert + {{- end }} + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{ end }} + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + waypoint: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: {{.ServiceAccount | quote}} + namespace: {{.Namespace | quote}} + annotations: + {{- toJsonMap (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") | nindent 4 }} + labels: + {{- toJsonMap + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + ) | nindent 4 }} + {{- if ge .KubeVersion 128 }} + # Safe since 1.28: https://github.com/kubernetes/kubernetes/pull/117412 + ownerReferences: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + name: "{{.Name}}" + uid: "{{.UID}}" + {{- end }} + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: {{.DeploymentName | quote}} + namespace: {{.Namespace | quote}} + annotations: + {{- toJsonMap (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") | nindent 4 }} + labels: + {{- toJsonMap + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + "gateway.istio.io/managed" "istio.io-mesh-controller" + ) | nindent 4 }} + ownerReferences: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + name: "{{.Name}}" + uid: "{{.UID}}" + spec: + selector: + matchLabels: + "{{.GatewayNameLabel}}": "{{.Name}}" + template: + metadata: + annotations: + {{- toJsonMap + (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") + (strdict "istio.io/rev" (.Revision | default "default")) + (strdict + "prometheus.io/path" "/stats/prometheus" + "prometheus.io/port" "15020" + "prometheus.io/scrape" "true" + ) | nindent 8 }} + labels: + {{- toJsonMap + (strdict + "sidecar.istio.io/inject" "false" + "istio.io/dataplane-mode" "none" + "service.istio.io/canonical-name" .DeploymentName + "service.istio.io/canonical-revision" "latest" + ) + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + "gateway.istio.io/managed" "istio.io-mesh-controller" + ) | nindent 8}} + spec: + terminationGracePeriodSeconds: 2 + serviceAccountName: {{.ServiceAccount | quote}} + containers: + - name: istio-proxy + ports: + - containerPort: 15021 + name: status-port + protocol: TCP + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .ProxyImage }}" + {{- end }} + {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} + args: + - proxy + - waypoint + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - {{.ServiceAccount}}.$(POD_NAMESPACE) + - --proxyLogLevel + - {{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel | quote}} + - --proxyComponentLogLevel + - {{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel | quote}} + - --log_output_level + - {{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level | quote}} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: ISTIO_META_SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: CA_ADDR + {{- if .Values.global.caAddress }} + value: {{ .Values.global.caAddress }} + {{- else }} + value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_CPU_LIMIT + valueFrom: + resourceFieldRef: + resource: limits.cpu + - name: PROXY_CONFIG + value: | + {{ protoToJSON .ProxyConfig }} + {{- if .ProxyConfig.ProxyMetadata }} + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + resource: limits.cpu + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + {{- $network := valueOrDefault (index .InfrastructureLabels `topology.istio.io/network`) .Values.global.network }} + {{- if $network }} + - name: ISTIO_META_NETWORK + value: "{{ $network }}" + {{- end }} + - name: ISTIO_META_INTERCEPTION_MODE + value: REDIRECT + - name: ISTIO_META_WORKLOAD_NAME + value: {{.DeploymentName}} + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/{{.Namespace}}/deployments/{{.DeploymentName}} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: ISTIO_META_MESH_ID + value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}" + {{- end }} + resources: + limits: + cpu: "2" + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + startupProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15021 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 1 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 4 + httpGet: + path: /healthz/ready + port: 15021 + scheme: HTTP + initialDelaySeconds: 0 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 1 + securityContext: + privileged: false + runAsGroup: 1337 + runAsUser: 0 + capabilities: + drop: + - ALL + volumeMounts: + - name: workload-socket + mountPath: /var/run/secrets/workload-spiffe-uds + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + - mountPath: /var/lib/istio/data + name: istio-data + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /var/run/secrets/tokens + name: istio-token + - mountPath: /etc/istio/pod + name: istio-podinfo + volumes: + - emptyDir: {} + name: workload-socket + - emptyDir: + medium: Memory + name: istio-envoy + - emptyDir: + medium: Memory + name: go-proxy-envoy + - emptyDir: {} + name: istio-data + - emptyDir: {} + name: go-proxy-data + - downwardAPI: + items: + - fieldRef: + fieldPath: metadata.labels + path: labels + - fieldRef: + fieldPath: metadata.annotations + path: annotations + name: istio-podinfo + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: istio-ca + expirationSeconds: 43200 + path: istio-token + - configMap: + name: istio-ca-root-cert + name: istiod-ca-cert + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + --- + apiVersion: v1 + kind: Service + metadata: + annotations: + {{ toJsonMap (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") | nindent 4 }} + labels: + {{- toJsonMap + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + ) | nindent 4 }} + name: {{.DeploymentName | quote}} + namespace: {{.Namespace | quote}} + ownerReferences: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + name: "{{.Name}}" + uid: "{{.UID}}" + spec: + ports: + {{- range $key, $val := .Ports }} + - name: {{ $val.Name | quote }} + port: {{ $val.Port }} + protocol: TCP + appProtocol: {{ $val.AppProtocol }} + {{- end }} + selector: + "{{.GatewayNameLabel}}": "{{.Name}}" + {{- if and (.Spec.Addresses) (eq .ServiceType "LoadBalancer") }} + loadBalancerIP: {{ (index .Spec.Addresses 0).Value | quote}} + {{- end }} + type: {{ .ServiceType | quote }} + --- + kube-gateway: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: {{.ServiceAccount | quote}} + namespace: {{.Namespace | quote}} + annotations: + {{- toJsonMap (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") | nindent 4 }} + labels: + {{- toJsonMap + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + ) | nindent 4 }} + {{- if ge .KubeVersion 128 }} + # Safe since 1.28: https://github.com/kubernetes/kubernetes/pull/117412 + ownerReferences: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + name: "{{.Name}}" + uid: "{{.UID}}" + {{- end }} + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: {{.DeploymentName | quote}} + namespace: {{.Namespace | quote}} + annotations: + {{- toJsonMap (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") | nindent 4 }} + labels: + {{- toJsonMap + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + ) | nindent 4 }} + ownerReferences: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + name: {{.Name}} + uid: "{{.UID}}" + spec: + selector: + matchLabels: + "{{.GatewayNameLabel}}": {{.Name}} + template: + metadata: + annotations: + {{- toJsonMap + (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") + (strdict "istio.io/rev" (.Revision | default "default")) + (strdict + "prometheus.io/path" "/stats/prometheus" + "prometheus.io/port" "15020" + "prometheus.io/scrape" "true" + ) | nindent 8 }} + labels: + {{- toJsonMap + (strdict + "sidecar.istio.io/inject" "false" + "service.istio.io/canonical-name" .DeploymentName + "service.istio.io/canonical-revision" "latest" + ) + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + ) | nindent 8 }} + spec: + {{- if ge .KubeVersion 122 }} + {{/* safe since 1.22: https://github.com/kubernetes/kubernetes/pull/103326. */}} + securityContext: + sysctls: + - name: net.ipv4.ip_unprivileged_port_start + value: "0" + {{- end }} + serviceAccountName: {{.ServiceAccount | quote}} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .ProxyImage }}" + {{- end }} + {{- if .Values.global.proxy.resources }} + resources: + {{- toYaml .Values.global.proxy.resources | nindent 10 }} + {{- end }} + {{with .Values.global.imagePullPolicy }}imagePullPolicy: "{{.}}"{{end}} + securityContext: + {{- if ge .KubeVersion 122 }} + # Safe since 1.22: https://github.com/kubernetes/kubernetes/pull/103326 + capabilities: + drop: + - ALL + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: true + runAsUser: {{ .ProxyUID | default "1337" }} + runAsGroup: {{ .ProxyGID | default "1337" }} + runAsNonRoot: true + {{- else }} + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + runAsUser: 0 + runAsGroup: 1337 + runAsNonRoot: false + allowPrivilegeEscalation: true + readOnlyRootFilesystem: true + {{- end }} + ports: + - containerPort: 15021 + name: status-port + protocol: TCP + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --proxyLogLevel + - {{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel | quote}} + - --proxyComponentLogLevel + - {{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel | quote}} + - --log_output_level + - {{ annotation .ObjectMeta `sidecar.istio.io/agentLogLevel` .Values.global.logging.level | quote}} + {{- if .Values.global.sts.servicePort }} + - --stsPort={{ .Values.global.sts.servicePort }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + {{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{- toYaml .Values.global.proxy.lifecycle | nindent 10 }} + {{- end }} + env: + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: CA_ADDR + {{- if .Values.global.caAddress }} + value: {{ .Values.global.caAddress }} + {{- else }} + value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Values.global.istioNamespace }}.svc:15012 + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_CPU_LIMIT + valueFrom: + resourceFieldRef: + resource: limits.cpu + - name: PROXY_CONFIG + value: | + {{ protoToJSON .ProxyConfig }} + - name: ISTIO_META_POD_PORTS + value: "[]" + - name: ISTIO_META_APP_CONTAINERS + value: "" + - name: GOMEMLIMIT + valueFrom: + resourceFieldRef: + resource: limits.memory + - name: GOMAXPROCS + valueFrom: + resourceFieldRef: + resource: limits.cpu + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName .ClusterID }}" + - name: ISTIO_META_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ .ProxyConfig.InterceptionMode.String }}" + {{- with (valueOrDefault (index .InfrastructureLabels "topology.istio.io/network") .Values.global.network) }} + - name: ISTIO_META_NETWORK + value: {{.|quote}} + {{- end }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{.DeploymentName|quote}} + - name: ISTIO_META_OWNER + value: "kubernetes://apis/apps/v1/namespaces/{{.Namespace}}/deployments/{{.DeploymentName}}" + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: ISTIO_META_MESH_ID + value: "{{ (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }}" + {{- end }} + {{- with (valueOrDefault .MeshConfig.TrustDomain .Values.global.trustDomain) }} + - name: TRUST_DOMAIN + value: "{{ . }}" + {{- end }} + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- with (index .InfrastructureLabels "topology.istio.io/network") }} + - name: ISTIO_META_REQUESTED_NETWORK_VIEW + value: {{.|quote}} + {{- end }} + startupProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15021 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 1 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + failureThreshold: 4 + httpGet: + path: /healthz/ready + port: 15021 + scheme: HTTP + initialDelaySeconds: 0 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 1 + volumeMounts: + - name: workload-socket + mountPath: /var/run/secrets/workload-spiffe-uds + - name: credential-socket + mountPath: /var/run/secrets/credential-uds + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + mountPath: /var/run/secrets/workload-spiffe-credentials + readOnly: true + {{- else }} + - name: workload-certs + mountPath: /var/run/secrets/workload-spiffe-credentials + {{- end }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + {{- end }} + - mountPath: /var/lib/istio/data + name: istio-data + # SDS channel between istioagent and Envoy + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /var/run/secrets/tokens + name: istio-token + - name: istio-podinfo + mountPath: /etc/istio/pod + volumes: + - emptyDir: {} + name: workload-socket + - emptyDir: {} + name: credential-socket + {{- if eq .Values.global.caName "GkeWorkloadCertificate" }} + - name: gke-workload-certificate + csi: + driver: workloadcertificates.security.cloud.google.com + {{- else}} + - emptyDir: {} + name: workload-certs + {{- end }} + # SDS channel between istioagent and Envoy + - emptyDir: + medium: Memory + name: istio-envoy + - name: istio-data + emptyDir: {} + - name: istio-podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + name: istio-ca-root-cert + {{- end }} + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + --- + apiVersion: v1 + kind: Service + metadata: + annotations: + {{ toJsonMap (omit .InfrastructureAnnotations "kubectl.kubernetes.io/last-applied-configuration" "gateway.istio.io/name-override" "gateway.istio.io/service-account" "gateway.istio.io/controller-version") | nindent 4 }} + labels: + {{- toJsonMap + .InfrastructureLabels + (strdict + "gateway.networking.k8s.io/gateway-name" .Name + "istio.io/gateway-name" .Name + ) | nindent 4 }} + name: {{.DeploymentName | quote}} + namespace: {{.Namespace | quote}} + ownerReferences: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + name: {{.Name}} + uid: {{.UID}} + spec: + ports: + {{- range $key, $val := .Ports }} + - name: {{ $val.Name | quote }} + port: {{ $val.Port }} + protocol: TCP + appProtocol: {{ $val.AppProtocol }} + {{- end }} + selector: + "{{.GatewayNameLabel}}": {{.Name}} + {{- if and (.Spec.Addresses) (eq .ServiceType "LoadBalancer") }} + loadBalancerIP: {{ (index .Spec.Addresses 0).Value | quote}} + {{- end }} + type: {{ .ServiceType | quote }} + --- \ No newline at end of file diff --git a/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.values.gen.yaml b/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.values.gen.yaml new file mode 100644 index 000000000000..aa6bd5af0b5e --- /dev/null +++ b/pkg/kube/inject/testdata/inputs/proxy-override-runas.yaml.34.values.gen.yaml @@ -0,0 +1,114 @@ +{ + "global": { + "autoscalingv2API": true, + "caAddress": "", + "caName": "", + "certSigners": [], + "configCluster": false, + "configValidation": true, + "defaultPodDisruptionBudget": { + "enabled": true + }, + "defaultResources": { + "requests": { + "cpu": "10m" + } + }, + "enabled": false, + "externalIstiod": false, + "hub": "gcr.io/istio-testing", + "imagePullPolicy": "", + "imagePullSecrets": [], + "istioNamespace": "istio-system", + "istiod": { + "enableAnalysis": false + }, + "logAsJson": false, + "logging": { + "level": "default:info" + }, + "meshID": "", + "meshNetworks": {}, + "mountMtlsCerts": false, + "multiCluster": { + "clusterName": "", + "enabled": false + }, + "namespace": "istio-system", + "network": "", + "omitSidecarInjectorConfigMap": false, + "operatorManageWebhooks": false, + "pilotCertProvider": "istiod", + "priorityClassName": "", + "proxy": { + "autoInject": "enabled", + "clusterDomain": "cluster.local", + "componentLogLevel": "misc:error", + "enableCoreDump": false, + "excludeIPRanges": "", + "excludeInboundPorts": "", + "excludeOutboundPorts": "", + "image": "proxyv2", + "includeIPRanges": "*", + "includeInboundPorts": "*", + "includeOutboundPorts": "", + "logLevel": "warning", + "privileged": false, + "readinessFailureThreshold": 4, + "readinessInitialDelaySeconds": 0, + "readinessPeriodSeconds": 15, + "resources": { + "limits": { + "cpu": "2000m", + "memory": "1024Mi" + }, + "requests": { + "cpu": "100m", + "memory": "128Mi" + } + }, + "startupProbe": { + "enabled": true, + "failureThreshold": 600 + }, + "statusPort": 15020, + "tracer": "none" + }, + "proxy_init": { + "image": "proxyv2" + }, + "remotePilotAddress": "", + "sds": { + "token": { + "aud": "istio-ca" + } + }, + "sts": { + "servicePort": 0 + }, + "tag": "latest", + "variant": "" + }, + "istio_cni": { + "chained": true, + "enabled": true, + "provider": "default" + }, + "pilot": { + "cni": { + "enabled": false, + "provider": "default" + } + }, + "revision": "", + "sidecarInjectorWebhook": { + "alwaysInjectSelector": [], + "defaultTemplates": [], + "enableNamespacesByDefault": false, + "injectedAnnotations": {}, + "neverInjectSelector": [], + "reinvocationPolicy": "Never", + "rewriteAppHTTPProbe": true, + "templates": {} + } +} \ No newline at end of file diff --git a/pkg/kube/inject/webhook.go b/pkg/kube/inject/webhook.go index 826a28c6d484..45d14a02dd95 100644 --- a/pkg/kube/inject/webhook.go +++ b/pkg/kube/inject/webhook.go @@ -58,7 +58,7 @@ import ( "istio.io/istio/pkg/slices" "istio.io/istio/pkg/util/protomarshal" "istio.io/istio/pkg/util/sets" - iptablesConstants "istio.io/istio/tools/istio-iptables/pkg/constants" + iptablesconstants "istio.io/istio/tools/istio-iptables/pkg/constants" ) var ( @@ -466,7 +466,7 @@ func injectPod(req InjectionParameters) ([]byte, error) { return nil, fmt.Errorf("failed to run injection template: %v", err) } - mergedPod, err = reapplyOverwrittenContainers(mergedPod, req.pod, injectedPodData) + mergedPod, err = reapplyOverwrittenContainers(mergedPod, req.pod, injectedPodData, req.proxyConfig) if err != nil { return nil, fmt.Errorf("failed to re apply container: %v", err) } @@ -497,7 +497,9 @@ func injectPod(req InjectionParameters) ([]byte, error) { // // Where "overlap" is a container defined in both the original and template pod. Typically, this would mean // the user has defined an `istio-proxy` container in their own pod spec. -func reapplyOverwrittenContainers(finalPod *corev1.Pod, originalPod *corev1.Pod, templatePod *corev1.Pod) (*corev1.Pod, error) { +func reapplyOverwrittenContainers(finalPod *corev1.Pod, originalPod *corev1.Pod, templatePod *corev1.Pod, + proxyConfig *meshconfig.ProxyConfig, +) (*corev1.Pod, error) { overrides := ParsedContainers{} existingOverrides := ParsedContainers{} if annotationOverrides, f := originalPod.Annotations[annotation.ProxyOverrides.Name]; f { @@ -525,7 +527,9 @@ func reapplyOverwrittenContainers(finalPod *corev1.Pod, originalPod *corev1.Pod, continue } overlay := *match.DeepCopy() - resetFieldsInAutoImageContainer(&overlay, &c) + if overlay.Image == AutoImage { + overlay.Image = "" + } overrides.Containers = append(overrides.Containers, overlay) newMergedPod, err := applyContainer(finalPod, overlay) @@ -546,7 +550,9 @@ func reapplyOverwrittenContainers(finalPod *corev1.Pod, originalPod *corev1.Pod, continue } overlay := *match.DeepCopy() - resetFieldsInAutoImageContainer(&overlay, &c) + if overlay.Image == AutoImage { + overlay.Image = "" + } overrides.InitContainers = append(overrides.InitContainers, overlay) newMergedPod, err := applyInitContainer(finalPod, overlay) @@ -568,23 +574,82 @@ func reapplyOverwrittenContainers(finalPod *corev1.Pod, originalPod *corev1.Pod, finalPod.Annotations[annotation.ProxyOverrides.Name] = string(js) } + adjustInitContainerUser(finalPod, originalPod, proxyConfig) + return finalPod, nil } -func resetFieldsInAutoImageContainer(original *corev1.Container, template *corev1.Container) { - if original.Image == AutoImage { - original.Image = "" +// adjustInitContainerUser adjusts the RunAsUser/Group fields and iptables parameter "-u " +// in the init/validation container so that they match the value of SecurityContext.RunAsUser/Group +// when it is present in the custom istio-proxy container supplied by the user. +func adjustInitContainerUser(finalPod *corev1.Pod, originalPod *corev1.Pod, proxyConfig *meshconfig.ProxyConfig) { + userContainer := FindSidecar(originalPod) + if userContainer == nil { + // if user doesn't override the istio-proxy container, there's nothing to do + return + } + + if userContainer.SecurityContext == nil || (userContainer.SecurityContext.RunAsUser == nil && userContainer.SecurityContext.RunAsGroup == nil) { + // if user doesn't override SecurityContext.RunAsUser/Group, there's nothing to do + return + } + + // Locate the istio-init or istio-validation container + var initContainer *corev1.Container + for _, name := range []string{InitContainerName, ValidationContainerName} { + if container := FindContainer(name, finalPod.Spec.InitContainers); container != nil { + initContainer = container + break + } + } + if initContainer == nil { + // should not happen + log.Warn("Could not find either istio-init or istio-validation container") + return + } + + // Overriding RunAsUser is now allowed in TPROXY mode, it must always run with uid=0 + tproxy := false + if proxyConfig.InterceptionMode == meshconfig.ProxyConfig_TPROXY { + tproxy = true + } else if mode, found := finalPod.Annotations[annotation.SidecarInterceptionMode.Name]; found && mode == iptablesconstants.TPROXY { + tproxy = true + } + + // RunAsUser cannot be overridden (ie, must remain 0) in TPROXY mode + if tproxy && userContainer.SecurityContext.RunAsUser != nil { + sidecar := FindSidecar(finalPod) + if sidecar == nil { + // Should not happen + log.Warn("Could not find the istio-proxy container") + return + } + *sidecar.SecurityContext.RunAsUser = 0 + } + + // Make sure the validation container runs with the same uid/gid as the proxy (init container is untouched, it must run with 0) + if !tproxy && initContainer.Name == ValidationContainerName { + if initContainer.SecurityContext == nil { + initContainer.SecurityContext = &corev1.SecurityContext{} + } + if userContainer.SecurityContext.RunAsUser != nil { + initContainer.SecurityContext.RunAsUser = userContainer.SecurityContext.RunAsUser + } + if userContainer.SecurityContext.RunAsGroup != nil { + initContainer.SecurityContext.RunAsGroup = userContainer.SecurityContext.RunAsGroup + } } - // If the original pod comes with SecurityContext.RunAsUser and the template defines a value different than the default (1337), - // then ignore the original value and stick with the final (merged one) - // This is likely a scenario in OpenShift when the istio-proxy container with image: auto is parsed, if SecurityContext.RunAsUser - // does not exist, OpenShift automatically assigns a value which is based on an annotation in the namespace. Regardless if the user - // provided that value or if it was assigned by OpenShift, the correct value is the one in the template, as set by the `.ProxyUID` field. - if original.SecurityContext != nil && template.SecurityContext != nil && template.SecurityContext.RunAsUser != nil && - *template.SecurityContext.RunAsUser != iptablesConstants.DefaultProxyUIDInt { - original.SecurityContext.RunAsUser = nil - original.SecurityContext.RunAsGroup = nil + // Find the "-u " parameter in the init container and replace it with the userid from SecurityContext.RunAsUser + // but only if it's not 0. iptables --uid-owner argument must not be 0. + if userContainer.SecurityContext.RunAsUser == nil || *userContainer.SecurityContext.RunAsUser == 0 { + return + } + for i := range initContainer.Args { + if initContainer.Args[i] == "-u" { + initContainer.Args[i+1] = fmt.Sprintf("%d", *userContainer.SecurityContext.RunAsUser) + return + } } } diff --git a/pkg/kube/kclient/client.go b/pkg/kube/kclient/client.go index bdc1e26bb34a..2f75d44b416d 100644 --- a/pkg/kube/kclient/client.go +++ b/pkg/kube/kclient/client.go @@ -333,17 +333,16 @@ func applyDynamicFilter[T controllers.ComparableObject](filter Filter, gvr schem // Namespace is special; we query all namespaces // Note: other cluster-scoped resources should just not use the filter for _, item := range ic.ListUnfiltered(metav1.NamespaceAll, klabels.Everything()) { - if !added.Contains(item.GetName()) && !removed.Contains(item.GetName()) { + if !added.Contains(item.GetName()) { continue } for _, c := range ic.registeredHandlers { - if added.Contains(item.GetName()) { - c.handler.OnAdd(item, false) - } else { - c.handler.OnDelete(item) - } + c.handler.OnAdd(item, false) } } + // Removes are currently NOT handled. We only have the namespace name here. We would need to have the object + // filter passthrough the entire namespace object, so we can pass the last known state to OnDelete. + // Fortunately, missing a namespace delete event usually doesn't matter since everything in the namespace gets torn down. } else { for ns := range added { for _, item := range ic.ListUnfiltered(ns, klabels.Everything()) { diff --git a/pkg/kube/kclient/client_test.go b/pkg/kube/kclient/client_test.go index b785509ac6b6..a89c11090652 100644 --- a/pkg/kube/kclient/client_test.go +++ b/pkg/kube/kclient/client_test.go @@ -17,6 +17,7 @@ package kclient_test import ( "fmt" "reflect" + "strings" "testing" "time" @@ -361,6 +362,18 @@ func TestFilterNamespace(t *testing.T) { return slices.Equal(tracker.Events(), []string{"add/selected"}) || slices.Equal(tracker.Events(), []string{"add/selected", "add/selected"}) }) + testns.Delete("selected", "") + // We may or may not get the deletion event, currently. + // Like above for adds, we cannot guarantee exactly once delivery. For adds we chose to give 1 or 2 events. + // For delete, it is usually not important to handle, so we choose to get 0 or 1 events here. + retry.UntilOrFail(t, func() bool { + events := slices.Filter(tracker.Events(), func(s string) bool { + // Ignore the adds + return !strings.HasPrefix(s, "add/") + }) + return slices.Equal(events, []string{"delete/selected"}) || + slices.Equal(events, nil) + }, retry.Timeout(time.Second*3)) } func TestFilter(t *testing.T) { diff --git a/pkg/kube/namespace/filter.go b/pkg/kube/namespace/filter.go index 5f6eac3b63c6..a79180c5ef6c 100644 --- a/pkg/kube/namespace/filter.go +++ b/pkg/kube/namespace/filter.go @@ -79,8 +79,13 @@ func NewDiscoveryNamespacesFilter( } }, DeleteFunc: func(ns *corev1.Namespace) { - // No need to notify handlers for deletes - f.namespaceDeleted(ns.ObjectMeta) + f.lock.Lock() + defer f.lock.Unlock() + // No need to notify handlers for deletes. The namespace was deleted, so the object will be as well (and a delete could not de-select). + // Note that specifically for the edge case of a Namespace watcher that is filtering, this will ignore deletes we should + // otherwise send. + // See kclient.applyDynamicFilter for rationale. + f.namespaceDeletedLocked(ns.ObjectMeta) }, }) // Start namespaces and wait for it to be ready now. This is required for subsequent users, so we want to block @@ -194,10 +199,9 @@ func (d *discoveryNamespacesFilter) namespaceUpdatedLocked(oldNs, newNs metav1.O return false, false } -// namespaceDeleted : if deleted namespace was a member, remove it -func (d *discoveryNamespacesFilter) namespaceDeleted(ns metav1.ObjectMeta) (membershipChanged bool) { +// namespaceDeletedLocked : if deleted namespace was a member, remove it +func (d *discoveryNamespacesFilter) namespaceDeletedLocked(ns metav1.ObjectMeta) { d.discoveryNamespaces.Delete(ns.Name) - return d.isSelectedLocked(ns.Labels) } // AddHandler registers a handler on namespace, which will be triggered when namespace selected or deselected. diff --git a/pkg/slices/slices.go b/pkg/slices/slices.go index 78a388c7e135..85d68850604d 100644 --- a/pkg/slices/slices.go +++ b/pkg/slices/slices.go @@ -259,3 +259,14 @@ func GroupUnique[T any, K comparable](data []T, f func(T) K) map[K]T { func Join(sep string, fields ...string) string { return strings.Join(fields, sep) } + +// Insert inserts the values v... into s at index i, +// returning the modified slice. +// The elements at s[i:] are shifted up to make room. +// In the returned slice r, r[i] == v[0], +// and r[i+len(v)] == value originally at r[i]. +// Insert panics if i is out of range. +// This function is O(len(s) + len(v)). +func Insert[S ~[]E, E any](s S, i int, v ...E) S { + return slices.Insert(s, i, v...) +} diff --git a/releasenotes/notes/51081.yaml b/releasenotes/notes/51081.yaml new file mode 100644 index 000000000000..4f3f69026c7b --- /dev/null +++ b/releasenotes/notes/51081.yaml @@ -0,0 +1,29 @@ +apiVersion: release-notes/v2 + +# This YAML file describes the format for specifying a release notes entry for Istio. +# This should be filled in for all user facing changes. + +# kind describes the type of change that this represents. +# Valid Values are: +# - bug-fix -- Used to specify that this change represents a bug fix. +# - security-fix -- Used to specify that this change represents a vulnerability fix. +# - feature -- Used to specify a new feature that has been added. +# - test -- Used to describe additional testing added. This file is optional for +# tests, but included for completeness. +kind: bug-fix + +# area describes the area that this change affects. +# Valid values are: +# - traffic-management +# - security +# - telemetry +# - installation +# - istioctl +# - documentation +area: traffic-management + +# releaseNotes is a markdown listing of any user facing changes. This will appear in the +# release notes. +releaseNotes: +- | + **Fixed** Explicitly fail to add pod to host ipset if ip already exists, rather than silently overwrite diff --git a/releasenotes/notes/alt-stat-name.yaml b/releasenotes/notes/alt-stat-name.yaml new file mode 100644 index 000000000000..6d438f5c6b3b --- /dev/null +++ b/releasenotes/notes/alt-stat-name.yaml @@ -0,0 +1,6 @@ +apiVersion: release-notes/v2 +kind: bug-fix +area: traffic-management +releaseNotes: +- | + **Fixed** an issue causing outboundstatname in Mesh Config in not honoured for subset clusters. diff --git a/releasenotes/notes/fix-custom-injection-runas.yaml b/releasenotes/notes/fix-custom-injection-runas.yaml new file mode 100644 index 000000000000..9653dafe59b0 --- /dev/null +++ b/releasenotes/notes/fix-custom-injection-runas.yaml @@ -0,0 +1,8 @@ +apiVersion: release-notes/v2 +kind: bug-fix +area: installation +docs: +- 'https://istio.io/latest/docs/setup/additional-setup/sidecar-injection/#customizing-injection' +releaseNotes: +- | + **Fixed** Custom injection of the `istio-proxy` container was not working properly if `SecurityContext.RunAs` fields were set. diff --git a/releasenotes/notes/push-cds-on-auto-passthrough-gateway-change.yaml b/releasenotes/notes/push-cds-on-auto-passthrough-gateway-change.yaml new file mode 100644 index 000000000000..73312274b041 --- /dev/null +++ b/releasenotes/notes/push-cds-on-auto-passthrough-gateway-change.yaml @@ -0,0 +1,6 @@ +apiVersion: release-notes/v2 +kind: bug-fix +area: traffic-management +releaseNotes: + - | + **Fixed** returning 503 errors by auto-passthrough gateways created after enabling mTLS. diff --git a/releasenotes/notes/release-channels-remote-cluster.yaml b/releasenotes/notes/release-channels-remote-cluster.yaml new file mode 100644 index 000000000000..9a0cd42b655b --- /dev/null +++ b/releasenotes/notes/release-channels-remote-cluster.yaml @@ -0,0 +1,8 @@ +apiVersion: release-notes/v2 +kind: feature +area: installation +issue: +- https://github.com/istio/enhancements/issues/173 +releaseNotes: +- | + **Added** a new, optional experimental admission policy that only allows stable features/fields to be used in Istio APIs when using a remote Istiod cluster. diff --git a/releasenotes/notes/serviceregistry-order.yaml b/releasenotes/notes/serviceregistry-order.yaml new file mode 100644 index 000000000000..6ecc815d02e4 --- /dev/null +++ b/releasenotes/notes/serviceregistry-order.yaml @@ -0,0 +1,8 @@ +apiVersion: release-notes/v2 +kind: bug-fix +area: traffic-management +issue: + - 50968 +releaseNotes: + - | + **Fixed** serviceRegistry orders influence the proxy labels, so we put the kubernetes registry in front. diff --git a/security/pkg/k8s/chiron/test-data/example-ca-cert.pem b/security/pkg/k8s/chiron/test-data/example-ca-cert.pem index 26eeec6ab192..b5276f31e34c 100644 --- a/security/pkg/k8s/chiron/test-data/example-ca-cert.pem +++ b/security/pkg/k8s/chiron/test-data/example-ca-cert.pem @@ -1,19 +1,22 @@ -----BEGIN CERTIFICATE----- -MIIDCzCCAfOgAwIBAgIQbfOzhcKTldFipQ1X2WXpHDANBgkqhkiG9w0BAQsFADAv -MS0wKwYDVQQDEyRhNzU5YzcyZC1lNjcyLTQwMzYtYWMzYy1kYzAxMDBmMTVkNWUw -HhcNMTkwNTE2MjIxMTI2WhcNMjQwNTE0MjMxMTI2WjAvMS0wKwYDVQQDEyRhNzU5 -YzcyZC1lNjcyLTQwMzYtYWMzYy1kYzAxMDBmMTVkNWUwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQC6sSAN80Ci0DYFpNDumGYoejMQai42g6nSKYS+ekvs -E7uT+eepO74wj8o6nFMNDu58+XgIsvPbWnn+3WtUjJfyiQXxmmTg8om4uY1C7R1H -gMsrL26pUaXZ/lTE8ZV5CnQJ9XilagY4iZKeptuZkxrWgkFBD7tr652EA3hmj+3h -4sTCQ+pBJKG8BJZDNRrCoiABYBMcFLJsaKuGZkJ6KtxhQEO9QxJVaDoSvlCRGa8R -fcVyYQyXOZ+0VHZJQgaLtqGpiQmlFttpCwDiLfMkk3UAd79ovkhN1MCq+O5N7YVt -eVQWaTUqUV2tKUFvVq21Zdl4dRaq+CF5U8uOqLY/4Kg9AgMBAAGjIzAhMA4GA1Ud -DwEB/wQEAwICBDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCg -oF71Ey2b1QY22C6BXcANF1+wPzxJovFeKYAnUqwh3rF7pIYCS/adZXOKlgDBsbcS -MxAGnCRi1s+A7hMYj3sQAbBXttc31557lRoJrx58IeN5DyshT53t7q4VwCzuCXFT -3zRHVRHQnO6LHgZx1FuKfwtkhfSXDyYU2fQYw2Hcb9krYU/alViVZdE0rENXCClq -xO7AQk5MJcGg6cfE5wWAKU1ATjpK4CN+RTn8v8ODLoI2SW3pfsnXxm93O+pp9HN4 -+O+1PQtNUWhCfh+g6BN2mYo2OEZ8qGSxDlMZej4YOdVkW8PHmFZTK0w9iJKqM5o1 -V6g5gZlqSoRhICK09tpc +MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x +ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9 +iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z +APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K +M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom +ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8 +LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T +BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC +AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w +A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8 +PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y +05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN +Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn +aFKltOc+RAjzDklcUPeG4Y6eMA== -----END CERTIFICATE----- \ No newline at end of file diff --git a/security/pkg/k8s/chiron/test-data/example-ca-cert2.pem b/security/pkg/k8s/chiron/test-data/example-ca-cert2.pem index b7fa73f81804..f20a8c6e267a 100644 --- a/security/pkg/k8s/chiron/test-data/example-ca-cert2.pem +++ b/security/pkg/k8s/chiron/test-data/example-ca-cert2.pem @@ -1,19 +1,32 @@ -----BEGIN CERTIFICATE----- -MIIDDDCCAfSgAwIBAgIRALsN8ND73NbYSKTZZa4jf2EwDQYJKoZIhvcNAQELBQAw -LzEtMCsGA1UEAxMkZTNlM2RlZWQtYzIyNi00OWM2LThmOTktNDU3NmRmMzQ0YWQ1 -MB4XDTE5MDYwMTE1NTU0M1oXDTI0MDUzMDE2NTU0M1owLzEtMCsGA1UEAxMkZTNl -M2RlZWQtYzIyNi00OWM2LThmOTktNDU3NmRmMzQ0YWQ1MIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA43oeK/hS92ANjmg50LCl3tM7eYAlBB/XgCl+bfp3 -KwEf+uW5yEvzSVHd2VPFI/kJJeLFrsyCRaU4FwxWcEr2Ld07DPL34oyZRRXQF0w6 -4ZNSVmevBNdZLqHcoIUtR1iFJbkctE93HpGw5Kg1NXRLDu47wQtzcC3GDOEk1amu -mL916R2OcYEeOcyRDnlbLcsTYRvK5WBQsux4E0iu2Eo9GIajKmbxVLxA9fsmqG4i -/HoVkLmCg+ZRPR/66AFLPFV1J3RWp0K4HKGzBeCyd2RC+o0g8tJX3EVSuQpqzS8p -i2t71cYu/Sf5gt3wXsNHyzE6bF1o+acyzWvJlBym/HsbAQIDAQABoyMwITAOBgNV -HQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA -kJXGkFEybCp7RxUSILuIqMtKcYcQU9ulKmLSn51VrpcRHP4SH7UJ0aXMjAdRLsop -em7YgbvToGNingqcmSJlunR3jXDecSXJLUO1xcfw6N+B2BXRgUv8wV42btr2EV6q -4HKou+MnKdrQkMUx218AT8TNPBb/Yx01m8YUS7mGUTApAhBneGEcKJ8xOznIuR5v -CihWQA9AmUvfixpXNpJc4vqiYErwIXrYpuwc79SRtLuO70vV7FCctz+4JPpR7mp9 -dHMZfGO1KXMbYT9P5bm+itlWSyrnn0qK/Cn5RHBoFyY91VcQJTgABS/z5O0pZ662 -sNzF00Jhi0gU7th75QT3MA== ------END CERTIFICATE----- \ No newline at end of file +MIIFeTCCA2GgAwIBAgIUQchu+RczGG1A4BnmrCcpkURQGTAwDQYJKoZIhvcNAQEL +BQAwIjEOMAwGA1UECgwFSXN0aW8xEDAOBgNVBAMMB1Jvb3QgQ0EwHhcNMjMxMjEx +MTYyNTI1WhcNMzMxMjA4MTYyNTI1WjA9MQ4wDAYDVQQKDAVJc3RpbzEYMBYGA1UE +AwwPSW50ZXJtZWRpYXRlIENBMREwDwYDVQQHDAhjbHVzdGVyMTCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAJCkq9Y68g9n0i4xkyYo4mygXIgaj94cvmu3 +X81CLEu/hYrl08acaKZMno+57ibAfxKBsWfA0FMp1eXZ3T9KYlNsSarC8c6RCPbX +Lzp4iPGMq5n/+OgCGaVUbaLuZB7F6gCJebyM3Du6Zap7X1xm3w2EpiVqHW6iAJqv +oBNtm7/uzFQiIU3UMeea/XBzo1FpDqNcuc/GgyILs1GA2+U4LfmcwhvUjF36bZ1q +WMnPfCMHwHTNiGikAJKSXqADz8+rthOyNZq3yFGV/ZOJf6yHOWiyP1BjojRbHCt1 +P8u2nWuD40iqreVrQw3h5Hsz6+mCIkUYFZ45yO0fyRZ/q46M8RKHluD1VI7X6R98 +wB+XPqh12tbXUQJw1/QdtUotszhQq/WUbewX9v4joGIel3MFpoBCoaHh4N4/S1Vk +9k32c4lEYeV5wO6DZSV9fuasN6KzaiPNNiufP2MnIzJSbal0uZJ0dmyhmHGLGsGc +t6zxAQpV8reqWZE1mZt94T4TnDpm61BDKRPRu7s6sP42iq6055c+5x3DhVqTInnB +uTi7oikTykZ2s0budYyjATNMUuz2RHZXxfb6ScqC5mEL0kbKCDgRzS0NS15LHpUX +Ue65PG8hiuWLuDTcQohWFkeIQyKUGL9uQ5qmmGK8FZwUU/9gY1JjrMw5sa+rVN/C +hkbRsHmBAgMBAAGjgYswgYgwHQYDVR0OBBYEFP/KjsSWWC+hw1cIaZLn1ZV3IeMq +MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgLkMCIGA1UdEQQbMBmC +F2lzdGlvZC5pc3Rpby1zeXN0ZW0uc3ZjMB8GA1UdIwQYMBaAFL3svuf0yV+M2BHp +EvDmo37j045gMA0GCSqGSIb3DQEBCwUAA4ICAQBO6P+y7UQ7HRyA7dOf2Dvze6xv +HKgjh8z5uKNbfvmgUT2gECQ+3g0LvDRYHU7w/isSmhCQxIGf+xc7r3+Rtyjg+uEc +8z0UBysbqrn8pZXPr+FPU5X5czUnwXlZwj02e1fY250LCmfHXFYuPzgwtlbJs2Ec +2exDG7EZWWX6l/mRFQR8HiF/jum2i06yjO1v+phUVenW/ym2fq+/lY/ZWebQasD7 +7PT3yT/Eage4AIj5zYmZzqJex3OKDiVltAUefnekFJBKqv1UIcWlijRPZPK8uYQk +IYHRL5fpa9E/HkwY8QopXPJi6Yfx76acY+dQd1xovY3noUVGzQV5wuaICS9V6H9B +5vkxDYbbABQQ9OJcy8XR7cqlkUATiH5hVRjMSKJiostO+CiVDWjZyJdNgR0kZeaa +9cSYBdTBxN82A/Vtq4ETq/PG5rR08KQY4HqIlOlo16OxGcJ2zVKSk5lTeI1wx/in +uOnJTo5mDJHOJrtYGuCLiqZp/Fbcz/Tb9Qccc1yw78feYiNV6JXKx3uPvfsNbXkY +KnsorT6OQ9G2d/zKPYUw+JEc1BJpk8okvGT8oTfvnfXty63ccN4+iyohQP/GwtQ9 +XiIJ0gGGQjY1VA/L2MOYV0hSMLgddvl4Pt8KXsxQ72gGl8a/s1oOKkYfpm/xchpd +3ldrrKbAwExwhsARrA== +-----END CERTIFICATE----- diff --git a/security/pkg/k8s/chiron/utils_test.go b/security/pkg/k8s/chiron/utils_test.go index e42604345dfd..3b8bdc5b8de4 100644 --- a/security/pkg/k8s/chiron/utils_test.go +++ b/security/pkg/k8s/chiron/utils_test.go @@ -42,44 +42,52 @@ import ( ) const ( + // exampleCACert copied from samples/certs/ca-cert.pem exampleCACert = `-----BEGIN CERTIFICATE----- -MIIDCzCCAfOgAwIBAgIQbfOzhcKTldFipQ1X2WXpHDANBgkqhkiG9w0BAQsFADAv -MS0wKwYDVQQDEyRhNzU5YzcyZC1lNjcyLTQwMzYtYWMzYy1kYzAxMDBmMTVkNWUw -HhcNMTkwNTE2MjIxMTI2WhcNMjQwNTE0MjMxMTI2WjAvMS0wKwYDVQQDEyRhNzU5 -YzcyZC1lNjcyLTQwMzYtYWMzYy1kYzAxMDBmMTVkNWUwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQC6sSAN80Ci0DYFpNDumGYoejMQai42g6nSKYS+ekvs -E7uT+eepO74wj8o6nFMNDu58+XgIsvPbWnn+3WtUjJfyiQXxmmTg8om4uY1C7R1H -gMsrL26pUaXZ/lTE8ZV5CnQJ9XilagY4iZKeptuZkxrWgkFBD7tr652EA3hmj+3h -4sTCQ+pBJKG8BJZDNRrCoiABYBMcFLJsaKuGZkJ6KtxhQEO9QxJVaDoSvlCRGa8R -fcVyYQyXOZ+0VHZJQgaLtqGpiQmlFttpCwDiLfMkk3UAd79ovkhN1MCq+O5N7YVt -eVQWaTUqUV2tKUFvVq21Zdl4dRaq+CF5U8uOqLY/4Kg9AgMBAAGjIzAhMA4GA1Ud -DwEB/wQEAwICBDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCg -oF71Ey2b1QY22C6BXcANF1+wPzxJovFeKYAnUqwh3rF7pIYCS/adZXOKlgDBsbcS -MxAGnCRi1s+A7hMYj3sQAbBXttc31557lRoJrx58IeN5DyshT53t7q4VwCzuCXFT -3zRHVRHQnO6LHgZx1FuKfwtkhfSXDyYU2fQYw2Hcb9krYU/alViVZdE0rENXCClq -xO7AQk5MJcGg6cfE5wWAKU1ATjpK4CN+RTn8v8ODLoI2SW3pfsnXxm93O+pp9HN4 -+O+1PQtNUWhCfh+g6BN2mYo2OEZ8qGSxDlMZej4YOdVkW8PHmFZTK0w9iJKqM5o1 -V6g5gZlqSoRhICK09tpc +MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x +ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9 +iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z +APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K +M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom +ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8 +LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T +BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC +AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w +A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8 +PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y +05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN +Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn +aFKltOc+RAjzDklcUPeG4Y6eMA== -----END CERTIFICATE-----` + // exampleIssuedCert copied from samples/certs/cert-chain.pem exampleIssuedCert = `-----BEGIN CERTIFICATE----- -MIIDGDCCAgCgAwIBAgIRAKvYcPLFqnJcwtshCGfNzTswDQYJKoZIhvcNAQELBQAw -LzEtMCsGA1UEAxMkYTc1OWM3MmQtZTY3Mi00MDM2LWFjM2MtZGMwMTAwZjE1ZDVl -MB4XDTE5MDgwNjE5NTU0NVoXDTI0MDgwNDE5NTU0NVowCzEJMAcGA1UEChMAMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyLIFJU5yJ5VXhbmizir+7Glm -1tVEYXKGiqYbMRbfsFm7V6Z4l00D9/eHvfTXaFpqhv6HBm31MArjYB3OaaV6krvT -whBUEPSkGBFe/eMPSFWBW27a0nw0cK2s/5yuFhTRtcUrZ9+ojJg4IS3oSm2UZ6UJ -DuNI3qwB6OlPQOcWX8uEp4eAaolD1lIbLRQYvxYrBqnyCZBLE+MJgA1/VB3dAECB -TxPtAqcwLFcvsM5ABys8yK8FrqRn5Bx54NiztgG+yU30W33xjdqzmEmuIIk4JjPU -ZQRsug7XClDvQKM6lbYcYS1td2zT08hdgURFXJ9VR64ALFp00/bvglpryu8FmQID -AQABo1MwUTAMBgNVHRMBAf8EAjAAMEEGA1UdEQQ6MDiCHHByb3RvbXV0YXRlLmlz -dGlvLXN5c3RlbS5zdmOCGHByb3RvbXV0YXRlLmlzdGlvLXN5c3RlbTANBgkqhkiG -9w0BAQsFAAOCAQEAhcVEZSuNMqMUJrWVb3b+6pmw9o1f7j6a51KWxOiIl6YuTYFS -WaR0lHSW8wLesjsjm1awWO/F3QRuYWbalANy7434GMAGF53u/uc+Z8aE3EItER9o -SpAJos6OfJqyok7JXDdOYRDD5/hBerj68R9llWzNJd27/1jZ0NF2sIE1W4QFddy/ -+8YA4+IqwkWB5/LbeRznl3EjFZDpCEJk0gg5XwAR5eIEy4QU8GueTwrDkssFdBGq -0naco7/Es7CWQscYdKHAgYgk0UAyu8sGV235Uw3hlOrbZ/kqvyUmsSujgT8irmDV -e+5z6MTAO6ktvHdQlSuH6ARn47bJrZOlkttAhg== +MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x +ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9 +iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z +APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K +M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom +ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8 +LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T +BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC +AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w +A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8 +PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y +05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN +Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn +aFKltOc+RAjzDklcUPeG4Y6eMA== -----END CERTIFICATE----- ` DefaulCertTTL = 24 * time.Hour @@ -138,21 +146,23 @@ func TestReadCACert(t *testing.T) { } for _, tc := range testCases { - cert, err := readCACert(tc.certPath) - if tc.shouldFail { - if err == nil { - t.Errorf("should have failed at readCACert()") - } else { - // Should fail, skip the current case. - continue + t.Run(tc.certPath, func(t *testing.T) { + cert, err := readCACert(tc.certPath) + if tc.shouldFail { + if err == nil { + t.Errorf("should have failed at readCACert()") + } else { + // Should fail, skip the current case. + return + } + } else if err != nil { + t.Errorf("failed at readCACert(): %v", err) } - } else if err != nil { - t.Errorf("failed at readCACert(): %v", err) - } - if !bytes.Equal(tc.expectedCert, cert) { - t.Error("the certificate read is unexpected") - } + if !bytes.Equal(tc.expectedCert, cert) { + t.Error("the certificate read is unexpected") + } + }) } }