-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add os_disk_encryption_set to azure_rm_virtualmachine (#1306)
* Add os_disk_encryption_set to azure_rm_virtualmachine Add the parameter `os_disk_encryption_set` to the `azure_rm_virtualmachine` module, making it possible to specify which DES to use when encrypting the OS disk for a newly created VM. * Improved checking update of DES for OSDisk To ensure that we won't try to *add* or *change* DES on an existing VM, the logic to check existing DES setting and comparing it to the desired state is fixed to handle both cases. The code is also polished to make it more readable. * Add integration tests Add a new kind of virtual machine tests which creates VMs with encrypted OS disk using the new property `os_disk_encryption_set`. I also added the generated inventory to `.gitignore` to avoid comitting it by mistake. * Polish the code * Fix os disk encryption in tests Ensure that the OS disk is encrypted in the integration tests. This requires the DES to be granted access to the KeyVault, and that the KeyVault is protected against purges. To avoid that we get conflicts with previously deleted, but unpurged KVs, they are named with a date-based suffix.
- Loading branch information
Showing
6 changed files
with
318 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ venv* | |
.vscode | ||
ansible_collections/ | ||
.idea/ | ||
tests/integration/inventory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
...ation/targets/azure_rm_virtualmachine/lookup_plugins/azure_service_principal_attribute.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# (c) 2018 Yunge Zhu, <[email protected]> | ||
# (c) 2017 Ansible Project | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
from __future__ import (absolute_import, division, print_function) | ||
__metaclass__ = type | ||
|
||
DOCUMENTATION = """ | ||
lookup: azure_service_principal_attribute | ||
requirements: | ||
- azure-graphrbac | ||
author: | ||
- Yunge Zhu <[email protected]> | ||
version_added: "2.7" | ||
short_description: Look up Azure service principal attributes. | ||
description: | ||
- Describes object id of your Azure service principal account. | ||
options: | ||
azure_client_id: | ||
description: azure service principal client id. | ||
azure_secret: | ||
description: azure service principal secret | ||
azure_tenant: | ||
description: azure tenant | ||
azure_cloud_environment: | ||
description: azure cloud environment | ||
""" | ||
|
||
EXAMPLES = """ | ||
set_fact: | ||
object_id: "{{ lookup('azure_service_principal_attribute', | ||
azure_client_id=azure_client_id, | ||
azure_secret=azure_secret, | ||
azure_tenant=azure_secret) }}" | ||
""" | ||
|
||
RETURN = """ | ||
_raw: | ||
description: | ||
Returns object id of service principal. | ||
""" | ||
|
||
from ansible.errors import AnsibleError | ||
from ansible.plugins.lookup import LookupBase | ||
from ansible.module_utils._text import to_native | ||
|
||
try: | ||
from azure.common.credentials import ServicePrincipalCredentials | ||
from azure.graphrbac import GraphRbacManagementClient | ||
from azure.cli.core import cloud as azure_cloud | ||
except ImportError: | ||
raise AnsibleError( | ||
"The lookup azure_service_principal_attribute requires azure.graphrbac, msrest") | ||
|
||
|
||
class LookupModule(LookupBase): | ||
def run(self, terms, variables, **kwargs): | ||
|
||
self.set_options(direct=kwargs) | ||
|
||
credentials = {} | ||
credentials['azure_client_id'] = self.get_option('azure_client_id', None) | ||
credentials['azure_secret'] = self.get_option('azure_secret', None) | ||
credentials['azure_tenant'] = self.get_option('azure_tenant', 'common') | ||
|
||
if credentials['azure_client_id'] is None or credentials['azure_secret'] is None: | ||
raise AnsibleError("Must specify azure_client_id and azure_secret") | ||
|
||
_cloud_environment = azure_cloud.AZURE_PUBLIC_CLOUD | ||
if self.get_option('azure_cloud_environment', None) is not None: | ||
cloud_environment = azure_cloud.get_cloud_from_metadata_endpoint(credentials['azure_cloud_environment']) | ||
|
||
try: | ||
azure_credentials = ServicePrincipalCredentials(client_id=credentials['azure_client_id'], | ||
secret=credentials['azure_secret'], | ||
tenant=credentials['azure_tenant'], | ||
resource=_cloud_environment.endpoints.active_directory_graph_resource_id) | ||
|
||
client = GraphRbacManagementClient(azure_credentials, credentials['azure_tenant'], | ||
base_url=_cloud_environment.endpoints.active_directory_graph_resource_id) | ||
|
||
response = list(client.service_principals.list(filter="appId eq '{0}'".format(credentials['azure_client_id']))) | ||
sp = response[0] | ||
|
||
return sp.object_id.split(',') | ||
except Exception as ex: | ||
raise AnsibleError("Failed to get service principal object id: %s" % to_native(ex)) | ||
return False |
107 changes: 107 additions & 0 deletions
107
tests/integration/targets/azure_rm_virtualmachine/tasks/azure_test_encrypted.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
- name: Set variables | ||
ansible.builtin.include_tasks: setup.yml | ||
|
||
- name: Set up disk encryption sets | ||
ansible.builtin.include_tasks: setup_des.yml | ||
|
||
- name: Create VM with encrypted disks | ||
azure_rm_virtualmachine: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ vm_name }}" | ||
admin_username: "testuser" | ||
ssh_password_enabled: false | ||
ssh_public_keys: | ||
- path: /home/testuser/.ssh/authorized_keys | ||
key_data: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDfoYlIV4lTPZTv7hXaVwQQuqBgGs4yeNRX0SPo2+HQt9u4X7IGwrtXc0nEUm6LfaCikMH58bOL8f20NTGz285kxdFHZRcBXtqmnMz2rXwhK9gwq5h1khc+GzHtdcJXsGA4y0xuaNcidcg04jxAlN/06fwb/VYwwWTVbypNC0gpGEpWckCNm8vlDlA55sU5et0SZ+J0RKVvEaweUOeNbFZqckGPA384imfeYlADppK/7eAxqfBVadVvZG8IJk4yvATgaIENIFj2cXxqu2mQ/Bp5Wr45uApvJsFXmi+v/nkiOEV1QpLOnEwAZo6EfFS4CCQtsymxJCl1PxdJ5LD4ZOtP [email protected]" | ||
vm_size: Standard_B1ms | ||
virtual_network: "{{ network_name }}" | ||
os_disk_encryption_set: "{{ des_results.state.id }}" | ||
managed_disk_type: Standard_LRS | ||
image: | ||
offer: 0001-com-ubuntu-server-focal | ||
publisher: Canonical | ||
sku: 20_04-lts | ||
version: latest | ||
register: vm_output | ||
|
||
- name: Query auto created security group before deleting | ||
azure_rm_securitygroup_info: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ vm_name }}01" | ||
register: nsg_result | ||
|
||
- name: Assert that security group were exist before deleting | ||
ansible.builtin.assert: | ||
that: | ||
- nsg_result.securitygroups | length == 1 | ||
- nsg_result.securitygroups[0].network_interfaces | length == 1 | ||
|
||
- name: Delete VM | ||
azure_rm_virtualmachine: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ vm_name }}" | ||
remove_on_absent: all_autocreated | ||
state: absent | ||
|
||
- name: Destroy encrypted OS disk | ||
azure_rm_manageddisk: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ vm_name }}" | ||
state: absent | ||
|
||
- name: Destroy auto created NIC | ||
azure_rm_networkinterface: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ vm_name }}01" | ||
state: absent | ||
register: nic_result | ||
|
||
- name: Destroy security group | ||
azure_rm_securitygroup: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ vm_name }}01" | ||
state: absent | ||
|
||
- name: Destroy auto created public IP | ||
azure_rm_publicipaddress: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ vm_name }}01" | ||
state: absent | ||
|
||
- name: Destroy subnet | ||
azure_rm_subnet: | ||
resource_group: "{{ resource_group }}" | ||
virtual_network: "{{ network_name }}" | ||
name: "{{ subnet_name }}" | ||
state: absent | ||
|
||
- name: Destroy virtual network | ||
azure_rm_virtualnetwork: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ network_name }}" | ||
state: absent | ||
|
||
- name: Destroy availability set | ||
azure_rm_availabilityset: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ availability_set }}" | ||
state: absent | ||
|
||
- name: Destroy storage account | ||
azure_rm_storageaccount: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ storage_account }}" | ||
force_delete_nonempty: true | ||
state: absent | ||
|
||
- name: Destroy disk encryption set | ||
azure_rm_diskencryptionset: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ des_name }}" | ||
state: absent | ||
|
||
- name: Destroy key vault | ||
azure_rm_keyvault: | ||
vault_name: "{{ vault_name }}" | ||
resource_group: "{{ resource_group }}" | ||
state: absent |
94 changes: 94 additions & 0 deletions
94
tests/integration/targets/azure_rm_virtualmachine/tasks/setup_des.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
- name: Set vault name | ||
ansible.builtin.set_fact: | ||
vault_name: "kv{{ uid_short }}{{ '%m%d%H%M%S' | strftime }}" | ||
|
||
- name: Lookup service principal object id | ||
ansible.builtin.set_fact: | ||
object_id: "{{ lookup('azure_service_principal_attribute', | ||
azure_client_id=azure_client_id, | ||
azure_secret=azure_secret, | ||
azure_tenant=azure_tenant) }}" | ||
register: object_id_facts | ||
|
||
- name: Create a key vault | ||
azure_rm_keyvault: | ||
resource_group: "{{ resource_group }}" | ||
vault_name: "{{ vault_name }}" | ||
enabled_for_disk_encryption: true | ||
enable_purge_protection: true | ||
vault_tenant: "{{ azure_tenant }}" | ||
sku: | ||
name: standard | ||
family: A | ||
access_policies: | ||
- tenant_id: "{{ azure_tenant }}" | ||
object_id: "{{ object_id }}" | ||
keys: | ||
- get | ||
- list | ||
- wrapkey | ||
- unwrapkey | ||
- create | ||
- update | ||
- import | ||
- delete | ||
- backup | ||
- restore | ||
- recover | ||
- purge | ||
|
||
- name: Create a key in key vault | ||
azure_rm_keyvaultkey: | ||
key_name: testkey | ||
keyvault_uri: https://{{ vault_name }}.vault.azure.net | ||
|
||
- name: Get latest version of key | ||
azure_rm_keyvaultkey_info: | ||
vault_uri: https://{{ vault_name }}.vault.azure.net | ||
name: testkey | ||
register: results | ||
|
||
- name: Assert the key vault facts | ||
ansible.builtin.set_fact: | ||
key_url: "{{ results['keys'][0]['kid'] }}" | ||
|
||
- name: Create disk encryption set | ||
azure_rm_diskencryptionset: | ||
resource_group: "{{ resource_group }}" | ||
name: "{{ des_name }}" | ||
source_vault: "{{ vault_name }}" | ||
key_url: "{{ key_url }}" | ||
state: present | ||
register: des_results | ||
|
||
- name: Grant DES access to key vault | ||
azure_rm_keyvault: | ||
resource_group: "{{ resource_group }}" | ||
vault_name: "{{ vault_name }}" | ||
enabled_for_disk_encryption: true | ||
enable_purge_protection: true | ||
vault_tenant: "{{ azure_tenant }}" | ||
sku: | ||
name: standard | ||
family: A | ||
access_policies: | ||
- tenant_id: "{{ azure_tenant }}" | ||
object_id: "{{ object_id }}" | ||
keys: | ||
- get | ||
- list | ||
- wrapkey | ||
- unwrapkey | ||
- create | ||
- update | ||
- import | ||
- delete | ||
- backup | ||
- restore | ||
- recover | ||
- purge | ||
- object_id: "{{ des_results.state.identity.principal_id }}" | ||
keys: | ||
- get | ||
- wrapkey | ||
- unwrapkey |