From 4dfa6f6cd6b4b97c80eb1e3c750ff9037cba0a15 Mon Sep 17 00:00:00 2001 From: QuentinBisson Date: Wed, 4 Dec 2024 11:50:57 +0100 Subject: [PATCH] add-private-dns-zone --- go.mod | 1 + go.sum | 2 + .../cloud/azure/privateendpoint.go | 106 ++++++++++++++++++ .../objectstorage/cloud/azure/service.go | 9 ++ .../objectstorage/cloud/azure/storage.go | 55 ++++++--- 5 files changed, 156 insertions(+), 17 deletions(-) create mode 100644 internal/pkg/service/objectstorage/cloud/azure/privateendpoint.go diff --git a/go.mod b/go.mod index c13484c..5e21aa8 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.1.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 github.com/aquilax/truncate v1.0.0 github.com/aws/aws-sdk-go-v2 v1.32.6 diff --git a/go.sum b/go.sum index 41de7e4..9f34fcc 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsI github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0/go.mod h1:AW8VEadnhw9xox+VaVd9sP7NjzOAnaZBLRH6Tq3cJ38= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.1.0 h1:Fd+iaEa+JBwzYo6OTWYSNqyvlPSLciMGsmsnYCKcXM0= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.1.0/go.mod h1:ulHyBFJOI0ONiRL4vcJTmS7rx18jQQlEPmAgo80cRdM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 h1:yzrctSl9GMIQ5lHu7jc8olOsGjWDCsBpJhWqfGa/YIM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0/go.mod h1:GE4m0rnnfwLGX0Y9A9A25Zx5N/90jneT5ABevqzhuFQ= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c= diff --git a/internal/pkg/service/objectstorage/cloud/azure/privateendpoint.go b/internal/pkg/service/objectstorage/cloud/azure/privateendpoint.go new file mode 100644 index 0000000..e2443cb --- /dev/null +++ b/internal/pkg/service/objectstorage/cloud/azure/privateendpoint.go @@ -0,0 +1,106 @@ +package azure + +import ( + "context" + "fmt" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" + + "github.com/giantswarm/object-storage-operator/api/v1alpha1" +) + +var subnetID = "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/virtualNetworks/%s/subnets/%s" + +func (s AzureObjectStorageAdapter) upsertPrivateEndpoint(ctx context.Context, bucket *v1alpha1.Bucket, storageAccountName string) (*armnetwork.PrivateEndpoint, error) { + // Create or Update Private endpoint + pollersResp, err := s.privateEndpointsClient.BeginCreateOrUpdate( + ctx, + s.cluster.GetResourceGroup(), + bucket.Spec.Name, + armnetwork.PrivateEndpoint{ + Location: to.Ptr(s.cluster.GetRegion()), + Properties: &armnetwork.PrivateEndpointProperties{ + CustomNetworkInterfaceName: to.Ptr(fmt.Sprintf("%s-nodes-nic", bucket.Spec.Name)), + PrivateLinkServiceConnections: []*armnetwork.PrivateLinkServiceConnection{ + { + Name: to.Ptr(bucket.Spec.Name), + Properties: &armnetwork.PrivateLinkServiceConnectionProperties{ + PrivateLinkServiceID: to.Ptr(fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Storage/storageAccounts/%s", s.cluster.GetSubscriptionID(), s.cluster.GetResourceGroup(), storageAccountName)), + GroupIDs: []*string{to.Ptr("blob")}, + }, + }, + }, + Subnet: &armnetwork.Subnet{ + ID: to.Ptr(s.subnetID()), + }, + }, + Tags: s.getBucketTags(bucket), + }, + nil, + ) + + if err != nil { + return nil, err + } + resp, err := pollersResp.PollUntilDone(ctx, nil) + if err != nil { + return nil, err + } + + return &resp.PrivateEndpoint, nil +} + +func (s AzureObjectStorageAdapter) upsertPrivateZone(ctx context.Context, bucket *v1alpha1.Bucket) (*armprivatedns.PrivateZone, error) { + pollersResp, err := s.privateZonesClient.BeginCreateOrUpdate( + ctx, + s.cluster.GetResourceGroup(), + bucket.Spec.Name, + armprivatedns.PrivateZone{ + Location: to.Ptr(s.cluster.GetRegion()), + Tags: s.getBucketTags(bucket), + }, + nil, + ) + if err != nil { + return nil, err + } + resp, err := pollersResp.PollUntilDone(ctx, nil) + if err != nil { + return nil, err + } + return &resp.PrivateZone, nil +} + +func (s AzureObjectStorageAdapter) upsertVirtualNetworkLink(ctx context.Context, bucket *v1alpha1.Bucket) (*armprivatedns.VirtualNetworkLink, error) { + pollersResp, err := s.virtualNetworkLinksClient.BeginCreateOrUpdate( + ctx, + s.cluster.GetResourceGroup(), + bucket.Spec.Name, + bucket.Spec.Name, + armprivatedns.VirtualNetworkLink{ + Location: to.Ptr(s.cluster.GetRegion()), + Properties: &armprivatedns.VirtualNetworkLinkProperties{ + RegistrationEnabled: to.Ptr(true), + VirtualNetwork: &armprivatedns.SubResource{ + ID: to.Ptr(s.subnetID()), + }, + }, + Tags: s.getBucketTags(bucket), + }, + nil, + ) + if err != nil { + return nil, err + } + resp, err := pollersResp.PollUntilDone(ctx, nil) + if err != nil { + return nil, err + } + return &resp.VirtualNetworkLink, nil +} + +func (s AzureObjectStorageAdapter) subnetID() string { + return fmt.Sprintf(subnetID, s.cluster.GetSubscriptionID(), s.cluster.GetResourceGroup(), s.cluster.GetVNetName(), "node-subnet") +} diff --git a/internal/pkg/service/objectstorage/cloud/azure/service.go b/internal/pkg/service/objectstorage/cloud/azure/service.go index 367e302..80c1a64 100644 --- a/internal/pkg/service/objectstorage/cloud/azure/service.go +++ b/internal/pkg/service/objectstorage/cloud/azure/service.go @@ -7,6 +7,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" "github.com/go-logr/logr" "github.com/pkg/errors" @@ -64,6 +65,12 @@ func (s AzureObjectStorageService) NewObjectStorageService(ctx context.Context, return nil, errors.WithStack(err) } + var privateZonesClientFactory *armprivatedns.ClientFactory + privateZonesClientFactory, err = armprivatedns.NewClientFactory(azureCredentials.SubscriptionID, cred, nil) + if err != nil { + return nil, errors.WithStack(err) + } + azurecluster, ok := cluster.(AzureCluster) if !ok { return nil, errors.New("Impossible to cast cluster into Azure cluster") @@ -73,6 +80,8 @@ func (s AzureObjectStorageService) NewObjectStorageService(ctx context.Context, storageClientFactory.NewBlobContainersClient(), storageClientFactory.NewManagementPoliciesClient(), networkClientFactory.NewPrivateEndpointsClient(), + privateZonesClientFactory.NewPrivateZonesClient(), + privateZonesClientFactory.NewVirtualNetworkLinksClient(), logger, azurecluster, client, diff --git a/internal/pkg/service/objectstorage/cloud/azure/storage.go b/internal/pkg/service/objectstorage/cloud/azure/storage.go index 301ee10..ad8c564 100644 --- a/internal/pkg/service/objectstorage/cloud/azure/storage.go +++ b/internal/pkg/service/objectstorage/cloud/azure/storage.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage" "github.com/go-logr/logr" v1 "k8s.io/api/core/v1" @@ -21,13 +22,15 @@ const ( ) type AzureObjectStorageAdapter struct { - storageAccountClient *armstorage.AccountsClient - blobContainerClient *armstorage.BlobContainersClient - managementPoliciesClient *armstorage.ManagementPoliciesClient - privateEndpointsClient *armnetwork.PrivateEndpointsClient - logger logr.Logger - cluster AzureCluster - client client.Client + storageAccountClient *armstorage.AccountsClient + blobContainerClient *armstorage.BlobContainersClient + managementPoliciesClient *armstorage.ManagementPoliciesClient + privateEndpointsClient *armnetwork.PrivateEndpointsClient + privateZonesClient *armprivatedns.PrivateZonesClient + virtualNetworkLinksClient *armprivatedns.VirtualNetworkLinksClient + logger logr.Logger + cluster AzureCluster + client client.Client } // NewAzureStorageService creates a new instance of AzureObjectStorageAdapter. @@ -41,17 +44,21 @@ func NewAzureStorageService( blobContainerClient *armstorage.BlobContainersClient, managementPoliciesClient *armstorage.ManagementPoliciesClient, privateEndpointsClient *armnetwork.PrivateEndpointsClient, + privateZonesClient *armprivatedns.PrivateZonesClient, + virtualNetworkLinksClient *armprivatedns.VirtualNetworkLinksClient, logger logr.Logger, cluster AzureCluster, client client.Client) AzureObjectStorageAdapter { return AzureObjectStorageAdapter{ - storageAccountClient: storageAccountClient, - blobContainerClient: blobContainerClient, - managementPoliciesClient: managementPoliciesClient, - privateEndpointsClient: privateEndpointsClient, - logger: logger, - cluster: cluster, - client: client, + storageAccountClient: storageAccountClient, + blobContainerClient: blobContainerClient, + managementPoliciesClient: managementPoliciesClient, + privateEndpointsClient: privateEndpointsClient, + privateZonesClient: privateZonesClient, + virtualNetworkLinksClient: virtualNetworkLinksClient, + logger: logger, + cluster: cluster, + client: client, } } @@ -76,8 +83,7 @@ func (s AzureObjectStorageAdapter) ExistsBucket(ctx context.Context, bucket *v1a return s.existsContainer(ctx, bucket, storageAccountName) } -// / CreateBucket creates the Storage Account if it not exists AND the Storage Container -// CreateBucket creates a bucket in Azure Object Storage. +// CreateBucket creates the Storage Account if it not exists AND the Storage Container // It checks if the storage account exists, and if not, it creates it. // Then, it creates a storage container within the storage account. // Finally, it retrieves the access key for 'key1' and creates a K8S Secret to store the storage account access key. @@ -90,6 +96,21 @@ func (s AzureObjectStorageAdapter) CreateBucket(ctx context.Context, bucket *v1a return err } + // TODO make sure this is not the case on public installations + if _, err := s.upsertPrivateZone(ctx, bucket); err != nil { + return err + } + + // TODO make sure this is not the case on public installations + if _, err := s.upsertVirtualNetworkLink(ctx, bucket); err != nil { + return err + } + + // TODO make sure this is not the case on public installations + if _, err := s.upsertPrivateEndpoint(ctx, bucket, storageAccountName); err != nil { + return err + } + if err := s.upsertContainer(ctx, bucket, storageAccountName); err != nil { return err } @@ -139,7 +160,7 @@ func (s AzureObjectStorageAdapter) CreateBucket(ctx context.Context, bucket *v1a return err } - s.logger.Info(fmt.Sprintf("created secret %s", bucket.Spec.Name)) + s.logger.Info(fmt.Sprintf("upserted secret %s", bucket.Spec.Name)) return nil }