Skip to content

Commit a202e93

Browse files
committed
migrate from adal to azidentity
adal is is out of support since March 31, 2023. This PR migrates from adal to azidentity for azure key vault Signed-off-by: sp98 <sapillai@redhat.com>
1 parent 5f4b25c commit a202e93

File tree

6 files changed

+177
-83
lines changed

6 files changed

+177
-83
lines changed

azure/azure_kv.go

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import (
44
"context"
55
"encoding/json"
66
"errors"
7+
"strings"
78
"time"
89

9-
"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
10-
"github.com/Azure/go-autorest/autorest/to"
10+
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
11+
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
12+
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
1113
"github.com/libopenstorage/secrets"
1214
"github.com/portworx/sched-ops/task"
1315
)
@@ -21,6 +23,10 @@ const (
2123
AzureClientID = "AZURE_CLIENT_ID"
2224
// AzureClientSecret of service principal account
2325
AzureClientSecret = "AZURE_CLIENT_SECRET"
26+
// AzureClientCertPath is path of the client certificate
27+
AzureClientCertPath = "AZURE_CLIENT_CERT_PATH"
28+
// AzureClientCertPassword is the password of the private key
29+
AzureClientCertPassword = "AZURE_CIENT_CERT_PASSWORD"
2430
// AzureEnviornment to connect
2531
AzureEnviornment = "AZURE_ENVIRONMENT"
2632
// AzureVaultURI of azure key vault
@@ -37,6 +43,7 @@ var (
3743
ErrAzureTenantIDNotSet = errors.New("AZURE_TENANT_ID not set.")
3844
ErrAzureClientIDNotSet = errors.New("AZURE_CLIENT_ID not set.")
3945
ErrAzureSecretIDNotSet = errors.New("AZURE_SECRET_ID not set.")
46+
ErrAzureAuthMedhodNotSet = errors.New("AZURE_SECRET_ID or AZURE_CLIENT_CERT_PATH not set")
4047
ErrAzureVaultURLNotSet = errors.New("AZURE_VAULT_URL not set.")
4148
ErrAzureEnvironmentNotset = errors.New("AZURE_ENVIRONMENT not set.")
4249
ErrAzureConfigMissing = errors.New("AzureConfig is not provided")
@@ -45,7 +52,7 @@ var (
4552
)
4653

4754
type azureSecrets struct {
48-
kv keyvault.BaseClient
55+
kv azsecrets.Client
4956
baseURL string
5057
}
5158

@@ -62,26 +69,34 @@ func New(
6269
return nil, ErrAzureClientIDNotSet
6370
}
6471
secretID := getAzureKVParams(secretConfig, AzureClientSecret)
65-
if secretID == "" {
66-
return nil, ErrAzureSecretIDNotSet
67-
}
68-
envName := getAzureKVParams(secretConfig, AzureEnviornment)
69-
if envName == "" {
70-
// we set back to default AzurePublicCloud
71-
envName = AzureCloud
72-
}
72+
clientCertPath := getAzureKVParams(secretConfig, AzureClientCertPath)
73+
clientCertPassword := getAzureKVParams(secretConfig, AzureClientCertPassword)
74+
7375
vaultURL := getAzureKVParams(secretConfig, AzureVaultURL)
7476
if vaultURL == "" {
7577
return nil, ErrAzureVaultURLNotSet
7678
}
7779

78-
client, err := getAzureVaultClient(clientID, secretID, tenantID, envName)
79-
if err != nil {
80-
return nil, err
80+
clientOpts := getAzureClientOptions(secretConfig)
81+
82+
var client *azsecrets.Client
83+
var err error
84+
if secretID != "" {
85+
client, err = getAzureVaultClient(clientID, secretID, tenantID, vaultURL, clientOpts)
86+
if err != nil {
87+
return nil, err
88+
}
89+
} else if clientCertPath != "" {
90+
client, err = getAzureVaultClientWithCert(clientID, tenantID, vaultURL, clientCertPath, clientCertPassword, clientOpts)
91+
if err != nil {
92+
return nil, err
93+
}
94+
} else {
95+
return nil, ErrAzureAuthMedhodNotSet
8196
}
8297

8398
return &azureSecrets{
84-
kv: client,
99+
kv: *client,
85100
baseURL: vaultURL,
86101
}, nil
87102
}
@@ -98,8 +113,13 @@ func (az *azureSecrets) GetSecret(
98113
}
99114

100115
t := func() (interface{}, bool, error) {
101-
secretResp, err := az.kv.GetSecret(ctx, az.baseURL, secretID, "")
116+
// passing empty version to always get the latest version of the secret.
117+
secretResp, err := az.kv.GetSecret(ctx, secretID, "", nil)
102118
if err != nil {
119+
// don't retry if Secret is not present
120+
if strings.Contains(err.Error(), "SecretNotFound") {
121+
return nil, false, secrets.ErrSecretNotFound
122+
}
103123
return nil, true, err
104124
}
105125
return secretResp, false, nil
@@ -109,7 +129,7 @@ func (az *azureSecrets) GetSecret(
109129
return nil, secrets.NoVersion, err
110130
}
111131

112-
secretResp, ok := resp.(keyvault.SecretBundle)
132+
secretResp, ok := resp.(azsecrets.GetSecretResponse)
113133
if !ok || secretResp.Value == nil {
114134
return nil, secrets.NoVersion, ErrInvalidSecretResp
115135
}
@@ -133,7 +153,7 @@ func (az *azureSecrets) PutSecret(
133153
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
134154
defer cancel()
135155

136-
var secretResp keyvault.SecretBundle
156+
var secretResp azsecrets.SecretBundle
137157
if secretName == "" {
138158
return secrets.NoVersion, secrets.ErrEmptySecretId
139159
}
@@ -146,10 +166,10 @@ func (az *azureSecrets) PutSecret(
146166
return secrets.NoVersion, err
147167
}
148168

169+
valueStr := string(value)
149170
t := func() (interface{}, bool, error) {
150-
secretResp, err = az.kv.SetSecret(ctx, az.baseURL, secretName, keyvault.SecretSetParameters{
151-
Value: to.StringPtr(string(value)),
152-
})
171+
params := azsecrets.SetSecretParameters{Value: &valueStr}
172+
az.kv.SetSecret(ctx, secretName, params, nil)
153173
if err != nil {
154174
return nil, true, err
155175
}
@@ -169,7 +189,7 @@ func (az *azureSecrets) DeleteSecret(
169189
if secretName == "" {
170190
return secrets.ErrEmptySecretId
171191
}
172-
_, err := az.kv.DeleteSecret(ctx, az.baseURL, secretName)
192+
_, err := az.kv.DeleteSecret(ctx, secretName, nil)
173193

174194
return err
175195
}
@@ -213,3 +233,17 @@ func init() {
213233
panic(err.Error())
214234
}
215235
}
236+
237+
func getAzureClientOptions(secretConfig map[string]interface{}) azcore.ClientOptions {
238+
opts := azcore.ClientOptions{}
239+
cloudEnv := getAzureKVParams(secretConfig, AzureEnviornment)
240+
if strings.EqualFold(cloudEnv, "AzureUSGovernment") {
241+
opts.Cloud = cloud.AzureGovernment
242+
} else if strings.EqualFold(cloudEnv, "AzureChinaCloud") {
243+
opts.Cloud = cloud.AzureChina
244+
} else {
245+
opts.Cloud = cloud.AzurePublic
246+
}
247+
return opts
248+
249+
}

azure/azure_kv_helper.go

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package azure
22

33
import (
4-
"net/url"
4+
"fmt"
55
"os"
6-
"strings"
76

8-
"github.com/Azure/azure-sdk-for-go/services/keyvault/2016-10-01/keyvault"
9-
"github.com/Azure/go-autorest/autorest"
10-
"github.com/Azure/go-autorest/autorest/adal"
11-
"github.com/Azure/go-autorest/autorest/azure"
7+
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
8+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
9+
"github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets"
1210
)
1311

1412
func getAzureKVParams(secretConfig map[string]interface{}, name string) string {
@@ -19,29 +17,46 @@ func getAzureKVParams(secretConfig map[string]interface{}, name string) string {
1917
}
2018
}
2119

22-
func getAzureVaultClient(clientID, secretID, tenantID, envName string) (keyvault.BaseClient, error) {
23-
var environment *azure.Environment
24-
alternateEndpoint, _ := url.Parse(
25-
"https://login.windows.net/" + tenantID + "/oauth2/token")
20+
func getAzureVaultClient(clientID, secretID, tenantID, vaultURL string, opts azcore.ClientOptions) (*azsecrets.Client, error) {
21+
cred, err := azidentity.NewClientSecretCredential(tenantID, clientID, secretID, nil)
22+
if err != nil {
23+
return nil, fmt.Errorf("failed to get client secret credentials. %v", err)
24+
}
25+
client, err := azsecrets.NewClient(vaultURL, cred, &azsecrets.ClientOptions{ClientOptions: opts})
26+
if err != nil {
27+
return nil, fmt.Errorf("failed to get client to access azure kv secrets. %v", err)
28+
}
29+
30+
return client, nil
31+
}
32+
33+
func getAzureVaultClientWithCert(clientID, tenantID, vaultURL, certPath, certPassword string, opts azcore.ClientOptions) (*azsecrets.Client, error) {
34+
certData, err := os.ReadFile(certPath)
35+
if err != nil {
36+
return nil, fmt.Errorf("failed read certificate from path %q. %v", certPath, err)
37+
}
2638

27-
keyClient := keyvault.New()
28-
env, err := azure.EnvironmentFromName(envName)
39+
var passphrase []byte
40+
if certPassword == "" {
41+
passphrase = nil
42+
} else {
43+
passphrase = []byte(certPassword)
44+
}
45+
46+
certs, key, err := azidentity.ParseCertificates(certData, passphrase)
2947
if err != nil {
30-
return keyClient, err
48+
return nil, fmt.Errorf("failed load certificate and private key. %v", err)
3149
}
32-
environment = &env
33-
oauthconfig, err := adal.NewOAuthConfig(
34-
environment.ActiveDirectoryEndpoint, tenantID)
50+
51+
cred, err := azidentity.NewClientCertificateCredential(tenantID, clientID, certs, key, &azidentity.ClientCertificateCredentialOptions{ClientOptions: opts})
3552
if err != nil {
36-
return keyClient, err
53+
return nil, fmt.Errorf("failed to construct client certificate credentials. %v", err)
3754
}
38-
oauthconfig.AuthorizeEndpoint = *alternateEndpoint
3955

40-
token, err := adal.NewServicePrincipalToken(
41-
*oauthconfig, clientID, secretID, strings.TrimSuffix(environment.KeyVaultEndpoint, "/"))
56+
client, err := azsecrets.NewClient(vaultURL, cred, nil)
4257
if err != nil {
43-
return keyClient, err
58+
return nil, fmt.Errorf("failed to get client to access azure kv secrets. %v", err)
4459
}
45-
keyClient.Authorizer = autorest.NewBearerAuthorizer(token)
46-
return keyClient, nil
60+
61+
return client, nil
4762
}

azure/azure_kv_test.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,24 @@ func TestNew(t *testing.T) {
1111
os.Unsetenv("AZURE_TENANT_ID")
1212
os.Unsetenv("AZURE_CLIENT_ID")
1313
os.Unsetenv("AZURE_CLIENT_SECRET")
14+
os.Unsetenv("AZURE_CLIENT_CERT_PATH")
1415
os.Unsetenv("AZURE_ENVIRONMENT")
1516
os.Unsetenv("AZURE_VAULT_URL")
1617

1718
// nil secret config
1819
_, err := New(nil)
19-
assert.Equal(t, err, ErrAzureTenantIDNotSet)
20+
assert.Equal(t, ErrAzureTenantIDNotSet, err)
2021
os.Setenv("AZURE_TENANT_ID", "invalid_tenant_id")
2122

2223
_, err = New(nil)
23-
assert.Equal(t, err, ErrAzureClientIDNotSet)
24+
assert.Equal(t, ErrAzureClientIDNotSet, err)
2425
os.Setenv("AZURE_CLIENT_ID", "invalid-client-id")
2526

2627
_, err = New(nil)
27-
assert.Equal(t, err, ErrAzureSecretIDNotSet)
28-
os.Setenv("AZURE_CLIENT_SECRET", "invalid-secret-id")
29-
30-
_, err = New(nil)
31-
assert.Equal(t, err, ErrAzureVaultURLNotSet)
28+
assert.Equal(t, ErrAzureVaultURLNotSet, err)
3229
os.Setenv("AZURE_VAULT_URL", "invalid-vault-url")
3330

3431
_, err = New(nil)
35-
assert.NoError(t, err, "Unepxected error on New")
32+
assert.Equal(t, ErrAzureAuthMedhodNotSet, err)
33+
os.Setenv("AZURE_CLIENT_SECRET", "invalid-secret-id")
3634
}

go.mod

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ module github.com/libopenstorage/secrets
33
go 1.13
44

55
require (
6-
github.com/Azure/azure-sdk-for-go v62.0.0+incompatible
7-
github.com/Azure/go-autorest/autorest v0.11.27
8-
github.com/Azure/go-autorest/autorest/adal v0.9.20
9-
github.com/Azure/go-autorest/autorest/to v0.4.0
106
github.com/IBM/keyprotect-go-client v0.5.1
117
github.com/aws/aws-sdk-go v1.44.164
128
github.com/golang/mock v1.6.0
@@ -18,21 +14,21 @@ require (
1814
github.com/portworx/kvdb v0.0.0-20200929023115-b312c7519467
1915
github.com/portworx/sched-ops v1.20.4-rc1
2016
github.com/sirupsen/logrus v1.9.0
21-
github.com/stretchr/testify v1.8.0
17+
github.com/stretchr/testify v1.8.4
2218
google.golang.org/api v0.83.0
2319
k8s.io/client-go v12.0.0+incompatible
2420
)
2521

2622
require (
27-
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
23+
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1
24+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1
25+
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0
2826
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
2927
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
3028
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3129
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
3230
github.com/go-openapi/jsonreference v0.20.0 // indirect
3331
github.com/go-test/deep v1.0.8 // indirect
34-
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
35-
github.com/google/uuid v1.3.0 // indirect
3632
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
3733
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
3834
github.com/imdario/mergo v0.3.13 // indirect

0 commit comments

Comments
 (0)