forked from bitnami-labs/sealed-secrets
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keyregistry.go
103 lines (90 loc) · 2.63 KB
/
keyregistry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package main
import (
"context"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"sync"
"time"
"github.com/bitnami-labs/sealed-secrets/pkg/crypto"
"k8s.io/client-go/kubernetes"
certUtil "k8s.io/client-go/util/cert"
)
// A Key holds the cryptographic key pair and some metadata about it.
type Key struct {
private *rsa.PrivateKey
cert *x509.Certificate
fingerprint string
creationTime time.Time
}
// A KeyRegistry manages the key pairs used to (un)seal secrets.
type KeyRegistry struct {
sync.Mutex
client kubernetes.Interface
namespace string
keyPrefix string
keyLabel string
keysize int
keys map[string]*Key
mostRecentKey *Key
}
// NewKeyRegistry creates a new KeyRegistry.
func NewKeyRegistry(client kubernetes.Interface, namespace, keyPrefix, keyLabel string, keysize int) *KeyRegistry {
return &KeyRegistry{
client: client,
namespace: namespace,
keyPrefix: keyPrefix,
keysize: keysize,
keyLabel: keyLabel,
keys: map[string]*Key{},
}
}
func (kr *KeyRegistry) generateKey(ctx context.Context) (string, error) {
key, cert, err := generatePrivateKeyAndCert(kr.keysize)
if err != nil {
return "", err
}
certs := []*x509.Certificate{cert}
generatedName, err := writeKey(ctx, kr.client, key, certs, kr.namespace, kr.keyLabel, kr.keyPrefix)
if err != nil {
return "", err
}
// Only store key to local store if write to k8s worked
if err := kr.registerNewKey(generatedName, key, cert, time.Now()); err != nil {
return "", err
}
log.Printf("New key written to %s/%s\n", kr.namespace, generatedName)
log.Printf("Certificate is \n%s\n", pem.EncodeToMemory(&pem.Block{Type: certUtil.CertificateBlockType, Bytes: cert.Raw}))
return generatedName, nil
}
func (kr *KeyRegistry) registerNewKey(keyName string, privKey *rsa.PrivateKey, cert *x509.Certificate, creationTime time.Time) error {
fingerprint, err := crypto.PublicKeyFingerprint(&privKey.PublicKey)
if err != nil {
return err
}
k := &Key{
private: privKey,
cert: cert,
fingerprint: fingerprint,
creationTime: creationTime,
}
kr.keys[k.fingerprint] = k
if kr.mostRecentKey == nil || kr.mostRecentKey.creationTime.Before(creationTime) {
kr.mostRecentKey = k
}
return nil
}
func (kr *KeyRegistry) latestPrivateKey() *rsa.PrivateKey {
return kr.mostRecentKey.private
}
// getCert returns the current certificate. This method can be called by another goroutine.
func (kr *KeyRegistry) getCert() (*x509.Certificate, error) {
kr.Lock()
defer kr.Unlock()
if kr.mostRecentKey == nil {
return nil, fmt.Errorf("key registry has no keys")
}
return kr.mostRecentKey.cert, nil
}