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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package component
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"time"
"k8s.io/client-go/rest"
)
var ErrRemoteVaultDisabled = errors.New("component: RemoteOpenBao vault access is disabled")
type KCPClient interface {
Workspace() string
RESTConfig() *rest.Config
}
type KCPClients interface {
Client(workspace string) (KCPClient, error)
}
type KCPClientsFunc func(workspace string) (KCPClient, error)
func (f KCPClientsFunc) Client(workspace string) (KCPClient, error) {
return f(workspace)
}
type CredentialRef struct {
Server string
Mount string
Path string
Version int
Keys []string
}
func (r CredentialRef) Check() error {
switch {
case r.Mount == "":
return errors.New("component: the credential ref has no mount")
case r.Path == "":
return fmt.Errorf("component: the credential ref in mount %q has no path", r.Mount)
case r.Version < 0:
return fmt.Errorf("component: the credential ref %s/%s has a negative version", r.Mount, r.Path)
}
return nil
}
type Credential struct {
Ref CredentialRef
Data map[string]any
LeaseID string
Renewable bool
ExpiresAt time.Time
}
func (c Credential) Value(key string) (string, bool) {
v, ok := c.Data[key]
if !ok {
return "", false
}
switch value := v.(type) {
case string:
return value, true
case []byte:
return string(value), true
default:
return "", false
}
}
func (c Credential) Bytes(key string) ([]byte, bool) {
v, ok := c.Data[key]
if !ok {
return nil, false
}
switch value := v.(type) {
case string:
return []byte(value), true
case []byte:
return append([]byte(nil), value...), true
default:
return nil, false
}
}
type CredentialResolver interface {
Resolve(ctx context.Context, ref CredentialRef) (Credential, error)
}
type CredentialResolverFunc func(ctx context.Context, ref CredentialRef) (Credential, error)
func (f CredentialResolverFunc) Resolve(ctx context.Context, ref CredentialRef) (Credential, error) {
return f(ctx, ref)
}
type CredentialWriter interface {
WriteCredential(ctx context.Context, ref CredentialRef, data map[string]any) error
}
type CredentialDeleter interface {
DeleteCredential(ctx context.Context, ref CredentialRef) error
}
type CertificateRequest struct {
Mount string
Role string
CommonName string
AltNames []string
IPSANs []string
TTL time.Duration
}
type Certificate struct {
CertificatePEM []byte
PrivateKeyPEM []byte
IssuingCAPEM []byte
CAChainPEM [][]byte
Serial string
}
type VaultClient interface {
ReadKV(ctx context.Context, mount, path string) (map[string]any, error)
IssueCertificate(ctx context.Context, req CertificateRequest) (Certificate, error)
}
type VaultClients interface {
Client(ctx context.Context, server string) (VaultClient, error)
}
type VaultClientsFunc func(ctx context.Context, server string) (VaultClient, error)
func (f VaultClientsFunc) Client(ctx context.Context, server string) (VaultClient, error) {
return f(ctx, server)
}
func (c Certificate) TLSConfig() (*tls.Config, error) {
if len(c.CertificatePEM) == 0 || len(c.PrivateKeyPEM) == 0 {
return nil, errors.New("component: a TLS config needs a certificate and its key")
}
pair, err := tls.X509KeyPair(c.CertificatePEM, c.PrivateKeyPEM)
if err != nil {
return nil, fmt.Errorf("component: the certificate and key: %w", err)
}
cfg := &tls.Config{Certificates: []tls.Certificate{pair}, MinVersion: tls.VersionTLS12}
chain := c.CAChainPEM
if len(chain) == 0 && len(c.IssuingCAPEM) > 0 {
chain = [][]byte{c.IssuingCAPEM}
}
if len(chain) > 0 {
pool := x509.NewCertPool()
for _, entry := range chain {
if !pool.AppendCertsFromPEM(entry) {
return nil, errors.New("component: the certificate CA chain holds no certificate")
}
}
cfg.RootCAs = pool
}
return cfg, nil
}
type VaultSession interface {
VaultClient
WriteKV(ctx context.Context, mount, path string, data map[string]any) error
DeleteKV(ctx context.Context, mount, path string) error
}