summaryrefslogtreecommitdiff
path: root/lib/ansible/modules/cloud/azure/azure_rm_keyvaultkey.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/modules/cloud/azure/azure_rm_keyvaultkey.py')
-rw-r--r--lib/ansible/modules/cloud/azure/azure_rm_keyvaultkey.py310
1 files changed, 0 insertions, 310 deletions
diff --git a/lib/ansible/modules/cloud/azure/azure_rm_keyvaultkey.py b/lib/ansible/modules/cloud/azure/azure_rm_keyvaultkey.py
deleted file mode 100644
index 8a3b7722cc..0000000000
--- a/lib/ansible/modules/cloud/azure/azure_rm_keyvaultkey.py
+++ /dev/null
@@ -1,310 +0,0 @@
-#!/usr/bin/python
-# Copyright: 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: azure_rm_keyvaultkey
-version_added: 2.5
-short_description: Use Azure KeyVault keys
-description:
- - Create or delete a key within a given keyvault.
- - By using Key Vault, you can encrypt keys and secrets.
- - Such as authentication keys, storage account keys, data encryption keys, .PFX files, and passwords.
-options:
- keyvault_uri:
- description:
- - URI of the keyvault endpoint.
- required: true
- key_name:
- description:
- - Name of the keyvault key.
- required: true
- byok_file:
- description:
- - BYOK file.
- pem_file:
- description:
- - PEM file.
- pem_password:
- description:
- - PEM password.
- state:
- description:
- - Assert the state of the key. Use C(present) to create a key and C(absent) to delete a key.
- default: present
- choices:
- - absent
- - present
-
-extends_documentation_fragment:
- - azure
- - azure_tags
-
-author:
- - Ian Philpot (@iphilpot)
-
-'''
-
-EXAMPLES = '''
- - name: Create a key
- azure_rm_keyvaultkey:
- key_name: MyKey
- keyvault_uri: https://contoso.vault.azure.net/
-
- - name: Delete a key
- azure_rm_keyvaultkey:
- key_name: MyKey
- keyvault_uri: https://contoso.vault.azure.net/
- state: absent
-'''
-
-RETURN = '''
-state:
- description:
- - Current state of the key.
- returned: success
- type: complex
- contains:
- key_id:
- description:
- - key resource path.
- type: str
- example: https://contoso.vault.azure.net/keys/hello/e924f053839f4431b35bc54393f98423
-'''
-
-from ansible.module_utils.azure_rm_common import AzureRMModuleBase
-
-try:
- import re
- import codecs
- from azure.keyvault import KeyVaultClient, KeyVaultId, KeyVaultAuthentication
- from azure.keyvault.models import KeyAttributes, JsonWebKey
- from azure.common.credentials import ServicePrincipalCredentials
- from azure.keyvault.models.key_vault_error import KeyVaultErrorException
- from msrestazure.azure_active_directory import MSIAuthentication
- from OpenSSL import crypto
-except ImportError:
- # This is handled in azure_rm_common
- pass
-
-
-class AzureRMKeyVaultKey(AzureRMModuleBase):
- ''' Module that creates or deletes keys in Azure KeyVault '''
-
- def __init__(self):
-
- self.module_arg_spec = dict(
- key_name=dict(type='str', required=True),
- keyvault_uri=dict(type='str', required=True),
- pem_file=dict(type='str'),
- pem_password=dict(type='str'),
- byok_file=dict(type='str'),
- state=dict(type='str', default='present', choices=['present', 'absent'])
- )
-
- self.results = dict(
- changed=False,
- state=dict()
- )
-
- self.key_name = None
- self.keyvault_uri = None
- self.pem_file = None
- self.pem_password = None
- self.state = None
- self.client = None
- self.tags = None
-
- required_if = [
- ('pem_password', 'present', ['pem_file'])
- ]
-
- super(AzureRMKeyVaultKey, self).__init__(self.module_arg_spec,
- supports_check_mode=True,
- required_if=required_if,
- supports_tags=True)
-
- def exec_module(self, **kwargs):
-
- for key in list(self.module_arg_spec.keys()) + ['tags']:
- setattr(self, key, kwargs[key])
-
- # Create KeyVaultClient
- self.client = self.get_keyvault_client()
-
- results = dict()
- changed = False
-
- try:
- results['key_id'] = self.get_key(self.key_name)
-
- # Key exists and will be deleted
- if self.state == 'absent':
- changed = True
-
- except KeyVaultErrorException:
- # Key doesn't exist
- if self.state == 'present':
- changed = True
-
- self.results['changed'] = changed
- self.results['state'] = results
-
- if not self.check_mode:
-
- # Create key
- if self.state == 'present' and changed:
- results['key_id'] = self.create_key(self.key_name, self.tags)
- self.results['state'] = results
- self.results['state']['status'] = 'Created'
- # Delete key
- elif self.state == 'absent' and changed:
- results['key_id'] = self.delete_key(self.key_name)
- self.results['state'] = results
- self.results['state']['status'] = 'Deleted'
- else:
- if self.state == 'present' and changed:
- self.results['state']['status'] = 'Created'
- elif self.state == 'absent' and changed:
- self.results['state']['status'] = 'Deleted'
-
- return self.results
-
- def get_keyvault_client(self):
- try:
- self.log("Get KeyVaultClient from MSI")
- credentials = MSIAuthentication(resource='https://vault.azure.net')
- return KeyVaultClient(credentials)
- except Exception:
- self.log("Get KeyVaultClient from service principal")
-
- # Create KeyVault Client using KeyVault auth class and auth_callback
- def auth_callback(server, resource, scope):
- if self.credentials['client_id'] is None or self.credentials['secret'] is None:
- self.fail('Please specify client_id, secret and tenant to access azure Key Vault.')
-
- tenant = self.credentials.get('tenant')
- if not self.credentials['tenant']:
- tenant = "common"
-
- authcredential = ServicePrincipalCredentials(
- client_id=self.credentials['client_id'],
- secret=self.credentials['secret'],
- tenant=tenant,
- cloud_environment=self._cloud_environment,
- resource="https://vault.azure.net")
-
- token = authcredential.token
- return token['token_type'], token['access_token']
-
- return KeyVaultClient(KeyVaultAuthentication(auth_callback))
-
- def get_key(self, name, version=''):
- ''' Gets an existing key '''
- key_bundle = self.client.get_key(self.keyvault_uri, name, version)
- if key_bundle:
- key_id = KeyVaultId.parse_key_id(key_bundle.key.kid)
- return key_id.id
-
- def create_key(self, name, tags, kty='RSA'):
- ''' Creates a key '''
- key_bundle = self.client.create_key(vault_base_url=self.keyvault_uri, key_name=name, kty=kty, tags=tags)
- key_id = KeyVaultId.parse_key_id(key_bundle.key.kid)
- return key_id.id
-
- def delete_key(self, name):
- ''' Deletes a key '''
- deleted_key = self.client.delete_key(self.keyvault_uri, name)
- key_id = KeyVaultId.parse_key_id(deleted_key.key.kid)
- return key_id.id
-
- def import_key(self, key_name, destination=None, key_ops=None, disabled=False, expires=None,
- not_before=None, tags=None, pem_file=None, pem_password=None, byok_file=None):
- """ Import a private key. Supports importing base64 encoded private keys from PEM files.
- Supports importing BYOK keys into HSM for premium KeyVaults. """
-
- def _to_bytes(hex_string):
- # zero pads and decodes a hex string
- if len(hex_string) % 2:
- hex_string = '{0}'.format(hex_string)
- return codecs.decode(hex_string, 'hex_codec')
-
- def _set_rsa_parameters(dest, src):
- # map OpenSSL parameter names to JsonWebKey property names
- conversion_dict = {
- 'modulus': 'n',
- 'publicExponent': 'e',
- 'privateExponent': 'd',
- 'prime1': 'p',
- 'prime2': 'q',
- 'exponent1': 'dp',
- 'exponent2': 'dq',
- 'coefficient': 'qi'
- }
- # regex: looks for matches that fit the following patterns:
- # integerPattern: 65537 (0x10001)
- # hexPattern:
- # 00:a0:91:4d:00:23:4a:c6:83:b2:1b:4c:15:d5:be:
- # d8:87:bd:c9:59:c2:e5:7a:f5:4a:e7:34:e8:f0:07:
- # The desired match should always be the first component of the match
- regex = re.compile(r'([^:\s]*(:[^\:)]+\))|([^:\s]*(:\s*[0-9A-Fa-f]{2})+))')
- # regex2: extracts the hex string from a format like: 65537 (0x10001)
- regex2 = re.compile(r'(?<=\(0x{1})([0-9A-Fa-f]*)(?=\))')
-
- key_params = crypto.dump_privatekey(crypto.FILETYPE_TEXT, src).decode('utf-8')
- for match in regex.findall(key_params):
- comps = match[0].split(':', 1)
- name = conversion_dict.get(comps[0], None)
- if name:
- value = comps[1].replace(' ', '').replace('\n', '').replace(':', '')
- try:
- value = _to_bytes(value)
- except Exception: # pylint:disable=broad-except
- # if decoding fails it is because of an integer pattern. Extract the hex
- # string and retry
- value = _to_bytes(regex2.findall(value)[0])
- setattr(dest, name, value)
-
- key_attrs = KeyAttributes(not disabled, not_before, expires)
- key_obj = JsonWebKey(key_ops=key_ops)
- if pem_file:
- key_obj.kty = 'RSA'
- with open(pem_file, 'r') as f:
- pem_data = f.read()
- # load private key and prompt for password if encrypted
- try:
- pem_password = str(pem_password).encode() if pem_password else None
- # despite documentation saying password should be a string, it needs to actually
- # be UTF-8 encoded bytes
- pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, pem_data, pem_password)
- except crypto.Error:
- pass # wrong password
- except TypeError:
- pass # no pass provided
- _set_rsa_parameters(key_obj, pkey)
- elif byok_file:
- with open(byok_file, 'rb') as f:
- byok_data = f.read()
- key_obj.kty = 'RSA-HSM'
- key_obj.t = byok_data
-
- return self.client.import_key(
- self.keyvault_uri, key_name, key_obj, destination == 'hsm', key_attrs, tags)
-
-
-def main():
- AzureRMKeyVaultKey()
-
-
-if __name__ == '__main__':
- main()