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
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
119 assert.Equal(t, expectedClientSecretInterfaceLines, secretLines[:1])
120 assert.Equal(t, expectedClientSecretPeerLines, secretLines[4:7])
121
122
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
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
134 expectedMTULine := fmt.Sprintf("MTU = %s", constants.MTU)
135 assert.Equal(t, expectedMTULine, secretLines[3])
136
137
138 expectedEndpointLine := fmt.Sprintf("Endpoint = %s:51820", loadBalancerIPAddress)
139 assert.Equal(t, expectedEndpointLine, secretLines[7])
140
141
142 expectedrelaypublickeyline := fmt.Sprintf("PublicKey = %s", testPublicKey)
143 assert.Equal(t, expectedrelaypublickeyline, secretLines[8])
144
145
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
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
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