Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions azure/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package azure
import (
"context"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-service-operator/v2/pkg/genruntime"
"github.com/Azure/go-autorest/autorest"
infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
Expand All @@ -44,6 +45,7 @@ type ServiceReconciler interface {
}

// Authorizer is an interface which can get the subscription ID, base URI, and authorizer for an Azure service.
// The Authorizer field is used by SDKv1 services while the Token is used by SDKv2 services.
type Authorizer interface {
SubscriptionID() string
ClientID() string
Expand All @@ -53,6 +55,7 @@ type Authorizer interface {
BaseURI() string
Authorizer() autorest.Authorizer
HashKey() string
Token() azcore.TokenCredential
}

// NetworkDescriber is an interface which can get common Azure Cluster Networking information.
Expand Down
57 changes: 57 additions & 0 deletions azure/mock_azure/azure_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion azure/scope/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"os"
"strings"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/go-autorest/autorest"
azureautorest "github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/azure/auth"
Expand All @@ -35,6 +36,7 @@ type AzureClients struct {
auth.EnvironmentSettings

Authorizer autorest.Authorizer
TokenCredential azcore.TokenCredential
ResourceManagerEndpoint string
ResourceManagerVMDNSSuffix string
}
Expand Down Expand Up @@ -65,6 +67,11 @@ func (c *AzureClients) SubscriptionID() string {
return c.Values[auth.SubscriptionID]
}

// Token returns the Azure token credential of the cluster used for SDKv2 services.
func (c *AzureClients) Token() azcore.TokenCredential {
return c.TokenCredential
}

// HashKey returns a base64 url encoded sha256 hash for the Auth scope (Azure TenantID + CloudEnv + SubscriptionID +
// ClientID).
func (c *AzureClients) HashKey() string {
Expand Down Expand Up @@ -133,7 +140,12 @@ func (c *AzureClients) setCredentialsWithProvider(ctx context.Context, subscript
}
c.Values[auth.ClientSecret] = strings.TrimSuffix(clientSecret, "\n")

c.Authorizer, err = credentialsProvider.GetAuthorizer(ctx, c.ResourceManagerEndpoint, c.Environment.ActiveDirectoryEndpoint, c.Environment.TokenAudience)
tokenCredential, err := credentialsProvider.GetTokenCredential(ctx, c.ResourceManagerEndpoint, c.Environment.ActiveDirectoryEndpoint, c.Environment.TokenAudience)
Comment thread
mboersma marked this conversation as resolved.
if err != nil {
return err
}
c.TokenCredential = tokenCredential
c.Authorizer, err = credentialsProvider.GetAuthorizer(ctx, tokenCredential, c.Environment.TokenAudience)
return err
}

Expand Down
2 changes: 1 addition & 1 deletion azure/scope/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (s *ClusterScope) BaseURI() string {
return s.ResourceManagerEndpoint
}

// Authorizer returns the Azure client Authorizer.
// Authorizer returns the Azure client Authorizer which is used for SDKv1 services.
func (s *ClusterScope) Authorizer() autorest.Authorizer {
return s.AzureClients.Authorizer
}
Expand Down
32 changes: 25 additions & 7 deletions azure/scope/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ const AzureSecretKey = "clientSecret"

// CredentialsProvider defines the behavior for azure identity based credential providers.
type CredentialsProvider interface {
GetAuthorizer(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string) (autorest.Authorizer, error)
GetAuthorizer(ctx context.Context, tokenCredential azcore.TokenCredential, tokenAudience string) (autorest.Authorizer, error)
GetClientID() string
GetClientSecret(ctx context.Context) (string, error)
GetTenantID() string
GetTokenCredential(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string) (azcore.TokenCredential, error)
}

// AzureCredentialsProvider represents a credential provider with azure cluster identity.
Expand Down Expand Up @@ -102,8 +103,13 @@ func NewAzureClusterCredentialsProvider(ctx context.Context, kubeClient client.C
}

// GetAuthorizer returns an Azure authorizer based on the provided azure identity. It delegates to AzureCredentialsProvider with AzureCluster metadata.
func (p *AzureClusterCredentialsProvider) GetAuthorizer(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string) (autorest.Authorizer, error) {
return p.AzureCredentialsProvider.GetAuthorizer(ctx, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience, p.AzureCluster.ObjectMeta)
func (p *AzureClusterCredentialsProvider) GetAuthorizer(ctx context.Context, tokenCredential azcore.TokenCredential, tokenAudience string) (autorest.Authorizer, error) {
return p.AzureCredentialsProvider.GetAuthorizer(ctx, tokenCredential, tokenAudience)
}

// GetTokenCredential returns an Azure TokenCredential based on the provided azure identity.
func (p *AzureClusterCredentialsProvider) GetTokenCredential(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string) (azcore.TokenCredential, error) {
return p.AzureCredentialsProvider.GetTokenCredential(ctx, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience, p.AzureCluster.ObjectMeta)
}

// NewManagedControlPlaneCredentialsProvider creates a new ManagedControlPlaneCredentialsProvider from the supplied inputs.
Expand Down Expand Up @@ -134,14 +140,20 @@ func NewManagedControlPlaneCredentialsProvider(ctx context.Context, kubeClient c
}

// GetAuthorizer returns an Azure authorizer based on the provided azure identity. It delegates to AzureCredentialsProvider with AzureManagedControlPlane metadata.
func (p *ManagedControlPlaneCredentialsProvider) GetAuthorizer(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string) (autorest.Authorizer, error) {
return p.AzureCredentialsProvider.GetAuthorizer(ctx, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience, p.AzureManagedControlPlane.ObjectMeta)
func (p *ManagedControlPlaneCredentialsProvider) GetAuthorizer(ctx context.Context, tokenCredential azcore.TokenCredential, tokenAudience string) (autorest.Authorizer, error) {
return p.AzureCredentialsProvider.GetAuthorizer(ctx, tokenCredential, tokenAudience)
}

// GetTokenCredential returns an Azure TokenCredential based on the provided azure identity.
func (p *ManagedControlPlaneCredentialsProvider) GetTokenCredential(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string) (azcore.TokenCredential, error) {
return p.AzureCredentialsProvider.GetTokenCredential(ctx, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience, p.AzureManagedControlPlane.ObjectMeta)
}

// GetAuthorizer returns an Azure authorizer based on the provided azure identity and cluster metadata.
func (p *AzureCredentialsProvider) GetAuthorizer(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string, clusterMeta metav1.ObjectMeta) (autorest.Authorizer, error) {
// GetTokenCredential returns an Azure TokenCredential based on the provided azure identity.
func (p *AzureCredentialsProvider) GetTokenCredential(ctx context.Context, resourceManagerEndpoint, activeDirectoryEndpoint, tokenAudience string, clusterMeta metav1.ObjectMeta) (azcore.TokenCredential, error) {
var authErr error
var cred azcore.TokenCredential

switch p.Identity.Spec.Type {
case infrav1.WorkloadIdentity:
azwiCredOptions, err := NewWorkloadIdentityCredentialOptions().
Expand Down Expand Up @@ -191,6 +203,12 @@ func (p *AzureCredentialsProvider) GetAuthorizer(ctx context.Context, resourceMa
if authErr != nil {
return nil, errors.Errorf("failed to get token from service principal identity: %v", authErr)
}

return cred, nil
}

// GetAuthorizer returns an Azure authorizer based on the provided azure identity, cluster metadata, and tokenCredential.
func (p *AzureCredentialsProvider) GetAuthorizer(ctx context.Context, cred azcore.TokenCredential, tokenAudience string) (autorest.Authorizer, error) {
// We must use TokenAudience for StackCloud, otherwise we get an
// AADSTS500011 error from the API
scope := tokenAudience
Expand Down
5 changes: 4 additions & 1 deletion azure/scope/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,10 @@ func (m *MachineScope) GetVMImage(ctx context.Context) (*infrav1.Image, error) {
return m.AzureMachine.Spec.Image, nil
}

svc := virtualmachineimages.New(m)
svc, err := virtualmachineimages.New(m)
if err != nil {
return nil, errors.Wrap(err, "failed to create virtualmachineimages service")
}

if m.AzureMachine.Spec.OSDisk.OSType == azure.WindowsOS {
runtime := m.AzureMachine.Annotations["runtime"]
Expand Down
4 changes: 3 additions & 1 deletion azure/scope/machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"reflect"
"testing"

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
azureautorest "github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -1398,9 +1399,10 @@ func TestMachineScope_GetVMImage(t *testing.T) {

clusterMock := mock_azure.NewMockClusterScoper(mockCtrl)
clusterMock.EXPECT().Authorizer().AnyTimes()
clusterMock.EXPECT().BaseURI().AnyTimes()
clusterMock.EXPECT().Location().AnyTimes()
clusterMock.EXPECT().SubscriptionID().AnyTimes()
clusterMock.EXPECT().CloudEnvironment().AnyTimes()
clusterMock.EXPECT().Token().Return(&azidentity.DefaultAzureCredential{}).AnyTimes()
svc := virtualmachineimages.Service{Client: mock_virtualmachineimages.NewMockClient(mockCtrl)}

tests := []struct {
Expand Down
8 changes: 6 additions & 2 deletions azure/scope/machinepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -656,12 +656,16 @@ func (m *MachinePoolScope) GetVMImage(ctx context.Context) (*infrav1.Image, erro
return m.AzureMachinePool.Spec.Template.Image, nil
}

svc := virtualmachineimages.New(m)

var (
err error
defaultImage *infrav1.Image
)

svc, err := virtualmachineimages.New(m)
if err != nil {
return nil, errors.Wrap(err, "failed to create virtualmachineimages service")
}

if m.AzureMachinePool.Spec.Template.OSDisk.OSType == azure.WindowsOS {
runtime := m.AzureMachinePool.Annotations["runtime"]
windowsServerVersion := m.AzureMachinePool.Annotations["windowsServerVersion"]
Expand Down
4 changes: 3 additions & 1 deletion azure/scope/machinepool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"reflect"
"testing"

"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
azureautorest "github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/azure/auth"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -401,9 +402,10 @@ func TestMachinePoolScope_GetVMImage(t *testing.T) {

clusterMock := mock_azure.NewMockClusterScoper(mockCtrl)
clusterMock.EXPECT().Authorizer().AnyTimes()
clusterMock.EXPECT().BaseURI().AnyTimes()
clusterMock.EXPECT().Location().AnyTimes()
clusterMock.EXPECT().SubscriptionID().AnyTimes()
clusterMock.EXPECT().CloudEnvironment().AnyTimes()
clusterMock.EXPECT().Token().Return(&azidentity.DefaultAzureCredential{}).AnyTimes()
cases := []struct {
Name string
Setup func(mp *expv1.MachinePool, amp *infrav1exp.AzureMachinePool)
Expand Down
15 changes: 15 additions & 0 deletions azure/services/agentpools/mock_agentpools/agentpools_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading