...

Source file src/edge-infra.dev/pkg/sds/remoteaccess/wireguard/client/integration/integration_test.go

Documentation: edge-infra.dev/pkg/sds/remoteaccess/wireguard/client/integration

     1  package integration
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  	corev1 "k8s.io/api/core/v1"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  
    18  	v1cluster "edge-infra.dev/pkg/edge/apis/cluster/v1alpha1"
    19  	"edge-infra.dev/pkg/sds/remoteaccess/constants"
    20  	v1vpnconfig "edge-infra.dev/pkg/sds/remoteaccess/k8s/apis/vpnconfigs/v1"
    21  	wc "edge-infra.dev/pkg/sds/remoteaccess/wireguard/client"
    22  	"edge-infra.dev/pkg/sds/remoteaccess/wireguard/store"
    23  	"edge-infra.dev/test/f2"
    24  	"edge-infra.dev/test/f2/x/ktest"
    25  )
    26  
    27  var f f2.Framework
    28  
    29  var (
    30  	projectID     = "ret-edge-b79we3ikmc7j9mihuwst2"
    31  	testPublicKey = "wbWuHrJEPC2Ui7XVQoWuM/8HZAG1FlLC/08L2vvEEgw="
    32  
    33  	loadBalancerIPAddress = "34.123.45.67"
    34  	outOfSubnetIPAddress  = "179.16.17.3"
    35  	inSubnetIPAddress     = "172.16.16.12"
    36  
    37  	clusterAName = "cluster-a"
    38  	clusterBName = "cluster-b"
    39  	testClusterA = createCluster(clusterAName)
    40  	testClusterB = createCluster(clusterBName)
    41  
    42  	testVPNConfig                     = createVPNConfig(clusterAName, inSubnetIPAddress)
    43  	testVPNConfigOutOfSubnetIPAddress = createVPNConfig(clusterBName, outOfSubnetIPAddress)
    44  
    45  	expectedClientSecretInterfaceLines = []string{
    46  		"[Interface]",
    47  	}
    48  	expectedClientSecretPeerLines = []string{
    49  		"",
    50  		"[Peer]",
    51  		"PersistentKeepalive = 25",
    52  	}
    53  
    54  	vpnNamespace = &corev1.Namespace{
    55  		ObjectMeta: metav1.ObjectMeta{
    56  			Name: constants.VPNNamespace,
    57  		},
    58  	}
    59  )
    60  
    61  func TestMain(m *testing.M) {
    62  	f = f2.New(context.Background(),
    63  		f2.WithExtensions(
    64  			ktest.New(),
    65  		)).
    66  		Setup(func(ctx f2.Context) (f2.Context, error) {
    67  			k, err := ktest.FromContext(ctx)
    68  			if err != nil {
    69  				return ctx, err
    70  			}
    71  			// Override timeouts if we aren't using a live cluster
    72  			if !*k.Env.UseExistingCluster {
    73  				k.Timeout = 5 * time.Second
    74  				k.Tick = 10 * time.Millisecond
    75  			}
    76  			return ctx, nil
    77  		}).Teardown()
    78  	os.Exit(f.Run(m))
    79  }
    80  
    81  func TestClientWireguard(t *testing.T) {
    82  	var (
    83  		client   *wc.Client
    84  		storeAWg *store.Store
    85  		storeBWg *store.Store
    86  		subnet   *net.IPNet
    87  		lbIP     net.IP
    88  	)
    89  	feature := f2.NewFeature("ClientWireguard").
    90  		Setup("create wireguard instances", func(ctx f2.Context, t *testing.T) f2.Context {
    91  			var err error
    92  			k := ktest.FromContextT(ctx, t)
    93  			require.NoError(t, k.Client.Create(ctx, vpnNamespace.DeepCopy()))
    94  
    95  			client, err = wc.Get(ctx, k.Client)
    96  			require.NoError(t, err)
    97  
    98  			storeAWg, err = store.Get(ctx, k.Client, testVPNConfig.DeepCopy(), testClusterA)
    99  			require.NoError(t, err)
   100  
   101  			storeBWg, err = store.Get(ctx, k.Client, testVPNConfigOutOfSubnetIPAddress.DeepCopy(), testClusterB)
   102  			require.NoError(t, err)
   103  			return ctx
   104  		}).
   105  		Setup("create subnet and load balancer IP", func(ctx f2.Context, t *testing.T) f2.Context {
   106  			var err error
   107  			_, subnet, err = net.ParseCIDR("172.16.16.0/28")
   108  			require.NoError(t, err)
   109  
   110  			lbIP = net.ParseIP(loadBalancerIPAddress)
   111  			return ctx
   112  		}).
   113  		Test("client secret contains expected data", func(ctx f2.Context, t *testing.T) f2.Context {
   114  			storeConfigs := map[string]*store.Store{clusterAName: storeAWg}
   115  			secret := client.GenerateConfigurationSecret(subnet, lbIP, testPublicKey, storeConfigs)
   116  			secretLines := getLinesFromWireguardSecretData(secret)
   117  
   118  			// assert expected lines appear in interface and peer sections
   119  			assert.Equal(t, expectedClientSecretInterfaceLines, secretLines[:1])
   120  			assert.Equal(t, expectedClientSecretPeerLines, secretLines[4:7])
   121  
   122  			// private key is not exposed, so check string is present and base64 encoded
   123  			assert.Equal(t, "PrivateKey = ", secretLines[1][:13])
   124  			privatekey := secretLines[1][13:]
   125  			_, err := base64.StdEncoding.DecodeString(privatekey)
   126  			assert.NoError(t, err)
   127  
   128  			// check client interface address is set
   129  			subnetMask := strings.Split(subnet.String(), "/")[1]
   130  			expectedInterfaceLine := fmt.Sprintf("Address = %s/%s", client.GetIPAddress(), subnetMask)
   131  			assert.Equal(t, expectedInterfaceLine, secretLines[2])
   132  
   133  			// check client interface MTU is set
   134  			expectedMTULine := fmt.Sprintf("MTU = %s", constants.MTU)
   135  			assert.Equal(t, expectedMTULine, secretLines[3])
   136  
   137  			// check relay external IP address is set as endpoint in peer config
   138  			expectedEndpointLine := fmt.Sprintf("Endpoint = %s:51820", loadBalancerIPAddress)
   139  			assert.Equal(t, expectedEndpointLine, secretLines[7])
   140  
   141  			// check relay public key is set in peer config
   142  			expectedrelaypublickeyline := fmt.Sprintf("PublicKey = %s", testPublicKey)
   143  			assert.Equal(t, expectedrelaypublickeyline, secretLines[8])
   144  
   145  			// check store ip address is set in peer config
   146  			expectedAllowedIPsLine := fmt.Sprintf("AllowedIPs = %s/32", storeConfigs[clusterAName].GetIPAddress())
   147  			assert.Equal(t, expectedAllowedIPsLine, secretLines[9])
   148  			return ctx
   149  		}).
   150  		Test("multiple stores are added to client secret", func(ctx f2.Context, t *testing.T) f2.Context {
   151  			storeConfigs := map[string]*store.Store{clusterAName: storeAWg, clusterBName: storeBWg}
   152  			secret := client.GenerateConfigurationSecret(subnet, lbIP, testPublicKey, storeConfigs)
   153  			secretLines := getLinesFromWireguardSecretData(secret)
   154  			allowedIPsLine := secretLines[9]
   155  
   156  			for _, storeConfig := range storeConfigs {
   157  				assert.Contains(t, allowedIPsLine, storeConfig.GetIPAddress().String())
   158  			}
   159  			return ctx
   160  		}).
   161  		Test("store can be removed from client secret", func(ctx f2.Context, t *testing.T) f2.Context {
   162  			// update store and check store ip address is set in peer config
   163  			storeConfigs := map[string]*store.Store{clusterAName: storeAWg}
   164  			secret := client.GenerateConfigurationSecret(subnet, lbIP, testPublicKey, storeConfigs)
   165  			secretLines := getLinesFromWireguardSecretData(secret)
   166  			expectedAllowedIPsLine := fmt.Sprintf("AllowedIPs = %s/32", storeConfigs[clusterAName].GetIPAddress())
   167  			assert.Equal(t, expectedAllowedIPsLine, secretLines[9])
   168  
   169  			// remove store and check peer is removed from relay config
   170  			storeConfigs = map[string]*store.Store{}
   171  			secret = client.GenerateConfigurationSecret(subnet, lbIP, testPublicKey, storeConfigs)
   172  			secretLines = getLinesFromWireguardSecretData(secret)
   173  			assert.NotContains(t, secretLines, "AllowedIPs = ")
   174  			return ctx
   175  		}).Feature()
   176  
   177  	f.Test(t, feature)
   178  }
   179  
   180  func getLinesFromWireguardSecretData(secret *corev1.Secret) []string {
   181  	secretData := secret.StringData[constants.WireguardSecretField]
   182  	return strings.Split(secretData, "\n")
   183  }
   184  
   185  func createCluster(name string) *v1cluster.Cluster {
   186  	return &v1cluster.Cluster{
   187  		ObjectMeta: metav1.ObjectMeta{Name: name},
   188  		Spec: v1cluster.ClusterSpec{
   189  			Banner:       "dev0-zynstra",
   190  			Fleet:        "store",
   191  			Location:     "us-east1-c",
   192  			Name:         "4c4d-30-05-22",
   193  			Organization: "edge-dev0-retail-gmi062",
   194  			ProjectID:    projectID,
   195  			Type:         "sds",
   196  		},
   197  	}
   198  }
   199  
   200  func createVPNConfig(name, ip string) *v1vpnconfig.VPNConfig {
   201  	return &v1vpnconfig.VPNConfig{
   202  		TypeMeta:   metav1.TypeMeta{Kind: "VPNConfig", APIVersion: "remoteaccess.edge.ncr.com"},
   203  		ObjectMeta: metav1.ObjectMeta{Namespace: constants.VPNNamespace, Name: name, UID: "1234"},
   204  		Spec: v1vpnconfig.VPNConfigSpec{
   205  			Enabled: true,
   206  		},
   207  		Status: &v1vpnconfig.VPNConfigStatus{
   208  			IP: ip,
   209  		},
   210  	}
   211  }
   212  

View as plain text