github.com/cilium/cilium@v1.16.2/pkg/policy/correlation/correlation_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package correlation 5 6 import ( 7 "net" 8 "testing" 9 10 "github.com/google/go-cmp/cmp" 11 "github.com/stretchr/testify/require" 12 "google.golang.org/protobuf/testing/protocmp" 13 14 flowpb "github.com/cilium/cilium/api/v1/flow" 15 "github.com/cilium/cilium/pkg/hubble/parser/getters" 16 "github.com/cilium/cilium/pkg/hubble/testutils" 17 "github.com/cilium/cilium/pkg/identity" 18 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/utils" 19 "github.com/cilium/cilium/pkg/labels" 20 monitorAPI "github.com/cilium/cilium/pkg/monitor/api" 21 "github.com/cilium/cilium/pkg/policy" 22 "github.com/cilium/cilium/pkg/policy/trafficdirection" 23 "github.com/cilium/cilium/pkg/u8proto" 24 ) 25 26 func TestCorrelatePolicy(t *testing.T) { 27 localIP := "1.2.3.4" 28 localIdentity := uint64(1234) 29 localID := uint64(12) 30 remoteIP := "5.6.7.8" 31 remoteIdentity := uint64(5678) 32 remoteID := uint64(56) 33 dstPort := uint32(443) 34 35 flow := &flowpb.Flow{ 36 EventType: &flowpb.CiliumEventType{ 37 Type: monitorAPI.MessageTypePolicyVerdict, 38 }, 39 Verdict: flowpb.Verdict_FORWARDED, 40 TrafficDirection: flowpb.TrafficDirection_EGRESS, 41 IP: &flowpb.IP{ 42 Source: localIP, 43 Destination: remoteIP, 44 }, 45 L4: &flowpb.Layer4{ 46 Protocol: &flowpb.Layer4_TCP{ 47 TCP: &flowpb.TCP{ 48 DestinationPort: dstPort, 49 }, 50 }, 51 }, 52 Source: &flowpb.Endpoint{ 53 ID: uint32(localID), 54 Identity: uint32(localIdentity), 55 }, 56 Destination: &flowpb.Endpoint{ 57 ID: uint32(remoteID), 58 Identity: uint32(remoteIdentity), 59 }, 60 PolicyMatchType: monitorAPI.PolicyMatchL3L4, 61 } 62 63 policyLabel := utils.GetPolicyLabels("foo-namespace", "web-policy", "1234-5678", utils.ResourceTypeCiliumNetworkPolicy) 64 policyKey := policy.Key{ 65 Identity: uint32(remoteIdentity), 66 DestPort: uint16(dstPort), 67 Nexthdr: uint8(u8proto.TCP), 68 TrafficDirection: trafficdirection.Egress.Uint8(), 69 } 70 ep := &testutils.FakeEndpointInfo{ 71 ID: localID, 72 Identity: identity.NumericIdentity(localIdentity), 73 IPv4: net.ParseIP(localIP), 74 PodName: "xwing", 75 PodNamespace: "default", 76 Labels: []string{"a", "b", "c"}, 77 PolicyMap: map[policy.Key]labels.LabelArrayList{ 78 policyKey: {policyLabel}, 79 }, 80 PolicyRevision: 1, 81 } 82 83 endpointGetter := &testutils.FakeEndpointGetter{ 84 OnGetEndpointInfoByID: func(id uint16) (endpoint getters.EndpointInfo, ok bool) { 85 if uint64(id) == ep.ID { 86 return ep, true 87 } 88 t.Fatalf("did not expect endpoint retrieval for non-local endpoint: %d", id) 89 return nil, false 90 }, 91 } 92 93 CorrelatePolicy(endpointGetter, flow) 94 95 expected := []*flowpb.Policy{ 96 { 97 Name: "web-policy", 98 Namespace: "foo-namespace", 99 Labels: []string{ 100 "k8s:io.cilium.k8s.policy.derived-from=CiliumNetworkPolicy", 101 "k8s:io.cilium.k8s.policy.name=web-policy", 102 "k8s:io.cilium.k8s.policy.namespace=foo-namespace", 103 "k8s:io.cilium.k8s.policy.uid=1234-5678", 104 }, 105 Revision: 1, 106 }, 107 } 108 109 require.Nil(t, flow.EgressDeniedBy) 110 require.Nil(t, flow.IngressDeniedBy) 111 require.Nil(t, flow.IngressAllowedBy) 112 if diff := cmp.Diff(expected, flow.EgressAllowedBy, protocmp.Transform()); diff != "" { 113 t.Fatalf("not equal (-want +got):\n%s", diff) 114 } 115 116 // check same flow at egress with deny 117 flow = &flowpb.Flow{ 118 EventType: &flowpb.CiliumEventType{ 119 Type: monitorAPI.MessageTypePolicyVerdict, 120 }, 121 Verdict: flowpb.Verdict_DROPPED, 122 DropReasonDesc: flowpb.DropReason_POLICY_DENY, 123 TrafficDirection: flowpb.TrafficDirection_EGRESS, 124 IP: &flowpb.IP{ 125 Source: localIP, 126 Destination: remoteIP, 127 }, 128 L4: &flowpb.Layer4{ 129 Protocol: &flowpb.Layer4_TCP{ 130 TCP: &flowpb.TCP{ 131 DestinationPort: dstPort, 132 }, 133 }, 134 }, 135 Source: &flowpb.Endpoint{ 136 ID: uint32(localID), 137 Identity: uint32(localIdentity), 138 }, 139 Destination: &flowpb.Endpoint{ 140 ID: uint32(remoteID), 141 Identity: uint32(remoteIdentity), 142 }, 143 PolicyMatchType: monitorAPI.PolicyMatchL3L4, 144 } 145 CorrelatePolicy(endpointGetter, flow) 146 147 require.Nil(t, flow.EgressAllowedBy) 148 require.Nil(t, flow.IngressAllowedBy) 149 require.Nil(t, flow.IngressDeniedBy) 150 if diff := cmp.Diff(expected, flow.EgressDeniedBy, protocmp.Transform()); diff != "" { 151 t.Fatalf("not equal (-want +got):\n%s", diff) 152 } 153 154 // check same flow at ingress 155 flow = &flowpb.Flow{ 156 EventType: &flowpb.CiliumEventType{ 157 Type: monitorAPI.MessageTypePolicyVerdict, 158 }, 159 Verdict: flowpb.Verdict_FORWARDED, 160 TrafficDirection: flowpb.TrafficDirection_INGRESS, 161 IP: &flowpb.IP{ 162 Source: localIP, 163 Destination: remoteIP, 164 }, 165 L4: &flowpb.Layer4{ 166 Protocol: &flowpb.Layer4_TCP{ 167 TCP: &flowpb.TCP{ 168 DestinationPort: dstPort, 169 }, 170 }, 171 }, 172 Source: &flowpb.Endpoint{ 173 ID: uint32(localID), 174 Identity: uint32(localIdentity), 175 }, 176 Destination: &flowpb.Endpoint{ 177 ID: uint32(remoteID), 178 Identity: uint32(remoteIdentity), 179 }, 180 PolicyMatchType: monitorAPI.PolicyMatchL3Only, 181 } 182 183 policyKey = policy.Key{ 184 Identity: uint32(localIdentity), 185 DestPort: 0, 186 InvertedPortMask: 0xffff, // this is a wildcard 187 Nexthdr: 0, 188 TrafficDirection: trafficdirection.Ingress.Uint8(), 189 } 190 ep = &testutils.FakeEndpointInfo{ 191 ID: remoteID, 192 Identity: identity.NumericIdentity(remoteIdentity), 193 IPv4: net.ParseIP(remoteIP), 194 PodName: "xwing", 195 PodNamespace: "default", 196 Labels: []string{"a", "b", "c"}, 197 PolicyMap: map[policy.Key]labels.LabelArrayList{ 198 policyKey: {policyLabel}, 199 }, 200 PolicyRevision: 1, 201 } 202 endpointGetter = &testutils.FakeEndpointGetter{ 203 OnGetEndpointInfoByID: func(id uint16) (endpoint getters.EndpointInfo, ok bool) { 204 if uint64(id) == ep.ID { 205 return ep, true 206 } 207 t.Fatalf("did not expect endpoint retrieval for non-remote endpoint: %d", id) 208 return nil, false 209 }, 210 } 211 CorrelatePolicy(endpointGetter, flow) 212 213 require.Nil(t, flow.EgressDeniedBy) 214 require.Nil(t, flow.IngressDeniedBy) 215 require.Nil(t, flow.EgressAllowedBy) 216 if diff := cmp.Diff(expected, flow.IngressAllowedBy, protocmp.Transform()); diff != "" { 217 t.Fatalf("not equal (-want +got):\n%s", diff) 218 } 219 220 // check same flow at ingress with deny 221 flow = &flowpb.Flow{ 222 EventType: &flowpb.CiliumEventType{ 223 Type: monitorAPI.MessageTypePolicyVerdict, 224 }, 225 Verdict: flowpb.Verdict_DROPPED, 226 DropReasonDesc: flowpb.DropReason_POLICY_DENY, 227 TrafficDirection: flowpb.TrafficDirection_INGRESS, 228 IP: &flowpb.IP{ 229 Source: localIP, 230 Destination: remoteIP, 231 }, 232 L4: &flowpb.Layer4{ 233 Protocol: &flowpb.Layer4_TCP{ 234 TCP: &flowpb.TCP{ 235 DestinationPort: dstPort, 236 }, 237 }, 238 }, 239 Source: &flowpb.Endpoint{ 240 ID: uint32(localID), 241 Identity: uint32(localIdentity), 242 }, 243 Destination: &flowpb.Endpoint{ 244 ID: uint32(remoteID), 245 Identity: uint32(remoteIdentity), 246 }, 247 PolicyMatchType: monitorAPI.PolicyMatchL3Only, 248 } 249 CorrelatePolicy(endpointGetter, flow) 250 251 require.Nil(t, flow.EgressAllowedBy) 252 require.Nil(t, flow.IngressAllowedBy) 253 require.Nil(t, flow.EgressDeniedBy) 254 if diff := cmp.Diff(expected, flow.IngressDeniedBy, protocmp.Transform()); diff != "" { 255 t.Fatalf("not equal (-want +got):\n%s", diff) 256 } 257 }