@@ -3,22 +3,31 @@ package backends
3
3
import (
4
4
"context"
5
5
"fmt"
6
- "github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
6
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore"
7
+ "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
8
+ "github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
7
9
"github.com/argoproj-labs/argocd-vault-plugin/pkg/utils"
8
- "path"
9
- "strings"
10
10
"time"
11
11
)
12
12
13
13
// AzureKeyVault is a struct for working with an Azure Key Vault backend
14
14
type AzureKeyVault struct {
15
- Client keyvault.BaseClient
15
+ Credential azcore.TokenCredential
16
+ ClientBuilder func (vaultURL string , credential azcore.TokenCredential , options * azsecrets.ClientOptions ) (AzSecretsClient , error )
17
+ }
18
+
19
+ type AzSecretsClient interface {
20
+ GetSecret (ctx context.Context , name string , version string , options * azsecrets.GetSecretOptions ) (azsecrets.GetSecretResponse , error )
21
+ NewListSecretPropertiesPager (options * azsecrets.ListSecretPropertiesOptions ) * runtime.Pager [azsecrets.ListSecretPropertiesResponse ]
16
22
}
17
23
18
24
// NewAzureKeyVaultBackend initializes a new Azure Key Vault backend
19
- func NewAzureKeyVaultBackend (client keyvault. BaseClient ) * AzureKeyVault {
25
+ func NewAzureKeyVaultBackend (credential azcore. TokenCredential , clientBuilder func ( vaultURL string , credential azcore. TokenCredential , options * azsecrets. ClientOptions ) ( * azsecrets. Client , error ) ) * AzureKeyVault {
20
26
return & AzureKeyVault {
21
- Client : client ,
27
+ Credential : credential ,
28
+ ClientBuilder : func (vaultURL string , credential azcore.TokenCredential , options * azsecrets.ClientOptions ) (AzSecretsClient , error ) {
29
+ return clientBuilder (vaultURL , credential , options )
30
+ },
22
31
}
23
32
}
24
33
@@ -29,59 +38,55 @@ func (a *AzureKeyVault) Login() error {
29
38
30
39
// GetSecrets gets secrets from Azure Key Vault and returns the formatted data
31
40
// For Azure Key Vault, `kvpath` is the unique name of your vault
41
+ // For Azure use the version here not make really sens as each secret have a different version but let support it
32
42
func (a * AzureKeyVault ) GetSecrets (kvpath string , version string , _ map [string ]string ) (map [string ]interface {}, error ) {
33
43
kvpath = fmt .Sprintf ("https://%s.vault.azure.net" , kvpath )
34
44
35
45
ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
36
46
defer cancel ()
37
47
38
- data := make ( map [ string ] interface {} )
48
+ verboseOptionalVersion ( "Azure Key Vault list all secrets from vault %s" , version , kvpath )
39
49
40
- utils .VerboseToStdErr ("Azure Key Vault listing secrets in vault %v" , kvpath )
41
- secretList , err := a .Client .GetSecretsComplete (ctx , kvpath , nil )
50
+ client , err := a .ClientBuilder (kvpath , a .Credential , nil )
42
51
if err != nil {
43
52
return nil , err
44
53
}
45
54
46
- utils .VerboseToStdErr ("Azure Key Vault list secrets response %v" , secretList )
47
- // Gather all secrets in Key Vault
48
-
49
- for ; secretList .NotDone (); secretList .NextWithContext (ctx ) {
50
- secret := path .Base (* secretList .Value ().ID )
51
- if version == "" {
52
- utils .VerboseToStdErr ("Azure Key Vault getting secret %s from vault %s" , secret , kvpath )
53
- secretResp , err := a .Client .GetSecret (ctx , kvpath , secret , "" )
54
- if err != nil {
55
- return nil , err
56
- }
55
+ data := make (map [string ]interface {})
57
56
58
- utils .VerboseToStdErr ("Azure Key Vault get unversioned secret response %v" , secretResp )
59
- data [secret ] = * secretResp .Value
60
- continue
57
+ pager := client .NewListSecretPropertiesPager (nil )
58
+ for pager .More () {
59
+ page , err := pager .NextPage (ctx )
60
+ if err != nil {
61
+ return nil , err
61
62
}
62
- // In Azure Key Vault the versions of a secret is first shown after running GetSecretVersions. So we need
63
- // to loop through the versions for each secret in order to find the secret that has the specific version.
64
- secretVersions , _ := a .Client .GetSecretVersionsComplete (ctx , kvpath , secret , nil )
65
- for ; secretVersions .NotDone (); secretVersions .NextWithContext (ctx ) {
66
- secretVersion := secretVersions .Value ()
63
+ for _ , secretVersion := range page .Value {
67
64
// Azure Key Vault has ability to enable/disable a secret, so lets honour that
68
65
if ! * secretVersion .Attributes .Enabled {
69
66
continue
70
67
}
71
- // Secret version matched given version
72
- if strings .Contains (* secretVersion .ID , version ) {
73
- utils .VerboseToStdErr ("Azure Key Vault getting secret %s from vault %s at version %s" , secret , kvpath , version )
74
- secretResp , err := a .Client .GetSecret (ctx , kvpath , secret , version )
68
+ name := secretVersion .ID .Name ()
69
+ // Secret version matched given version ?
70
+ if version == "" || secretVersion .ID .Version () == version {
71
+ verboseOptionalVersion ("Azure Key Vault getting secret %s from vault %s" , version , name , kvpath )
72
+ secret , err := client .GetSecret (ctx , name , version , nil )
75
73
if err != nil {
76
74
return nil , err
77
75
}
78
-
79
- utils .VerboseToStdErr ("Azure Key Vault get versioned secret response %v" , secretResp )
80
- data [secret ] = * secretResp .Value
76
+ utils .VerboseToStdErr ("Azure Key Vault get secret response %v" , secret )
77
+ data [name ] = * secret .Value
78
+ } else {
79
+ verboseOptionalVersion ("Azure Key Vault getting secret %s from vault %s" , version , name , kvpath )
80
+ secret , err := client .GetSecret (ctx , name , version , nil )
81
+ if err != nil || ! * secretVersion .Attributes .Enabled {
82
+ utils .VerboseToStdErr ("Azure Key Vault get versioned secret not found %s" , err )
83
+ continue
84
+ }
85
+ utils .VerboseToStdErr ("Azure Key Vault get versioned secret response %v" , secret )
86
+ data [name ] = * secret .Value
81
87
}
82
88
}
83
89
}
84
-
85
90
return data , nil
86
91
}
87
92
@@ -92,15 +97,28 @@ func (a *AzureKeyVault) GetIndividualSecret(kvpath, secret, version string, anno
92
97
ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
93
98
defer cancel ()
94
99
95
- utils . VerboseToStdErr ("Azure Key Vault getting secret %s from vault %s at version %s" , secret , kvpath , version )
100
+ verboseOptionalVersion ("Azure Key Vault getting individual secret %s from vault %s" , version , secret , kvpath )
96
101
97
102
kvpath = fmt .Sprintf ("https://%s.vault.azure.net" , kvpath )
98
- data , err := a .Client .GetSecret (ctx , kvpath , secret , version )
103
+ client , err := a .ClientBuilder (kvpath , a .Credential , nil )
104
+ if err != nil {
105
+ return nil , err
106
+ }
107
+
108
+ data , err := client .GetSecret (ctx , secret , version , nil )
99
109
if err != nil {
100
110
return nil , err
101
111
}
102
112
103
- utils .VerboseToStdErr ("Azure Key Vault get versioned secret response %v" , data )
113
+ utils .VerboseToStdErr ("Azure Key Vault get individual secret response %v" , data )
104
114
105
115
return * data .Value , nil
106
116
}
117
+
118
+ func verboseOptionalVersion (format string , version string , message ... interface {}) {
119
+ if version == "" {
120
+ utils .VerboseToStdErr (format , message ... )
121
+ } else {
122
+ utils .VerboseToStdErr (format + " at version %s" , append (message , version )... )
123
+ }
124
+ }
0 commit comments