2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-03-22 11:03:15 -04:00
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/Azure/azure-sdk-for-go/profiles/latest/authorization/mgmt/authorization"
|
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
|
2022-06-10 07:18:30 -04:00
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/applicationinsights/armapplicationinsights"
|
2022-07-27 16:02:33 -04:00
|
|
|
armcomputev2 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v2"
|
2022-03-22 11:03:15 -04:00
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork"
|
|
|
|
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
|
|
|
|
"github.com/Azure/azure-sdk-for-go/services/graphrbac/1.6/graphrbac"
|
|
|
|
"github.com/Azure/go-autorest/autorest"
|
|
|
|
"github.com/Azure/go-autorest/autorest/azure/auth"
|
2022-06-07 05:08:44 -04:00
|
|
|
"github.com/edgelesssys/constellation/internal/cloud/cloudprovider"
|
2022-06-08 02:17:52 -04:00
|
|
|
"github.com/edgelesssys/constellation/internal/cloud/cloudtypes"
|
2022-03-22 11:03:15 -04:00
|
|
|
"github.com/edgelesssys/constellation/internal/state"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
graphAPIResource = "https://graph.windows.net"
|
|
|
|
managementAPIResource = "https://management.azure.com"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Client is a client for Azure.
|
|
|
|
type Client struct {
|
|
|
|
networksAPI
|
|
|
|
networkSecurityGroupsAPI
|
2022-08-25 09:12:08 -04:00
|
|
|
resourceAPI
|
2022-03-22 11:03:15 -04:00
|
|
|
scaleSetsAPI
|
2022-09-06 04:05:51 -04:00
|
|
|
virtualMachineScaleSetVMsAPI
|
2022-03-22 11:03:15 -04:00
|
|
|
publicIPAddressesAPI
|
|
|
|
networkInterfacesAPI
|
2022-05-24 04:04:42 -04:00
|
|
|
loadBalancersAPI
|
2022-03-22 11:03:15 -04:00
|
|
|
applicationsAPI
|
|
|
|
servicePrincipalsAPI
|
|
|
|
roleAssignmentsAPI
|
2022-06-10 07:18:30 -04:00
|
|
|
applicationInsightsAPI
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2022-08-25 09:12:08 -04:00
|
|
|
pollFrequency time.Duration
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2022-06-29 09:26:29 -04:00
|
|
|
workers cloudtypes.Instances
|
|
|
|
controlPlanes cloudtypes.Instances
|
2022-03-22 11:03:15 -04:00
|
|
|
|
|
|
|
name string
|
|
|
|
uid string
|
|
|
|
resourceGroup string
|
|
|
|
location string
|
|
|
|
subscriptionID string
|
|
|
|
tenantID string
|
|
|
|
subnetID string
|
2022-06-29 09:26:29 -04:00
|
|
|
controlPlaneScaleSet string
|
|
|
|
workerScaleSet string
|
2022-05-24 04:04:42 -04:00
|
|
|
loadBalancerName string
|
|
|
|
loadBalancerPubIP string
|
2022-03-22 11:03:15 -04:00
|
|
|
networkSecurityGroup string
|
|
|
|
adAppObjectID string
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewFromDefault creates a client with initialized clients.
|
|
|
|
func NewFromDefault(subscriptionID, tenantID string) (*Client, error) {
|
|
|
|
cred, err := azidentity.NewDefaultAzureCredential(nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
graphAuthorizer, err := getAuthorizer(graphAPIResource)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
managementAuthorizer, err := getAuthorizer(managementAPIResource)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-07-27 16:02:33 -04:00
|
|
|
netAPI, err := armnetwork.NewVirtualNetworksClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
netSecGrpAPI, err := armnetwork.NewSecurityGroupsClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
scaleSetAPI, err := armcomputev2.NewVirtualMachineScaleSetsClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-09-06 04:05:51 -04:00
|
|
|
virtualMachineScaleSetVMsAPI, err := armcomputev2.NewVirtualMachineScaleSetVMsClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-07-27 16:02:33 -04:00
|
|
|
publicIPAddressesAPI, err := armnetwork.NewPublicIPAddressesClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
networkInterfacesAPI, err := armnetwork.NewInterfacesClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
loadBalancersAPI, err := armnetwork.NewLoadBalancersClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
applicationInsightsAPI, err := armapplicationinsights.NewComponentsClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-08-25 09:12:08 -04:00
|
|
|
resourceAPI, err := armresources.NewClient(subscriptionID, cred, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-03-22 11:03:15 -04:00
|
|
|
applicationsAPI := graphrbac.NewApplicationsClient(tenantID)
|
|
|
|
applicationsAPI.Authorizer = graphAuthorizer
|
|
|
|
servicePrincipalsAPI := graphrbac.NewServicePrincipalsClient(tenantID)
|
|
|
|
servicePrincipalsAPI.Authorizer = graphAuthorizer
|
|
|
|
roleAssignmentsAPI := authorization.NewRoleAssignmentsClient(subscriptionID)
|
|
|
|
roleAssignmentsAPI.Authorizer = managementAuthorizer
|
|
|
|
|
|
|
|
return &Client{
|
2022-09-06 04:05:51 -04:00
|
|
|
networksAPI: netAPI,
|
|
|
|
networkSecurityGroupsAPI: netSecGrpAPI,
|
|
|
|
resourceAPI: resourceAPI,
|
|
|
|
scaleSetsAPI: scaleSetAPI,
|
|
|
|
virtualMachineScaleSetVMsAPI: virtualMachineScaleSetVMsAPI,
|
|
|
|
publicIPAddressesAPI: publicIPAddressesAPI,
|
|
|
|
networkInterfacesAPI: networkInterfacesAPI,
|
|
|
|
loadBalancersAPI: loadBalancersAPI,
|
|
|
|
applicationsAPI: applicationsAPI,
|
|
|
|
servicePrincipalsAPI: servicePrincipalsAPI,
|
|
|
|
roleAssignmentsAPI: roleAssignmentsAPI,
|
|
|
|
applicationInsightsAPI: applicationInsightsAPI,
|
|
|
|
subscriptionID: subscriptionID,
|
|
|
|
tenantID: tenantID,
|
|
|
|
workers: cloudtypes.Instances{},
|
|
|
|
controlPlanes: cloudtypes.Instances{},
|
|
|
|
pollFrequency: time.Second * 5,
|
2022-03-22 11:03:15 -04:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewInitialized creates and initializes client by setting the subscriptionID, location and name
|
|
|
|
// of the Constellation.
|
2022-08-25 09:12:08 -04:00
|
|
|
func NewInitialized(subscriptionID, tenantID, name, location, resourceGroup string) (*Client, error) {
|
2022-03-22 11:03:15 -04:00
|
|
|
client, err := NewFromDefault(subscriptionID, tenantID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-08-25 09:12:08 -04:00
|
|
|
err = client.init(location, name, resourceGroup)
|
2022-03-22 11:03:15 -04:00
|
|
|
return client, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// init initializes the client.
|
2022-08-25 09:12:08 -04:00
|
|
|
func (c *Client) init(location, name, resourceGroup string) error {
|
2022-03-22 11:03:15 -04:00
|
|
|
c.location = location
|
|
|
|
c.name = name
|
2022-08-25 09:12:08 -04:00
|
|
|
c.resourceGroup = resourceGroup
|
2022-03-22 11:03:15 -04:00
|
|
|
uid, err := c.generateUID()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.uid = uid
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetState returns the state of the client as ConstellationState.
|
2022-08-01 06:35:35 -04:00
|
|
|
func (c *Client) GetState() state.ConstellationState {
|
|
|
|
return state.ConstellationState{
|
|
|
|
Name: c.name,
|
|
|
|
UID: c.uid,
|
|
|
|
CloudProvider: cloudprovider.Azure.String(),
|
2022-08-01 10:51:34 -04:00
|
|
|
LoadBalancerIP: c.loadBalancerPubIP,
|
2022-08-01 06:35:35 -04:00
|
|
|
AzureLocation: c.location,
|
|
|
|
AzureSubscription: c.subscriptionID,
|
|
|
|
AzureTenant: c.tenantID,
|
|
|
|
AzureResourceGroup: c.resourceGroup,
|
|
|
|
AzureNetworkSecurityGroup: c.networkSecurityGroup,
|
|
|
|
AzureSubnet: c.subnetID,
|
|
|
|
AzureWorkerScaleSet: c.workerScaleSet,
|
|
|
|
AzureControlPlaneScaleSet: c.controlPlaneScaleSet,
|
|
|
|
AzureWorkerInstances: c.workers,
|
|
|
|
AzureControlPlaneInstances: c.controlPlanes,
|
|
|
|
AzureADAppObjectID: c.adAppObjectID,
|
2022-03-22 11:03:15 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetState sets the state of the client to the handed ConstellationState.
|
2022-08-01 06:35:35 -04:00
|
|
|
func (c *Client) SetState(stat state.ConstellationState) {
|
2022-03-22 11:03:15 -04:00
|
|
|
c.resourceGroup = stat.AzureResourceGroup
|
|
|
|
c.name = stat.Name
|
|
|
|
c.uid = stat.UID
|
2022-08-01 10:51:34 -04:00
|
|
|
c.loadBalancerPubIP = stat.LoadBalancerIP
|
2022-03-22 11:03:15 -04:00
|
|
|
c.location = stat.AzureLocation
|
|
|
|
c.subscriptionID = stat.AzureSubscription
|
|
|
|
c.tenantID = stat.AzureTenant
|
|
|
|
c.subnetID = stat.AzureSubnet
|
|
|
|
c.networkSecurityGroup = stat.AzureNetworkSecurityGroup
|
2022-07-29 02:10:51 -04:00
|
|
|
c.workerScaleSet = stat.AzureWorkerScaleSet
|
|
|
|
c.controlPlaneScaleSet = stat.AzureControlPlaneScaleSet
|
|
|
|
c.workers = stat.AzureWorkerInstances
|
|
|
|
c.controlPlanes = stat.AzureControlPlaneInstances
|
2022-03-22 11:03:15 -04:00
|
|
|
c.adAppObjectID = stat.AzureADAppObjectID
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) generateUID() (string, error) {
|
|
|
|
letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
|
|
|
|
|
|
|
const uidLen = 5
|
|
|
|
uid := make([]byte, uidLen)
|
|
|
|
for i := 0; i < uidLen; i++ {
|
|
|
|
n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
uid[i] = letters[n.Int64()]
|
|
|
|
}
|
|
|
|
return string(uid), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// getAuthorizer creates an autorest.Authorizer for different Azure AD APIs using either environment variables or azure cli credentials.
|
|
|
|
func getAuthorizer(resource string) (autorest.Authorizer, error) {
|
|
|
|
authorizer, cliErr := auth.NewAuthorizerFromCLIWithResource(resource)
|
|
|
|
if cliErr == nil {
|
|
|
|
return authorizer, nil
|
|
|
|
}
|
|
|
|
authorizer, envErr := auth.NewAuthorizerFromEnvironmentWithResource(resource)
|
|
|
|
if envErr == nil {
|
|
|
|
return authorizer, nil
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("unable to create authorizer from env or cli: %v %v", envErr, cliErr)
|
|
|
|
}
|