diff --git a/charts/osm/README.md b/charts/osm/README.md index 50fe41d1ad..193198901d 100644 --- a/charts/osm/README.md +++ b/charts/osm/README.md @@ -98,6 +98,7 @@ The following table lists the configurable parameters of the osm chart and their | OpenServiceMesh.image.registry | string | `"openservicemesh"` | Container image registry | | OpenServiceMesh.image.tag | string | `"v0.9.0"` | Container image tag | | OpenServiceMesh.imagePullSecrets | list | `[]` | `osm-controller` image pull secret | +| OpenServiceMesh.inboundPortExclusionList | list | `[]` | Specifies a global list of ports to exclude from inbound traffic interception by the sidecar proxy. If specified, must be a list of positive integers. | | OpenServiceMesh.injector.autoScale | object | `{"enable":false,"maxReplicas":5,"minReplicas":1,"targetAverageUtilization":80}` | Auto scale configuration | | OpenServiceMesh.injector.autoScale.enable | bool | `false` | Enable Autoscale | | OpenServiceMesh.injector.autoScale.maxReplicas | int | `5` | Maximum replicas for autoscale | diff --git a/charts/osm/crds/meshconfig.yaml b/charts/osm/crds/meshconfig.yaml index cd594f0562..5017a8f058 100644 --- a/charts/osm/crds/meshconfig.yaml +++ b/charts/osm/crds/meshconfig.yaml @@ -108,6 +108,13 @@ spec: type: integer minimum: 1 maximum: 65535 + inboundPortExclusionList: + description: Global list of ports to exclude from inbound traffic interception by the sidecar proxy. + type: array + items: + type: integer + minimum: 1 + maximum: 65535 useHTTPSIngress: description: Enable HTTPS ingress on the mesh type: boolean diff --git a/charts/osm/templates/preset-mesh-config.yaml b/charts/osm/templates/preset-mesh-config.yaml index 0330c6e933..c2c528a32c 100644 --- a/charts/osm/templates/preset-mesh-config.yaml +++ b/charts/osm/templates/preset-mesh-config.yaml @@ -15,6 +15,7 @@ spec: useHTTPSIngress: {{.Values.OpenServiceMesh.useHTTPSIngress}} enablePermissiveTrafficPolicyMode: {{.Values.OpenServiceMesh.enablePermissiveTrafficPolicy}} outboundPortExclusionList: {{.Values.OpenServiceMesh.outboundPortExclusionList}} + inboundPortExclusionList: {{.Values.OpenServiceMesh.inboundPortExclusionList}} outboundIPRangeExclusionList: {{.Values.OpenServiceMesh.outboundIPRangeExclusionList}} observability: enableDebugServer: {{.Values.OpenServiceMesh.enableDebugServer}} diff --git a/charts/osm/values.schema.json b/charts/osm/values.schema.json index 82ba4bf3f8..db79b06bb8 100644 --- a/charts/osm/values.schema.json +++ b/charts/osm/values.schema.json @@ -788,6 +788,23 @@ ] ] }, + "inboundPortExclusionList": { + "$id": "#/properties/OpenServiceMesh/properties/inboundPortExclusionList", + "type": "array", + "title": "The inboundPortExclusionList schema", + "description": "Inbound port exluclusion list for sidecar traffic interception", + "items": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + }, + "examples": [ + [ + 6379, + 3315 + ] + ] + }, "grafana": { "$id": "#/properties/OpenServiceMesh/properties/grafana", "type": "object", diff --git a/charts/osm/values.yaml b/charts/osm/values.yaml index 3b5ebf87ee..235883c036 100644 --- a/charts/osm/values.yaml +++ b/charts/osm/values.yaml @@ -200,6 +200,10 @@ OpenServiceMesh: # If specified, must be a list of positive integers. outboundPortExclusionList: [] + # -- Specifies a global list of ports to exclude from inbound traffic interception by the sidecar proxy. + # If specified, must be a list of positive integers. + inboundPortExclusionList: [] + # # -- OSM's sidecar injector parameters injector: diff --git a/docs/example/manifests/meshconfig/mesh-config.yaml b/docs/example/manifests/meshconfig/mesh-config.yaml index a4dcf87622..9531af3437 100644 --- a/docs/example/manifests/meshconfig/mesh-config.yaml +++ b/docs/example/manifests/meshconfig/mesh-config.yaml @@ -17,6 +17,7 @@ spec: observability: enableDebugServer: true outboundPortExclusionList: [] + inboundPortExclusionList: [] outboundIPRangeExclusionList: [] tracing: enable: false diff --git a/pkg/apis/config/v1alpha1/mesh_config.go b/pkg/apis/config/v1alpha1/mesh_config.go index e28874dfc3..80c2b8395d 100644 --- a/pkg/apis/config/v1alpha1/mesh_config.go +++ b/pkg/apis/config/v1alpha1/mesh_config.go @@ -75,6 +75,9 @@ type TrafficSpec struct { // OutboundPortExclusionList defines a global list of ports to exclude from outbound traffic interception by the sidecar proxy. OutboundPortExclusionList []int `json:"outboundPortExclusionList,omitempty"` + // InboundPortExclusionList defines a global list of ports to exclude from inbound traffic interception by the sidecar proxy. + InboundPortExclusionList []int `json:"inboundPortExclusionList,omitempty"` + // UseHTTPSIngress defines a boolean indicating if HTTPS Ingress is enabled globally in the mesh. UseHTTPSIngress bool `json:"useHTTPSIngress,omitempty"` diff --git a/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go index 90d875a3cf..fe40adf588 100644 --- a/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/config/v1alpha1/zz_generated.deepcopy.go @@ -310,6 +310,11 @@ func (in *TrafficSpec) DeepCopyInto(out *TrafficSpec) { *out = make([]int, len(*in)) copy(*out, *in) } + if in.InboundPortExclusionList != nil { + in, out := &in.InboundPortExclusionList, &out.InboundPortExclusionList + *out = make([]int, len(*in)) + copy(*out, *in) + } out.InboundExternalAuthorization = in.InboundExternalAuthorization return } diff --git a/pkg/configurator/methods.go b/pkg/configurator/methods.go index a078e7df66..a03fffa59a 100644 --- a/pkg/configurator/methods.go +++ b/pkg/configurator/methods.go @@ -151,6 +151,11 @@ func (c *Client) GetOutboundPortExclusionList() []int { return c.getMeshConfig().Spec.Traffic.OutboundPortExclusionList } +// GetInboundPortExclusionList returns the list of ports (positive integers) to exclude from inbound sidecar interception +func (c *Client) GetInboundPortExclusionList() []int { + return c.getMeshConfig().Spec.Traffic.InboundPortExclusionList +} + // IsPrivilegedInitContainer returns whether init containers should be privileged func (c *Client) IsPrivilegedInitContainer() bool { return c.getMeshConfig().Spec.Sidecar.EnablePrivilegedInitContainer diff --git a/pkg/configurator/methods_test.go b/pkg/configurator/methods_test.go index 43aad28244..1be4c15684 100644 --- a/pkg/configurator/methods_test.go +++ b/pkg/configurator/methods_test.go @@ -306,6 +306,21 @@ func TestCreateUpdateConfig(t *testing.T) { assert.Equal([]int{7070, 6080}, cfg.GetOutboundPortExclusionList()) }, }, + { + name: "GetIboundPortExclusionList", + initialMeshConfigData: &v1alpha1.MeshConfigSpec{}, + checkCreate: func(assert *tassert.Assertions, cfg Configurator) { + assert.Nil(cfg.GetInboundPortExclusionList()) + }, + updatedMeshConfigData: &v1alpha1.MeshConfigSpec{ + Traffic: v1alpha1.TrafficSpec{ + InboundPortExclusionList: []int{7070, 6080}, + }, + }, + checkUpdate: func(assert *tassert.Assertions, cfg Configurator) { + assert.Equal([]int{7070, 6080}, cfg.GetInboundPortExclusionList()) + }, + }, { name: "IsPrivilegedInitContainer", initialMeshConfigData: &v1alpha1.MeshConfigSpec{ diff --git a/pkg/configurator/mock_client_generated.go b/pkg/configurator/mock_client_generated.go index 7444eda412..b7e514e206 100644 --- a/pkg/configurator/mock_client_generated.go +++ b/pkg/configurator/mock_client_generated.go @@ -107,6 +107,20 @@ func (mr *MockConfiguratorMockRecorder) GetInboundExternalAuthConfig() *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInboundExternalAuthConfig", reflect.TypeOf((*MockConfigurator)(nil).GetInboundExternalAuthConfig)) } +// GetInboundPortExclusionList mocks base method +func (m *MockConfigurator) GetInboundPortExclusionList() []int { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetInboundPortExclusionList") + ret0, _ := ret[0].([]int) + return ret0 +} + +// GetInboundPortExclusionList indicates an expected call of GetInboundPortExclusionList +func (mr *MockConfiguratorMockRecorder) GetInboundPortExclusionList() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInboundPortExclusionList", reflect.TypeOf((*MockConfigurator)(nil).GetInboundPortExclusionList)) +} + // GetInitContainerImage mocks base method func (m *MockConfigurator) GetInitContainerImage() string { m.ctrl.T.Helper() diff --git a/pkg/configurator/types.go b/pkg/configurator/types.go index fd4974019f..6c7c5f73d3 100644 --- a/pkg/configurator/types.go +++ b/pkg/configurator/types.go @@ -79,6 +79,9 @@ type Configurator interface { // GetOutboundPortExclusionList returns the list of ports to exclude from outbound sidecar interception GetOutboundPortExclusionList() []int + // GetInboundPortExclusionList returns the list of ports to exclude from inbound sidecar interception + GetInboundPortExclusionList() []int + // IsPrivilegedInitContainer determines whether init containers should be privileged IsPrivilegedInitContainer() bool diff --git a/pkg/injector/init_container.go b/pkg/injector/init_container.go index 7a9a185a22..68933e63e1 100644 --- a/pkg/injector/init_container.go +++ b/pkg/injector/init_container.go @@ -9,8 +9,8 @@ import ( ) func getInitContainerSpec(containerName string, cfg configurator.Configurator, outboundIPRangeExclusionList []string, outboundPortExclusionList []int, - enablePrivilegedInitContainer bool) corev1.Container { - iptablesInitCommandsList := generateIptablesCommands(outboundIPRangeExclusionList, outboundPortExclusionList) + inboundPortExclusionList []int, enablePrivilegedInitContainer bool) corev1.Container { + iptablesInitCommandsList := generateIptablesCommands(outboundIPRangeExclusionList, outboundPortExclusionList, inboundPortExclusionList) iptablesInitCommand := strings.Join(iptablesInitCommandsList, " && ") return corev1.Container{ diff --git a/pkg/injector/init_container_test.go b/pkg/injector/init_container_test.go index 04b7e0a6ce..a4d2a03e67 100644 --- a/pkg/injector/init_container_test.go +++ b/pkg/injector/init_container_test.go @@ -23,12 +23,10 @@ var _ = Describe("Test functions creating Envoy bootstrap configuration", func() mockConfigurator := configurator.NewMockConfigurator(mockCtrl) Context("test getInitContainerSpec()", func() { - It("Creates init container without outbound ip range exclusion list", func() { + It("Creates init container without ip range exclusion list", func() { mockConfigurator.EXPECT().GetInitContainerImage().Return(containerImage).Times(1) - var outboundIPRangeExclusionList []string = nil - var outboundPortExclusionList []int = nil privileged := privilegedFalse - actual := getInitContainerSpec(containerName, mockConfigurator, outboundIPRangeExclusionList, outboundPortExclusionList, privileged) + actual := getInitContainerSpec(containerName, mockConfigurator, nil, nil, nil, privileged) expected := corev1.Container{ Name: "-container-name-", @@ -59,9 +57,8 @@ var _ = Describe("Test functions creating Envoy bootstrap configuration", func() It("Creates init container with outbound exclusion list", func() { mockConfigurator.EXPECT().GetInitContainerImage().Return(containerImage).Times(1) outboundIPRangeExclusionList := []string{"1.1.1.1/32", "10.0.0.10/24"} - var outboundPortExclusionList []int = nil privileged := privilegedFalse - actual := getInitContainerSpec(containerName, mockConfigurator, outboundIPRangeExclusionList, outboundPortExclusionList, privileged) + actual := getInitContainerSpec(containerName, mockConfigurator, outboundIPRangeExclusionList, nil, nil, privileged) expected := corev1.Container{ Name: "-container-name-", @@ -91,10 +88,8 @@ var _ = Describe("Test functions creating Envoy bootstrap configuration", func() It("Creates init container with privileged true", func() { mockConfigurator.EXPECT().GetInitContainerImage().Return(containerImage).Times(1) - var outboundIPRangeExclusionList []string = nil - var outboundPortExclusionList []int = nil privileged := privilegedTrue - actual := getInitContainerSpec(containerName, mockConfigurator, outboundIPRangeExclusionList, outboundPortExclusionList, privileged) + actual := getInitContainerSpec(containerName, mockConfigurator, nil, nil, nil, privileged) expected := corev1.Container{ Name: "-container-name-", @@ -124,10 +119,8 @@ var _ = Describe("Test functions creating Envoy bootstrap configuration", func() It("Creates init container without outbound port exclusion list", func() { mockConfigurator.EXPECT().GetInitContainerImage().Return(containerImage).Times(1) - var outboundIPRangeExclusionList []string = nil - var outboundPortExclusionList []int = nil privileged := privilegedFalse - actual := getInitContainerSpec(containerName, mockConfigurator, outboundIPRangeExclusionList, outboundPortExclusionList, privileged) + actual := getInitContainerSpec(containerName, mockConfigurator, nil, nil, nil, privileged) expected := corev1.Container{ Name: "-container-name-", @@ -157,10 +150,9 @@ var _ = Describe("Test functions creating Envoy bootstrap configuration", func() It("init container with outbound port exclusion list", func() { mockConfigurator.EXPECT().GetInitContainerImage().Return(containerImage).Times(1) - var outboundIPRangeExclusionList []string = nil outboundPortExclusionList := []int{6060, 7070} privileged := privilegedFalse - actual := getInitContainerSpec(containerName, mockConfigurator, outboundIPRangeExclusionList, outboundPortExclusionList, privileged) + actual := getInitContainerSpec(containerName, mockConfigurator, nil, outboundPortExclusionList, nil, privileged) expected := corev1.Container{ Name: "-container-name-", diff --git a/pkg/injector/iptables.go b/pkg/injector/iptables.go index bd98f8660e..d96d434e91 100644 --- a/pkg/injector/iptables.go +++ b/pkg/injector/iptables.go @@ -69,7 +69,7 @@ var iptablesInboundStaticRules = []string{ } // generateIptablesCommands generates a list of iptables commands to set up sidecar interception and redirection -func generateIptablesCommands(outboundIPRangeExclusionList []string, outboundPortExclusionList []int) []string { +func generateIptablesCommands(outboundIPRangeExclusionList []string, outboundPortExclusionList []int, inboundPortExclusionList []int) []string { var cmd []string // 1. Create redirection chains @@ -89,7 +89,7 @@ func generateIptablesCommands(outboundIPRangeExclusionList []string, outboundPor cmd = append(cmd, rule) } - // 5. Create dynamic outbound ports exclusion rule + // 5. Create dynamic outbound ports exclusion rules if len(outboundPortExclusionList) > 0 { var portExclusionListStr []string for _, port := range outboundPortExclusionList { @@ -100,5 +100,16 @@ func generateIptablesCommands(outboundIPRangeExclusionList []string, outboundPor cmd = append(cmd, rule) } + // 6. Create dynamic inbound ports exclusion rules + if len(inboundPortExclusionList) > 0 { + var portExclusionListStr []string + for _, port := range inboundPortExclusionList { + portExclusionListStr = append(portExclusionListStr, strconv.Itoa(port)) + } + inboundPortsToExclude := strings.Join(portExclusionListStr, ",") + rule := fmt.Sprintf("iptables -t nat -I PROXY_INBOUND -p tcp --match multiport --dports %s -j RETURN", inboundPortsToExclude) + cmd = append(cmd, rule) + } + return cmd } diff --git a/pkg/injector/iptables_test.go b/pkg/injector/iptables_test.go new file mode 100644 index 0000000000..f207c23bf4 --- /dev/null +++ b/pkg/injector/iptables_test.go @@ -0,0 +1,43 @@ +package injector + +import ( + "testing" + + tassert "github.com/stretchr/testify/assert" +) + +func TestGenerateIptablesCommands(t *testing.T) { + assert := tassert.New(t) + + outboundIPRangeExclusion := []string{"1.1.1.1/32", "2.2.2.2/32"} + outboundPortExclusion := []int{10, 20} + inboundPortExclusion := []int{30, 40} + + actual := generateIptablesCommands(outboundIPRangeExclusion, outboundPortExclusion, inboundPortExclusion) + + expected := []string{ + "iptables -t nat -N PROXY_INBOUND", + "iptables -t nat -N PROXY_IN_REDIRECT", + "iptables -t nat -N PROXY_OUTPUT", + "iptables -t nat -N PROXY_REDIRECT", + "iptables -t nat -A PROXY_REDIRECT -p tcp -j REDIRECT --to-port 15001", + "iptables -t nat -A PROXY_REDIRECT -p tcp --dport 15000 -j ACCEPT", + "iptables -t nat -A OUTPUT -p tcp -j PROXY_OUTPUT", + "iptables -t nat -A PROXY_OUTPUT -m owner --uid-owner 1500 -j RETURN", + "iptables -t nat -A PROXY_OUTPUT -d 127.0.0.1/32 -j RETURN", + "iptables -t nat -A PROXY_OUTPUT -j PROXY_REDIRECT", + "iptables -t nat -A PROXY_IN_REDIRECT -p tcp -j REDIRECT --to-port 15003", + "iptables -t nat -A PREROUTING -p tcp -j PROXY_INBOUND", + "iptables -t nat -A PROXY_INBOUND -p tcp --dport 15010 -j RETURN", + "iptables -t nat -A PROXY_INBOUND -p tcp --dport 15901 -j RETURN", + "iptables -t nat -A PROXY_INBOUND -p tcp --dport 15902 -j RETURN", + "iptables -t nat -A PROXY_INBOUND -p tcp --dport 15903 -j RETURN", + "iptables -t nat -A PROXY_INBOUND -p tcp -j PROXY_IN_REDIRECT", + "iptables -t nat -I PROXY_OUTPUT -d 1.1.1.1/32 -j RETURN", + "iptables -t nat -I PROXY_OUTPUT -d 2.2.2.2/32 -j RETURN", + "iptables -t nat -I PROXY_OUTPUT -p tcp --match multiport --dports 10,20 -j RETURN", + "iptables -t nat -I PROXY_INBOUND -p tcp --match multiport --dports 30,40 -j RETURN", + } + + assert.ElementsMatch(expected, actual) +} diff --git a/pkg/injector/patch.go b/pkg/injector/patch.go index caa32a4fc8..906c7c0dd4 100644 --- a/pkg/injector/patch.go +++ b/pkg/injector/patch.go @@ -54,13 +54,18 @@ func (wh *mutatingWebhook) createPatch(pod *corev1.Pod, req *admissionv1.Admissi // Create volume for envoy TLS secret pod.Spec.Volumes = append(pod.Spec.Volumes, getVolumeSpec(envoyBootstrapConfigName)...) - podOutboundPortExclusionList, _ := wh.getPodOutboundPortExclusionList(pod, namespace) + // Build outbound port exclusion list + podOutboundPortExclusionList, _ := wh.getPortExclusionListForPod(pod, namespace, outboundPortExclusionListAnnotation) globalOutboundPortExclusionList := wh.configurator.GetOutboundPortExclusionList() - outboundPortExclusionList := mergePortExclusionLists(podOutboundPortExclusionList, globalOutboundPortExclusionList) + // Build inbound port exclusion list + podInboundPortExclusionList, _ := wh.getPortExclusionListForPod(pod, namespace, inboundPortExclusionListAnnotation) + globalInboundPortExclusionList := wh.configurator.GetInboundPortExclusionList() + inboundPortExclusionList := mergePortExclusionLists(podInboundPortExclusionList, globalInboundPortExclusionList) + // Add the Init Container - initContainer := getInitContainerSpec(constants.InitContainerName, wh.configurator, wh.configurator.GetOutboundIPRangeExclusionList(), outboundPortExclusionList, wh.configurator.IsPrivilegedInitContainer()) + initContainer := getInitContainerSpec(constants.InitContainerName, wh.configurator, wh.configurator.GetOutboundIPRangeExclusionList(), outboundPortExclusionList, inboundPortExclusionList, wh.configurator.IsPrivilegedInitContainer()) pod.Spec.InitContainers = append(pod.Spec.InitContainers, initContainer) // Add the Envoy sidecar @@ -102,22 +107,20 @@ func makePatches(req *admissionv1.AdmissionRequest, pod *corev1.Pod) []jsonpatch return admissionResponse.Patches } -func mergePortExclusionLists(podOutboundPortExclusionList, globalOutboundPortExclusionList []int) []int { +func mergePortExclusionLists(podSpecificPortExclusionList, globalPortExclusionList []int) []int { portExclusionListMap := mapset.NewSet() var portExclusionListMerged []int // iterate over the global outbound ports to be excluded - for _, port := range globalOutboundPortExclusionList { - addedToSet := portExclusionListMap.Add(port) - if addedToSet { + for _, port := range globalPortExclusionList { + if addedToSet := portExclusionListMap.Add(port); addedToSet { portExclusionListMerged = append(portExclusionListMerged, port) } } - // iterate over the pod level outbound ports to be excluded - for _, port := range podOutboundPortExclusionList { - addedToSet := portExclusionListMap.Add(port) - if addedToSet { + // iterate over the pod specific ports to be excluded + for _, port := range podSpecificPortExclusionList { + if addedToSet := portExclusionListMap.Add(port); addedToSet { portExclusionListMerged = append(portExclusionListMerged, port) } } diff --git a/pkg/injector/patch_test.go b/pkg/injector/patch_test.go index d1d14b94ff..6e609c32b5 100644 --- a/pkg/injector/patch_test.go +++ b/pkg/injector/patch_test.go @@ -112,6 +112,7 @@ func TestCreatePatch(t *testing.T) { mockConfigurator.EXPECT().IsPrivilegedInitContainer().Return(false).Times(1) mockConfigurator.EXPECT().GetOutboundIPRangeExclusionList().Return(nil).Times(1) mockConfigurator.EXPECT().GetOutboundPortExclusionList().Return(nil).Times(1) + mockConfigurator.EXPECT().GetInboundPortExclusionList().Return(nil).Times(1) mockConfigurator.EXPECT().GetProxyResources().Return(corev1.ResourceRequirements{}).Times(1) pod := tests.NewPodFixture(namespace, podName, tests.BookstoreServiceAccountName, nil) diff --git a/pkg/injector/webhook.go b/pkg/injector/webhook.go index 87977ff2df..467c57506c 100644 --- a/pkg/injector/webhook.go +++ b/pkg/injector/webhook.go @@ -55,8 +55,11 @@ const ( // injectorServiceName is the name of the OSM sidecar injector service injectorServiceName = "osm-injector" - // outboundPortExclusionListAnnotation is the annotation used for outbound port exclusion + // outboundPortExclusionListAnnotation is the annotation used for outbound port exclusions outboundPortExclusionListAnnotation = "openservicemesh.io/outbound-port-exclusion-list" + + // inboundPortExclusionListAnnotation is the annotation used for inbound port exclusions + inboundPortExclusionListAnnotation = "openservicemesh.io/inbound-port-exclusion-list" ) // NewMutatingWebhook starts a new web server handling requests from the injector MutatingWebhookConfiguration @@ -319,18 +322,21 @@ func (wh *mutatingWebhook) mustInject(pod *corev1.Pod, namespace string) (bool, return false, nil } -// getPodOutboundPortExclusionList gets a list of ports to exclude from outbound sidecar interception. +// getPortExclusionListForPod gets a list of ports to exclude from sidecar traffic interception for the given +// pod and annotation kind. +// +// Ports are excluded from sidecar interception when the pod is explicitly annotated with a single or +// comma separate list of ports. // -// Outbound Ports are excluded from sidecar interception when: -// 1. The pod is explicitly annotated with a single or comma separate list of ports +// The kind of exclusion (inbound vs outbound) is determined by the specified annotation. // // The function returns an error when it is unable to determine whether ports need to be excluded from outbound sidecar interception. -func (wh *mutatingWebhook) getPodOutboundPortExclusionList(pod *corev1.Pod, namespace string) ([]int, error) { +func (wh *mutatingWebhook) getPortExclusionListForPod(pod *corev1.Pod, namespace string, annotation string) ([]int, error) { var ports []int // Check if the pod is annotated for outbound port exclusion - ports, err := isAnnotatedForOutboundPortExclusion(pod.Annotations, pod.Kind, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)) + ports, err := isAnnotatedForPortExclusion(pod.Annotations, annotation, pod.Kind, fmt.Sprintf("%s/%s", pod.Namespace, pod.Name)) if err != nil { - log.Error().Err(err).Msg("Error determining outbound ports for exclusion on pod") + log.Error().Err(err).Msgf("Error determining port exclusions for annotation %s on pod %s/%s", annotation, namespace, pod.Name) return ports, err } @@ -354,19 +360,19 @@ func isAnnotatedForInjection(annotations map[string]string, objectKind string, o return } -func isAnnotatedForOutboundPortExclusion(annotations map[string]string, objectKind string, objectName string) (ports []int, err error) { - outboundPortsToExclude, ok := annotations[outboundPortExclusionListAnnotation] +func isAnnotatedForPortExclusion(annotations map[string]string, portAnnotation string, objectKind string, objectName string) (ports []int, err error) { + portsToExcludeStr, ok := annotations[portAnnotation] if !ok { return ports, err } - log.Trace().Msgf("%s %s has outbound port exclusion annotation: '%s:%s'", objectKind, objectName, outboundPortExclusionListAnnotation, outboundPortsToExclude) - portsToExclude := strings.Split(outboundPortsToExclude, ",") + log.Trace().Msgf("%s %s has port exclusion annotation: '%s:%s'", objectKind, objectName, portAnnotation, portsToExcludeStr) + portsToExclude := strings.Split(portsToExcludeStr, ",") for _, portStr := range portsToExclude { portStr := strings.TrimSpace(portStr) portInt, ok := strconv.Atoi(portStr) if ok != nil || portInt <= 0 { - err = errors.Errorf("Invalid port for key %q: %s", outboundPortExclusionListAnnotation, outboundPortsToExclude) + err = errors.Errorf("Invalid port '%s' specified for annotation '%s'", portStr, portAnnotation) ports = nil return ports, err } diff --git a/pkg/injector/webhook_test.go b/pkg/injector/webhook_test.go index 2de4188ed1..87fb03ee41 100644 --- a/pkg/injector/webhook_test.go +++ b/pkg/injector/webhook_test.go @@ -657,38 +657,56 @@ var _ = Describe("Testing Injector Functions", func() { }) }) -func TestIsAnnotatedForOutboundPortExclusion(t *testing.T) { +func TestIsAnnotatedForPortExclusion(t *testing.T) { assert := tassert.New(t) testCases := []struct { name string - annotation map[string]string + annotations map[string]string + forAnnotation string expectedError error expectedPorts []int }{ { name: "contains outbound port exclusion list annotation", - annotation: map[string]string{outboundPortExclusionListAnnotation: "6060, 7070"}, + annotations: map[string]string{outboundPortExclusionListAnnotation: "6060, 7070"}, + forAnnotation: outboundPortExclusionListAnnotation, expectedError: nil, expectedPorts: []int{6060, 7070}, }, { - name: "does not contains outbound port exclusion list annontation", - annotation: nil, + name: "contains inbound port exclusion list annotation", + annotations: map[string]string{inboundPortExclusionListAnnotation: "6060, 7070"}, + forAnnotation: inboundPortExclusionListAnnotation, expectedError: nil, + expectedPorts: []int{6060, 7070}, + }, + { + name: "does not contains port exclusion list annontation", + annotations: nil, + forAnnotation: "", + expectedError: nil, + expectedPorts: nil, + }, + { + name: "contains outbound port exclusion list annontation but invalid port", + annotations: map[string]string{outboundPortExclusionListAnnotation: "6060, -7070"}, + forAnnotation: outboundPortExclusionListAnnotation, + expectedError: errors.Errorf("Invalid port '%s' specified for annotation '%s'", "-7070", outboundPortExclusionListAnnotation), expectedPorts: nil, }, { - name: "ontains outbound port exclusion list annontation but invalid port", - annotation: map[string]string{outboundPortExclusionListAnnotation: "6060, -7070"}, - expectedError: errors.Errorf("Invalid port for key %q: %s", outboundPortExclusionListAnnotation, "6060, -7070"), + name: "contains inbound port exclusion list annontation but invalid port", + annotations: map[string]string{inboundPortExclusionListAnnotation: "6060, -7070"}, + forAnnotation: inboundPortExclusionListAnnotation, + expectedError: errors.Errorf("Invalid port '%s' specified for annotation '%s'", "-7070", inboundPortExclusionListAnnotation), expectedPorts: nil, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - ports, err := isAnnotatedForOutboundPortExclusion(tc.annotation, "-kind-", "-name-") + ports, err := isAnnotatedForPortExclusion(tc.annotations, tc.forAnnotation, "-kind-", "-name-") if err != nil { assert.EqualError(tc.expectedError, err.Error()) } else { @@ -705,25 +723,43 @@ func TestGetPodOutboundPortExclusionList(t *testing.T) { testCases := []struct { name string podAnnotation map[string]string + forAnnotation string expectedError error expectedPorts []int }{ { name: "contains outbound port exclusion list annotation", podAnnotation: map[string]string{outboundPortExclusionListAnnotation: "6060, 7070"}, + forAnnotation: outboundPortExclusionListAnnotation, expectedError: nil, expectedPorts: []int{6060, 7070}, }, { - name: "does not contains outbound port exclusion list annontation", + name: "contains inbound port exclusion list annotation", + podAnnotation: map[string]string{inboundPortExclusionListAnnotation: "6060, 7070"}, + forAnnotation: inboundPortExclusionListAnnotation, + expectedError: nil, + expectedPorts: []int{6060, 7070}, + }, + { + name: "does not contains any port exclusion list annontation", podAnnotation: nil, + forAnnotation: "", expectedError: nil, expectedPorts: nil, }, { name: "contains outbound port exclusion list annontation but invalid port", podAnnotation: map[string]string{outboundPortExclusionListAnnotation: "6060, -7070"}, - expectedError: errors.Errorf("Invalid port for key %q: %s", outboundPortExclusionListAnnotation, "6060, -7070"), + forAnnotation: outboundPortExclusionListAnnotation, + expectedError: errors.Errorf("Invalid port '%s' specified for annotation '%s'", "-7070", outboundPortExclusionListAnnotation), + expectedPorts: nil, + }, + { + name: "contains inbound port exclusion list annontation but invalid port", + podAnnotation: map[string]string{inboundPortExclusionListAnnotation: "6060, -7070"}, + forAnnotation: inboundPortExclusionListAnnotation, + expectedError: errors.Errorf("Invalid port '%s' specified for annotation '%s'", "-7070", inboundPortExclusionListAnnotation), expectedPorts: nil, }, } @@ -770,7 +806,7 @@ func TestGetPodOutboundPortExclusionList(t *testing.T) { mockKubeController.EXPECT().IsMonitoredNamespace(namespace).Return(true).Times(1) mockKubeController.EXPECT().GetNamespace(namespace).Return(retNs) - ports, err := wh.getPodOutboundPortExclusionList(pod, namespace) + ports, err := wh.getPortExclusionListForPod(pod, namespace, tc.forAnnotation) if err != nil { assert.EqualError(tc.expectedError, err.Error()) } else {