Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ec2_win_password - migrate to boto3 #759

Merged
merged 3 commits into from
Oct 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/759-ec2_win_password.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ec2_win_password - module updated to use the boto3 AWS SDK (https://github.com/ansible-collections/community.aws/pull/759).
35 changes: 20 additions & 15 deletions plugins/modules/ec2_win_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
---
module: ec2_win_password
version_added: 1.0.0
short_description: Gets the default administrator password for ec2 windows instances
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.
author: "Rick Mendes (@rickmendes)"
options:
instance_id:
Expand Down Expand Up @@ -55,10 +54,6 @@

requirements:
- cryptography
- boto >= 2.49.0
notes:
- As of Ansible 2.4, this module requires the python cryptography module rather than the
older pycrypto module.
'''

EXAMPLES = '''
Expand Down Expand Up @@ -110,11 +105,15 @@
except ImportError:
HAS_CRYPTOGRAPHY = False

try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule

from ansible.module_utils._text import to_bytes

from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ec2_connect
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry


def setup_module_object():
Expand All @@ -126,10 +125,19 @@ def setup_module_object():
wait=dict(type='bool', default=False, required=False),
wait_timeout=dict(default=120, required=False, type='int'),
)
module = AnsibleAWSModule(argument_spec=argument_spec)
mutually_exclusive = [['key_file', 'key_data']]
module = AnsibleAWSModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive)
return module


def _get_password(module, client, instance_id):
try:
data = client.get_password_data(aws_retry=True, InstanceId=instance_id)['PasswordData']
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(e, msg='Failed to get password data')
return data


def ec2_win_password(module):
instance_id = module.params.get('instance_id')
key_file = module.params.get('key_file')
Expand All @@ -144,21 +152,21 @@ def ec2_win_password(module):
wait = module.params.get('wait')
wait_timeout = module.params.get('wait_timeout')

ec2 = ec2_connect(module)
client = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff())

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)
data = _get_password(module, client, instance_id)
decoded = b64decode(data)
if not decoded:
time.sleep(5)
else:
break
else:
data = ec2.get_password_data(instance_id)
data = _get_password(module, client, instance_id)
decoded = b64decode(data)

if wait and datetime.datetime.now() >= end:
Expand Down Expand Up @@ -198,9 +206,6 @@ def ec2_win_password(module):
def main():
module = setup_module_object()

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.')

Expand Down
2 changes: 2 additions & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ netaddr
awscli
# Used for comparing SSH Public keys to the Amazon fingerprints
pycrypto
# Used by ec2_win_password
cryptography
34 changes: 24 additions & 10 deletions tests/unit/plugins/modules/test_ec2_win_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
string_cipher = base64.b64encode(base64_cipher)
'''

import datetime

from ansible.module_utils._text import to_bytes
from ansible.module_utils._text import to_text
from ansible_collections.community.aws.tests.unit.compat.mock import patch
Expand All @@ -31,25 +33,37 @@


class TestEc2WinPasswordModule(ModuleTestCase):
@patch('ansible_collections.community.aws.plugins.modules.ec2_win_password.ec2_connect')
def test_decryption(self, mock_connect):

path = fixture_prefix + '/ec2_win_password.pem'
# Future: It would be good to generate this data on the fly and use a
# temporary certificate and password.
PEM_PATH = fixture_prefix + '/ec2_win_password.pem'
UNENCRYPTED_DATA = 'Ansible_AWS_EC2_Win_Password'
ENCRYPTED_DATA = 'L2k1iFiu/TRrjGr6Rwco/T3C7xkWxUw4+YPYpGGOmP3KDdy3hT1' \
'8RvdDJ2i0e+y7wUcH43DwbRYSlkSyALY/nzjSV9R5NChUyVs3W5' \
'5oiVuyTKsk0lor8dFJ9z9unq14tScZHvyQ3Nx1ggOtS18S9Pk55q' \
'IaCXfx26ucH76VRho='
INSTANCE_ID = 'i-12345'

@patch('ansible_collections.community.aws.plugins.modules.s3_bucket_notification.AnsibleAWSModule.client')
def test_decryption(self, mock_client):

path = self.PEM_PATH
with open(path, 'r') as f:
pem = to_text(f.read())

with self.assertRaises(AnsibleExitJson) as exec_info:
set_module_args({'instance_id': 'i-12345',
'key_data': pem
set_module_args({'instance_id': self.INSTANCE_ID,
'key_data': pem,
})
module = setup_module_object()
mock_connect().get_password_data.return_value = 'L2k1iFiu/TRrjGr6Rwco/T3C7xkWxUw4+YPYpGGOmP3KDdy3hT1' \
'8RvdDJ2i0e+y7wUcH43DwbRYSlkSyALY/nzjSV9R5NChUyVs3W5' \
'5oiVuyTKsk0lor8dFJ9z9unq14tScZHvyQ3Nx1ggOtS18S9Pk55q' \
'IaCXfx26ucH76VRho='
mock_client().get_password_data.return_value = {
'InstanceId': self.INSTANCE_ID,
'PasswordData': self.ENCRYPTED_DATA,
'Timestamp': datetime.datetime.now(),
}
ec2_win_password(module)

self.assertEqual(
exec_info.exception.args[0]['win_password'],
to_bytes('Ansible_AWS_EC2_Win_Password'),
to_bytes(self.UNENCRYPTED_DATA),
)
1 change: 1 addition & 0 deletions tests/unit/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ boto3
boto

placebo
cryptography