From 54a099cc0e37647daadbb4981236bafa55919a32 Mon Sep 17 00:00:00 2001 From: Chitender Kumar Date: Sun, 12 Nov 2023 16:01:45 +0000 Subject: [PATCH 1/3] adding functionality to define allow_shared_key_access,Identity Block for Key Vault Encryption Prerequisites,Inclusion of Key Vault Properties in Encryption Block,Incorporate Network ACL Rule Sets in create_account Requests --- plugins/modules/azure_rm_storageaccount.py | 69 +++++++++++++++++++--- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/plugins/modules/azure_rm_storageaccount.py b/plugins/modules/azure_rm_storageaccount.py index c7c280ef4..c9ac096bd 100644 --- a/plugins/modules/azure_rm_storageaccount.py +++ b/plugins/modules/azure_rm_storageaccount.py @@ -711,6 +711,14 @@ def __init__(self): blob_cors=dict(type='list', options=cors_rule_spec, elements='dict'), static_website=dict(type='dict', options=static_website_spec), is_hns_enabled=dict(type='bool'), + allow_shared_key_access=dict(type='bool'), + identity=dict( + type='dict', + options=dict( + type=dict(type='str', choices=["SystemAssigned", "UserAssigned", "None"]), + user_assigned_identities=dict(type='str', required=False) + ) + ), encryption=dict( type='dict', options=dict( @@ -736,7 +744,21 @@ def __init__(self): ) ), require_infrastructure_encryption=dict(type='bool'), - key_source=dict(type='str', choices=["Microsoft.Storage", "Microsoft.Keyvault"], default='Microsoft.Storage') + key_source=dict(type='str', choices=["Microsoft.Storage", "Microsoft.Keyvault"], default='Microsoft.Storage'), + key_vault_properties=dict( + type='dict', + options=dict( + key_vault_uri=dict(type='str', required=True), + key_name=dict(type='str', required=True), + key_version=dict(type='str') + ) + ), + encryption_identity=dict( + type='dict', + options=dict( + encryption_user_assigned_identity=dict(type='str', required=False) # This will hold the resource ID of the user-assigned identity + ) + ) ) ) ) @@ -766,6 +788,8 @@ def __init__(self): self.static_website = None self.encryption = None self.is_hns_enabled = None + self.allow_shared_key_access = None + self.identity = None super(AzureRMStorageAccount, self).__init__(self.module_arg_spec, supports_check_mode=True) @@ -815,6 +839,13 @@ def exec_module(self, **kwargs): elif self.state == 'failover' and self.account_dict: self.failover_account() self.results['state'] = self.get_account() + # # Check if 'identity' parameter exists and process it + if hasattr(self, 'identity') and self.identity: + if 'user_assigned_identities' in self.identity and isinstance(self.identity['user_assigned_identities'], str): + # Convert the string to a dictionary + identity_resource_id = self.identity['user_assigned_identities'] + self.identity['user_assigned_identities'] = {identity_resource_id: {}} + return self.results @@ -836,6 +867,15 @@ def get_account(self): try: account_obj = self.storage_client.storage_accounts.get_properties(self.resource_group, self.name) + if account_obj.identity and 'user_assigned_identities' in account_obj.identity: + # Check if user_assigned_identities is a dictionary + if isinstance(account_obj.identity['user_assigned_identities'], dict): + # Assuming there's only one key in the dictionary, + # convert the dictionary to a string (the key of the dictionary) + identity_resource_id_keys = list(account_obj.identity['user_assigned_identities'].keys()) + if identity_resource_id_keys: + account_obj.identity['user_assigned_identities'] = identity_resource_id_keys[0] + blob_mgmt_props = self.storage_client.blob_services.get_service_properties(self.resource_group, self.name) if self.kind != "FileStorage": blob_client_props = self.get_blob_service_client(self.resource_group, self.name).get_service_properties() @@ -844,7 +884,7 @@ def get_account(self): if account_obj: account_dict = self.account_obj_to_dict(account_obj, blob_mgmt_props, blob_client_props) - + # print("account dict:{}".format(account_dict)) return account_dict def account_obj_to_dict(self, account_obj, blob_mgmt_props=None, blob_client_props=None): @@ -870,11 +910,12 @@ def account_obj_to_dict(self, account_obj, blob_mgmt_props=None, blob_client_pro allow_blob_public_access=account_obj.allow_blob_public_access, network_acls=account_obj.network_rule_set, is_hns_enabled=account_obj.is_hns_enabled if account_obj.is_hns_enabled else False, + allow_shared_key_access=account_obj.allow_shared_key_access if account_obj.allow_shared_key_access else False, static_website=dict( enabled=False, index_document=None, error_document404_path=None, - ), + ) ) account_dict['custom_domain'] = None if account_obj.custom_domain: @@ -1182,6 +1223,12 @@ def create_account(self): if not self.access_tier and self.kind == 'BlobStorage': self.fail('Parameter error: access_tier required when creating a storage account of type BlobStorage.') + # # Check if 'identity' parameter exists and process it + if hasattr(self, 'identity') and self.identity: + if 'user_assigned_identities' in self.identity and isinstance(self.identity['user_assigned_identities'], str): + # Convert the string to a dictionary + identity_resource_id = self.identity['user_assigned_identities'] + self.identity['user_assigned_identities'] = {identity_resource_id: {}} self.check_name_availability() self.results['changed'] = True @@ -1198,12 +1245,15 @@ def create_account(self): allow_blob_public_access=self.allow_blob_public_access, encryption=self.encryption, is_hns_enabled=self.is_hns_enabled, + allow_shared_key_access=self.allow_shared_key_access, + network_rule_set=self.network_acls, + identity=self.identity, tags=dict() ) if self.tags: account_dict['tags'] = self.tags - if self.network_acls: - account_dict['network_acls'] = self.network_acls + # if self.network_acls: + # account_dict['network_acls'] = self.network_acls if self.blob_cors: account_dict['blob_cors'] = self.blob_cors if self.static_website: @@ -1223,7 +1273,10 @@ def create_account(self): allow_blob_public_access=self.allow_blob_public_access, encryption=self.encryption, is_hns_enabled=self.is_hns_enabled, - access_tier=self.access_tier) + allow_shared_key_access=self.allow_shared_key_access, + access_tier=self.access_tier, + network_rule_set=self.network_acls, + identity=self.identity) self.log(str(parameters)) try: poller = self.storage_client.storage_accounts.begin_create(self.resource_group, self.name, parameters) @@ -1231,8 +1284,8 @@ def create_account(self): except Exception as e: self.log('Error creating storage account.') self.fail("Failed to create account: {0}".format(str(e))) - if self.network_acls: - self.set_network_acls() + # if self.network_acls: + # self.set_network_acls() if self.blob_cors: self.set_blob_cors() if self.static_website: From 968610c9390dfec3eec477e6c19acc123767fb33 Mon Sep 17 00:00:00 2001 From: Chitender Kumar Date: Tue, 14 Nov 2023 11:42:45 +0530 Subject: [PATCH 2/3] adding documentation for new vars. --- plugins/modules/azure_rm_storageaccount.py | 70 +++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/plugins/modules/azure_rm_storageaccount.py b/plugins/modules/azure_rm_storageaccount.py index c9ac096bd..baa606dfe 100644 --- a/plugins/modules/azure_rm_storageaccount.py +++ b/plugins/modules/azure_rm_storageaccount.py @@ -17,6 +17,26 @@ description: - Create, update or delete a storage account. options: + allow_shared_key_access: + description: + - when Allow storage account key access is disabled, any requests to the account that are authorized with shared key, including shared access signature (SAS), will be denied. + type: boolean + default: True + identity: + description: + - Identity for the resource. + type: dict + contains: + type: + description: + - The identity type. Required. Known values are: "None", "SystemAssigned", "UserAssigned", and "SystemAssigned,UserAssigned". + type: str + sample: true + user_assigned_identities: + description: + - Gets or sets a list of key value pairs that describe the set of User Assigned identities that will be used with this storage account. The key is the ARM resource identifier of the identity. Only 1 User Assigned identity is permitted here. + type: str + sample: true resource_group: description: - Name of the resource group to use. @@ -294,11 +314,40 @@ choices: - Microsoft.Storage - Microsoft.Keyvault + key_vault_properties: + description: + - list of Microsoft Keyvault properties needed in order to create Storage account with encryption enabled with Microsoft KeyVault for CMK. + type: dict + contains: + key_vault_uri: + description: + - The Uri of KeyVault. + type: str + key_name: + description: + - The name of KeyVault key. + type: str + key_version: + description: + - The version of KeyVault key. + type: str + encryption_identity: + description: + - The identity to be used with service-side encryption at rest. + type: dict + contains: + encryption_user_assigned_identity: + description: + - Resource identifier of the UserAssigned identity to be associated with server-side encryption on the storage account. + type: str + + require_infrastructure_encryption: description: - A boolean indicating whether or not the service applies a secondary layer of encryption with platform managed keys for data at rest. type: bool + extends_documentation_fragment: - azure.azcollection.azure - azure.azcollection.azure_tags @@ -450,6 +499,25 @@ type: dict returned: always sample: {'enabled': true} + key_vault_properties: + description: + - list of Microsoft Keyvault properties needed in order to create Storage account with encryption enabled with Microsoft KeyVault for CMK. + type: dict + sample: false + contains: + key_vault_uri: + description: + - The Uri of KeyVault. + type: str + key_name: + description: + - The name of KeyVault key. + type: str + key_version: + description: + - The version of KeyVault key. + type: str + id: description: - Resource ID. @@ -845,8 +913,6 @@ def exec_module(self, **kwargs): # Convert the string to a dictionary identity_resource_id = self.identity['user_assigned_identities'] self.identity['user_assigned_identities'] = {identity_resource_id: {}} - - return self.results def check_name_availability(self): From 4c0d7fc519f8f3a01e888ab93d949633d6e4e6e1 Mon Sep 17 00:00:00 2001 From: Chitender Kumar Date: Tue, 14 Nov 2023 13:36:38 +0530 Subject: [PATCH 3/3] updating document to fix sanity issue --- plugins/modules/azure_rm_storageaccount.py | 33 +++++++++++++--------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/plugins/modules/azure_rm_storageaccount.py b/plugins/modules/azure_rm_storageaccount.py index baa606dfe..bb0a21690 100644 --- a/plugins/modules/azure_rm_storageaccount.py +++ b/plugins/modules/azure_rm_storageaccount.py @@ -19,24 +19,26 @@ options: allow_shared_key_access: description: - - when Allow storage account key access is disabled, any requests to the account that are authorized with shared key, including shared access signature (SAS), will be denied. - type: boolean + - When disabled, storage account key access denies all requests authorized by shared key or SAS. + type: bool default: True identity: description: - Identity for the resource. type: dict - contains: + suboptions: type: description: - - The identity type. Required. Known values are: "None", "SystemAssigned", "UserAssigned", and "SystemAssigned,UserAssigned". + - The identity type. Required. type: str - sample: true + choices: + - None + - SystemAssigned + - UserAssigned user_assigned_identities: description: - - Gets or sets a list of key value pairs that describe the set of User Assigned identities that will be used with this storage account. The key is the ARM resource identifier of the identity. Only 1 User Assigned identity is permitted here. + - Sets a single User Assigned identity for the account, using key-value pairs where the key is the identity's ARM resource ID. type: str - sample: true resource_group: description: - Name of the resource group to use. @@ -318,24 +320,27 @@ description: - list of Microsoft Keyvault properties needed in order to create Storage account with encryption enabled with Microsoft KeyVault for CMK. type: dict - contains: + suboptions: key_vault_uri: description: - The Uri of KeyVault. type: str + required: true key_name: description: - The name of KeyVault key. type: str + required: true key_version: description: - The version of KeyVault key. type: str + encryption_identity: description: - The identity to be used with service-side encryption at rest. type: dict - contains: + suboptions: encryption_user_assigned_identity: description: - Resource identifier of the UserAssigned identity to be associated with server-side encryption on the storage account. @@ -779,11 +784,11 @@ def __init__(self): blob_cors=dict(type='list', options=cors_rule_spec, elements='dict'), static_website=dict(type='dict', options=static_website_spec), is_hns_enabled=dict(type='bool'), - allow_shared_key_access=dict(type='bool'), + allow_shared_key_access=dict(type='bool', default='True'), identity=dict( type='dict', options=dict( - type=dict(type='str', choices=["SystemAssigned", "UserAssigned", "None"]), + type=dict(type='str', choices=['SystemAssigned', 'UserAssigned', 'None']), user_assigned_identities=dict(type='str', required=False) ) ), @@ -816,10 +821,10 @@ def __init__(self): key_vault_properties=dict( type='dict', options=dict( - key_vault_uri=dict(type='str', required=True), + key_vault_uri=dict(type='str', required=True, no_log=True), key_name=dict(type='str', required=True), - key_version=dict(type='str') - ) + key_version=dict(type='str', no_log=True) + ), no_log=True ), encryption_identity=dict( type='dict',