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
package vault
import (
"context"
"errors"
"fmt"
"log/slog"
commonv1 "github.com/johnandersen777/socialweb-computer-kcp/api/common/v1alpha1"
"github.com/johnandersen777/socialweb-computer-kcp/internal/bus"
contractvault "github.com/johnandersen777/socialweb-computer-kcp/internal/contract/vault"
"github.com/johnandersen777/socialweb-computer-kcp/internal/kit/tlsreload"
"github.com/johnandersen777/socialweb-computer-kcp/internal/vault/openbao"
)
var caKeys = []string{"caBundle", "ca.crt", "ca", "certificate", "value"}
type Roots struct {
bus *bus.Bus
log *slog.Logger
pools tlsreload.Pools
}
func NewRoots(b *bus.Bus, log *slog.Logger) *Roots {
if log == nil {
log = slog.New(slog.DiscardHandler)
}
return &Roots{bus: b, log: log}
}
func (r *Roots) Pool(ctx context.Context, from commonv1.ObjectRef, caRef *commonv1.ObjectRef, caSecret *commonv1.SecretRef) (*tlsreload.Pool, error) {
if caRef != nil && caRef.IsZero() {
caRef = nil
}
switch {
case caRef == nil && caSecret == nil:
return nil, nil
case caRef != nil && caSecret != nil:
return nil, errors.New("vault: tls names both caRef and caSecretRef")
case r == nil || r.bus == nil:
return nil, errors.New("vault: the CA refs need the bus")
}
fingerprint := ""
if caRef != nil {
fingerprint = "trust:" + caRef.String()
} else {
to, _, _, err := secretTarget(from, *caSecret)
if err != nil {
return nil, err
}
fingerprint = "secret:" + to.String() + "/" + SecretScope(*caSecret) + "#" + caSecret.Key
}
return r.pools.Get(from.String(), fingerprint, func() (*tlsreload.Pool, func(), error) {
if caRef != nil {
to := *caRef
to.Workspace = to.InWorkspace(from.Workspace)
trust, err := bus.Resolve[contractvault.Trust](ctx, r.bus, from, to,
bus.Capability{Name: contractvault.CapabilityRead, Scope: []string{contractvault.TrustScope}})
if err != nil {
return nil, nil, fmt.Errorf("vault: the CA bundle of %s for %s: %w", to.String(), from.String(), err)
}
pool, stop := tlsreload.TrustPool(ctx, trust, r.log.With("ca", to.String()))
return pool, stop, nil
}
ref := *caSecret
pool := tlsreload.SecretPool(func(ctx context.Context) ([]byte, error) {
data, err := ReadSecret(ctx, r.bus, from, ref)
if err != nil {
return nil, err
}
value := SecretValue(data, ref.Key, caKeys...)
if value == "" {
return nil, fmt.Errorf("vault: the CA secret %s holds no CA bundle", SecretScope(ref))
}
return []byte(value), nil
}, SecretRenew, r.log)
return pool, func() {}, nil
})
}
func (r *Roots) Drop(from commonv1.ObjectRef) {
if r != nil {
r.pools.Drop(from.String())
}
}
func Remote(b *bus.Bus, log *slog.Logger) *openbao.Remote {
roots := NewRoots(b, log)
return &openbao.Remote{Enabled: true, Roots: roots.Pool, Release: roots.Drop,
Secrets: func(ctx context.Context, from commonv1.ObjectRef, ref commonv1.SecretRef) (map[string]any, error) {
return ReadSecret(ctx, b, from, ref)
}}
}