-
Notifications
You must be signed in to change notification settings - Fork 19
/
ssh.go
143 lines (120 loc) · 3.73 KB
/
ssh.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package generator
import (
"bytes"
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/ForgeRock/secret-agent/api/v1alpha1"
"github.com/ForgeRock/secret-agent/pkg/secretsmanager"
"github.com/pkg/errors"
sshlib "golang.org/x/crypto/ssh"
corev1 "k8s.io/api/core/v1"
)
// SSH randomly generated of specified length
type SSH struct {
Name string
PrivateKeyRSA *rsa.PrivateKey
PrivateKeyPEM []byte
PublicKeyPEM []byte
}
// References return names of secrets that should be looked up
func (ssh *SSH) References() ([]string, []string) {
return []string{}, []string{}
}
// LoadReferenceData loads references from data
func (ssh *SSH) LoadReferenceData(data map[string][]byte) error {
return nil
}
// LoadSecretFromManager populates SSH data from secret manager
func (ssh *SSH) LoadSecretFromManager(context context.Context, sm secretsmanager.SecretManager, namespace, secretName string) error {
var err error
sshPrivateFmt := fmt.Sprintf("%s_%s_%s", namespace, secretName, ssh.Name)
sshPublicFmt := fmt.Sprintf("%s_%s_%s.pub", namespace, secretName, ssh.Name)
ssh.PrivateKeyPEM, err = sm.LoadSecret(context, sshPrivateFmt)
if err != nil {
return err
}
ssh.PublicKeyPEM, err = sm.LoadSecret(context, sshPublicFmt)
if err != nil {
return err
}
return nil
}
// EnsureSecretManager populates secrets manager from SSH data
func (ssh *SSH) EnsureSecretManager(context context.Context, sm secretsmanager.SecretManager, namespace, secretName string) error {
sshPrivateFmt := fmt.Sprintf("%s_%s_%s", namespace, secretName, ssh.Name)
sshPublicFmt := fmt.Sprintf("%s_%s_%s.pub", namespace, secretName, ssh.Name)
if err := sm.EnsureSecret(context, sshPrivateFmt, ssh.PrivateKeyPEM); err != nil {
return err
}
if err := sm.EnsureSecret(context, sshPublicFmt, ssh.PublicKeyPEM); err != nil {
return err
}
return nil
}
// InSecret return true if the key is one found in the secret
func (ssh *SSH) InSecret(secObject *corev1.Secret) bool {
if secObject.Data == nil || secObject.Data[ssh.Name] == nil || ssh.IsEmpty() {
return false
}
if bytes.Compare(ssh.PrivateKeyPEM, secObject.Data[ssh.Name]) == 0 &&
bytes.Compare(ssh.PublicKeyPEM, secObject.Data[fmt.Sprintf("%s.pub", ssh.Name)]) == 0 {
return true
}
return false
}
// Generate generates data
func (ssh *SSH) Generate() error {
var err error
ssh.PrivateKeyRSA, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return errors.WithStack(err)
}
publicKey, err := sshlib.NewPublicKey(&ssh.PrivateKeyRSA.PublicKey)
if err != nil {
return errors.WithStack(err)
}
buffer := &bytes.Buffer{}
block := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(ssh.PrivateKeyRSA),
}
if err := pem.Encode(buffer, block); err != nil {
return errors.WithStack(err)
}
ssh.PrivateKeyPEM = buffer.Bytes()
ssh.PublicKeyPEM = sshlib.MarshalAuthorizedKey(publicKey)
return nil
}
// IsEmpty boolean determines if the struct is empty
func (ssh *SSH) IsEmpty() bool {
if len(ssh.PrivateKeyPEM) == 0 || len(ssh.PublicKeyPEM) == 0 {
return true
}
return false
}
// LoadFromData loads data from kubernetes secret
func (ssh *SSH) LoadFromData(secData map[string][]byte) {
ssh.PrivateKeyPEM = secData[ssh.Name]
ssh.PublicKeyPEM = secData[fmt.Sprintf("%s.pub", ssh.Name)]
return
}
// ToKubernetes "marshals" object to kubernetes object
func (ssh *SSH) ToKubernetes(secret *corev1.Secret) {
// data could be nil
if secret.Data == nil {
secret.Data = make(map[string][]byte)
}
secret.Data[ssh.Name] = ssh.PrivateKeyPEM
secret.Data[fmt.Sprintf("%s.pub", ssh.Name)] = ssh.PublicKeyPEM
}
// NewSSH creates new SSH type for reconciliation
func NewSSH(keyConfig *v1alpha1.KeyConfig) *SSH {
ssh := &SSH{
Name: keyConfig.Name,
}
return ssh
}