Skip to content

Commit

Permalink
r/storage_account_customer_managed_key: refactoring to use `hashicorp…
Browse files Browse the repository at this point in the history
…/go-azure-sdk`
  • Loading branch information
tombuildsstuff committed Mar 27, 2024
1 parent ec36b01 commit 3a57e43
Showing 1 changed file with 90 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage" // nolint: staticcheck
"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
"github.com/hashicorp/go-azure-sdk/resource-manager/keyvault/2023-07-01/managedhsms"
"github.com/hashicorp/go-azure-sdk/resource-manager/storage/2023-01-01/storageaccounts"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/locks"
Expand Down Expand Up @@ -98,7 +99,7 @@ func resourceStorageAccountCustomerManagedKey() *pluginsdk.Resource {
}

func resourceStorageAccountCustomerManagedKeyCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error {
storageClient := meta.(*clients.Client).Storage.AccountsClient
storageClient := meta.(*clients.Client).Storage.ResourceManager.StorageAccounts
keyVaultsClient := meta.(*clients.Client).KeyVault
vaultsClient := keyVaultsClient.VaultsClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
Expand All @@ -112,19 +113,21 @@ func resourceStorageAccountCustomerManagedKeyCreateUpdate(d *pluginsdk.ResourceD
locks.ByName(id.StorageAccountName, storageAccountResourceName)
defer locks.UnlockByName(id.StorageAccountName, storageAccountResourceName)

storageAccount, err := storageClient.GetProperties(ctx, id.ResourceGroupName, id.StorageAccountName, "")
existing, err := storageClient.GetProperties(ctx, *id, storageaccounts.DefaultGetPropertiesOperationOptions())
if err != nil {
return fmt.Errorf("retrieving %s: %+v", *id, err)
}
if storageAccount.AccountProperties == nil {
return fmt.Errorf("retrieving %s: `properties` was nil", id)
if existing.Model == nil {
return fmt.Errorf("retrieving %s: `model` was nil", id)
}
if existing.Model.Properties == nil {
return fmt.Errorf("retrieving %s: `model.Properties` was nil", id)
}

if d.IsNewResource() {
// whilst this looks superfluous given encryption is enabled by default, due to the way
// the Azure API works this technically can be nil
if storageAccount.AccountProperties.Encryption != nil {
if storageAccount.AccountProperties.Encryption.KeySource == storage.KeySourceMicrosoftKeyvault {
if existing.Model != nil && existing.Model.Properties != nil && existing.Model.Properties.Encryption != nil && existing.Model.Properties.Encryption.KeySource != nil {
if *existing.Model.Properties.Encryption.KeySource == storageaccounts.KeySourceMicrosoftPointKeyvault {
return tf.ImportAsExistsError("azurerm_storage_account_customer_managed_key", id.ID())
}
}
Expand Down Expand Up @@ -171,35 +174,34 @@ func resourceStorageAccountCustomerManagedKeyCreateUpdate(d *pluginsdk.ResourceD
userAssignedIdentity := d.Get("user_assigned_identity_id").(string)
federatedIdentityClientID := d.Get("federated_identity_client_id").(string)

props := storage.AccountUpdateParameters{
AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{
Encryption: &storage.Encryption{
Services: &storage.EncryptionServices{
Blob: &storage.EncryptionService{
payload := storageaccounts.StorageAccountUpdateParameters{
Properties: &storageaccounts.StorageAccountPropertiesUpdateParameters{
Encryption: &storageaccounts.Encryption{
Services: &storageaccounts.EncryptionServices{
Blob: &storageaccounts.EncryptionService{
Enabled: utils.Bool(true),
},
File: &storage.EncryptionService{
File: &storageaccounts.EncryptionService{
Enabled: utils.Bool(true),
},
},
EncryptionIdentity: &storage.EncryptionIdentity{
EncryptionUserAssignedIdentity: utils.String(userAssignedIdentity),
Identity: &storageaccounts.EncryptionIdentity{
UserAssignedIdentity: utils.String(userAssignedIdentity),
},
KeySource: storage.KeySourceMicrosoftKeyvault,
KeyVaultProperties: &storage.KeyVaultProperties{
KeyName: utils.String(keyName),
KeyVersion: utils.String(keyVersion),
KeyVaultURI: utils.String(keyVaultURI),
KeySource: pointer.To(storageaccounts.KeySourceMicrosoftPointKeyvault),
Keyvaultproperties: &storageaccounts.KeyVaultProperties{
Keyname: utils.String(keyName),
Keyversion: utils.String(keyVersion),
Keyvaulturi: utils.String(keyVaultURI),
},
},
},
}

if federatedIdentityClientID != "" {
props.Encryption.EncryptionIdentity.EncryptionFederatedIdentityClientID = utils.String(federatedIdentityClientID)
payload.Properties.Encryption.Identity.FederatedIdentityClientId = utils.String(federatedIdentityClientID)
}

if _, err = storageClient.Update(ctx, id.ResourceGroupName, id.StorageAccountName, props); err != nil {
if _, err = storageClient.Update(ctx, *id, payload); err != nil {
return fmt.Errorf("updating Customer Managed Key for %s: %+v", id, err)
}

Expand All @@ -208,7 +210,7 @@ func resourceStorageAccountCustomerManagedKeyCreateUpdate(d *pluginsdk.ResourceD
}

func resourceStorageAccountCustomerManagedKeyRead(d *pluginsdk.ResourceData, meta interface{}) error {
storageClient := meta.(*clients.Client).Storage.AccountsClient
storageClient := meta.(*clients.Client).Storage.ResourceManager.StorageAccounts
keyVaultsClient := meta.(*clients.Client).KeyVault
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()
Expand All @@ -218,83 +220,76 @@ func resourceStorageAccountCustomerManagedKeyRead(d *pluginsdk.ResourceData, met
return err
}

storageAccount, err := storageClient.GetProperties(ctx, id.ResourceGroupName, id.StorageAccountName, "")
resp, err := storageClient.GetProperties(ctx, *id, storageaccounts.DefaultGetPropertiesOperationOptions())
if err != nil {
if utils.ResponseWasNotFound(storageAccount.Response) {
if response.WasNotFound(resp.HttpResponse) {
log.Printf("[DEBUG] %q was not found - removing from state!", *id)
d.SetId("")
return nil
}

return fmt.Errorf("retrieving %s: %+v", id, err)
}
if storageAccount.AccountProperties == nil {
return fmt.Errorf("retrieving %s: `properties` was nil", id)
}
if storageAccount.AccountProperties.Encryption == nil || storageAccount.AccountProperties.Encryption.KeySource != storage.KeySourceMicrosoftKeyvault {
log.Printf("[DEBUG] Customer Managed Key was not defined for %s - removing from state!", id)
d.SetId("")
return nil
}

encryption := *storageAccount.AccountProperties.Encryption

keyName := ""
keyVaultURI := ""
keyVersion := ""
if props := encryption.KeyVaultProperties; props != nil {
if props.KeyName != nil {
keyName = *props.KeyName
}
if props.KeyVaultURI != nil {
keyVaultURI = *props.KeyVaultURI
}
if props.KeyVersion != nil {
keyVersion = *props.KeyVersion
}
}
d.Set("storage_account_id", id.ID())

userAssignedIdentity := ""
federatedIdentityClientID := ""
if props := encryption.EncryptionIdentity; props != nil {
if props.EncryptionUserAssignedIdentity != nil {
userAssignedIdentity = *props.EncryptionUserAssignedIdentity
}
if props.EncryptionFederatedIdentityClientID != nil {
federatedIdentityClientID = *props.EncryptionFederatedIdentityClientID
enabled := false
if model := resp.Model; model != nil {
if props := model.Properties; props != nil {
if encryption := props.Encryption; encryption != nil && encryption.KeySource != nil && *encryption.KeySource == storageaccounts.KeySourceMicrosoftPointKeyvault {
enabled = true

keyName := ""
keyVaultURI := ""
keyVersion := ""
if keyVaultProps := encryption.Keyvaultproperties; keyVaultProps != nil {
keyName = pointer.From(keyVaultProps.Keyname)
keyVaultURI = pointer.From(keyVaultProps.Keyvaulturi)
keyVersion = pointer.From(keyVaultProps.Keyversion)
}
if keyVaultURI == "" {
return fmt.Errorf("retrieving %s: `properties.encryption.keyVaultProperties.keyVaultURI` was nil", id)
}

federatedIdentityClientID := ""
userAssignedIdentity := ""
if identityProps := encryption.Identity; identityProps != nil {
federatedIdentityClientID = pointer.From(identityProps.FederatedIdentityClientId)
userAssignedIdentity = pointer.From(identityProps.UserAssignedIdentity)
}

// now we have the key vault uri we can look up the ID
// we can't look up the ID when using federated identity as the key will be under different tenant
keyVaultID := ""
if federatedIdentityClientID == "" {
subscriptionResourceId := commonids.NewSubscriptionID(id.SubscriptionId)
tmpKeyVaultID, err := keyVaultsClient.KeyVaultIDFromBaseUrl(ctx, subscriptionResourceId, keyVaultURI)
if err != nil {
return fmt.Errorf("retrieving Key Vault ID from the Base URI %q: %+v", keyVaultURI, err)
}
keyVaultID = pointer.From(tmpKeyVaultID)
}

d.Set("key_vault_id", keyVaultID)
d.Set("key_vault_uri", keyVaultURI)
d.Set("key_name", keyName)
d.Set("key_version", keyVersion)
d.Set("user_assigned_identity_id", userAssignedIdentity)
d.Set("federated_identity_client_id", federatedIdentityClientID)
}
}
}

if keyVaultURI == "" {
return fmt.Errorf("retrieving %s: `properties.encryption.keyVaultProperties.keyVaultURI` was nil", id)
}

// now we have the key vault uri we can look up the ID

// we can't look up the ID when using federated identity as the key will be under different tenant
keyVaultID := ""
if federatedIdentityClientID == "" {
subscriptionResourceId := commonids.NewSubscriptionID(id.SubscriptionId)
tmpKeyVaultID, err := keyVaultsClient.KeyVaultIDFromBaseUrl(ctx, subscriptionResourceId, keyVaultURI)
if err != nil {
return fmt.Errorf("retrieving Key Vault ID from the Base URI %q: %+v", keyVaultURI, err)
}
keyVaultID = pointer.From(tmpKeyVaultID)
if !enabled {
log.Printf("[DEBUG] Customer Managed Key was not defined for %s - removing from state!", id)
d.SetId("")
return nil
}

d.Set("storage_account_id", id.ID())
d.Set("key_vault_id", keyVaultID)
d.Set("key_vault_uri", keyVaultURI)
d.Set("key_name", keyName)
d.Set("key_version", keyVersion)
d.Set("user_assigned_identity_id", userAssignedIdentity)
d.Set("federated_identity_client_id", federatedIdentityClientID)

return nil
}

func resourceStorageAccountCustomerManagedKeyDelete(d *pluginsdk.ResourceData, meta interface{}) error {
storageClient := meta.(*clients.Client).Storage.AccountsClient
storageClient := meta.(*clients.Client).Storage.ResourceManager.StorageAccounts
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

Expand All @@ -307,9 +302,9 @@ func resourceStorageAccountCustomerManagedKeyDelete(d *pluginsdk.ResourceData, m
defer locks.UnlockByName(id.StorageAccountName, storageAccountResourceName)

// confirm it still exists prior to trying to update it, else we'll get an error
storageAccount, err := storageClient.GetProperties(ctx, id.ResourceGroupName, id.StorageAccountName, "")
storageAccount, err := storageClient.GetProperties(ctx, *id, storageaccounts.DefaultGetPropertiesOperationOptions())
if err != nil {
if utils.ResponseWasNotFound(storageAccount.Response) {
if response.WasNotFound(storageAccount.HttpResponse) {
return nil
}

Expand All @@ -320,24 +315,24 @@ func resourceStorageAccountCustomerManagedKeyDelete(d *pluginsdk.ResourceData, m
// "Delete" doesn't really make sense it should really be a "Revert to Default"
// So instead of the Delete func actually deleting the Storage Account I am
// making it reset the Storage Account to its default state
props := storage.AccountUpdateParameters{
AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{
Encryption: &storage.Encryption{
Services: &storage.EncryptionServices{
Blob: &storage.EncryptionService{
payload := storageaccounts.StorageAccountUpdateParameters{
Properties: &storageaccounts.StorageAccountPropertiesUpdateParameters{
Encryption: &storageaccounts.Encryption{
Services: &storageaccounts.EncryptionServices{
Blob: &storageaccounts.EncryptionService{
Enabled: utils.Bool(true),
},
File: &storage.EncryptionService{
File: &storageaccounts.EncryptionService{
Enabled: utils.Bool(true),
},
},
KeySource: storage.KeySourceMicrosoftStorage,
KeySource: pointer.To(storageaccounts.KeySourceMicrosoftPointStorage),
},
},
}

if _, err = storageClient.Update(ctx, id.ResourceGroupName, id.StorageAccountName, props); err != nil {
return fmt.Errorf("removing Customer Managed Key for %s: %+v", id, err)
if _, err = storageClient.Update(ctx, *id, payload); err != nil {
return fmt.Errorf("removing Customer Managed Key for %s: %+v", *id, err)
}

return nil
Expand Down

0 comments on commit 3a57e43

Please sign in to comment.