community.general/lib/ansible/modules/cloud/amazon/ec2_win_password.py

202 lines
6.4 KiB
Python

#!/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: ec2_win_password
short_description: gets the default administrator password for ec2 windows instances
description:
- Gets the default administrator password from any EC2 Windows instance. The instance is referenced by its id (e.g. C(i-XXXXXXX)). This module
has a dependency on python-boto.
version_added: "2.0"
author: "Rick Mendes (@rickmendes)"
options:
instance_id:
description:
- The instance id to get the password data from.
required: true
key_file:
description:
- Path to the file containing the key pair used on the instance, conflicts with key_data.
required: false
key_data:
version_added: "2.8"
description:
- Variable that references the private key (usually stored in vault), conflicts with key_file.
required: false
key_passphrase:
version_added: "2.0"
description:
- The passphrase for the instance key pair. The key must use DES or 3DES encryption for this module to decrypt it. You can use openssl to
convert your password protected keys if they do not use DES or 3DES. ex) C(openssl rsa -in current_key -out new_key -des3).
wait:
version_added: "2.0"
description:
- Whether or not to wait for the password to be available before returning.
type: bool
default: 'no'
wait_timeout:
version_added: "2.0"
description:
- Number of seconds to wait before giving up.
default: 120
extends_documentation_fragment:
- aws
- ec2
requirements:
- cryptography
notes:
- As of Ansible 2.4, this module requires the python cryptography module rather than the
older pycrypto module.
'''
EXAMPLES = '''
# Example of getting a password
- name: get the Administrator password
ec2_win_password:
profile: my-boto-profile
instance_id: i-XXXXXX
region: us-east-1
key_file: "~/aws-creds/my_test_key.pem"
# Example of getting a password using a variable
- name: get the Administrator password
ec2_win_password:
profile: my-boto-profile
instance_id: i-XXXXXX
region: us-east-1
key_data: "{{ ec2_private_key }}"
# Example of getting a password with a password protected key
- name: get the Administrator password
ec2_win_password:
profile: my-boto-profile
instance_id: i-XXXXXX
region: us-east-1
key_file: "~/aws-creds/my_protected_test_key.pem"
key_passphrase: "secret"
# Example of waiting for a password
- name: get the Administrator password
ec2_win_password:
profile: my-boto-profile
instance_id: i-XXXXXX
region: us-east-1
key_file: "~/aws-creds/my_test_key.pem"
wait: yes
wait_timeout: 45
'''
import datetime
import time
from base64 import b64decode
try:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
from cryptography.hazmat.primitives.serialization import load_pem_private_key
HAS_CRYPTOGRAPHY = True
except ImportError:
HAS_CRYPTOGRAPHY = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import HAS_BOTO, ec2_argument_spec, ec2_connect
from ansible.module_utils._text import to_bytes
def main():
argument_spec = ec2_argument_spec()
argument_spec.update(dict(
instance_id=dict(required=True),
key_file=dict(required=False, default=None, type='path'),
key_passphrase=dict(no_log=True, default=None, required=False),
key_data=dict(no_log=True, default=None, required=False),
wait=dict(type='bool', default=False, required=False),
wait_timeout=dict(default=120, required=False, type='int'),
)
)
module = AnsibleModule(argument_spec=argument_spec)
if not HAS_BOTO:
module.fail_json(msg='Boto required for this module.')
if not HAS_CRYPTOGRAPHY:
module.fail_json(msg='cryptography package required for this module.')
instance_id = module.params.get('instance_id')
key_file = module.params.get('key_file')
key_data = module.params.get('key_data')
if module.params.get('key_passphrase') is None:
b_key_passphrase = None
else:
b_key_passphrase = to_bytes(module.params.get('key_passphrase'), errors='surrogate_or_strict')
wait = module.params.get('wait')
wait_timeout = module.params.get('wait_timeout')
ec2 = ec2_connect(module)
if wait:
start = datetime.datetime.now()
end = start + datetime.timedelta(seconds=wait_timeout)
while datetime.datetime.now() < end:
data = ec2.get_password_data(instance_id)
decoded = b64decode(data)
if not decoded:
time.sleep(5)
else:
break
else:
data = ec2.get_password_data(instance_id)
decoded = b64decode(data)
if wait and datetime.datetime.now() >= end:
module.fail_json(msg="wait for password timeout after %d seconds" % wait_timeout)
if key_file is not None and key_data is None:
try:
with open(key_file, 'rb') as f:
key = load_pem_private_key(f.read(), b_key_passphrase, default_backend())
except IOError as e:
# Handle bad files
module.fail_json(msg="I/O error (%d) opening key file: %s" % (e.errno, e.strerror))
except (ValueError, TypeError) as e:
# Handle issues loading key
module.fail_json(msg="unable to parse key file")
elif key_data is not None and key_file is None:
try:
key = load_pem_private_key(key_data, b_key_passphrase, default_backend())
except (ValueError, TypeError) as e:
module.fail_json(msg="unable to parse key data")
try:
decrypted = key.decrypt(decoded, PKCS1v15())
except ValueError as e:
decrypted = None
if decrypted is None:
module.exit_json(win_password='', changed=False)
else:
if wait:
elapsed = datetime.datetime.now() - start
module.exit_json(win_password=decrypted, changed=True, elapsed=elapsed.seconds)
else:
module.exit_json(win_password=decrypted, changed=True)
if __name__ == '__main__':
main()