1 package client
2
3 import (
4 "context"
5 "fmt"
6 "net"
7 "strings"
8
9 appsv1 "k8s.io/api/apps/v1"
10 corev1 "k8s.io/api/core/v1"
11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 "k8s.io/apimachinery/pkg/labels"
13 "sigs.k8s.io/controller-runtime/pkg/client"
14
15 "edge-infra.dev/pkg/k8s/runtime/objectrestarter"
16 "edge-infra.dev/pkg/sds/ingress/emissary"
17 "edge-infra.dev/pkg/sds/remoteaccess/constants"
18 wg "edge-infra.dev/pkg/sds/remoteaccess/wireguard"
19 secrets "edge-infra.dev/pkg/sds/remoteaccess/wireguard/secret"
20 "edge-infra.dev/pkg/sds/remoteaccess/wireguard/store"
21 )
22
23 type Client struct {
24 *wg.Instance
25 }
26
27
28 func Get(ctx context.Context, c client.Client) (*Client, error) {
29 wg, err := wg.GetInstance(ctx, c, constants.ClientName, "cluster-infra", nil)
30 return &Client{Instance: wg}, err
31 }
32
33 var emissaryIngressLabelSelector = labels.Set{constants.K8sNameLabel: emissary.IngressName}
34
35 func (cl *Client) UpdateWireguardSecret(ctx context.Context, c client.Client, subnetCIDR *net.IPNet, relayExternalIPAddress net.IP, relayPublicKey string, stores map[string]*store.Store) error {
36 secret := cl.GenerateConfigurationSecret(subnetCIDR, relayExternalIPAddress, relayPublicKey, stores)
37 if err := secrets.CreateOrPatchSecret(ctx, c, secret); err != nil {
38 return err
39 }
40 return cl.updateEmissaryDeployment(ctx, c)
41 }
42
43 func (cl *Client) GenerateConfigurationSecret(subnetCIDR *net.IPNet, relayExternalIPAddress net.IP, relayPublicKey string, storeConfigs map[string]*store.Store) *corev1.Secret {
44 wg0ConfigString := cl.wg0ConfigString(subnetCIDR, relayExternalIPAddress, relayPublicKey, storeConfigs)
45 return &corev1.Secret{
46 ObjectMeta: metav1.ObjectMeta{
47 Namespace: emissary.IngressNamespace,
48 Name: constants.ClientName,
49 },
50 StringData: map[string]string{constants.WireguardSecretField: wg0ConfigString},
51 }
52 }
53
54 func (cl *Client) wg0ConfigString(subnetCIDR *net.IPNet, relayExternalIP net.IP, relayPublicKey string, storeConfigs map[string]*store.Store) string {
55 allowedIPs := getAllowedIPs(storeConfigs)
56 interfaceConfig := cl.interfaceConfigString(subnetCIDR)
57 clientConfig := cl.peerConfigString(relayExternalIP, relayPublicKey, allowedIPs)
58 return interfaceConfig + clientConfig
59 }
60
61 func getAllowedIPs(storeConfigs map[string]*store.Store) []string {
62 var allowedIPs []string
63 for _, storeConfig := range storeConfigs {
64 if storeConfig.IsEnabled {
65 allowedIPs = append(allowedIPs, fmt.Sprintf("%s/32", storeConfig.GetIPAddress()))
66 }
67 }
68 return allowedIPs
69 }
70
71 func (cl *Client) interfaceConfigString(subnetCIDR *net.IPNet) string {
72 prefLen, _ := subnetCIDR.Mask.Size()
73 return fmt.Sprintf(
74 "[Interface]\nPrivateKey = %s\nAddress = %s/%d\nMTU = %s\n",
75 cl.GetPrivateKey(),
76 cl.GetIPAddress(),
77 prefLen,
78 constants.MTU,
79 )
80 }
81
82 func (cl *Client) peerConfigString(relayExternalIP net.IP, relayPublicKey string, allowedIPs []string) string {
83 peerConfigString := fmt.Sprintf(
84 "\n[Peer]\nPersistentKeepalive = 25\nEndpoint = %s:51820\nPublicKey = %s\n",
85 relayExternalIP,
86 relayPublicKey,
87 )
88 if len(allowedIPs) > 0 {
89 peerConfigString = fmt.Sprintf("%sAllowedIPs = %s\n", peerConfigString, strings.Join(allowedIPs, ", "))
90 }
91 return peerConfigString
92 }
93
94
95
96 func (cl *Client) updateEmissaryDeployment(ctx context.Context, c client.Client) error {
97 if injected, err := emissaryDeploymentIsInjected(ctx, c); err != nil {
98 return err
99 } else if injected {
100 return nil
101 }
102
103
104 deployment := &appsv1.Deployment{}
105 if err := c.Get(ctx, client.ObjectKey{Namespace: emissary.IngressNamespace, Name: emissary.IngressName}, deployment); err != nil {
106 return err
107 }
108 return objectrestarter.Restart(ctx, c, deployment)
109 }
110
111 func emissaryDeploymentIsInjected(ctx context.Context, c client.Client) (bool, error) {
112 podList := &corev1.PodList{}
113 if err := c.List(ctx, podList, &client.ListOptions{
114 LabelSelector: labels.SelectorFromSet(emissaryIngressLabelSelector),
115 Namespace: emissary.IngressNamespace,
116 }); err != nil {
117 return false, err
118 }
119
120
121 for _, pod := range podList.Items {
122 if !hasWireguardContainer(pod) {
123 return false, nil
124 }
125 }
126
127 return true, nil
128 }
129
130 func hasWireguardContainer(pod corev1.Pod) bool {
131 for _, container := range pod.Spec.Containers {
132 if container.Name == constants.WireguardContainerName {
133 return true
134 }
135 }
136 return false
137 }
138
View as plain text