pkg/providers/az-client.go (134 lines of code) (raw):

package providers import ( "context" "errors" "fmt" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/subscription/armsubscription" "github.com/google/uuid" log "github.com/sirupsen/logrus" ) //go:generate mockgen -source=./az-client.go -destination=./mock/az-client.go . type AzClientInterface interface { AssignSpRole(ctx context.Context, subscriptionId, resourceGroup, servicePrincipalObjectID, roleId string) error AzAcrExists(acrName string) bool AzAksExists(aksName string, resourceGroup string) bool AzAppExists(appName string) bool CreateAzApp(appName string) (string, error) CreateServicePrincipal(appId string) (string, error) EnsureAzCli() error EnsureAzCliLoggedIn() error GetAzCliVersion() (string, error) GetAzSubscriptionLabels() ([]SubLabel, error) GetAzUpgrade() string GetCurrentAzSubscriptionLabel() (SubLabel, error) GetServicePrincipal(appId string) (string, error) IsLoggedInToAz() bool IsSubscriptionIdValid(subscriptionId string) error IsValidResourceGroup(subscriptionId string, resourceGroup string) error ListResourceGroups(ctx context.Context, subscriptionID string) ([]armresources.ResourceGroup, error) ListTenants(ctx context.Context) ([]armsubscription.TenantIDDescription, error) LogInToAz() error UpgradeAzCli() ValidateAzCliInstalled() error } // assert AzClient implements AzClientInterface var _ AzClientInterface = &AzClient{} // AzClient is a struct that contains the Azure client and its dependencies // It is used to interact with Azure resources // Create a new AzClient with NewAzClient type AzClient struct { Credential *azidentity.DefaultAzureCredential TenantClient *armsubscription.TenantsClient RoleAssignClient *armauthorization.RoleAssignmentsClient ResourceGroupClient *armresources.ResourceGroupsClient CommandRunner CommandRunner } func NewAzClient(cred *azidentity.DefaultAzureCredential) (*AzClient, error) { azClient := &AzClient{ Credential: cred, CommandRunner: &DefaultCommandRunner{}, } err := azClient.EnsureAzCli() if err != nil { log.Fatal(err) } return azClient, nil } func (az *AzClient) ListResourceGroups(ctx context.Context, subscriptionID string) ([]armresources.ResourceGroup, error) { log.Debug("listing Azure resource groups for subscription ", subscriptionID) if az.ResourceGroupClient == nil { c, err := armresources.NewResourceGroupsClient(subscriptionID, az.Credential, nil) if err != nil { return nil, fmt.Errorf("failed to create resource group client: %w", err) } az.ResourceGroupClient = c } var rgs []armresources.ResourceGroup pager := az.ResourceGroupClient.NewListPager(nil) for pager.More() { page, err := pager.NextPage(ctx) if err != nil { return nil, fmt.Errorf("listing resource groups page: %w", err) } for _, rg := range page.Value { if rg == nil { return nil, errors.New("nil rg") } rgs = append(rgs, *rg) } } return rgs, nil } func (az *AzClient) ListTenants(ctx context.Context) ([]armsubscription.TenantIDDescription, error) { log.Debug("Starting to list Azure Tenants") // Initialize the tenant slice to store the results. tenants := make([]armsubscription.TenantIDDescription, 0) if az.TenantClient == nil { c, err := armsubscription.NewTenantsClient(az.Credential, nil) if err != nil { return nil, fmt.Errorf("failed to create tenant client: %w", err) } az.TenantClient = c } pager := az.TenantClient.NewListPager(nil) for pager.More() { page, err := pager.NextPage(ctx) if err != nil { return nil, fmt.Errorf("listing tenants page: %w", err) } for _, t := range page.Value { if t == nil { return nil, errors.New("nil tenant") // this should never happen but it's good to check just in case } tenants = append(tenants, *t) } } log.Debugf("Successfully listed %d Azure tenants", len(tenants)) return tenants, nil } func (az *AzClient) AssignSpRole(ctx context.Context, subscriptionId, resourceGroup, servicePrincipalObjectID, roleId string) error { log.Debug("Assigning contributor role to service principal...") if az.RoleAssignClient == nil { c, err := armauthorization.NewRoleAssignmentsClient(subscriptionId, az.Credential, nil) if err != nil { return fmt.Errorf("failed to create role assignment client: %w", err) } az.RoleAssignClient = c } scope := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s", subscriptionId, resourceGroup) objectID := servicePrincipalObjectID raUid := uuid.New().String() fullAssignmentId := fmt.Sprintf("/%s/providers/Microsoft.Authorization/roleAssignments/%s", scope, raUid) fullDefinitionId := fmt.Sprintf("/providers/Microsoft.Authorization/roleDefinitions/%s", roleId) principalType := armauthorization.PrincipalTypeServicePrincipal parameters := armauthorization.RoleAssignmentCreateParameters{ Properties: &armauthorization.RoleAssignmentProperties{ PrincipalID: &objectID, RoleDefinitionID: &fullDefinitionId, PrincipalType: &principalType, }, } _, err := az.RoleAssignClient.CreateByID(ctx, fullAssignmentId, parameters, nil) if err != nil { return fmt.Errorf("creating role assignment: %w", err) } log.Debug("Role assigned successfully!") return nil }