blob: 962b3b764fcca6508de8b7d160bd96650f2b813e [file] [log] [blame]
giolekvab64297c2021-12-13 14:36:32 +04001package main
2
3import (
4 "context"
5 "crypto"
6 "crypto/ed25519"
7 "crypto/rand"
giolekva3f0dcda2021-12-22 23:32:49 +04008 "crypto/rsa"
9 "crypto/x509"
10 "encoding/base64"
giolekvab64297c2021-12-13 14:36:32 +040011 "fmt"
12
giolekvacc3ebcb2021-12-17 10:52:17 +040013 "github.com/jinzhu/copier"
giolekvab64297c2021-12-13 14:36:32 +040014 "github.com/slackhq/nebula/cert"
15
16 corev1 "k8s.io/api/core/v1"
17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18 "k8s.io/client-go/kubernetes"
19
20 nebulav1 "github.com/giolekva/pcloud/core/nebula/controller/apis/nebula/v1"
21 clientset "github.com/giolekva/pcloud/core/nebula/controller/generated/clientset/versioned"
22)
23
24type nebulaCA struct {
25 Name string
26 Namespace string
27 Nodes []nebulaNode
28}
29
30type nebulaNode struct {
31 Name string
32 Namespace string
33 IP string
34}
35
36type Manager struct {
37 kubeClient kubernetes.Interface
38 nebulaClient clientset.Interface
39 namespace string
giolekvaf58a7692021-12-15 18:05:39 +040040 caName string
giolekvacc3ebcb2021-12-17 10:52:17 +040041 cfgTmpl map[string]interface{}
giolekvab64297c2021-12-13 14:36:32 +040042}
43
44func (m *Manager) ListAll() ([]*nebulaCA, error) {
45 ret := make([]*nebulaCA, 0)
46 cas, err := m.nebulaClient.LekvaV1().NebulaCAs("").List(context.TODO(), metav1.ListOptions{})
47 if err != nil {
48 return nil, err
49 }
50 for _, ca := range cas.Items {
51 ret = append(ret, &nebulaCA{
52 Name: ca.Name,
53 Namespace: ca.Namespace,
54 Nodes: make([]nebulaNode, 0),
55 })
56 }
57 nodes, err := m.nebulaClient.LekvaV1().NebulaNodes("").List(context.TODO(), metav1.ListOptions{})
58 if err != nil {
59 return nil, err
60 }
61 for _, node := range nodes.Items {
62 for _, ca := range ret {
63 if ca.Name == node.Spec.CAName {
64 ca.Nodes = append(ca.Nodes, nebulaNode{
65 Name: node.Name,
66 Namespace: node.Namespace,
67 IP: node.Spec.IPCidr,
68 })
69 }
70 }
71 }
72 return ret, nil
73}
74
giolekva3f0dcda2021-12-22 23:32:49 +040075func (m *Manager) CreateNode(namespace, name, caNamespace, caName, ipCidr, pubKey string, encPubKey []byte) (string, string, error) {
giolekvab64297c2021-12-13 14:36:32 +040076 node := &nebulav1.NebulaNode{
77 ObjectMeta: metav1.ObjectMeta{
78 Name: name,
79 Namespace: namespace,
80 },
81 Spec: nebulav1.NebulaNodeSpec{
82 CAName: caName,
83 CANamespace: caNamespace,
84 IPCidr: ipCidr,
85 PubKey: pubKey,
86 SecretName: fmt.Sprintf("%s-cert", name),
87 },
88 }
giolekva3f0dcda2021-12-22 23:32:49 +040089 if encPubKey != nil {
90 node.Spec.EncPubKey = base64.StdEncoding.EncodeToString(encPubKey)
91 }
giolekvab64297c2021-12-13 14:36:32 +040092 node, err := m.nebulaClient.LekvaV1().NebulaNodes(namespace).Create(context.TODO(), node, metav1.CreateOptions{})
93 if err != nil {
94 return "", "", err
95 }
96 return node.Namespace, node.Name, nil
97}
98
giolekvacc3ebcb2021-12-17 10:52:17 +040099func (m *Manager) GetNodeConfig(namespace, name string) (map[string]interface{}, error) {
100 secret, err := m.getNodeSecret(namespace, name)
101 if err != nil {
102 return nil, err
103 }
104 var c map[string]interface{}
105 if err := copier.CopyWithOption(&c, m.cfgTmpl, copier.Option{DeepCopy: true}); err != nil {
106 return nil, err
107 }
108 var pki map[string]interface{}
109 var ok bool
110 if pki, ok = c["pki"].(map[string]interface{}); !ok {
111 panic("Should not reach")
112 }
113 pki["ca"] = string(secret.Data["ca.crt"])
114 pki["cert"] = string(secret.Data["host.crt"])
115 return c, nil
116}
117
giolekvab64297c2021-12-13 14:36:32 +0400118func (m *Manager) GetNodeCertQR(namespace, name string) ([]byte, error) {
119 secret, err := m.getNodeSecret(namespace, name)
120 if err != nil {
121 return nil, err
122 }
123 return secret.Data["host.png"], nil
124}
125
126func (m *Manager) GetCACertQR(namespace, name string) ([]byte, error) {
giolekvaf58a7692021-12-15 18:05:39 +0400127 secret, err := m.getCASecret(namespace, name)
giolekvab64297c2021-12-13 14:36:32 +0400128 if err != nil {
129 return nil, err
130 }
131 return secret.Data["ca.png"], nil
132}
133
giolekvab64297c2021-12-13 14:36:32 +0400134func (m *Manager) Sign(message []byte) ([]byte, error) {
giolekvaf58a7692021-12-15 18:05:39 +0400135 secret, err := m.getCASecret(m.namespace, m.caName)
giolekvab64297c2021-12-13 14:36:32 +0400136 if err != nil {
137 return nil, err
138 }
139 edPriv, _, err := cert.UnmarshalEd25519PrivateKey(secret.Data["ca.key"])
140 if err != nil {
141 return nil, err
142 }
143 return edPriv.Sign(rand.Reader, message, crypto.Hash(0))
144}
145
146func (m *Manager) VerifySignature(message, signature []byte) (bool, error) {
giolekvaf58a7692021-12-15 18:05:39 +0400147 secret, err := m.getCASecret(m.namespace, m.caName)
giolekvab64297c2021-12-13 14:36:32 +0400148 if err != nil {
149 return false, err
150 }
151 edPriv, _, err := cert.UnmarshalEd25519PrivateKey(secret.Data["ca.key"])
152 if err != nil {
153 return false, err
154 }
155 return ed25519.Verify(edPriv.Public().(ed25519.PublicKey), message, signature), nil
156}
157
giolekvaf58a7692021-12-15 18:05:39 +0400158func (m *Manager) getCASecret(namespace, name string) (*corev1.Secret, error) {
159 ca, err := m.nebulaClient.LekvaV1().NebulaCAs(namespace).Get(context.TODO(), name, metav1.GetOptions{})
160 if err != nil {
161 return nil, err
162 }
163 return m.kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), ca.Spec.SecretName, metav1.GetOptions{})
164}
165
giolekvab64297c2021-12-13 14:36:32 +0400166func (m *Manager) getNodeSecret(namespace, name string) (*corev1.Secret, error) {
167 node, err := m.nebulaClient.LekvaV1().NebulaNodes(namespace).Get(context.TODO(), name, metav1.GetOptions{})
168 if err != nil {
169 return nil, err
170 }
171 return m.kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), node.Spec.SecretName, metav1.GetOptions{})
172}
giolekva3f0dcda2021-12-22 23:32:49 +0400173
174func (m *Manager) GetNodeEncryptionPublicKey(namespace, name string) (*rsa.PublicKey, error) {
175 node, err := m.nebulaClient.LekvaV1().NebulaNodes(namespace).Get(context.TODO(), name, metav1.GetOptions{})
176 if err != nil {
177 return nil, err
178 }
179 k, err := base64.StdEncoding.DecodeString(node.Spec.EncPubKey)
180 if err != nil {
181 return nil, err
182 }
183 return x509.ParsePKCS1PublicKey(k)
184}