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