44 "bytes"
55 "context"
66 "fmt"
7+ "strings"
78 "sync"
89 "time"
910
@@ -13,6 +14,7 @@ import (
1314 "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
1415 "github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming"
1516 "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
17+ "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault"
1618 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
1719 "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
1820 "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
@@ -24,6 +26,11 @@ import (
2426 aztypes "github.com/openshift/installer/pkg/types/azure"
2527)
2628
29+ var (
30+ vaultsClient * armkeyvault.VaultsClient
31+ keysClient * armkeyvault.KeysClient
32+ )
33+
2734// CreateStorageAccountInput contains the input parameters for creating a
2835// storage account.
2936type CreateStorageAccountInput struct {
@@ -32,6 +39,7 @@ type CreateStorageAccountInput struct {
3239 StorageAccountName string
3340 Region string
3441 Tags map [string ]* string
42+ CustomerManagedKey * aztypes.CustomerManagedKey
3543 CloudName aztypes.CloudEnvironment
3644 TokenCredential azcore.TokenCredential
3745 CloudConfiguration cloud.Configuration
@@ -73,6 +81,33 @@ func CreateStorageAccount(ctx context.Context, in *CreateStorageAccountInput) (*
7381 return nil , fmt .Errorf ("failed to get storage account factory %w" , err )
7482 }
7583
84+ logrus .Debugf ("Generating Encrytption for Storage Account using Customer Managed Key" )
85+ encryption , err := GenerateStorageAccountEncryption (
86+ ctx ,
87+ & CustomerManagedKeyInput {
88+ SubscriptionID : in .SubscriptionID ,
89+ ResourceGroupName : in .ResourceGroupName ,
90+ CustomerManagedKey : in .CustomerManagedKey ,
91+ TokenCredential : in .TokenCredential ,
92+ },
93+ )
94+ if err != nil {
95+ return nil , fmt .Errorf ("error generating encryption information for provided customer managed key: %w" , err )
96+ }
97+
98+ sku := armstorage.SKU {
99+ Name : to .Ptr (armstorage .SKUNameStandardLRS ),
100+ }
101+ if in .CustomerManagedKey != nil && in .CustomerManagedKey .KeyVault .Name != "" {
102+ // When encryption is enabled, Ignition is is stored as a page blob
103+ // (and not a block blob). To support this case, `Kind` can continue to be
104+ // `StorageV2` and yhe `SKU` needs to be `Premium_LRS`.
105+ //https://learn.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal
106+ sku = armstorage.SKU {
107+ Name : to .Ptr (armstorage .SKUNamePremiumLRS ),
108+ }
109+ }
110+
76111 logrus .Debugf ("Creating storage account" )
77112 accountsClient := storageClientFactory .NewAccountsClient ()
78113 pollerResponse , err := accountsClient .BeginCreate (
@@ -82,16 +117,15 @@ func CreateStorageAccount(ctx context.Context, in *CreateStorageAccountInput) (*
82117 armstorage.AccountCreateParameters {
83118 Kind : to .Ptr (armstorage .KindStorageV2 ),
84119 Location : to .Ptr (in .Region ),
85- SKU : & armstorage.SKU {
86- Name : to .Ptr (armstorage .SKUNameStandardLRS ), // XXX Premium_LRS if disk encryption if used
87- },
120+ SKU : & sku ,
88121 Properties : & armstorage.AccountPropertiesCreateParameters {
89- AllowBlobPublicAccess : to .Ptr (true ), // XXX true if using disk encryption
122+ AllowBlobPublicAccess : to .Ptr (true ),
90123 AllowSharedKeyAccess : to .Ptr (true ),
91124 IsLocalUserEnabled : to .Ptr (true ),
92125 LargeFileSharesState : to .Ptr (armstorage .LargeFileSharesStateEnabled ),
93126 PublicNetworkAccess : to .Ptr (armstorage .PublicNetworkAccessEnabled ),
94127 MinimumTLSVersion : & minimumTLSVersion ,
128+ Encryption : encryption ,
95129 },
96130 Tags : in .Tags ,
97131 },
@@ -384,3 +418,84 @@ func CreateBlockBlob(ctx context.Context, in *CreateBlockBlobInput) (string, err
384418
385419 return sasURL , nil
386420}
421+
422+ // CustomerManagedKeyInput contains the input parameters for creating the
423+ // customer managed key and identity.
424+ type CustomerManagedKeyInput struct {
425+ SubscriptionID string
426+ ResourceGroupName string
427+ CustomerManagedKey * aztypes.CustomerManagedKey
428+ TokenCredential azcore.TokenCredential
429+ }
430+
431+ // GenerateStorageAccountEncryption generates all the Encryption information for the Storage Account
432+ // using the Customer Managed Key.
433+ func GenerateStorageAccountEncryption (ctx context.Context , in * CustomerManagedKeyInput ) (* armstorage.Encryption , error ) {
434+ logrus .Debugf ("Generating Encryption for Storage Account" )
435+
436+ if in .CustomerManagedKey == nil {
437+ logrus .Debugf ("No Customer Managed Key. So, Encryption not enabled on storage account." )
438+ return & armstorage.Encryption {}, nil
439+ }
440+
441+ keyvaultClientFactory , err := armkeyvault .NewClientFactory (
442+ in .SubscriptionID ,
443+ in .TokenCredential ,
444+ nil )
445+ if err != nil {
446+ return nil , fmt .Errorf ("failed to get key vault client factory %w" , err )
447+ }
448+
449+ keysClient = keyvaultClientFactory .NewKeysClient ()
450+
451+ keysClientResponse , err := keysClient .Get (
452+ ctx ,
453+ in .CustomerManagedKey .KeyVault .ResourceGroup ,
454+ in .CustomerManagedKey .KeyVault .Name ,
455+ in .CustomerManagedKey .KeyVault .KeyName ,
456+ & armkeyvault.KeysClientGetOptions {})
457+ if err != nil {
458+ return nil , fmt .Errorf ("failed to get customer managed key %s from key vault %s: %w" , in .CustomerManagedKey .KeyVault .KeyName , in .CustomerManagedKey .KeyVault .Name , err )
459+ }
460+
461+ vaultsClient = keyvaultClientFactory .NewVaultsClient ()
462+
463+ keyVault , err := vaultsClient .Get (
464+ ctx ,
465+ in .CustomerManagedKey .KeyVault .ResourceGroup ,
466+ in .CustomerManagedKey .KeyVault .Name ,
467+ & armkeyvault.VaultsClientGetOptions {})
468+ if err != nil {
469+ return nil , fmt .Errorf ("failed to get key vault %s which contains customer managed key: %w" , in .CustomerManagedKey .KeyVault .Name , err )
470+ }
471+
472+ keyType := armstorage .KeyTypeAccount
473+ keySource := armstorage .KeySourceMicrosoftKeyvault
474+
475+ keyURIWithVersionSplit := strings .Split (* keysClientResponse .Key .Properties .KeyURIWithVersion , "/" )
476+ versionPosition := len (keyURIWithVersionSplit ) - 1
477+
478+ encryption := & armstorage.Encryption {
479+ Services : & armstorage.EncryptionServices {
480+ Blob : & armstorage.EncryptionService {
481+ Enabled : to .Ptr (true ),
482+ KeyType : & keyType ,
483+ },
484+ File : & armstorage.EncryptionService {
485+ Enabled : to .Ptr (true ),
486+ KeyType : & keyType ,
487+ },
488+ },
489+ EncryptionIdentity : & armstorage.EncryptionIdentity {
490+ EncryptionUserAssignedIdentity : & in .CustomerManagedKey .UserAssignedIdentityKey ,
491+ },
492+ KeySource : & keySource ,
493+ KeyVaultProperties : & armstorage.KeyVaultProperties {
494+ KeyName : keysClientResponse .Key .Name ,
495+ KeyVersion : & keyURIWithVersionSplit [versionPosition ],
496+ KeyVaultURI : keyVault .Properties .VaultURI ,
497+ },
498+ }
499+
500+ return encryption , nil
501+ }
0 commit comments