-
Notifications
You must be signed in to change notification settings - Fork 8
/
keyvault.go
101 lines (90 loc) · 2.59 KB
/
keyvault.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
package keyvault
import (
"context"
"crypto/x509"
"encoding/base64"
"errors"
"os"
"strings"
vault "github.com/hashicorp/vault/api"
"github.com/notaryproject/notation-hashicorp-vault/internal/crypto"
)
type VaultClientWrapper struct {
vaultClient *vault.Client
keyID string
kvEngineName string
transitEngineName string
transitKeyID string
}
func NewVaultClientFromKeyID(id string, pluginConfig map[string]string) (*VaultClientWrapper, error) {
// read addr and token from environment variables
vaultAddr := os.Getenv("VAULT_ADDR")
if len(vaultAddr) < 1 {
return nil, errors.New("failed to load vault address")
}
// prepare a client with the given base address
client, err := vault.NewClient(&vault.Config{
Address: vaultAddr,
})
if err != nil {
return nil, err
}
transitName, ok := pluginConfig["transitName"]
if !ok {
transitName = "transit"
}
kvName, ok := pluginConfig["kvName"]
if !ok {
kvName = "secret"
}
transitKeyName, ok := pluginConfig["transitKeyName"]
if !ok {
transitKeyName = id
}
return &VaultClientWrapper{
vaultClient: client,
keyID: id,
kvEngineName: kvName,
transitEngineName: transitName,
transitKeyID: transitKeyName,
}, nil
}
func (vw *VaultClientWrapper) GetCertificateChain(ctx context.Context) ([]*x509.Certificate, error) {
// read a certChain
secret, err := vw.vaultClient.KVv2(vw.kvEngineName).Get(ctx, vw.keyID)
if err != nil {
return nil, err
}
certString, ok := secret.Data["certificate"].(string)
if !ok {
return nil, errors.New("failed to parse certificate from KV secrets engine")
}
certBytes := []byte(certString)
return crypto.ParseCertificates(certBytes)
}
func (vw *VaultClientWrapper) SignWithTransit(ctx context.Context, encodedData string, signAlgorithm string, hashAlgorithm string) ([]byte, error) {
// sign with transit SE
transitSignReq := map[string]interface{}{
"input": encodedData,
"marshaling_algorithm": "asn1",
"prehashed": true,
"salt_length": "hash",
"signature_algorithm": signAlgorithm,
"hash_algorithm": hashAlgorithm,
}
path := vw.transitEngineName + "/sign/" + vw.transitKeyID
resp, err := vw.vaultClient.Logical().WriteWithContext(ctx, path, transitSignReq)
if err != nil {
return nil, err
}
signature, ok := resp.Data["signature"].(string)
if !ok {
return nil, errors.New("failed to parse signature from TransitSign response")
}
items := strings.Split(signature, ":")
sigBytes, err := base64.StdEncoding.DecodeString(items[2])
if err != nil {
return nil, err
}
return sigBytes, nil
}