go.ligato.io/vpp-agent/v3@v3.5.0/tests/e2e/060_acl_test.go (about) 1 // Copyright (c) 2019 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package e2e 16 17 import ( 18 "context" 19 "fmt" 20 "testing" 21 22 . "github.com/onsi/gomega" 23 24 "go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler" 25 linux_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" 26 linux_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/linux/l3" 27 linux_namespace "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace" 28 vpp_acl "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/acl" 29 vpp_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 30 . "go.ligato.io/vpp-agent/v3/tests/e2e/e2etest" 31 ) 32 33 func vppACLs(ctx *TestCtx) (string, error) { 34 return ctx.ExecVppctl("show", "acl-plugin", "acl") 35 } 36 37 // Test access control between microservices connected over VPP on the L3 layer. 38 func TestL3ACLs(t *testing.T) { 39 ctx := Setup(t) 40 defer ctx.Teardown() 41 42 const ( 43 // microservice1 44 vppTap1Name = "vpp-tap1" 45 vppTap1IP = "10.10.10.1" 46 linuxTap1Name = "linux-tap1" 47 linuxTap1Hostname = "tap" 48 linuxTap1IP = "10.10.10.10" 49 50 // private network 51 vppTap2Name = "vpp-tap2" 52 vppTap2IP = "192.168.1.1" 53 linuxTap2Name = "linux-tap2" 54 linuxTap2Hostname = "tap" 55 linuxTap2IP = "192.168.1.2" 56 57 netMask = "/24" 58 ms1Name = "microservice1" 59 ms2Name = "microservice2" 60 61 // acl 62 ms1BlockedUDPPort = 9000 63 ms2BlockedTCPPort = 8000 64 ms1Net = "10.10.10.0" + netMask 65 ms2Net = "192.168.1.0" + netMask 66 ms1IngressACLName = "ms1-ingress" 67 ms1EgressACLName = "ms1-egress" 68 ms2IngressACLName = "ms2-ingress" 69 ms2EgressACLName = "ms2-egress" 70 anyAddr = "0.0.0.0/0" 71 ) 72 73 vppTap1 := &vpp_interfaces.Interface{ 74 Name: vppTap1Name, 75 Type: vpp_interfaces.Interface_TAP, 76 Enabled: true, 77 IpAddresses: []string{vppTap1IP + netMask}, 78 Link: &vpp_interfaces.Interface_Tap{ 79 Tap: &vpp_interfaces.TapLink{ 80 Version: 2, 81 ToMicroservice: MsNamePrefix + ms1Name, 82 }, 83 }, 84 } 85 86 linuxTap1 := &linux_interfaces.Interface{ 87 Name: linuxTap1Name, 88 Type: linux_interfaces.Interface_TAP_TO_VPP, 89 Enabled: true, 90 IpAddresses: []string{linuxTap1IP + netMask}, 91 HostIfName: linuxTap1Hostname, 92 Link: &linux_interfaces.Interface_Tap{ 93 Tap: &linux_interfaces.TapLink{ 94 VppTapIfName: vppTap1Name, 95 }, 96 }, 97 Namespace: &linux_namespace.NetNamespace{ 98 Type: linux_namespace.NetNamespace_MICROSERVICE, 99 Reference: MsNamePrefix + ms1Name, 100 }, 101 } 102 103 vppTap2 := &vpp_interfaces.Interface{ 104 Name: vppTap2Name, 105 Type: vpp_interfaces.Interface_TAP, 106 Enabled: true, 107 IpAddresses: []string{vppTap2IP + netMask}, 108 Link: &vpp_interfaces.Interface_Tap{ 109 Tap: &vpp_interfaces.TapLink{ 110 Version: 2, 111 ToMicroservice: MsNamePrefix + ms2Name, 112 }, 113 }, 114 } 115 116 linuxTap2 := &linux_interfaces.Interface{ 117 Name: linuxTap2Name, 118 Type: linux_interfaces.Interface_TAP_TO_VPP, 119 Enabled: true, 120 IpAddresses: []string{linuxTap2IP + netMask}, 121 HostIfName: linuxTap2Hostname, 122 Link: &linux_interfaces.Interface_Tap{ 123 Tap: &linux_interfaces.TapLink{ 124 VppTapIfName: vppTap2Name, 125 }, 126 }, 127 Namespace: &linux_namespace.NetNamespace{ 128 Type: linux_namespace.NetNamespace_MICROSERVICE, 129 Reference: MsNamePrefix + ms2Name, 130 }, 131 } 132 133 ms1DefaultRoute := &linux_l3.Route{ 134 OutgoingInterface: linuxTap1Name, 135 Scope: linux_l3.Route_GLOBAL, 136 DstNetwork: "0.0.0.0/0", 137 GwAddr: vppTap1IP, 138 } 139 140 ms2DefaultRoute := &linux_l3.Route{ 141 OutgoingInterface: linuxTap2Name, 142 Scope: linux_l3.Route_GLOBAL, 143 DstNetwork: "0.0.0.0/0", 144 GwAddr: vppTap2IP, 145 } 146 147 permitAll := &vpp_acl.ACL_Rule{ 148 Action: vpp_acl.ACL_Rule_PERMIT, 149 IpRule: &vpp_acl.ACL_Rule_IpRule{ 150 Ip: &vpp_acl.ACL_Rule_IpRule_Ip{ 151 SourceNetwork: anyAddr, 152 DestinationNetwork: anyAddr, 153 }, 154 }, 155 } 156 157 anyPort := &vpp_acl.ACL_Rule_IpRule_PortRange{ 158 LowerPort: 0, 159 UpperPort: uint32(^uint16(0)), 160 } 161 162 // connections initiated from microservice1 should not be blocked by 163 // ACL on the egress side (from the VPP point of view) 164 ms1IngressACL := &vpp_acl.ACL{ 165 Name: ms1IngressACLName, 166 Rules: []*vpp_acl.ACL_Rule{ 167 { 168 Action: vpp_acl.ACL_Rule_REFLECT, 169 IpRule: &vpp_acl.ACL_Rule_IpRule{ 170 Ip: &vpp_acl.ACL_Rule_IpRule_Ip{ 171 SourceNetwork: anyAddr, 172 DestinationNetwork: anyAddr, 173 }, 174 }, 175 }, 176 }, 177 Interfaces: &vpp_acl.ACL_Interfaces{ 178 Ingress: []string{ 179 vppTap1Name, 180 }, 181 }, 182 } 183 showMs1IngressACL := "{ms1-ingress}\r\n" + 184 " 0: ipv4 permit+reflect src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0 dport 0\r\n" 185 186 // microservice2 is not allowed to ping microservice1 and it also cannot 187 // send UDP packet to port 9000 188 ms1EgressACL := &vpp_acl.ACL{ 189 Name: ms1EgressACLName, 190 Rules: []*vpp_acl.ACL_Rule{ 191 { 192 Action: vpp_acl.ACL_Rule_DENY, 193 IpRule: &vpp_acl.ACL_Rule_IpRule{ 194 Ip: &vpp_acl.ACL_Rule_IpRule_Ip{ 195 SourceNetwork: ms2Net, 196 DestinationNetwork: anyAddr, 197 Protocol: 17, 198 }, 199 Udp: &vpp_acl.ACL_Rule_IpRule_Udp{ 200 SourcePortRange: anyPort, 201 DestinationPortRange: &vpp_acl.ACL_Rule_IpRule_PortRange{ 202 LowerPort: ms1BlockedUDPPort, 203 UpperPort: ms1BlockedUDPPort, 204 }, 205 }, 206 }, 207 }, 208 { 209 Action: vpp_acl.ACL_Rule_DENY, 210 IpRule: &vpp_acl.ACL_Rule_IpRule{ 211 Ip: &vpp_acl.ACL_Rule_IpRule_Ip{ 212 SourceNetwork: anyAddr, 213 DestinationNetwork: anyAddr, 214 }, 215 Icmp: &vpp_acl.ACL_Rule_IpRule_Icmp{ 216 // any ICMP packet 217 IcmpCodeRange: &vpp_acl.ACL_Rule_IpRule_Icmp_Range{ 218 First: 0, 219 Last: 255, 220 }, 221 IcmpTypeRange: &vpp_acl.ACL_Rule_IpRule_Icmp_Range{ 222 First: 0, 223 Last: 255, 224 }, 225 }, 226 }, 227 }, 228 permitAll, // permit the rest 229 }, 230 Interfaces: &vpp_acl.ACL_Interfaces{ 231 Egress: []string{ 232 vppTap1Name, 233 }, 234 }, 235 } 236 showMs1EgressACL := fmt.Sprintf( 237 "{ms1-egress}\r\n"+ 238 " 0: ipv4 deny src %s dst 0.0.0.0/0 proto 17 sport 0-65535 dport %d\r\n"+ 239 " 1: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 1 sport 0-255 dport 0-255\r\n"+ 240 " 2: ipv4 permit src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0 dport 0\r\n", 241 ms2Net, ms1BlockedUDPPort) 242 243 // microservice2 is not allowed to initiate TCP connections to ms1 on well-known 244 // ports (<1024) 245 ms2IngressACL := &vpp_acl.ACL{ 246 Name: ms2IngressACLName, 247 Rules: []*vpp_acl.ACL_Rule{ 248 { 249 Action: vpp_acl.ACL_Rule_DENY, 250 IpRule: &vpp_acl.ACL_Rule_IpRule{ 251 Ip: &vpp_acl.ACL_Rule_IpRule_Ip{ 252 SourceNetwork: anyAddr, 253 DestinationNetwork: ms1Net, 254 }, 255 Tcp: &vpp_acl.ACL_Rule_IpRule_Tcp{ 256 SourcePortRange: anyPort, 257 DestinationPortRange: &vpp_acl.ACL_Rule_IpRule_PortRange{ 258 LowerPort: 0, 259 UpperPort: 1023, 260 }, 261 }, 262 }, 263 }, 264 permitAll, // permit the rest 265 }, 266 Interfaces: &vpp_acl.ACL_Interfaces{ 267 Ingress: []string{ 268 vppTap2Name, 269 }, 270 }, 271 } 272 showMs2IngressACL := fmt.Sprintf( 273 "{ms2-ingress}\r\n"+ 274 " 0: ipv4 deny src 0.0.0.0/0 dst %s proto 6 sport 0-65535 dport 0-1023\r\n"+ 275 " 1: ipv4 permit src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0 dport 0\r\n", 276 ms1Net) 277 278 // microservice1 is not allowed to connect to microservice2 on TCP port 8000 279 ms2EgressACL := &vpp_acl.ACL{ 280 Name: ms2EgressACLName, 281 Rules: []*vpp_acl.ACL_Rule{ 282 { 283 Action: vpp_acl.ACL_Rule_DENY, 284 IpRule: &vpp_acl.ACL_Rule_IpRule{ 285 Ip: &vpp_acl.ACL_Rule_IpRule_Ip{ 286 SourceNetwork: linuxTap1IP + "/32", 287 DestinationNetwork: anyAddr, 288 }, 289 Tcp: &vpp_acl.ACL_Rule_IpRule_Tcp{ 290 SourcePortRange: anyPort, 291 DestinationPortRange: &vpp_acl.ACL_Rule_IpRule_PortRange{ 292 LowerPort: ms2BlockedTCPPort, 293 UpperPort: ms2BlockedTCPPort, 294 }, 295 }, 296 }, 297 }, 298 permitAll, // permit the rest 299 }, 300 Interfaces: &vpp_acl.ACL_Interfaces{ 301 Egress: []string{ 302 vppTap2Name, 303 }, 304 }, 305 } 306 showMs2EgressACL := fmt.Sprintf( 307 "{ms2-egress}\r\n"+ 308 " 0: ipv4 deny src %s/32 dst 0.0.0.0/0 proto 6 sport 0-65535 dport %d\r\n"+ 309 " 1: ipv4 permit src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0 dport 0\r\n", 310 linuxTap1IP, ms2BlockedTCPPort) 311 312 checkAccess := func(aclsConfigured bool) { 313 beAllowed := Succeed() 314 beBlocked := Not(Succeed()) 315 if !aclsConfigured { 316 beBlocked = Succeed() 317 } 318 319 // ICMP 320 ctx.ExpectWithOffset(1, ctx.PingFromMs(ms1Name, linuxTap2IP)).To(beAllowed) // reflected by ms1IngressACL 321 ctx.ExpectWithOffset(1, ctx.PingFromMs(ms2Name, linuxTap1IP)).To(beBlocked) // blocked by ms1EgressACL 322 323 // TCP 324 ctx.ExpectWithOffset(1, ctx.TestConnection(ms1Name, ms2Name, linuxTap2IP, linuxTap2IP, 325 ms2BlockedTCPPort, ms2BlockedTCPPort, false, Tapv2InputNode)).To(beBlocked) // blocked by ms2EgressACL 326 ctx.ExpectWithOffset(1, ctx.TestConnection(ms1Name, ms2Name, linuxTap2IP, linuxTap2IP, 327 8080, 8080, false, Tapv2InputNode)).To(beAllowed) 328 ctx.ExpectWithOffset(1, ctx.TestConnection(ms1Name, ms2Name, linuxTap2IP, linuxTap2IP, 329 80, 80, false, Tapv2InputNode)).To(beAllowed) 330 ctx.ExpectWithOffset(1, ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP, 331 ms2BlockedTCPPort, ms2BlockedTCPPort, false, Tapv2InputNode)).To(beAllowed) 332 ctx.ExpectWithOffset(1, ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP, 333 8080, 8080, false, Tapv2InputNode)).To(beAllowed) 334 ctx.ExpectWithOffset(1, ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP, 335 80, 80, false, Tapv2InputNode)).To(beBlocked) // blocked by ms2IngressACL 336 337 // UDP 338 ctx.ExpectWithOffset(1, ctx.TestConnection(ms1Name, ms2Name, linuxTap2IP, linuxTap2IP, 339 ms1BlockedUDPPort, ms1BlockedUDPPort, true, Tapv2InputNode)).To(beAllowed) 340 ctx.ExpectWithOffset(1, ctx.TestConnection(ms1Name, ms2Name, linuxTap2IP, linuxTap2IP, 341 9999, 9999, true, Tapv2InputNode)).To(beAllowed) 342 ctx.ExpectWithOffset(1, ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP, 343 ms1BlockedUDPPort, ms1BlockedUDPPort, true, Tapv2InputNode)).To(beBlocked) // blocked by ms1EgressACL 344 ctx.ExpectWithOffset(1, ctx.TestConnection(ms2Name, ms1Name, linuxTap1IP, linuxTap1IP, 345 9999, 9999, true, Tapv2InputNode)).To(beAllowed) 346 } 347 348 ctx.StartMicroservice(ms1Name) 349 ctx.StartMicroservice(ms2Name) 350 ctx.Expect(vppACLs(ctx)).ShouldNot(SatisfyAny( 351 ContainSubstring(showMs1IngressACL), ContainSubstring(showMs1EgressACL), 352 ContainSubstring(showMs2IngressACL), ContainSubstring(showMs2EgressACL))) 353 req := ctx.GenericClient().ChangeRequest() 354 err := req.Update( 355 vppTap1, 356 linuxTap1, 357 vppTap2, 358 linuxTap2, 359 ms1DefaultRoute, ms2DefaultRoute, 360 ms1IngressACL, ms1EgressACL, 361 ms2IngressACL, ms2EgressACL, 362 ).Send(context.Background()) 363 ctx.Expect(err).ToNot(HaveOccurred(), "Transaction connecting microservices and configuring ACLs failed") 364 365 ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 366 "TAP attached to a newly started microservice1 should be eventually configured") 367 ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 368 "TAP attached to a newly started microservice2 should be eventually configured") 369 370 ctx.Expect(vppACLs(ctx)).Should(SatisfyAll( 371 ContainSubstring(showMs1IngressACL), ContainSubstring(showMs1EgressACL), 372 ContainSubstring(showMs2IngressACL), ContainSubstring(showMs2EgressACL))) 373 checkAccess(true) 374 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 375 376 // remove ACL configuration 377 req = ctx.GenericClient().ChangeRequest() 378 err = req.Delete( 379 ms1IngressACL, ms1EgressACL, 380 ms2IngressACL, ms2EgressACL, 381 ).Send(context.Background()) 382 ctx.Expect(err).ToNot(HaveOccurred(), "Transaction removing ACLs failed") 383 384 ctx.Expect(vppACLs(ctx)).ShouldNot(SatisfyAny( 385 ContainSubstring(showMs1IngressACL), ContainSubstring(showMs1EgressACL), 386 ContainSubstring(showMs2IngressACL), ContainSubstring(showMs2EgressACL))) 387 checkAccess(false) 388 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 389 390 // get back the ACL configuration 391 req = ctx.GenericClient().ChangeRequest() 392 err = req.Update( 393 ms1IngressACL, ms1EgressACL, 394 ms2IngressACL, ms2EgressACL, 395 ).Send(context.Background()) 396 ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating ACLs failed") 397 398 ctx.Expect(vppACLs(ctx)).Should(SatisfyAll( 399 ContainSubstring(showMs1IngressACL), ContainSubstring(showMs1EgressACL), 400 ContainSubstring(showMs2IngressACL), ContainSubstring(showMs2EgressACL))) 401 checkAccess(true) 402 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 403 404 // restart both microservices 405 ctx.StopMicroservice(ms1Name) 406 ctx.StopMicroservice(ms2Name) 407 ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_PENDING), 408 "Without microservice, the associated VPP-TAP should be pending") 409 ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_PENDING), 410 "Without microservice, the associated VPP-TAP should be pending") 411 ctx.StartMicroservice(ms1Name) 412 ctx.StartMicroservice(ms2Name) 413 ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 414 "VPP-TAP attached to a re-started microservice1 should be eventually configured") 415 ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 416 "VPP-TAP attached to a re-started microservice1 should be eventually configured") 417 418 ctx.Expect(vppACLs(ctx)).Should(SatisfyAll( 419 ContainSubstring(showMs1IngressACL), ContainSubstring(showMs1EgressACL), 420 ContainSubstring(showMs2IngressACL), ContainSubstring(showMs2EgressACL))) 421 checkAccess(true) 422 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 423 424 } 425 426 // TODO: L2 ACLs