Skip to content

Commit 6b643dc

Browse files
committed
Azure: User Customer Managed Key to enable Storage Account Encryption
1 parent 5748014 commit 6b643dc

File tree

2 files changed

+120
-4
lines changed

2 files changed

+120
-4
lines changed

pkg/infrastructure/azure/azure.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
329329
CloudName: platform.CloudName,
330330
Region: platform.Region,
331331
Tags: tags,
332+
CustomerManagedKey: platform.CustomerManagedKey,
332333
TokenCredential: tokenCredential,
333334
CloudConfiguration: cloudConfiguration,
334335
})

pkg/infrastructure/azure/storage.go

Lines changed: 119 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
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.
2936
type 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

Comments
 (0)