1 package wireguard
2
3 import (
4 "context"
5 "net"
6 "time"
7
8 corev1 "k8s.io/api/core/v1"
9 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10
11 v1vpnconfig "edge-infra.dev/pkg/sds/remoteaccess/k8s/apis/vpnconfigs/v1"
12
13 "k8s.io/apimachinery/pkg/api/errors"
14
15 "sigs.k8s.io/controller-runtime/pkg/client"
16
17 "edge-infra.dev/pkg/edge/k8objectsutils"
18 "edge-infra.dev/pkg/lib/crypto"
19 "edge-infra.dev/pkg/sds/remoteaccess/constants"
20 secrets "edge-infra.dev/pkg/sds/remoteaccess/wireguard/secret"
21 )
22
23 const (
24 SecretPrefix string = "keys-"
25 SecretExpires string = "expires"
26 SecretPublicKey string = "publicKey"
27 SecretPrivateKey string = "privateKey"
28 SecretIPAddress string = "ipAddress"
29 )
30
31 type Instance struct {
32 IPAddress net.IP
33 PublicKey string
34 PrivateKey string
35 }
36
37 func (i *Instance) GetIPAddress() net.IP {
38 return i.IPAddress
39 }
40
41 func (i *Instance) GetPublicKey() string {
42 return i.PublicKey
43 }
44
45 func (i *Instance) GetPrivateKey() string {
46 return i.PrivateKey
47 }
48
49
50 func New(ctx context.Context, c client.Client, name, clusterEdgeID string, vpnConfig *v1vpnconfig.VPNConfig) (*Instance, error) {
51 wgKey, err := crypto.GenerateWireguardKeyPair()
52 if err != nil {
53 return nil, err
54 }
55 instance := &Instance{
56 PublicKey: wgKey.PublicKey(),
57 PrivateKey: wgKey.PrivateKey(),
58 }
59 if err := createInstanceSecret(ctx, c, name, clusterEdgeID, instance, vpnConfig); err != nil {
60 return nil, err
61 }
62 return instance, nil
63 }
64
65
66 func (i *Instance) UpdateIPAddress(ctx context.Context, c client.Client, name, clusterEdgeID string, ip net.IP) error {
67 i.IPAddress = ip
68 return updateInstanceSecret(ctx, c, name, clusterEdgeID, i)
69 }
70
71
72
73
74 func GetInstance(ctx context.Context, c client.Client, name, clusterEdgeID string, vpnConfig *v1vpnconfig.VPNConfig) (*Instance, error) {
75 secret := &corev1.Secret{}
76 secretName := k8objectsutils.NameWithPrefix(SecretPrefix+name, clusterEdgeID)
77
78 err := c.Get(ctx, client.ObjectKey{Namespace: constants.VPNNamespace, Name: secretName}, secret)
79 if err != nil && !errors.IsNotFound(err) {
80 return nil, err
81 }
82 if errors.IsNotFound(err) {
83 return New(ctx, c, name, clusterEdgeID, vpnConfig)
84 }
85
86
87 expires, err := time.Parse(time.RFC3339, secret.Annotations[SecretExpires])
88 if err != nil {
89 return nil, err
90 }
91 if time.Now().After(expires) {
92 return rotateInstanceSecret(ctx, c, name, clusterEdgeID, secret, vpnConfig)
93 }
94
95 return instanceFromSecret(secret), nil
96 }
97
98 func rotateInstanceSecret(ctx context.Context, c client.Client, name, clusterEdgeID string, secret *corev1.Secret, vpnConfig *v1vpnconfig.VPNConfig) (*Instance, error) {
99
100 old := instanceFromSecret(secret)
101
102 if err := c.Delete(ctx, secret); err != nil {
103 return nil, err
104 }
105
106 instance, err := New(ctx, c, name, clusterEdgeID, vpnConfig)
107 if err != nil {
108 return nil, err
109 }
110
111 err = instance.UpdateIPAddress(ctx, c, name, clusterEdgeID, old.IPAddress)
112 return instance, err
113 }
114
115 func instanceFromSecret(secret *corev1.Secret) *Instance {
116 return &Instance{
117 PublicKey: string(secret.Data[SecretPublicKey]),
118 PrivateKey: string(secret.Data[SecretPrivateKey]),
119 IPAddress: net.ParseIP(string(secret.Data[SecretIPAddress])),
120 }
121 }
122
123 func createInstanceSecret(ctx context.Context, c client.Client, name, clusterEdgeID string, instance *Instance, vpnConfig *v1vpnconfig.VPNConfig) error {
124 secretName := k8objectsutils.NameWithPrefix(SecretPrefix+name, clusterEdgeID)
125 secret := &corev1.Secret{
126 ObjectMeta: metav1.ObjectMeta{
127 Name: secretName,
128 Namespace: constants.VPNNamespace,
129 Annotations: map[string]string{
130 SecretExpires: secrets.ExpireAt().Format(time.RFC3339),
131 },
132 OwnerReferences: createOwnerReferences(name, vpnConfig),
133 },
134 Data: map[string][]byte{
135 SecretPublicKey: []byte(instance.GetPublicKey()),
136 SecretPrivateKey: []byte(instance.GetPrivateKey()),
137 SecretIPAddress: []byte(instance.GetIPAddress().String()),
138 },
139 }
140 return c.Create(ctx, secret)
141 }
142
143 func updateInstanceSecret(ctx context.Context, c client.Client, name, clusterEdgeID string, instance *Instance) error {
144 secretName := k8objectsutils.NameWithPrefix(SecretPrefix+name, clusterEdgeID)
145 secret := &corev1.Secret{}
146 if err := c.Get(ctx, client.ObjectKey{Namespace: constants.VPNNamespace, Name: secretName}, secret); err != nil {
147 return err
148 }
149 secret.Data[SecretPublicKey] = []byte(instance.GetPublicKey())
150 secret.Data[SecretPrivateKey] = []byte(instance.GetPrivateKey())
151 secret.Data[SecretIPAddress] = []byte(instance.GetIPAddress().String())
152 return c.Update(ctx, secret)
153 }
154
155 func createOwnerReferences(name string, vpnConfig *v1vpnconfig.VPNConfig) []metav1.OwnerReference {
156 if name != constants.StoreName || vpnConfig == nil {
157 return []metav1.OwnerReference{}
158 }
159 return []metav1.OwnerReference{
160 {
161 APIVersion: vpnConfig.APIVersion,
162 Kind: vpnConfig.Kind,
163 Name: vpnConfig.GetName(),
164 UID: vpnConfig.GetUID(),
165 },
166 }
167 }
168
View as plain text