Skip to content

Commit

Permalink
cache credentials from AzureClusterIdentity
Browse files Browse the repository at this point in the history
  • Loading branch information
nojnhuh committed Sep 23, 2024
1 parent fa56973 commit b8f23bd
Show file tree
Hide file tree
Showing 33 changed files with 250 additions and 158 deletions.
13 changes: 7 additions & 6 deletions azure/scope/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ import (
// ClusterScopeParams defines the input parameters used to create a new Scope.
type ClusterScopeParams struct {
AzureClients
Client client.Client
Cluster *clusterv1.Cluster
AzureCluster *infrav1.AzureCluster
Cache *ClusterCache
Timeouts azure.AsyncReconciler
Client client.Client
Cluster *clusterv1.Cluster
AzureCluster *infrav1.AzureCluster
Cache *ClusterCache
Timeouts azure.AsyncReconciler
CredentialCache azure.CredentialCache
}

// NewClusterScope creates a new Scope from the supplied parameters.
Expand All @@ -77,7 +78,7 @@ func NewClusterScope(ctx context.Context, params ClusterScopeParams) (*ClusterSc
return nil, errors.New("failed to generate new scope from nil AzureCluster")
}

credentialsProvider, err := NewAzureCredentialsProvider(ctx, params.Client, params.AzureCluster.Spec.IdentityRef, params.AzureCluster.Namespace)
credentialsProvider, err := NewAzureCredentialsProvider(ctx, params.CredentialCache, params.Client, params.AzureCluster.Spec.IdentityRef, params.AzureCluster.Namespace)
if err != nil {
return nil, errors.Wrap(err, "failed to init credentials provider")
}
Expand Down
7 changes: 4 additions & 3 deletions azure/scope/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,10 @@ func TestNewClusterScope(t *testing.T) {
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build()

_, err := NewClusterScope(context.TODO(), ClusterScopeParams{
Cluster: cluster,
AzureCluster: azureCluster,
Client: fakeClient,
Cluster: cluster,
AzureCluster: azureCluster,
Client: fakeClient,
CredentialCache: azure.NewCredentialCache(),
})
g.Expect(err).NotTo(HaveOccurred())
}
Expand Down
24 changes: 15 additions & 9 deletions azure/scope/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
"sigs.k8s.io/cluster-api-provider-azure/azure"
"sigs.k8s.io/cluster-api-provider-azure/util/tele"
"sigs.k8s.io/controller-runtime/pkg/client"
)
Expand All @@ -48,10 +49,12 @@ type CredentialsProvider interface {
type AzureCredentialsProvider struct {
Client client.Client
Identity *infrav1.AzureClusterIdentity

cache azure.CredentialCache
}

// NewAzureCredentialsProvider creates a new AzureClusterCredentialsProvider from the supplied inputs.
func NewAzureCredentialsProvider(ctx context.Context, kubeClient client.Client, identityRef *corev1.ObjectReference, defaultNamespace string) (*AzureCredentialsProvider, error) {
func NewAzureCredentialsProvider(ctx context.Context, cache azure.CredentialCache, kubeClient client.Client, identityRef *corev1.ObjectReference, defaultNamespace string) (*AzureCredentialsProvider, error) {
if identityRef == nil {
return nil, errors.New("failed to generate new AzureClusterCredentialsProvider from empty identityName")
}
Expand All @@ -70,6 +73,7 @@ func NewAzureCredentialsProvider(ctx context.Context, kubeClient client.Client,
return &AzureCredentialsProvider{
Client: kubeClient,
Identity: identity,
cache: cache,
}, nil
}

Expand All @@ -90,7 +94,12 @@ func (p *AzureCredentialsProvider) GetTokenCredential(ctx context.Context, resou
if err != nil {
return nil, errors.Wrapf(err, "failed to setup azwi options for identity %s", p.Identity.Name)
}
cred, authErr = NewWorkloadIdentityCredential(azwiCredOptions)
cred, authErr = p.cache.GetOrStoreWorkloadIdentity(&azidentity.WorkloadIdentityCredentialOptions{
ClientOptions: azwiCredOptions.ClientOptions,
TenantID: azwiCredOptions.TenantID,
ClientID: azwiCredOptions.ClientID,
TokenFilePath: azwiCredOptions.TokenFilePath,
})

case infrav1.ManualServicePrincipal:
log.Info("Identity type ManualServicePrincipal is deprecated and will be removed in a future release. See https://capz.sigs.k8s.io/topics/identities to find a supported identity type.")
Expand All @@ -113,24 +122,21 @@ func (p *AzureCredentialsProvider) GetTokenCredential(ctx context.Context, resou
},
},
}
cred, authErr = azidentity.NewClientSecretCredential(p.GetTenantID(), p.Identity.Spec.ClientID, clientSecret, &options)
cred, authErr = p.cache.GetOrStoreClientSecret(p.GetTenantID(), p.Identity.Spec.ClientID, clientSecret, &options)

case infrav1.ServicePrincipalCertificate:
// TODO: there's no way this was working before??
clientSecret, err := p.GetClientSecret(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to get client secret")
}
certs, key, err := azidentity.ParseCertificates([]byte(clientSecret), nil)
if err != nil {
return nil, errors.Wrap(err, "failed to parse certificate data")
}
cred, authErr = azidentity.NewClientCertificateCredential(p.GetTenantID(), p.Identity.Spec.ClientID, certs, key, nil)
cred, authErr = p.cache.GetOrStoreClientCert(p.GetTenantID(), p.Identity.Spec.ClientID, []byte(clientSecret), nil, nil)

case infrav1.UserAssignedMSI:
options := azidentity.ManagedIdentityCredentialOptions{
ID: azidentity.ClientID(p.Identity.Spec.ClientID),
}
cred, authErr = azidentity.NewManagedIdentityCredential(&options)
cred, authErr = p.cache.GetOrStoreManagedIdentity(&options)

default:
return nil, errors.Errorf("identity type %s not supported", p.Identity.Spec.Type)
Expand Down
76 changes: 63 additions & 13 deletions azure/scope/identity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ package scope

import (
"context"
"encoding/base64"
"testing"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
. "github.com/onsi/gomega"
"go.uber.org/mock/gomock"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
"sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

Expand Down Expand Up @@ -192,20 +196,13 @@ func TestHasClientSecret(t *testing.T) {
}

func TestGetTokenCredential(t *testing.T) {
g := NewWithT(t)

// Test cert data was generated with this command:
// openssl req -x509 -noenc -days 3650 -newkey rsa:2048 --keyout - -subj /CN=localhost | base64
encodedCertData := "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRRGpyZEVyOVAwVGFVRVMKZHNwRTZjeW8yMk5VOHloUnJiWWxWOVZIMnZXdm5Qc1RoWGN4aG5kK2NVcWRORUJzd2h3Z0ZsVVFjZy9lU1Z4dwpyciszbmgrYkZUWldQY1krMUxRWXhmcEtHc3JDWFFmQjgyTERKSVpEWDRnSFlyV2YzWjI3MmpYTjFYZUZBS3RpCndES2dEWFh1UEg3cjVsSDd2QzNSWGVBZmZxTHdRSmhaZitOb0hOdHY5TUg5SWRVa1FmbURGWnRJL0NRekNyYjYKK3ZPUzZFbVVEL1EyRk5IQnpneENndUdxZ055QmNRYnhKOVFuZytaaklGdWhHWVhKbHN5UlV0ZXh5elRSNS92MApWTks4VXNaZ1JCRmhYcXJCdi9Sb0NDRyt4VkpZdG1kMFFzcnZOekRxRzZRbmpVQjIxelZYcXpLRWtXMmdSdGpYCmN3NHZZUWVoQWdNQkFBRUNnZ0VBUzZ4dGpnMG5Bb2trMGpTK1pPcEtsa01aQUZhemEzWnZ5SGlwa0hEejRQTXQKdGw3UmI1b1FaR3ZXVDJyYkVPcnhleTdCQmk3TEhHaEl1OEV4UXAvaFJHUG9CQUVUUDdYbHlDZ2hXUGtQdEV0RQpkVS9tWHhMb04wTnN6SHVmLzJzaTdwbUg4WXFHWjZRQjB0Z3IyMnV0NjBtYksrQUpGc0VFZjRhU3BCVXNwZXBKCjI4MDBzUUhzcVBFNkw2a1lrZloyR1JSWTFWOXZVcllFT0RLWnBXek1oTjNVQTluQUtIOVBCNnh2UDJPZHlNTmgKaEtnbVVVTU5JRnR3cjhwWmxKbjYwY2YwVXJXcmM1Q3ZxUUx1YUdZbHpEZ1VRR1Y0SkVWanFtOUY2bE1mRVBVdwplTjcwTVZlMXBjTGVMcTJyR0NWV1UzZ2FraC9IdkpxbFIvc2E1NDZIZ3dLQmdRRHlmMXZreVg0dzVzYm9pNkRKCmNsNWRNVUx0TU1ScEIxT2FNRlZPSmpJOWdaSjhtQ2RSanFYZFlvNWFTMktJcXhpZTh0R0c5K1NvaHhEQVdsNHQKbFNVdERzRTQ0ZlNtSUxxQzV6SWF3TlJRbm5rdjBYOEx3bVl1MFFkN1lBakpNbExUV3lEUnNqRDlYUnE0bnNSKwptSlZ3cnQ4NWlTcFM1VUZ5cnlFelBiRmowd0tCZ1FEd1d6cmFlTjBFY2NmMWlJWW1Rc1l5K3lNRUFsSE5SNXlpCmdQWHVBaFN5YnYySlJlUmhkVWIzOWhMci9Mdkt3MFplWGlMV1htWVVHcGJ5elB5WEltMHMrUEwzTFdsNjVHVEYKbCtjZlY1d2ZBZERrazZyQWRFUEVFMnB4Tjg1Q2h5YVBZUG9ZcjBvaG1WOTdWUWNZYzVGcVkrajF0TTZSMVJEdAovZldCU2E4aU93S0JnUUNwYTFkdFdXVERqNGdxVWRyc3d1MndtRWtVNDd4bFVJd1ZMbTE2NHU2NHovemk5WDZLCjJXbUNhV2ZoSjhmWWlnanlpOXpkT2ZYVDFFRmMwZ1g0UExvelo1cVJQalFwbUxZVjNLYkIwRFRGZW1KYWlUZ0UKcERXMXdhNURnUTNDVzFsSWR1TlAvZm1DR2ZrZ1FUUXc2ak9GL1hiUmdNWkVFZzJPclZJNXRZRm9wd0tCZ0VSOQppcWpFdGg1VkdlakNqWStMaVpUdmNVdnNLVWs0dGM2c3R1ZXFtaUU2ZFc3UGhzT3F1cDFmOW9aZWoxaTVDbTFMCm45dThMSlJmKzFHV3pnZDNIT3NxeVhsYjdHbkRlVi9BNkhCSzg4YjJLb05uL01rNG1ETGdZWDEvckh2U3JVOUEKRUNSR2x2WTZFVFpBeFhQWFFzR3hWS25uYXRHdGlGUjVBS05senMwUEFvR0FhNStYK0RVcUdoOWFFNUlEM3dydgpqa2p4UTJLTEZKQ05TcThmOUdTdXZwdmdYc3RIaDZ3S29NNnZNd0lTaGpnWHVVUkg4VWI0dWhSc1dueE1pbGRGCjdFRStRYVdVOWpuQ20ySFFZQXJmWHJBV3c2REJ1ZGlTa0JxZ0tjNkhqREh1bjVmWGxZVW84VWVzTk1RT3JnN2IKYnlkUVo1LzRWLzFvU1dQRVRrN2pTcjA9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURDVENDQWZHZ0F3SUJBZ0lVRlNudEVuK1R2NkhNMnhKUmVFQ0pwSmNDN2lVd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZERVNNQkFHQTFVRUF3d0piRzlqWVd4b2IzTjBNQjRYRFRJME1ERXdPREU1TlRReE5Gb1hEVE0wTURFdwpOVEU1TlRReE5Gb3dGREVTTUJBR0ExVUVBd3dKYkc5allXeG9iM04wTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGCkFBT0NBUThBTUlJQkNnS0NBUUVBNDYzUksvVDlFMmxCRW5iS1JPbk1xTnRqVlBNb1VhMjJKVmZWUjlyMXI1ejcKRTRWM01ZWjNmbkZLblRSQWJNSWNJQlpWRUhJUDNrbGNjSzYvdDU0Zm14VTJWajNHUHRTMEdNWDZTaHJLd2wwSAp3Zk5pd3lTR1ExK0lCMksxbjkyZHU5bzF6ZFYzaFFDcllzQXlvQTExN2p4KzYrWlIrN3d0MFYzZ0gzNmk4RUNZCldYL2phQnpiYi9UQi9TSFZKRUg1Z3hXYlNQd2tNd3EyK3Zyemt1aEpsQS8wTmhUUndjNE1Rb0xocW9EY2dYRUcKOFNmVUo0UG1ZeUJib1JtRnlaYk1rVkxYc2NzMDBlZjc5RlRTdkZMR1lFUVJZVjZxd2IvMGFBZ2h2c1ZTV0xabgpkRUxLN3pjdzZodWtKNDFBZHRjMVY2c3loSkZ0b0ViWTEzTU9MMkVIb1FJREFRQUJvMU13VVRBZEJnTlZIUTRFCkZnUVVmcnkvS0R0YW13TWxSUXNGUGJCaHpkdjJVNWN3SHdZRFZSMGpCQmd3Rm9BVWZyeS9LRHRhbXdNbFJRc0YKUGJCaHpkdjJVNWN3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBeVlzdApWdmV3S1JScHVZUldjNFhHNlduWXBoVWR5WkxNb0lscTBzeVoxYWo2WWJxb0s5Tk1IQVlFbkN2U292NnpJWk9hCnRyaHVVY2Y5R0Z6NWUwaUoyeklsRGMzMTJJd3N2NDF4aUMvYnMxNmtFbjhZZi9TdWpFWGFzajd2bUEzSHJGV2YKd1pUSC95Rkw1YXpvL2YrbEExUTI4WXdxRnBIbWxlMHkwTzUzVXRoNHAwdG13bG51K0NyTzlmSHAza1RsYjdmRAo2bXFmazlOcnQ4dE9DNGFIWURvcXRZVWdaaHg1OHhzSE1PVGV0S2VSbHA4SE1GOW9ST3RyaXo0blltNkloVHdvCjVrMUExM1MzQmpheGtaQ3lQWENnWHNzdVhhZ05MYXNycjVRcStWZ2RiL25EaFZlaFY4K1o0SjBZbnp5OU1ac0UKSDFOMU5mTXRzQStQRXF0UFhBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
certPEM, err := base64.StdEncoding.DecodeString(encodedCertData)
g.Expect(err).NotTo(HaveOccurred())

tests := []struct {
name string
cluster *infrav1.AzureCluster
secret *corev1.Secret
identity *infrav1.AzureClusterIdentity
ActiveDirectoryAuthorityHost string
cacheExpect func(*mock_azure.MockCredentialCache)
}{
{
name: "workload identity",
Expand All @@ -225,6 +222,13 @@ func TestGetTokenCredential(t *testing.T) {
TenantID: fakeTenantID,
},
},
cacheExpect: func(cache *mock_azure.MockCredentialCache) {
cache.EXPECT().GetOrStoreWorkloadIdentity(&azidentity.WorkloadIdentityCredentialOptions{
TenantID: fakeTenantID,
ClientID: fakeClientID,
TokenFilePath: getProjectedTokenPath(),
})
},
},
{
name: "manual service principal",
Expand All @@ -241,6 +245,7 @@ func TestGetTokenCredential(t *testing.T) {
Spec: infrav1.AzureClusterIdentitySpec{
Type: infrav1.ManualServicePrincipal,
TenantID: fakeTenantID,
ClientID: fakeClientID,
ClientSecret: corev1.SecretReference{
Name: "test-identity-secret",
},
Expand All @@ -255,6 +260,21 @@ func TestGetTokenCredential(t *testing.T) {
},
},
ActiveDirectoryAuthorityHost: "https://login.microsoftonline.com",
cacheExpect: func(cache *mock_azure.MockCredentialCache) {
cache.EXPECT().GetOrStoreClientSecret(fakeTenantID, fakeClientID, "fooSecret", &azidentity.ClientSecretCredentialOptions{
ClientOptions: azcore.ClientOptions{
Cloud: cloud.Configuration{
ActiveDirectoryAuthorityHost: "https://login.microsoftonline.com",
Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
cloud.ResourceManager: {
Audience: "",
Endpoint: "",
},
},
},
},
})
},
},
{
name: "service principal",
Expand All @@ -271,6 +291,7 @@ func TestGetTokenCredential(t *testing.T) {
Spec: infrav1.AzureClusterIdentitySpec{
Type: infrav1.ServicePrincipal,
TenantID: fakeTenantID,
ClientID: fakeClientID,
ClientSecret: corev1.SecretReference{
Name: "test-identity-secret",
},
Expand All @@ -285,6 +306,21 @@ func TestGetTokenCredential(t *testing.T) {
},
},
ActiveDirectoryAuthorityHost: "https://login.microsoftonline.com",
cacheExpect: func(cache *mock_azure.MockCredentialCache) {
cache.EXPECT().GetOrStoreClientSecret(fakeTenantID, fakeClientID, "fooSecret", &azidentity.ClientSecretCredentialOptions{
ClientOptions: azcore.ClientOptions{
Cloud: cloud.Configuration{
ActiveDirectoryAuthorityHost: "https://login.microsoftonline.com",
Services: map[cloud.ServiceName]cloud.ServiceConfiguration{
cloud.ResourceManager: {
Audience: "",
Endpoint: "",
},
},
},
},
})
},
},
{
name: "service principal certificate",
Expand All @@ -301,6 +337,7 @@ func TestGetTokenCredential(t *testing.T) {
Spec: infrav1.AzureClusterIdentitySpec{
Type: infrav1.ServicePrincipalCertificate,
TenantID: fakeTenantID,
ClientID: fakeClientID,
ClientSecret: corev1.SecretReference{
Name: "test-identity-secret",
},
Expand All @@ -311,9 +348,12 @@ func TestGetTokenCredential(t *testing.T) {
Name: "test-identity-secret",
},
Data: map[string][]byte{
"clientSecret": certPEM,
"clientSecret": []byte("fooSecret"),
},
},
cacheExpect: func(cache *mock_azure.MockCredentialCache) {
cache.EXPECT().GetOrStoreClientCert(fakeTenantID, fakeClientID, []byte("fooSecret"), nil, nil)
},
},
{
name: "user-assigned identity",
Expand All @@ -330,8 +370,14 @@ func TestGetTokenCredential(t *testing.T) {
Spec: infrav1.AzureClusterIdentitySpec{
Type: infrav1.UserAssignedMSI,
TenantID: fakeTenantID,
ClientID: fakeClientID,
},
},
cacheExpect: func(cache *mock_azure.MockCredentialCache) {
cache.EXPECT().GetOrStoreManagedIdentity(&azidentity.ManagedIdentityCredentialOptions{
ID: azidentity.ClientID(fakeClientID),
})
},
},
}

Expand All @@ -351,11 +397,15 @@ func TestGetTokenCredential(t *testing.T) {
initObjects = append(initObjects, tt.secret)
}
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(initObjects...).Build()
provider, err := NewAzureCredentialsProvider(context.Background(), fakeClient, tt.cluster.Spec.IdentityRef, "")

mockCtrl := gomock.NewController(t)
cache := mock_azure.NewMockCredentialCache(mockCtrl)
tt.cacheExpect(cache)

provider, err := NewAzureCredentialsProvider(context.Background(), cache, fakeClient, tt.cluster.Spec.IdentityRef, "")
g.Expect(err).NotTo(HaveOccurred())
cred, err := provider.GetTokenCredential(context.Background(), "", tt.ActiveDirectoryAuthorityHost, "")
_, err = provider.GetTokenCredential(context.Background(), "", tt.ActiveDirectoryAuthorityHost, "")
g.Expect(err).NotTo(HaveOccurred())
g.Expect(cred).NotTo(BeNil())
})
}
}
3 changes: 2 additions & 1 deletion azure/scope/managedcontrolplane.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type ManagedControlPlaneScopeParams struct {
ManagedMachinePools []ManagedMachinePool
Cache *ManagedControlPlaneCache
Timeouts azure.AsyncReconciler
CredentialCache azure.CredentialCache
}

// NewManagedControlPlaneScope creates a new Scope from the supplied parameters.
Expand All @@ -90,7 +91,7 @@ func NewManagedControlPlaneScope(ctx context.Context, params ManagedControlPlane
return nil, errors.New("failed to generate new scope from nil ControlPlane")
}

credentialsProvider, err := NewAzureCredentialsProvider(ctx, params.Client, params.ControlPlane.Spec.IdentityRef, params.ControlPlane.Namespace)
credentialsProvider, err := NewAzureCredentialsProvider(ctx, params.CredentialCache, params.Client, params.ControlPlane.Spec.IdentityRef, params.ControlPlane.Namespace)
if err != nil {
return nil, errors.Wrap(err, "failed to init credentials provider")
}
Expand Down
1 change: 1 addition & 0 deletions azure/scope/managedcontrolplane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func TestNewManagedControlPlaneScope(t *testing.T) {
},
},
},
CredentialCache: azure.NewCredentialCache(),
}
fakeIdentity := &infrav1.AzureClusterIdentity{
ObjectMeta: metav1.ObjectMeta{
Expand Down
30 changes: 0 additions & 30 deletions azure/scope/workload_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ limitations under the License.
package scope

import (
"context"
"os"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -125,31 +123,3 @@ func (w *WorkloadIdentityCredentialOptions) WithDefaults() (*WorkloadIdentityCre
}
return w, nil
}

// NewWorkloadIdentityCredential returns a workload identity credential.
func NewWorkloadIdentityCredential(options *WorkloadIdentityCredentialOptions) (azcore.TokenCredential, error) {
w := &workloadIdentityCredential{file: options.TokenFilePath}
cred, err := azidentity.NewClientAssertionCredential(options.TenantID, options.ClientID, w.getAssertion, &azidentity.ClientAssertionCredentialOptions{ClientOptions: options.ClientOptions})
if err != nil {
return nil, err
}
w.cred = cred
return w, nil
}

// GetToken returns the token for azwi.
func (w *workloadIdentityCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
return w.cred.GetToken(ctx, opts)
}

func (w *workloadIdentityCredential) getAssertion(context.Context) (string, error) {
if now := time.Now(); w.lastRead.Add(azureFederatedTokenFileRefreshTime).Before(now) {
content, err := os.ReadFile(w.file)
if err != nil {
return "", err
}
w.assertion = string(content)
w.lastRead = now
}
return w.assertion, nil
}
Loading

0 comments on commit b8f23bd

Please sign in to comment.