blob: 40f6eeb4638b62453c590ed9e5ea2400dd312e5a [file] [log] [blame]
giolekvab64297c2021-12-13 14:36:32 +04001package main
2
3import (
4 "context"
5 "crypto"
6 "crypto/ed25519"
7 "crypto/rand"
8 "errors"
9 "fmt"
10
11 "inet.af/netaddr"
12
13 "github.com/slackhq/nebula/cert"
14
15 corev1 "k8s.io/api/core/v1"
16 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17 "k8s.io/client-go/kubernetes"
18
19 nebulav1 "github.com/giolekva/pcloud/core/nebula/controller/apis/nebula/v1"
20 clientset "github.com/giolekva/pcloud/core/nebula/controller/generated/clientset/versioned"
21)
22
23type nebulaCA struct {
24 Name string
25 Namespace string
26 Nodes []nebulaNode
27}
28
29type nebulaNode struct {
30 Name string
31 Namespace string
32 IP string
33}
34
35type Manager struct {
36 kubeClient kubernetes.Interface
37 nebulaClient clientset.Interface
38 namespace string
39 caSecretName string
40}
41
42func (m *Manager) ListAll() ([]*nebulaCA, error) {
43 ret := make([]*nebulaCA, 0)
44 cas, err := m.nebulaClient.LekvaV1().NebulaCAs("").List(context.TODO(), metav1.ListOptions{})
45 if err != nil {
46 return nil, err
47 }
48 for _, ca := range cas.Items {
49 ret = append(ret, &nebulaCA{
50 Name: ca.Name,
51 Namespace: ca.Namespace,
52 Nodes: make([]nebulaNode, 0),
53 })
54 }
55 nodes, err := m.nebulaClient.LekvaV1().NebulaNodes("").List(context.TODO(), metav1.ListOptions{})
56 if err != nil {
57 return nil, err
58 }
59 for _, node := range nodes.Items {
60 for _, ca := range ret {
61 if ca.Name == node.Spec.CAName {
62 ca.Nodes = append(ca.Nodes, nebulaNode{
63 Name: node.Name,
64 Namespace: node.Namespace,
65 IP: node.Spec.IPCidr,
66 })
67 }
68 }
69 }
70 return ret, nil
71}
72
73func (m *Manager) CreateNode(namespace, name, caNamespace, caName, ipCidr, pubKey string) (string, string, error) {
74 node := &nebulav1.NebulaNode{
75 ObjectMeta: metav1.ObjectMeta{
76 Name: name,
77 Namespace: namespace,
78 },
79 Spec: nebulav1.NebulaNodeSpec{
80 CAName: caName,
81 CANamespace: caNamespace,
82 IPCidr: ipCidr,
83 PubKey: pubKey,
84 SecretName: fmt.Sprintf("%s-cert", name),
85 },
86 }
87 node, err := m.nebulaClient.LekvaV1().NebulaNodes(namespace).Create(context.TODO(), node, metav1.CreateOptions{})
88 if err != nil {
89 return "", "", err
90 }
91 return node.Namespace, node.Name, nil
92}
93
94func (m *Manager) GetNodeCertQR(namespace, name string) ([]byte, error) {
95 secret, err := m.getNodeSecret(namespace, name)
96 if err != nil {
97 return nil, err
98 }
99 return secret.Data["host.png"], nil
100}
101
102func (m *Manager) GetCACertQR(namespace, name string) ([]byte, error) {
103 ca, err := m.nebulaClient.LekvaV1().NebulaCAs(namespace).Get(context.TODO(), name, metav1.GetOptions{})
104 if err != nil {
105 return nil, err
106 }
107 secret, err := m.kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), ca.Spec.SecretName, metav1.GetOptions{})
108 if err != nil {
109 return nil, err
110 }
111 return secret.Data["ca.png"], nil
112}
113
114func (m *Manager) getNextIP() (netaddr.IP, error) {
115 nodes, err := m.nebulaClient.LekvaV1().NebulaNodes(m.namespace).List(context.TODO(), metav1.ListOptions{})
116 if err != nil {
117 return netaddr.IP{}, err
118 }
119 var max netaddr.IP
120 for _, node := range nodes.Items {
121 ip := netaddr.MustParseIPPrefix(node.Spec.IPCidr)
122 if max.Less(ip.IP()) {
123 max = ip.IP()
124 }
125 }
126 n := max.Next()
127 if n.IsZero() {
128 return n, errors.New("IP address range exhausted")
129 }
130 return n, nil
131}
132
133func (m *Manager) Sign(message []byte) ([]byte, error) {
134 secret, err := m.kubeClient.CoreV1().Secrets(m.namespace).Get(context.TODO(), m.caSecretName, metav1.GetOptions{})
135 if err != nil {
136 return nil, err
137 }
138 edPriv, _, err := cert.UnmarshalEd25519PrivateKey(secret.Data["ca.key"])
139 if err != nil {
140 return nil, err
141 }
142 return edPriv.Sign(rand.Reader, message, crypto.Hash(0))
143}
144
145func (m *Manager) VerifySignature(message, signature []byte) (bool, error) {
146 secret, err := m.kubeClient.CoreV1().Secrets(m.namespace).Get(context.TODO(), m.caSecretName, metav1.GetOptions{})
147 if err != nil {
148 return false, err
149 }
150 edPriv, _, err := cert.UnmarshalEd25519PrivateKey(secret.Data["ca.key"])
151 if err != nil {
152 return false, err
153 }
154 return ed25519.Verify(edPriv.Public().(ed25519.PublicKey), message, signature), nil
155}
156
157func (m *Manager) getNodeSecret(namespace, name string) (*corev1.Secret, error) {
158 node, err := m.nebulaClient.LekvaV1().NebulaNodes(namespace).Get(context.TODO(), name, metav1.GetOptions{})
159 if err != nil {
160 return nil, err
161 }
162 return m.kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), node.Spec.SecretName, metav1.GetOptions{})
163}