ec2_vpc_nacl and ec2_vpc_nacl_info migrate to AnsibleAWSModule and add tests (#63163)

* Move EC2 networking objects into network-policy.json

* ec2_vpc_nacl: Add integration tests

* ec2_vpc_nacl: Migrate tests to use module_defaults

* ec2_vpc_nacl: (integration tests) Add missing AWS permissions

* ec2_vpc_nacl: (integration tests) Update tests for ipv6 support

* ec2_vpc_nacl: Migrate to AnsibleAWSModule

* Fix sanity tests for ec2_vpc_nacl and ec2_vpc_nacl_info

* ec2_vpc_nacl_info: Migrate to AnsibleAWSModule

* ec2_vpc_nacl_info: (integration tests) Rename from ec2_vpc_nacl_facts to ec2_vpc_nacl_info and add a test using a filter (by tag)

* Pick availability zones dynamically

Rather than assuming that AZa and AZb always exist (they don't), query to find out which AZs we have available first

* Test that the NACLs we get back are actually the *saml* NACL rather than duplicates/delete remove

* Cleanup IPv6 tests a little.

Note: IPv6 support for ec2_vpc_nacl not complete yet.

This provides the initial framework, and should ensure things don't start exploding when support is added.

* Removing subnets by name from a NACL *is* now supported

* Fix ec2_vpc_nacl return documentation
pull/63259/head
Mark Chappell 5 years ago committed by Jill R
parent 811127d64d
commit dbc9444572

@ -38,61 +38,21 @@
"ec2:*LaunchTemplate",
"ec2:*LaunchTemplateVersion",
"ec2:*LaunchTemplateVersions",
"ec2:AllocateAddress",
"ec2:AssociateAddress",
"ec2:AssociateDhcpOptions",
"ec2:AssociateRouteTable",
"ec2:AssociateVpcCidrBlock",
"ec2:AssociateSubnetCidrBlock",
"ec2:AttachInternetGateway",
"ec2:AttachNetworkInterface",
"ec2:AttachVolume",
"ec2:AttachVpnGateway",
"ec2:CreateCustomerGateway",
"ec2:CreateDhcpOptions",
"ec2:CreateImage",
"ec2:CreateInternetGateway",
"ec2:CreateKeyPair",
"ec2:CreateNatGateway",
"ec2:CreateNetworkInterface",
"ec2:CreateRoute",
"ec2:CreateRouteTable",
"ec2:CreateSecurityGroup",
"ec2:CreateSnapshot",
"ec2:CreateSubnet",
"ec2:CreateTags",
"ec2:CreateVpc",
"ec2:CreateVpnConnection",
"ec2:CreateVpnGateway",
"ec2:DeleteCustomerGateway",
"ec2:DeleteDhcpOptions",
"ec2:DeleteInternetGateway",
"ec2:DeleteKeyPair",
"ec2:DeleteNatGateway",
"ec2:DeleteNetworkInterface",
"ec2:DeleteRoute",
"ec2:DeleteRouteTable",
"ec2:DeleteSnapshot",
"ec2:DeleteSubnet",
"ec2:DeleteTags",
"ec2:DeleteVpc",
"ec2:DeleteVpnConnection",
"ec2:DeleteVpnGateway",
"ec2:DeregisterImage",
"ec2:DetachInternetGateway",
"ec2:DetachVpnGateway",
"ec2:Describe*",
"ec2:DisassociateAddress",
"ec2:DisassociateRouteTable",
"ec2:DisassociateSubnetCidrBlock",
"ec2:ImportKeyPair",
"ec2:ModifyImageAttribute",
"ec2:ModifyInstanceAttribute",
"ec2:ModifySubnetAttribute",
"ec2:ModifyVpcAttribute",
"ec2:RegisterImage",
"ec2:ReleaseAddress",
"ec2:ReplaceRouteTableAssociation",
"ec2:ReplaceIamInstanceProfileAssociation",
"ec2:ReportInstanceStatus"
],

@ -23,6 +23,59 @@
],
"Resource": "*"
},
{
"Sid": "AllowUnspecifiedEC2NetworkingResource",
"Effect": "Allow",
"Action": [
"ec2:AllocateAddress",
"ec2:AssociateAddress",
"ec2:AssociateDhcpOptions",
"ec2:AssociateRouteTable",
"ec2:AssociateVpcCidrBlock",
"ec2:AssociateSubnetCidrBlock",
"ec2:AttachInternetGateway",
"ec2:AttachNetworkInterface",
"ec2:AttachVpnGateway",
"ec2:CreateCustomerGateway",
"ec2:CreateDhcpOptions",
"ec2:CreateNatGateway",
"ec2:CreateNetworkAcl",
"ec2:CreateNetworkAclEntry",
"ec2:CreateNetworkInterface",
"ec2:CreateRoute",
"ec2:CreateRouteTable",
"ec2:CreateSubnet",
"ec2:CreateVpc",
"ec2:CreateVpnConnection",
"ec2:CreateVpnGateway",
"ec2:DeleteCustomerGateway",
"ec2:DeleteDhcpOptions",
"ec2:DeleteInternetGateway",
"ec2:DeleteNatGateway",
"ec2:DeleteNetworkAcl",
"ec2:DeleteNetworkAclEntry",
"ec2:DeleteNetworkInterface",
"ec2:DeleteRoute",
"ec2:DeleteRouteTable",
"ec2:DeleteSubnet",
"ec2:DeleteVpc",
"ec2:DeleteVpnConnection",
"ec2:DeleteVpnGateway",
"ec2:DetachInternetGateway",
"ec2:DetachVpnGateway",
"ec2:Describe*",
"ec2:DisassociateAddress",
"ec2:DisassociateRouteTable",
"ec2:DisassociateSubnetCidrBlock",
"ec2:ModifySubnetAttribute",
"ec2:ModifyVpcAttribute",
"ec2:ReleaseAddress",
"ec2:ReplaceNetworkAclAssociation",
"ec2:ReplaceNetworkAclEntry",
"ec2:ReplaceRouteTableAssociation"
],
"Resource": "*"
},
{
"Sid": "AllowCloudfrontUsage",
"Effect": "Allow",

@ -24,23 +24,27 @@ options:
- Tagged name identifying a network ACL.
- One and only one of the I(name) or I(nacl_id) is required.
required: false
type: str
nacl_id:
description:
- NACL id identifying a network ACL.
- One and only one of the I(name) or I(nacl_id) is required.
required: false
version_added: "2.4"
type: str
vpc_id:
description:
- VPC id of the requesting VPC.
- Required when state present.
required: false
type: str
subnets:
description:
- The list of subnets that should be associated with the network ACL.
- Must be specified as a list
- Each subnet can be specified as subnet ID, or its tagged name.
required: false
type: list
egress:
description:
- A list of rules for outgoing traffic. Each rule must be specified as a list.
@ -51,6 +55,7 @@ options:
See examples.
default: []
required: false
type: list
ingress:
description:
- List of rules for incoming traffic. Each rule must be specified as a list.
@ -61,15 +66,18 @@ options:
See examples.
default: []
required: false
type: list
tags:
description:
- Dictionary of tags to look for and apply when creating a network ACL.
required: false
type: dict
state:
description:
- Creates or modifies an existing NACL
- Deletes a NACL and reassociates subnets to the default NACL
required: false
type: str
choices: ['present', 'absent']
default: present
author: Mike Mochan (@mmochan)
@ -140,19 +148,19 @@ task:
description: The result of the create, or delete action.
returned: success
type: dict
nacl_id:
description: The id of the NACL (when creating or updating an ACL)
returned: success
type: str
sample: acl-123456789abcdef01
'''
try:
import botocore
import boto3
HAS_BOTO3 = True
except ImportError:
HAS_BOTO3 = False
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import boto3_conn, ec2_argument_spec, get_aws_connection_info
pass # Handled by AnsibleAWSModule
from ansible.module_utils.aws.core import AnsibleAWSModule
# VPC-supported IANA protocol numbers
# http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
@ -379,7 +387,7 @@ def create_network_acl(vpc_id, client, module):
else:
nacl = client.create_network_acl(VpcId=vpc_id)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
return nacl
@ -388,7 +396,7 @@ def create_network_acl_entry(params, client, module):
if not module.check_mode:
client.create_network_acl_entry(**params)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def create_tags(nacl_id, client, module):
@ -397,7 +405,7 @@ def create_tags(nacl_id, client, module):
if not module.check_mode:
client.create_tags(Resources=[nacl_id], Tags=load_tags(module))
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def delete_network_acl(nacl_id, client, module):
@ -405,7 +413,7 @@ def delete_network_acl(nacl_id, client, module):
if not module.check_mode:
client.delete_network_acl(NetworkAclId=nacl_id)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def delete_network_acl_entry(params, client, module):
@ -413,7 +421,7 @@ def delete_network_acl_entry(params, client, module):
if not module.check_mode:
client.delete_network_acl_entry(**params)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def delete_tags(nacl_id, client, module):
@ -421,7 +429,7 @@ def delete_tags(nacl_id, client, module):
if not module.check_mode:
client.delete_tags(Resources=[nacl_id])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def describe_acl_associations(subnets, client, module):
@ -432,7 +440,7 @@ def describe_acl_associations(subnets, client, module):
{'Name': 'association.subnet-id', 'Values': subnets}
])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
associations = results['NetworkAcls'][0]['Associations']
return [a['NetworkAclAssociationId'] for a in associations if a['SubnetId'] in subnets]
@ -448,7 +456,7 @@ def describe_network_acl(client, module):
{'Name': 'tag:Name', 'Values': [module.params.get('name')]}
])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
return nacl
@ -456,7 +464,7 @@ def find_acl_by_id(nacl_id, client, module):
try:
return client.describe_network_acls(NetworkAclIds=[nacl_id])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def find_default_vpc_nacl(vpc_id, client, module):
@ -464,7 +472,7 @@ def find_default_vpc_nacl(vpc_id, client, module):
response = client.describe_network_acls(Filters=[
{'Name': 'vpc-id', 'Values': [vpc_id]}])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
nacls = response['NetworkAcls']
return [n['NetworkAclId'] for n in nacls if n['IsDefault'] is True]
@ -475,7 +483,7 @@ def find_subnet_ids_by_nacl_id(nacl_id, client, module):
{'Name': 'association.network-acl-id', 'Values': [nacl_id]}
])
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
if results['NetworkAcls']:
associations = results['NetworkAcls'][0]['Associations']
return [s['SubnetId'] for s in associations if s['SubnetId']]
@ -492,7 +500,7 @@ def replace_network_acl_association(nacl_id, subnets, client, module):
if not module.check_mode:
client.replace_network_acl_association(**params)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def replace_network_acl_entry(entries, Egress, nacl_id, client, module):
@ -503,7 +511,7 @@ def replace_network_acl_entry(entries, Egress, nacl_id, client, module):
if not module.check_mode:
client.replace_network_acl_entry(**params)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def restore_default_acl_association(params, client, module):
@ -511,7 +519,7 @@ def restore_default_acl_association(params, client, module):
if not module.check_mode:
client.replace_network_acl_association(**params)
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e))
module.fail_json_aws(e)
def subnets_to_associate(nacl, client, module):
@ -525,20 +533,19 @@ def subnets_to_associate(nacl, client, module):
{'Name': 'subnet-id', 'Values': params}])
all_found.extend(subnets.get('Subnets', []))
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
module.fail_json_aws(e)
if len(params) != len(all_found):
try:
subnets = client.describe_subnets(Filters=[
{'Name': 'tag:Name', 'Values': params}])
all_found.extend(subnets.get('Subnets', []))
except botocore.exceptions.ClientError as e:
module.fail_json(msg=str(e), exception=traceback.format_exc())
module.fail_json_aws(e)
return list(set(s['SubnetId'] for s in all_found if s.get('SubnetId')))
def main():
argument_spec = ec2_argument_spec()
argument_spec.update(dict(
argument_spec = dict(
vpc_id=dict(),
name=dict(),
nacl_id=dict(),
@ -547,21 +554,15 @@ def main():
ingress=dict(required=False, type='list', default=list()),
egress=dict(required=False, type='list', default=list()),
state=dict(default='present', choices=['present', 'absent']),
),
)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=[['name', 'nacl_id']],
required_if=[['state', 'present', ['vpc_id']]])
module = AnsibleAWSModule(argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=[['name', 'nacl_id']],
required_if=[['state', 'present', ['vpc_id']]])
if not HAS_BOTO3:
module.fail_json(msg='json, botocore and boto3 are required.')
state = module.params.get('state').lower()
try:
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
client = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_kwargs)
except botocore.exceptions.NoCredentialsError as e:
module.fail_json(msg="Can't authorize connection - %s" % str(e))
client = module.client('ec2')
invocations = {
"present": setup_network_acl,

@ -27,6 +27,7 @@ options:
required: false
default: []
aliases: [nacl_id]
type: list
filters:
description:
- A dict of filters to apply. Each dict item consists of a filter key and a filter value. See \
@ -34,6 +35,7 @@ options:
names and values are case sensitive.
required: false
default: {}
type: dict
notes:
- By default, the module will return all Network ACLs.
@ -109,10 +111,9 @@ try:
except ImportError:
pass # caught by imported HAS_BOTO3
from ansible.module_utils.aws.core import AnsibleAWSModule
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import (ec2_argument_spec, boto3_conn, get_aws_connection_info,
ansible_dict_to_boto3_filter_list, HAS_BOTO3,
from ansible.module_utils.ec2 import (ansible_dict_to_boto3_filter_list,
camel_dict_to_snake_dict, boto3_tag_list_to_ansible_dict)
@ -132,11 +133,9 @@ def list_ec2_vpc_nacls(connection, module):
try:
nacls = connection.describe_network_acls(NetworkAclIds=nacl_ids, Filters=filters)
except ClientError as e:
module.fail_json(msg="Unable to describe network ACLs {0}: {1}".format(nacl_ids, to_native(e)),
exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
module.fail_json_aws(e, msg="Unable to describe network ACLs {0}: {1}".format(nacl_ids, to_native(e)))
except BotoCoreError as e:
module.fail_json(msg="Unable to describe network ACLs {0}: {1}".format(nacl_ids, to_native(e)),
exception=traceback.format_exc())
module.fail_json_aws(e, msg="Unable to describe network ACLs {0}: {1}".format(nacl_ids, to_native(e)))
# Turn the boto3 result in to ansible_friendly_snaked_names
snaked_nacls = []
@ -203,24 +202,15 @@ def nacl_entry_to_list(entry):
def main():
argument_spec = ec2_argument_spec()
argument_spec.update(
dict(
nacl_ids=dict(default=[], type='list', aliases=['nacl_id']),
filters=dict(default={}, type='dict')
)
)
argument_spec = dict(
nacl_ids=dict(default=[], type='list', aliases=['nacl_id']),
filters=dict(default={}, type='dict'))
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
if module._name == 'ec2_vpc_nacl_facts':
module.deprecate("The 'ec2_vpc_nacl_facts' module has been renamed to 'ec2_vpc_nacl_info'", version='2.13')
if not HAS_BOTO3:
module.fail_json(msg='boto3 required for this module')
region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
connection = boto3_conn(module, conn_type='client', resource='ec2',
region=region, endpoint=ec2_url, **aws_connect_params)
connection = module.client('ec2')
list_ec2_vpc_nacls(connection, module)

@ -0,0 +1,3 @@
ec2_vpc_nacl_info
cloud/aws
shippable/aws/group2

@ -0,0 +1,3 @@
dependencies:
- prepare_tests
- setup_ec2

@ -0,0 +1,162 @@
# ============================================================
- name: create ingress and egress rules using subnet IDs
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- name: assert the network acl was created
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].ingress | length == 3
- nacl_facts.nacls[0].egress | length == 1
# ============================================================
- name: remove an ingress rule
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- name: assert the network acl changed
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].ingress | length == 2
- nacl_facts.nacls[0].egress | length == 1
# ============================================================
- name: remove the egress rule
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
egress: []
state: 'present'
register: nacl
- name: assert the network acl changed
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].ingress | length == 2
- nacl_facts.nacls[0].egress | length == 0
# ============================================================
- name: add egress rules
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
egress:
- [100, 'tcp', 'allow', '10.0.0.0/24', null, null, 22, 22]
- [200, 'udp', 'allow', '10.0.0.0/24', null, null, 22, 22]
state: 'present'
register: nacl
- name: assert the network acl changed
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].ingress | length == 2
- nacl_facts.nacls[0].egress | length == 2
# ============================================================
- name: remove the network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
state: absent
register: nacl
until: nacl is success
ignore_errors: yes
retries: 5
delay: 5
- name: assert nacl was removed
assert:
that:
- nacl.changed

@ -0,0 +1,178 @@
- block:
- name: create a VPC
ec2_vpc_net:
cidr_block: 10.230.231.0/24
name: "{{ resource_prefix }}-ipv6"
state: present
ipv6_cidr: yes
register: vpc_result
- set_fact:
vpc_ipv6_cidr: "{{ vpc_result.vpc.ipv6_cidr_block_association_set[0].ipv6_cidr_block }}"
# ============================================================
- name: create subnet with IPv6 (expected changed=true)
ec2_vpc_subnet:
cidr: 10.230.231.0/26
vpc_id: "{{ vpc_result.vpc.id }}"
ipv6_cidr: "{{ vpc_ipv6_cidr | regex_replace('::/56', '::/64') }}"
state: present
tags:
Name: "{{ resource_prefix }}-ipv6-subnet-1"
register: vpc_subnet_ipv6
- name: assert creation with IPv6 happened (expected changed=true)
assert:
that:
- "vpc_subnet_ipv6.subnet.ipv6_cidr_block == '{{ vpc_ipv6_cidr | regex_replace('::/56', '::/64') }}'"
# ============================================================
- name: create ingress and egress rules using subnet names
ec2_vpc_nacl:
vpc_id: "{{ vpc_result.vpc.id }}"
name: "{{ resource_prefix }}-acl"
subnets:
- "{{ resource_prefix }}-ipv6-subnet-1"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- assert:
that:
- nacl.nacl_id
- set_fact:
nacl_id: "{{ nacl.nacl_id }}"
- name: add ipv6 entries
ec2_vpc_nacl:
vpc_id: "{{ vpc_result.vpc.id }}"
name: "{{ resource_prefix }}-acl"
subnets:
- "{{ resource_prefix }}-ipv6-subnet-1"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [205, 'ipv6-tcp', 'allow', '::/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
- [305, 'ipv6-icmp', 'allow', '::/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
- [105, 'all', 'allow', '::/0', null, null, null, null]
state: 'present'
register: nacl
# FIXME: Currently IPv6 rules are not supported - uncomment assertion when
# fixed (and add some nacl_info tests)
ignore_errors: yes
- name: get network ACL facts (test that it works with ipv6 entries)
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl_id }}"
register: nacl_facts
#- assert:
# that:
# - nacl.changed
# - nacl.nacl_id == nacl_id
- name: purge ingress entries
ec2_vpc_nacl:
vpc_id: "{{ vpc_result.vpc.id }}"
name: "{{ resource_prefix }}-acl"
subnets:
- "{{ resource_prefix }}-ipv6-subnet-1"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress: []
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
- [105, 'all', 'allow', '::/0', null, null, null, null]
state: 'present'
register: nacl
# FIXME: Currently IPv6 rules are not supported - uncomment assertion when
# fixed (and add some nacl_info tests)
ignore_errors: yes
#- assert:
# that:
# - nacl.changed
# - nacl.nacl_id == nacl_id
- name: purge egress entries
ec2_vpc_nacl:
vpc_id: "{{ vpc_result.vpc.id }}"
name: "{{ resource_prefix }}-acl"
subnets:
- "{{ resource_prefix }}-ipv6-subnet-1"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress: []
egress: []
state: 'present'
register: nacl
- assert:
that:
- nacl.changed
# ============================================================
- name: remove subnet ipv6 cidr (expected changed=true)
ec2_vpc_subnet:
cidr: 10.230.231.0/26
vpc_id: "{{ vpc_result.vpc.id }}"
state: absent
register: vpc_remove_ipv6_cidr
- name: assert subnet ipv6 cidr removed (expected changed=true)
assert:
that:
- 'vpc_remove_ipv6_cidr.changed'
always:
################################################
# TEARDOWN STARTS HERE
################################################
- name: remove network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc_result.vpc.id }}"
name: "{{ resource_prefix }}-acl"
state: absent
register: removed_acl
until: removed_acl is success
retries: 5
delay: 5
ignore_errors: yes
- name: tidy up subnet
ec2_vpc_subnet:
cidr: 10.230.231.0/26
vpc_id: "{{ vpc_result.vpc.id }}"
state: absent
register: removed_subnet
until: removed_subnet is success
retries: 5
delay: 5
ignore_errors: yes
- name: tidy up VPC
ec2_vpc_net:
name: "{{ resource_prefix }}-ipv6"
state: absent
cidr_block: 10.230.231.0/24
register: removed_vpc
until: removed_vpc is success
retries: 5
delay: 5
ignore_errors: yes

@ -0,0 +1,170 @@
---
- module_defaults:
group/aws:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}"
block:
# ============================================================
- name: test without any parameters
ec2_vpc_nacl:
register: result
ignore_errors: yes
- name: assert required parameters
assert:
that:
- result.failed
- "result.msg == 'one of the following is required: name, nacl_id'"
- name: get network ACL info without any parameters
ec2_vpc_nacl_info:
register: nacl_facts
- name: assert we don't error
assert:
that:
- nacl_facts is succeeded
- name: get network ACL info with invalid ID
ec2_vpc_nacl_info:
nacl_ids:
- 'acl-000000000000'
register: nacl_facts
ignore_errors: yes
- name: assert message mentions missing ACLs
assert:
that:
- nacl_facts is failed
- '"does not exist" in nacl_facts.msg'
# ============================================================
- name: fetch AZ availability
aws_az_info:
register: az_info
- name: Assert that we have multiple AZs available to us
assert:
that: az_info.availability_zones | length >= 2
- name: pick AZs
set_fact:
az_one: '{{ az_info.availability_zones[0].zone_name }}'
az_two: '{{ az_info.availability_zones[1].zone_name }}'
# ============================================================
- name: create a VPC
ec2_vpc_net:
cidr_block: 10.230.230.0/24
name: "{{ resource_prefix }}"
state: present
register: vpc
- name: create subnets
ec2_vpc_subnet:
cidr: "{{ item.cidr }}"
az: "{{ item.az }}"
vpc_id: "{{ vpc.vpc.id }}"
state: present
tags:
Name: "{{ item.name }}"
with_items:
- cidr: 10.230.230.0/26
az: "{{ az_one }}"
name: "{{ resource_prefix }}-subnet-1"
- cidr: 10.230.230.64/26
az: "{{ az_two }}"
name: "{{ resource_prefix }}-subnet-2"
- cidr: 10.230.230.128/26
az: "{{ az_one }}"
name: "{{ resource_prefix }}-subnet-3"
- cidr: 10.230.230.192/26
az: "{{ az_two }}"
name: "{{ resource_prefix }}-subnet-4"
register: subnets
# ============================================================
- include_tasks: tasks/subnet_ids.yml
vars:
vpc_id: "{{ vpc.vpc.id }}"
subnet_ids: "{{ subnets | json_query('results[*].subnet.id') }}"
- include_tasks: tasks/subnet_names.yml
vars:
vpc_id: "{{ vpc.vpc.id }}"
subnet_names: "{{ subnets | json_query('results[*].subnet.tags.Name') }}"
- include_tasks: tasks/tags.yml
vars:
vpc_id: "{{ vpc.vpc.id }}"
subnet_ids: "{{ subnets | json_query('results[*].subnet.id') }}"
- include_tasks: tasks/ingress_and_egress.yml
vars:
vpc_id: "{{ vpc.vpc.id }}"
subnet_ids: "{{ subnets | json_query('results[*].subnet.id') }}"
- include_tasks: tasks/ipv6.yml
# ============================================================
always:
- name: remove network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc.vpc.id }}"
name: "{{ resource_prefix }}-acl"
state: absent
register: removed_acl
until: removed_acl is success
retries: 5
delay: 5
ignore_errors: yes
- name: remove subnets
ec2_vpc_subnet:
cidr: "{{ item.cidr }}"
az: "{{ aws_region}}{{ item.az }}"
vpc_id: "{{ vpc.vpc.id }}"
state: absent
tags:
Public: "{{ item.public | string }}"
Name: "{{ item.public | ternary('public', 'private') }}-{{ item.az }}"
with_items:
- cidr: 10.230.230.0/26
az: "a"
public: "True"
- cidr: 10.230.230.64/26
az: "b"
public: "True"
- cidr: 10.230.230.128/26
az: "a"
public: "False"
- cidr: 10.230.230.192/26
az: "b"
public: "False"
ignore_errors: yes
register: removed_subnets
until: removed_subnets is success
retries: 5
delay: 5
- name: remove the VPC
ec2_vpc_net:
cidr_block: 10.230.230.0/24
name: "{{ resource_prefix }}"
state: absent
ignore_errors: yes
register: removed_vpc
until: removed_vpc is success
retries: 5
delay: 5
# ============================================================

@ -0,0 +1,142 @@
# ============================================================
- name: create ingress and egress rules using subnet IDs
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- set_fact:
nacl_id: "{{ nacl.nacl_id }}"
- name: assert the network acl was created
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].nacl_id == nacl_id
- nacl_facts.nacls[0].subnets | length == 4
- nacl_facts.nacls[0].subnets | sort == subnet_ids | sort
- nacl_facts.nacls[0].ingress | length == 3
- nacl_facts.nacls[0].egress | length == 1
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
# ============================================================
- name: test idempotence
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- name: assert the network acl already existed
assert:
that:
- not nacl.changed
- nacl.nacl_id == nacl_id
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts_idem
- name: assert the facts are the same as before
assert:
that:
- nacl_facts_idem == nacl_facts
# ============================================================
- name: remove a subnet from the network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets:
- "{{ subnet_ids[0] }}"
- "{{ subnet_ids[1] }}"
- "{{ subnet_ids[2] }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- name: assert the network ACL changed
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- nacl.nacl_id == nacl_id
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_id:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].nacl_id == nacl_id
- nacl_facts.nacls[0].subnets | length == 3
- subnet_ids[3] not in nacl_facts.nacls[0].subnets
- nacl_facts.nacls[0].ingress | length == 3
- nacl_facts.nacls[0].egress | length == 1
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
# ============================================================
- name: remove the network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
state: absent
register: nacl
until: nacl is success
ignore_errors: yes
retries: 5
delay: 5
- name: assert nacl was removed
assert:
that:
- nacl.changed

@ -0,0 +1,140 @@
# ============================================================
- name: create ingress and egress rules using subnet names
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_names }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- set_fact:
nacl_id: "{{ nacl.nacl_id }}"
- name: assert the network acl was created
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].nacl_id == nacl_id
- nacl_facts.nacls[0].subnets | length == 4
- nacl_facts.nacls[0].ingress | length == 3
- nacl_facts.nacls[0].egress | length == 1
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
# ============================================================
- name: test idempotence
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_names }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- name: assert the network acl already existed
assert:
that:
- not nacl.changed
- nacl.nacl_id == nacl_id
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts_idem
- name: assert the facts are the same as before
assert:
that:
- nacl_facts_idem == nacl_facts
# ============================================================
- name: remove a subnet from the network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets:
- "{{ subnet_names[0] }}"
- "{{ subnet_names[1] }}"
- "{{ subnet_names[2] }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
ingress:
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 22, 22]
- [200, 'tcp', 'allow', '0.0.0.0/0', null, null, 80, 80]
- [300, 'icmp', 'allow', '0.0.0.0/0', 0, 8]
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, null, null]
state: 'present'
register: nacl
- name: assert the network ACL changed
assert:
that:
- nacl.changed
- nacl.nacl_id == nacl_id
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].nacl_id == nacl_id
- nacl_facts.nacls[0].subnets | length == 3
- nacl_facts.nacls[0].ingress | length == 3
- nacl_facts.nacls[0].egress | length == 1
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
# ============================================================
- name: remove the network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
state: absent
register: nacl
until: nacl is success
ignore_errors: yes
retries: 5
delay: 5
- name: assert nacl was removed
assert:
that:
- nacl.changed

@ -0,0 +1,117 @@
# ============================================================
- name: create a network ACL using subnet IDs
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
state: 'present'
register: nacl
- name: assert the network acl was created
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls[0].tags | length == 1
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
# ============================================================
- name: add a tag
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
tags:
Created_by: "Ansible test {{ resource_prefix }}"
state: 'present'
register: nacl
- name: assert the network acl changed
assert:
that:
- nacl.changed
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the facts are the same as before
assert:
that:
- nacl_facts.nacls[0].tags | length == 2
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
- "'{{ nacl_facts.nacls[0].tags.Created_by }}' == 'Ansible test {{ resource_prefix }}'"
- name: get network ACL facts by filter
ec2_vpc_nacl_info:
filters:
"tag:Created_by": "Ansible test {{ resource_prefix }}"
register: nacl_facts
- name: assert the facts are the same as before
assert:
that:
- nacl_facts.nacls | length == 1
- nacl_facts.nacls[0].tags | length == 2
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
- "'{{ nacl_facts.nacls[0].tags.Created_by }}' == 'Ansible test {{ resource_prefix }}'"
# ============================================================
- name: remove a tag
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
subnets: "{{ subnet_ids }}"
state: 'present'
register: nacl
- name: assert the network acl was created
assert:
that:
- nacl.changed
- nacl.nacl_id.startswith('acl-')
- name: get network ACL facts
ec2_vpc_nacl_info:
nacl_ids:
- "{{ nacl.nacl_id }}"
register: nacl_facts
- name: assert the nacl has the correct attributes
assert:
that:
- nacl_facts.nacls[0].tags | length == 1
- "'{{ nacl_facts.nacls[0].tags.Name }}' == '{{ resource_prefix }}-acl'"
# ============================================================
- name: remove the network ACL
ec2_vpc_nacl:
vpc_id: "{{ vpc_id }}"
name: "{{ resource_prefix }}-acl"
state: absent
register: nacl
until: nacl is success
ignore_errors: yes
retries: 5
delay: 5
- name: assert nacl was removed
assert:
that:
- nacl.changed

@ -818,9 +818,6 @@ lib/ansible/modules/cloud/amazon/ec2_vpc_endpoint_info.py validate-modules:doc-m
lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/amazon/ec2_vpc_igw.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/amazon/ec2_vpc_igw_info.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/amazon/ec2_vpc_nacl.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/amazon/ec2_vpc_nacl.py validate-modules:doc-missing-type
lib/ansible/modules/cloud/amazon/ec2_vpc_nacl_info.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/cloud/amazon/ec2_vpc_nat_gateway.py pylint:blacklisted-name
lib/ansible/modules/cloud/amazon/ec2_vpc_nat_gateway.py validate-modules:doc-default-does-not-match-spec
lib/ansible/modules/cloud/amazon/ec2_vpc_nat_gateway.py validate-modules:parameter-type-not-in-doc

Loading…
Cancel
Save