mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-10-11 10:54:02 -07:00
* Move profile and region checking to module_utils.ec2 Remove ProfileNotFound checking from individual modules There are plenty of `if not region:` checks that could be removed, once more thorough testing of this change has occured The ec2_asg, iam_managed_policy and ec2_vpc_subnet_facts modules would also benefit from this change but as they do not have tests and are marked stableinterface, they do not get this change.
327 lines
11 KiB
Python
327 lines
11 KiB
Python
#!/usr/bin/python
|
|
# Copyright (c) 2017 Ansible Project
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
'status': ['preview'],
|
|
'supported_by': 'community'}
|
|
|
|
DOCUMENTATION = '''
|
|
module: aws_acm_facts
|
|
short_description: Retrieve certificate facts from AWS Certificate Manager service
|
|
description:
|
|
- Retrieve facts for ACM certificates
|
|
version_added: "2.5"
|
|
options:
|
|
name:
|
|
description:
|
|
- The name of an ACM certificate
|
|
status:
|
|
description:
|
|
- Status to filter the certificate results
|
|
choices: ['PENDING_VALIDATION', 'ISSUED', 'INACTIVE', 'EXPIRED', 'VALIDATION_TIMED_OUT']
|
|
|
|
requirements:
|
|
- boto3
|
|
author:
|
|
- Will Thames (@willthames)
|
|
extends_documentation_fragment: aws
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
- name: obtain all ACM certificates
|
|
aws_acm_facts:
|
|
|
|
- name: obtain all facts for a single ACM certificate
|
|
aws_acm_facts:
|
|
name: "*.example_com"
|
|
|
|
- name: obtain all certificates pending validiation
|
|
aws_acm_facts:
|
|
statuses:
|
|
- PENDING_VALIDATION
|
|
'''
|
|
|
|
RETURN = '''
|
|
certificates:
|
|
description: A list of certificates
|
|
returned: always
|
|
type: complex
|
|
contains:
|
|
certificate:
|
|
description: The ACM Certificate body
|
|
returned: when certificate creation is complete
|
|
sample: '-----BEGIN CERTIFICATE-----\\nMII.....-----END CERTIFICATE-----\\n'
|
|
type: string
|
|
certificate_arn:
|
|
description: Certificate ARN
|
|
returned: always
|
|
sample: arn:aws:acm:ap-southeast-2:123456789012:certificate/abcd1234-abcd-1234-abcd-123456789abc
|
|
type: string
|
|
certificate_chain:
|
|
description: Full certificate chain for the certificate
|
|
returned: when certificate creation is complete
|
|
sample: '-----BEGIN CERTIFICATE-----\\nMII...\\n-----END CERTIFICATE-----\\n-----BEGIN CERTIFICATE-----\\n...'
|
|
type: string
|
|
created_at:
|
|
description: Date certificate was created
|
|
returned: always
|
|
sample: '2017-08-15T10:31:19+10:00'
|
|
type: string
|
|
domain_name:
|
|
description: Domain name for the certificate
|
|
returned: always
|
|
sample: '*.example.com'
|
|
type: string
|
|
domain_validation_options:
|
|
description: Options used by ACM to validate the certificate
|
|
returned: when certificate type is AMAZON_ISSUED
|
|
type: complex
|
|
contains:
|
|
domain_name:
|
|
description: Fully qualified domain name of the certificate
|
|
returned: always
|
|
sample: example.com
|
|
type: string
|
|
validation_domain:
|
|
description: The domain name ACM used to send validation emails
|
|
returned: always
|
|
sample: example.com
|
|
type: string
|
|
validation_emails:
|
|
description: A list of email addresses that ACM used to send domain validation emails
|
|
returned: always
|
|
sample:
|
|
- admin@example.com
|
|
- postmaster@example.com
|
|
type: list
|
|
validation_status:
|
|
description: Validation status of the domain
|
|
returned: always
|
|
sample: SUCCESS
|
|
type: string
|
|
failure_reason:
|
|
description: Reason certificate request failed
|
|
returned: only when certificate issuing failed
|
|
type: string
|
|
sample: NO_AVAILABLE_CONTACTS
|
|
in_use_by:
|
|
description: A list of ARNs for the AWS resources that are using the certificate.
|
|
returned: always
|
|
sample: []
|
|
type: list
|
|
issued_at:
|
|
description: Date certificate was issued
|
|
returned: always
|
|
sample: '2017-01-01T00:00:00+10:00'
|
|
type: string
|
|
issuer:
|
|
description: Issuer of the certificate
|
|
returned: always
|
|
sample: Amazon
|
|
type: string
|
|
key_algorithm:
|
|
description: Algorithm used to generate the certificate
|
|
returned: always
|
|
sample: RSA-2048
|
|
type: string
|
|
not_after:
|
|
description: Date after which the certificate is not valid
|
|
returned: always
|
|
sample: '2019-01-01T00:00:00+10:00'
|
|
type: string
|
|
not_before:
|
|
description: Date before which the certificate is not valid
|
|
returned: always
|
|
sample: '2017-01-01T00:00:00+10:00'
|
|
type: string
|
|
renewal_summary:
|
|
description: Information about managed renewal process
|
|
returned: when certificate is issued by Amazon and a renewal has been started
|
|
type: complex
|
|
contains:
|
|
domain_validation_options:
|
|
description: Options used by ACM to validate the certificate
|
|
returned: when certificate type is AMAZON_ISSUED
|
|
type: complex
|
|
contains:
|
|
domain_name:
|
|
description: Fully qualified domain name of the certificate
|
|
returned: always
|
|
sample: example.com
|
|
type: string
|
|
validation_domain:
|
|
description: The domain name ACM used to send validation emails
|
|
returned: always
|
|
sample: example.com
|
|
type: string
|
|
validation_emails:
|
|
description: A list of email addresses that ACM used to send domain validation emails
|
|
returned: always
|
|
sample:
|
|
- admin@example.com
|
|
- postmaster@example.com
|
|
type: list
|
|
validation_status:
|
|
description: Validation status of the domain
|
|
returned: always
|
|
sample: SUCCESS
|
|
type: string
|
|
renewal_status:
|
|
description: Status of the domain renewal
|
|
returned: always
|
|
sample: PENDING_AUTO_RENEWAL
|
|
type: string
|
|
revocation_reason:
|
|
description: Reason for certificate revocation
|
|
returned: when the certificate has been revoked
|
|
sample: SUPERCEDED
|
|
type: string
|
|
revoked_at:
|
|
description: Date certificate was revoked
|
|
returned: when the certificate has been revoked
|
|
sample: '2017-09-01T10:00:00+10:00'
|
|
type: string
|
|
serial:
|
|
description: The serial number of the certificate
|
|
returned: always
|
|
sample: 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f
|
|
type: string
|
|
signature_algorithm:
|
|
description: Algorithm used to sign the certificate
|
|
returned: always
|
|
sample: SHA256WITHRSA
|
|
type: string
|
|
status:
|
|
description: Status of the certificate in ACM
|
|
returned: always
|
|
sample: ISSUED
|
|
type: string
|
|
subject:
|
|
description: The name of the entity that is associated with the public key contained in the certificate
|
|
returned: always
|
|
sample: CN=*.example.com
|
|
type: string
|
|
subject_alternative_names:
|
|
description: Subject Alternative Names for the certificate
|
|
returned: always
|
|
sample:
|
|
- '*.example.com'
|
|
type: list
|
|
tags:
|
|
description: Tags associated with the certificate
|
|
returned: always
|
|
type: dict
|
|
sample:
|
|
Application: helloworld
|
|
Environment: test
|
|
type:
|
|
description: The source of the certificate
|
|
returned: always
|
|
sample: AMAZON_ISSUED
|
|
type: string
|
|
'''
|
|
|
|
import traceback
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
from ansible.module_utils.ec2 import boto3_conn, ec2_argument_spec, get_aws_connection_info
|
|
from ansible.module_utils.ec2 import camel_dict_to_snake_dict, AWSRetry, HAS_BOTO3, boto3_tag_list_to_ansible_dict
|
|
|
|
|
|
try:
|
|
import botocore
|
|
except ImportError:
|
|
pass # caught by imported HAS_BOTO3
|
|
|
|
|
|
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
|
|
def list_certificates_with_backoff(client, statuses=None):
|
|
paginator = client.get_paginator('list_certificates')
|
|
kwargs = dict()
|
|
if statuses:
|
|
kwargs['CertificateStatuses'] = statuses
|
|
return paginator.paginate(**kwargs).build_full_result()['CertificateSummaryList']
|
|
|
|
|
|
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
|
|
def get_certificate_with_backoff(client, certificate_arn):
|
|
response = client.get_certificate(CertificateArn=certificate_arn)
|
|
# strip out response metadata
|
|
return {'Certificate': response['Certificate'],
|
|
'CertificateChain': response['CertificateChain']}
|
|
|
|
|
|
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
|
|
def describe_certificate_with_backoff(client, certificate_arn):
|
|
return client.describe_certificate(CertificateArn=certificate_arn)['Certificate']
|
|
|
|
|
|
@AWSRetry.backoff(tries=5, delay=5, backoff=2.0)
|
|
def list_certificate_tags_with_backoff(client, certificate_arn):
|
|
return client.list_tags_for_certificate(CertificateArn=certificate_arn)['Tags']
|
|
|
|
|
|
def get_certificates(client, module, name=None, statuses=None):
|
|
try:
|
|
all_certificates = list_certificates_with_backoff(client, statuses)
|
|
except botocore.exceptions.ClientError as e:
|
|
module.fail_json(msg="Couldn't obtain certificates",
|
|
exception=traceback.format_exc(),
|
|
**camel_dict_to_snake_dict(e.response))
|
|
if name:
|
|
certificates = [cert for cert in all_certificates
|
|
if cert['DomainName'] == name]
|
|
else:
|
|
certificates = all_certificates
|
|
|
|
results = []
|
|
for certificate in certificates:
|
|
try:
|
|
cert_data = describe_certificate_with_backoff(client, certificate['CertificateArn'])
|
|
except botocore.exceptions.ClientError as e:
|
|
module.fail_json(msg="Couldn't obtain certificate metadata for domain %s" % certificate['DomainName'],
|
|
exception=traceback.format_exc(),
|
|
**camel_dict_to_snake_dict(e.response))
|
|
try:
|
|
cert_data.update(get_certificate_with_backoff(client, certificate['CertificateArn']))
|
|
except botocore.exceptions.ClientError as e:
|
|
if e.response['Error']['Code'] != "RequestInProgressException":
|
|
module.fail_json(msg="Couldn't obtain certificate data for domain %s" % certificate['DomainName'],
|
|
exception=traceback.format_exc(),
|
|
**camel_dict_to_snake_dict(e.response))
|
|
cert_data = camel_dict_to_snake_dict(cert_data)
|
|
try:
|
|
tags = list_certificate_tags_with_backoff(client, certificate['CertificateArn'])
|
|
except botocore.exceptions.ClientError as e:
|
|
module.fail_json(msg="Couldn't obtain tags for domain %s" % certificate['DomainName'],
|
|
exception=traceback.format_exc(),
|
|
**camel_dict_to_snake_dict(e.response))
|
|
cert_data['tags'] = boto3_tag_list_to_ansible_dict(tags)
|
|
results.append(cert_data)
|
|
return results
|
|
|
|
|
|
def main():
|
|
argument_spec = ec2_argument_spec()
|
|
argument_spec.update(
|
|
dict(
|
|
name=dict(),
|
|
statuses=dict(type='list'),
|
|
)
|
|
)
|
|
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
|
|
|
if not HAS_BOTO3:
|
|
module.fail_json('boto3 and botocore are required by this module')
|
|
|
|
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
|
|
client = boto3_conn(module, conn_type='client', resource='acm',
|
|
region=region, endpoint=ec2_url, **aws_connect_kwargs)
|
|
|
|
certificates = get_certificates(client, module, name=module.params['name'], statuses=module.params['statuses'])
|
|
module.exit_json(certificates=certificates)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|