/
keyvault.go
150 lines (120 loc) · 4.03 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
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
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation and Dapr Contributors.
// Licensed under the MIT License.
// ------------------------------------------------------------
package keyvault
import (
"context"
"fmt"
"strconv"
"strings"
kv "github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
"github.com/dapr/components-contrib/secretstores"
"github.com/dapr/kit/logger"
)
// Keyvault secret store component metadata properties
const (
componentSPNCertificate = "spnCertificate"
componentSPNCertificateFile = "spnCertificateFile"
componentSPNCertificatePassword = "spnCertificatePassword"
componentSPNClientID = "spnClientId"
componentSPNTenantID = "spnTenantId"
componentVaultName = "vaultName"
VersionID = "version_id"
secretItemIDPrefix = "/secrets/"
)
type keyvaultSecretStore struct {
vaultName string
vaultClient kv.BaseClient
logger logger.Logger
}
// NewAzureKeyvaultSecretStore returns a new Kubernetes secret store
func NewAzureKeyvaultSecretStore(logger logger.Logger) secretstores.SecretStore {
return &keyvaultSecretStore{
vaultName: "",
vaultClient: kv.New(),
logger: logger,
}
}
// Init creates a Kubernetes client
func (k *keyvaultSecretStore) Init(metadata secretstores.Metadata) error {
settings := EnvironmentSettings{
Values: metadata.Properties,
}
authorizer, err := settings.GetAuthorizer()
if err == nil {
k.vaultClient.Authorizer = authorizer
}
k.vaultName = settings.Values[componentVaultName]
return err
}
// GetSecret retrieves a secret using a key and returns a map of decrypted string/string values
func (k *keyvaultSecretStore) GetSecret(req secretstores.GetSecretRequest) (secretstores.GetSecretResponse, error) {
versionID := ""
if value, ok := req.Metadata[VersionID]; ok {
versionID = value
}
secretResp, err := k.vaultClient.GetSecret(context.Background(), k.getVaultURI(), req.Name, versionID)
if err != nil {
return secretstores.GetSecretResponse{}, err
}
secretValue := ""
if secretResp.Value != nil {
secretValue = *secretResp.Value
}
return secretstores.GetSecretResponse{
Data: map[string]string{
req.Name: secretValue,
},
}, nil
}
// BulkGetSecret retrieves all secrets in the store and returns a map of decrypted string/string values
func (k *keyvaultSecretStore) BulkGetSecret(req secretstores.BulkGetSecretRequest) (secretstores.BulkGetSecretResponse, error) {
vaultURI := k.getVaultURI()
maxResults, err := k.getMaxResultsFromMetadata(req.Metadata)
if err != nil {
return secretstores.BulkGetSecretResponse{}, err
}
secretsResp, err := k.vaultClient.GetSecretsComplete(context.Background(), vaultURI, maxResults)
if err != nil {
return secretstores.BulkGetSecretResponse{}, err
}
resp := secretstores.BulkGetSecretResponse{
Data: map[string]map[string]string{},
}
secretIDPrefix := vaultURI + secretItemIDPrefix
for secretsResp.NotDone() {
secretEnabled := secretsResp.Value().Attributes.Enabled
if *secretEnabled {
secretItem := secretsResp.Value()
secretName := strings.TrimPrefix(*secretItem.ID, secretIDPrefix)
secretResp, err := k.vaultClient.GetSecret(context.Background(), vaultURI, secretName, "")
if err != nil {
return secretstores.BulkGetSecretResponse{}, err
}
secretValue := ""
if secretResp.Value != nil {
secretValue = *secretResp.Value
}
resp.Data[secretName] = map[string]string{secretName: secretValue}
}
secretsResp.NextWithContext(context.Background())
}
return resp, nil
}
// getVaultURI returns Azure Key Vault URI
func (k *keyvaultSecretStore) getVaultURI() string {
return fmt.Sprintf("https://%s.vault.azure.net", k.vaultName)
}
func (k *keyvaultSecretStore) getMaxResultsFromMetadata(metadata map[string]string) (*int32, error) {
if s, ok := metadata["maxresults"]; ok && s != "" {
/* #nosec */
val, err := strconv.Atoi(s)
if err != nil {
return nil, err
}
converted := int32(val)
return &converted, nil
}
return nil, nil
}