From 99a4adb2993f0572b4bc5a4fe9f955cb25b13c77 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Mon, 23 May 2022 13:08:50 +0200 Subject: [PATCH] New Modules : NetworkFirewall firewall (#1107) New Modules : NetworkFirewall firewall SUMMARY New modules for managing the NetworkFirewall firewall resources. ISSUE TYPE New Module Pull Request COMPONENT NAME networkfirewall networkfirewall_info ADDITIONAL INFORMATION TODO: Finish up documentation (usage examples) Integration tests Reviewed-by: Markus Bergholz Reviewed-by: Mark Chappell --- meta/runtime.yml | 2 + plugins/module_utils/networkfirewall.py | 581 ++- plugins/modules/networkfirewall.py | 365 ++ plugins/modules/networkfirewall_info.py | 236 + .../targets/networkfirewall/aliases | 7 + .../targets/networkfirewall/defaults/main.yml | 35 + .../targets/networkfirewall/meta/main.yml | 2 + .../targets/networkfirewall/tasks/cleanup.yml | 123 + .../targets/networkfirewall/tasks/complex.yml | 612 +++ .../targets/networkfirewall/tasks/main.yml | 35 + .../targets/networkfirewall/tasks/setup.yml | 118 + .../targets/networkfirewall/tasks/simple.yml | 3893 +++++++++++++++++ 12 files changed, 6002 insertions(+), 7 deletions(-) create mode 100644 plugins/modules/networkfirewall.py create mode 100644 plugins/modules/networkfirewall_info.py create mode 100644 tests/integration/targets/networkfirewall/aliases create mode 100644 tests/integration/targets/networkfirewall/defaults/main.yml create mode 100644 tests/integration/targets/networkfirewall/meta/main.yml create mode 100644 tests/integration/targets/networkfirewall/tasks/cleanup.yml create mode 100644 tests/integration/targets/networkfirewall/tasks/complex.yml create mode 100644 tests/integration/targets/networkfirewall/tasks/main.yml create mode 100644 tests/integration/targets/networkfirewall/tasks/setup.yml create mode 100644 tests/integration/targets/networkfirewall/tasks/simple.yml diff --git a/meta/runtime.yml b/meta/runtime.yml index e536d4d4d1b..e55427fca15 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -150,6 +150,8 @@ action_groups: - lambda_info - lambda_policy - lightsail + - networkfirewall + - networkfirewall_info - networkfirewall_policy - networkfirewall_policy_info - networkfirewall_rule_group diff --git a/plugins/module_utils/networkfirewall.py b/plugins/module_utils/networkfirewall.py index 40fc2dcd97d..920c9f09233 100644 --- a/plugins/module_utils/networkfirewall.py +++ b/plugins/module_utils/networkfirewall.py @@ -5,6 +5,7 @@ __metaclass__ = type from copy import deepcopy +import time from ansible.module_utils._text import to_text from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict @@ -21,6 +22,8 @@ from ansible_collections.community.aws.plugins.module_utils.base import BaseResourceManager from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory +from ansible_collections.community.aws.plugins.module_utils.ec2 import BaseEc2Manager + def _merge_set(current, new, purge): _current = set(current) @@ -71,6 +74,7 @@ def _waiter_model_data(self): operation='DescribeRuleGroup', delay=5, maxAttempts=120, acceptors=[ + dict(state='failure', matcher='path', expected='DELETING', argument='RuleGroupResponse.RuleGroupStatus'), dict(state='success', matcher='path', expected='ACTIVE', argument='RuleGroupResponse.RuleGroupStatus'), ] ), @@ -86,6 +90,7 @@ def _waiter_model_data(self): operation='DescribeFirewallPolicy', delay=5, maxAttempts=120, acceptors=[ + dict(state='failure', matcher='path', expected='DELETING', argument='FirewallPolicyResponse.FirewallPolicyStatus'), dict(state='success', matcher='path', expected='ACTIVE', argument='FirewallPolicyResponse.FirewallPolicyStatus'), ] ), @@ -97,6 +102,33 @@ def _waiter_model_data(self): dict(state='success', matcher='error', expected='ResourceNotFoundException'), ] ), + firewall_active=dict( + operation='DescribeFirewall', + delay=5, maxAttempts=120, + acceptors=[ + dict(state='failure', matcher='path', expected='DELETING', argument='FirewallStatus.Status'), + dict(state='retry', matcher='path', expected='PROVISIONING', argument='FirewallStatus.Status'), + dict(state='success', matcher='path', expected='READY', argument='FirewallStatus.Status'), + ] + ), + firewall_updated=dict( + operation='DescribeFirewall', + delay=5, maxAttempts=240, + acceptors=[ + dict(state='failure', matcher='path', expected='DELETING', argument='FirewallStatus.Status'), + dict(state='retry', matcher='path', expected='PROVISIONING', argument='FirewallStatus.Status'), + dict(state='retry', matcher='path', expected='PENDING', argument='FirewallStatus.ConfigurationSyncStateSummary'), + dict(state='success', matcher='path', expected='IN_SYNC', argument='FirewallStatus.ConfigurationSyncStateSummary'), + ] + ), + firewall_deleted=dict( + operation='DescribeFirewall', + delay=5, maxAttempts=240, + acceptors=[ + dict(state='retry', matcher='path', expected='DELETING', argument='FirewallStatus.Status'), + dict(state='success', matcher='error', expected='ResourceNotFoundException'), + ] + ), ) data.update(nw_data) return data @@ -160,7 +192,7 @@ def _update_rule_group(self, **params): self._update_token = update_token return result.get('RuleGroupResponse', None) - @Boto3Mixin.aws_error_handler('update rule group') + @Boto3Mixin.aws_error_handler('delete rule group') def _delete_rule_group(self, **params): try: result = self.client.delete_rule_group(aws_retry=True, **params) @@ -227,7 +259,7 @@ def _update_policy(self, **params): self._update_token = update_token return result.get('FirewallPolicyResponse', None) - @Boto3Mixin.aws_error_handler('update firewall policy') + @Boto3Mixin.aws_error_handler('delete firewall policy') def _delete_policy(self, **params): try: result = self.client.delete_firewall_policy(aws_retry=True, **params) @@ -247,6 +279,144 @@ def _wait_policy_active(self, **params): waiter.wait(**params) +class NFFirewallBoto3Mixin(NetworkFirewallBoto3Mixin): + # Paginators can't be (easily) wrapped, so we wrap this method with the + # retry - retries the full fetch, but better than simply giving up. + @AWSRetry.jittered_backoff() + def _paginated_list_firewalls(self, **params): + paginator = self.client.get_paginator('list_firewalls') + result = paginator.paginate(**params).build_full_result() + return result.get('Firewalls', None) + + @Boto3Mixin.aws_error_handler('list all firewalls') + def _list_firewalls(self, **params): + return self._paginated_list_firewalls(**params) + + @Boto3Mixin.aws_error_handler('describe firewall') + def _describe_firewall(self, **params): + try: + result = self.client.describe_firewall(aws_retry=True, **params) + except is_boto3_error_code('ResourceNotFoundException'): + return None + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + firewall = result.get('Firewall', None) + metadata = result.get('FirewallStatus', None) + return dict(Firewall=firewall, FirewallMetadata=metadata) + + @Boto3Mixin.aws_error_handler('create firewall') + def _create_firewall(self, **params): + result = self.client.create_firewall(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallStatus', None) + + @Boto3Mixin.aws_error_handler('update firewall description') + def _update_firewall_description(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.update_firewall_description(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallName', None) + + @Boto3Mixin.aws_error_handler('update firewall subnet change protection') + def _update_subnet_change_protection(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.update_subnet_change_protection(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallName', None) + + @Boto3Mixin.aws_error_handler('update firewall policy change protection') + def _update_firewall_policy_change_protection(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.update_firewall_policy_change_protection(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallName', None) + + @Boto3Mixin.aws_error_handler('update firewall deletion protection') + def _update_firewall_delete_protection(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.update_firewall_delete_protection(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallName', None) + + @Boto3Mixin.aws_error_handler('associate policy with firewall') + def _associate_firewall_policy(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.associate_firewall_policy(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallName', None) + + @Boto3Mixin.aws_error_handler('associate subnets with firewall') + def _associate_subnets(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.associate_subnets(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallName', None) + + @Boto3Mixin.aws_error_handler('disassociate subnets from firewall') + def _disassociate_subnets(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.disassociate_subnets(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('FirewallName', None) + + @Boto3Mixin.aws_error_handler('delete firewall') + def _delete_firewall(self, **params): + try: + result = self.client.delete_firewall(aws_retry=True, **params) + except is_boto3_error_code('ResourceNotFoundException'): + return None + + return result.get('FirewallStatus', None) + + @Boto3Mixin.aws_error_handler('firewall to finish deleting') + def _wait_firewall_deleted(self, **params): + waiter = self.nf_waiter_factory.get_waiter('firewall_deleted') + waiter.wait(**params) + + @Boto3Mixin.aws_error_handler('firewall to finish updating') + def _wait_firewall_updated(self, **params): + waiter = self.nf_waiter_factory.get_waiter('firewall_updated') + waiter.wait(**params) + + @Boto3Mixin.aws_error_handler('firewall to become active') + def _wait_firewall_active(self, **params): + waiter = self.nf_waiter_factory.get_waiter('firewall_active') + waiter.wait(**params) + + class BaseNetworkFirewallManager(BaseResourceManager): def __init__(self, module): r""" @@ -345,6 +515,12 @@ def _set_metadata_value(self, key, value, description=None, immutable=False): def _get_metadata_value(self, key, default=None): return self._metadata_updates.get(key, self._preupdate_metadata.get(key, default)) + def _set_tag_values(self, desired_tags): + return self._set_metadata_value('Tags', ansible_dict_to_boto3_tag_list(desired_tags)) + + def _get_tag_values(self): + return self._get_metadata_value('Tags', []) + def _flush_tagging(self): changed = False tags_to_add = self._tagging_updates.get('add') @@ -374,7 +550,7 @@ def set_tags(self, tags, purge_tags): # Tags are returned as a part of the metadata, but have to be updated # via dedicated tagging methods - current_tags = boto3_tag_list_to_ansible_dict(self._get_metadata_value('Tags', [])) + current_tags = boto3_tag_list_to_ansible_dict(self._get_tag_values()) # So that diff works in check mode we need to know the full target state if purge_tags: @@ -396,7 +572,7 @@ def set_tags(self, tags, purge_tags): # Tags are a stored as a list, but treated like a list, the # simplisic '==' in _set_metadata_value doesn't do the comparison # properly - return self._set_metadata_value('Tags', ansible_dict_to_boto3_tag_list(desired_tags)) + return self._set_tag_values(desired_tags) return False @@ -472,7 +648,7 @@ def _transform_rule_variables(variables): def delete(self, name=None, rule_type=None, arn=None): - id_params = self._get_id_params(name=name, rule_type=rule_type, arn=None) + id_params = self._get_id_params(name=name, rule_type=rule_type, arn=arn) result = self._get_rule_group(**id_params) if not result: @@ -791,7 +967,6 @@ def _get_rule_group(self, **params): return dict(RuleGroup=rule_group, RuleGroupMetadata=metadata) def get_resource(self): - id_params = self._get_id_params() return self.get_rule_group() def _do_creation_wait(self, **params): @@ -854,7 +1029,7 @@ def _get_id_params(self, name=None, arn=None): def delete(self, name=None, arn=None): - id_params = self._get_id_params(name=name, arn=None) + id_params = self._get_id_params(name=name, arn=arn) result = self._get_policy(**id_params) if not result: @@ -1193,3 +1368,395 @@ def _do_deletion_wait(self, **params): all_params = self._get_id_params() all_params.update(params) return self._wait_policy_deleted(**all_params) + + +class NetworkFirewallManager(NFFirewallBoto3Mixin, NFPolicyBoto3Mixin, BaseNetworkFirewallManager): + + name = None + arn = None + ec2_manager = None + _subnet_updates = None + _policy_list_cache = None + _slow_start_change = False + + def __init__(self, module, name=None, arn=None): + super().__init__(module) + # Name parameter is unique (by region) and can not be modified. + self.name = name + self.arn = arn + self.ec2_manager = BaseEc2Manager(module=module) + self._subnet_updates = dict() + if self.name or self.arn: + firewall = deepcopy(self.get_firewall()) + self.original_resource = firewall + + def _extra_error_output(self): + output = super(NetworkFirewallManager, self)._extra_error_output() + if self.name: + output['FirewallName'] = self.name + if self.arn: + output['FirewallArn'] = self.arn + return output + + def _get_preupdate_arn(self): + return self._get_resource_value('FirewallArn') + + def _get_id_params(self, name=None, arn=None): + if arn: + return dict(FirewallArn=arn) + if self.arn: + return dict(FirewallArn=self.arn) + if not name: + name = self.name + if not name: + # Users should never see this, but let's cover ourself + self.module.fail_json(msg='Firewall identifier parameters missing') + return dict(FirewallName=name) + + def delete(self, name=None, arn=None): + + id_params = self._get_id_params(name=name, arn=arn) + result = self._get_firewall(**id_params) + + if not result: + return False + + self.updated_resource = dict() + + # Firewall is already in the process of being deleted (takes time) + firewall_status = self._get_metadata_value('Status', '').upper() + if firewall_status == 'DELETING': + self._wait_for_deletion() + return False + + if self.module.check_mode: + self.changed = True + return True + + if 'DeleteProtection' in self._resource_updates: + self._update_firewall_delete_protection( + DeleteProtection=self._resource_updates['DeleteProtection'], **id_params, + ) + + result = self._delete_firewall(**id_params) + self._wait_for_deletion() + self.changed |= bool(result) + return bool(result) + + def list(self, vpc_ids=None): + params = dict() + if vpc_ids: + params['VpcIds'] = vpc_ids + firewalls = self._list_firewalls(**params) + if not firewalls: + return list() + + return [f.get('FirewallArn', None) for f in firewalls] + + def _normalize_firewall(self, firewall): + if firewall is None: + return None + subnets = [s.get('SubnetId') for s in firewall.get('SubnetMappings', [])] + firewall = self._normalize_boto3_resource(firewall, add_tags=True) + firewall['subnets'] = subnets + return firewall + + def _normalize_sync_state_config(self, policy): + return self._normalize_boto3_resource(policy) + + def _normalize_sync_state(self, state): + config = {k: self._normalize_sync_state_config(v) for k, v in state.pop('Config', {}).items()} + state = self._normalize_boto3_resource(state) + state['config'] = config or {} + return state + + def _normalize_firewall_metadata(self, firewall_metadata): + if firewall_metadata is None: + return None + states = {k: self._normalize_sync_state(v) for k, v in firewall_metadata.pop('SyncStates', {}).items()} + metadata = self._normalize_boto3_resource(firewall_metadata, add_tags=False) + metadata['sync_states'] = states or {} + return metadata + + def _normalize_firewall_result(self, result): + if result is None: + return None + firewall = self._normalize_firewall(result.get('Firewall', None)) + firewall_metadata = self._normalize_firewall_metadata(result.get('FirewallMetadata', None)) + result = camel_dict_to_snake_dict(result) + if firewall: + result['firewall'] = firewall + if firewall_metadata: + result['firewall_metadata'] = firewall_metadata + return result + + def _normalize_resource(self, resource): + return self._normalize_firewall_result(resource) + + def get_firewall(self, name=None, arn=None): + + id_params = self._get_id_params(name=name, arn=arn) + result = self._get_firewall(**id_params) + + if not result: + return None + + firewall = self._normalize_firewall_result(result) + return firewall + + @property + def _subnets(self): + subnet_mappings = self._get_resource_value('SubnetMappings', []) + subnets = [s.get('SubnetId') for s in subnet_mappings] + return subnets + + def _subnets_to_vpc(self, subnets, subnet_details=None): + if not subnets: + return None + if not subnet_details: + subnet_details = self.ec2_manager._describe_subnets(SubnetIds=list(subnets)) + vpcs = [s.get('VpcId') for s in subnet_details] + if len(set(vpcs)) > 1: + self.module.fail_json( + msg='Firewall subnets may only be in one VPC, multiple VPCs found', + vpcs=list(set(vpcs)), subnets=subnet_details) + return vpcs[0] + + def _format_subnet_mapping(self, subnets): + if not subnets: + return [] + return [dict(SubnetId=s) for s in subnets] + + @property + def _policy_name_cache(self): + if self._policy_list_cache: + return self._policy_list_cache + results = self._list_policies() + if not results: + return dict() + + policy_cache = {p.get('Name', None): p.get('Arn', None) for p in results} + self._policy_list_cache = policy_cache + return policy_cache + + def _canonicalize_policy(self, name): + """Iterates through a mixed list of ARNs and Names converting them to + ARNs. + """ + arn = None + # : is only valid in ARNs + if ':' in name: + arn = name + else: + arn = self._policy_name_cache.get(name, None) + if not arn: + self.module.fail_json('Unable to fetch ARN for policy', name=name, + policy_name_cache=self._policy_name_cache) + arn_info = parse_aws_arn(arn) + if not arn_info: + self.module.fail_json('Unable to parse ARN for policy', arn=arn, arn_info=arn_info) + arn_type = arn_info['resource'].split('/')[0] + if arn_type != 'firewall-policy': + self.module.fail_json('Policy ARN not of expected resource type', name=name, + arn=arn, expected_type='firewall-policy', found_type=arn_type) + + return arn + + def set_policy(self, policy): + if policy is None: + return False + + # Because the canonicalization of a non-ARN policy name will require an API call, + # try comparing the current name to the policy name we've been passed. + # If they match we don't need to perform the lookup. + current_policy = self._get_resource_value('FirewallPolicyArn', None) + if current_policy: + arn_info = parse_aws_arn(current_policy) + current_name = arn_info['resource'].split('/')[-1] + if current_name == policy: + return False + + policy = self._canonicalize_policy(policy) + return self._set_resource_value('FirewallPolicyArn', policy) + + def set_subnets(self, subnets, purge=True): + if subnets is None: + return False + current_subnets = set(self._subnets) + desired_subnets = set(subnets) + if not purge: + desired_subnets = desired_subnets.union(current_subnets) + + # We don't need to perform EC2 lookups if we're not changing anything. + if current_subnets == desired_subnets: + return False + + subnet_details = self.ec2_manager._describe_subnets(SubnetIds=list(desired_subnets)) + vpc = self._subnets_to_vpc(desired_subnets, subnet_details) + self._set_resource_value('VpcId', vpc, description='firewall VPC', immutable=True) + + azs = [s.get('AvailabilityZoneId') for s in subnet_details] + if len(azs) != len(set(azs)): + self.module.fail_json( + msg='Only one subnet per availability zone may set.', + availability_zones=azs, subnets=subnet_details) + + subnets_to_add = list(desired_subnets.difference(current_subnets)) + subnets_to_remove = list(current_subnets.difference(desired_subnets)) + self._subnet_updates = dict(add=subnets_to_add, remove=subnets_to_remove) + self._set_resource_value('SubnetMappings', self._format_subnet_mapping(desired_subnets)) + return True + + def set_policy_change_protection(self, protection): + return self._set_resource_value('FirewallPolicyChangeProtection', protection) + + def set_subnet_change_protection(self, protection): + return self._set_resource_value('SubnetChangeProtection', protection) + + def set_delete_protection(self, protection): + return self._set_resource_value('DeleteProtection', protection) + + def set_description(self, description): + return self._set_resource_value('Description', description) + + def _do_create_resource(self): + metadata, resource = self._merge_changes(filter_metadata=False) + params = metadata + params.update(self._get_id_params()) + params.update(resource) + response = self._create_firewall(**params) + return bool(response) + + def _generate_updated_resource(self): + metadata, resource = self._merge_changes(filter_metadata=False) + resource.update(self._get_id_params()) + updated_resource = dict( + Firewall=resource, + FirewallMetadata=metadata + ) + return updated_resource + + def _flush_create(self): + # # Apply some pre-flight tests before trying to run the creation. + # if 'Capacity' not in self._metadata_updates: + # self.module.fail_json('Capacity must be provided when creating a new Rule Group') + + return super(NetworkFirewallManager, self)._flush_create() + + def _do_update_resource(self): + # There are no 'metadata' components of a Firewall to update + resource_updates = self._resource_updates + if not resource_updates: + return False + if self.module.check_mode: + return True + + id_params = self._get_id_params() + + # There's no tool for 'bulk' updates, we need to iterate through these + # one at a time... + if 'Description' in resource_updates: + self._update_firewall_description( + Description=resource_updates['Description'], **id_params, + ) + if 'DeleteProtection' in resource_updates: + self._update_firewall_delete_protection( + DeleteProtection=resource_updates['DeleteProtection'], **id_params, + ) + + # Disable Change Protection... + # When disabling change protection, do so *before* making changes + if 'FirewallPolicyChangeProtection' in resource_updates: + if not self._get_resource_value('FirewallPolicyChangeProtection'): + self._update_firewall_policy_change_protection( + FirewallPolicyChangeProtection=resource_updates['FirewallPolicyChangeProtection'], **id_params, + ) + if 'SubnetChangeProtection' in resource_updates: + if not self._get_resource_value('SubnetChangeProtection'): + self._update_subnet_change_protection( + SubnetChangeProtection=resource_updates['SubnetChangeProtection'], **id_params, + ) + + # General Changes + if 'SubnetMappings' in resource_updates: + self._slow_start_change = True + subnets_to_add = self._subnet_updates.get('add', None) + subnets_to_remove = self._subnet_updates.get('remove', None) + if subnets_to_remove: + self._disassociate_subnets( + SubnetIds=subnets_to_remove, **id_params) + if subnets_to_add: + subnets_to_add = self._format_subnet_mapping(subnets_to_add) + self._associate_subnets( + SubnetMappings=subnets_to_add, **id_params) + + if 'FirewallPolicyArn' in resource_updates: + self._slow_start_change = True + self._associate_firewall_policy( + FirewallPolicyArn=resource_updates['FirewallPolicyArn'], + **id_params + ) + + # Enable Change Protection. + # When enabling change protection, do so *after* making changes + if 'FirewallPolicyChangeProtection' in resource_updates: + if self._get_resource_value('FirewallPolicyChangeProtection'): + self._update_firewall_policy_change_protection( + FirewallPolicyChangeProtection=resource_updates['FirewallPolicyChangeProtection'], **id_params, + ) + if 'SubnetChangeProtection' in resource_updates: + if self._get_resource_value('SubnetChangeProtection'): + self._update_subnet_change_protection( + SubnetChangeProtection=resource_updates['SubnetChangeProtection'], **id_params, + ) + return True + + def _flush_update(self): + changed = False + changed |= self._flush_tagging() + changed |= super(NetworkFirewallManager, self)._flush_update() + self._subnet_updates = dict() + self._slow_start_change = False + return changed + + def _get_firewall(self, **params): + result = self._describe_firewall(**params) + if not result: + return None + + firewall = result.get('Firewall', None) + metadata = result.get('FirewallMetadata', None) + self._preupdate_resource = deepcopy(firewall) + self._preupdate_metadata = deepcopy(metadata) + return dict(Firewall=firewall, FirewallMetadata=metadata) + + def get_resource(self): + return self.get_firewall() + + def _do_creation_wait(self, **params): + all_params = self._get_id_params() + all_params.update(params) + return self._wait_firewall_active(**all_params) + + def _do_deletion_wait(self, **params): + all_params = self._get_id_params() + all_params.update(params) + return self._wait_firewall_deleted(**all_params) + + def _do_update_wait(self, **params): + # It takes a couple of seconds before the firewall starts to update + # the subnets and policies, pause if we know we've changed them. We'll + # be waiting subtantially more than this... + if self._slow_start_change: + time.sleep(4) + all_params = self._get_id_params() + all_params.update(params) + return self._wait_firewall_updated(**all_params) + + # Unlike RuleGroups and Policies for some reason Firewalls have the tags set + # directly on the resource. + def _set_tag_values(self, desired_tags): + return self._set_resource_value('Tags', ansible_dict_to_boto3_tag_list(desired_tags)) + + def _get_tag_values(self): + return self._get_resource_value('Tags', []) diff --git a/plugins/modules/networkfirewall.py b/plugins/modules/networkfirewall.py new file mode 100644 index 00000000000..fefb565fef5 --- /dev/null +++ b/plugins/modules/networkfirewall.py @@ -0,0 +1,365 @@ +#!/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 + + +DOCUMENTATION = ''' +module: networkfirewall +short_description: manage AWS Network Firewall firewalls +version_added: 4.0.0 +description: + - A module for creating, updating and deleting AWS Network Firewall firewalls. +options: + arn: + description: + - The ARN of the firewall. + - Exactly one of I(arn) or I(name) must be provided. + required: false + type: str + aliases: ['firewall_arn'] + name: + description: + - The name of the firewall. + - Cannot be updated after creation. + - Exactly one of I(arn) or I(name) must be provided. + required: false + type: str + aliases: ['firewall_name'] + state: + description: + - Create or remove the firewall. + required: false + choices: ['present', 'absent'] + default: 'present' + type: str + description: + description: + - A description for the firewall. + required: false + type: str + tags: + description: + - A dictionary representing the tags associated with the firewall. + - 'For example C({"Example Tag": "some example value"})' + - Unless I(purge_tags=False) all other tags will be removed from the + firewall. + type: dict + required: false + delete_protection: + description: + - When I(delete_protection=True), the firewall is protected from deletion. + - Defaults to C(false) when not provided on creation. + type: bool + required: false + policy_change_protection: + description: + - When I(policy_change_protection=True), the firewall is protected from + changes to which policy is attached to the firewall. + - Defaults to C(false) when not provided on creation. + type: bool + required: false + aliases: ['firewall_policy_change_protection'] + subnet_change_protection: + description: + - When I(subnet_change_protection=True), the firewall is protected from + changes to which subnets is attached to the firewall. + - Defaults to C(false) when not provided on creation. + type: bool + required: false + purge_tags: + description: + - If I(purge_tags=true) and I(tags) is defined existing tags will be + purged from the resource to match exactly what is defined by the + I(tags) parameter. + type: bool + required: false + default: True + wait: + description: + - On creation, whether to wait for the firewall to reach the C(READY) + state. + - On deletion, whether to wait for the firewall to reach the C(DELETED) + state. + - On update, whether to wait for the firewall to reach the C(IN_SYNC) + configuration synchronization state. + type: bool + required: false + default: true + wait_timeout: + description: + - Maximum time, in seconds, to wait for the firewall to reach the + expected state. + - Defaults to 600 seconds. + type: int + required: false + subnets: + description: + - The ID of the subnets to which the firewall will be associated. + - Required when creating a new firewall. + type: list + elements: str + required: false + purge_subnets: + description: + - If I(purge_subnets=true), existing subnets will be removed from the + firewall as necessary to match exactly what is defined by I(subnets). + type: bool + required: false + default: true + policy: + description: + - The ARN of the Network Firewall policy to use for the firewall. + - Required when creating a new firewall. + type: str + required: false + aliases: ['firewall_policy_arn'] + +author: Mark Chappell (@tremble) +extends_documentation_fragment: + - amazon.aws.aws + - amazon.aws.ec2 +''' + +EXAMPLES = ''' +# Create an AWS Network Firewall +- community.aws.networkfirewall: + name: 'ExampleFirewall' + state: present + policy: 'ExamplePolicy' + subnets: + - 'subnet-123456789abcdef01' + +# Create an AWS Network Firewall with various options, don't wait for creation +# to finish. +- community.aws.networkfirewall: + name: 'ExampleFirewall' + state: present + delete_protection: True + description: "An example Description" + policy: 'ExamplePolicy' + policy_change_protection: True + subnets: + - 'subnet-123456789abcdef01' + - 'subnet-abcdef0123456789a' + subnet_change_protection: True + tags: + ExampleTag: Example Value + another_tag: another_example + wait: false + + +# Delete an AWS Network Firewall +- community.aws.networkfirewall: + state: absent + name: 'ExampleFirewall' +''' + +RETURN = ''' +firewall: + description: The full details of the firewall + returned: success + type: dict + contains: + firewall: + description: The details of the firewall + type: dict + returned: success + contains: + delete_protection: + description: A flag indicating whether it is possible to delete the firewall. + type: str + returned: success + example: true + description: + description: A description of the firewall. + type: str + returned: success + example: "Description" + firewall_arn: + description: The ARN of the firewall. + type: str + returned: success + example: "arn:aws:network-firewall:us-east-1:123456789012:firewall/ExampleFirewall" + firewall_id: + description: A unique ID for the firewall. + type: str + returned: success + example: "12345678-abcd-1234-abcd-123456789abc" + firewall_name: + description: The name of the firewall. + type: str + returned: success + example: "ExampleFirewall" + firewall_policy_arn: + description: The ARN of the firewall policy used by the firewall. + type: str + returned: success + example: "arn:aws:network-firewall:us-east-1:123456789012:firewall-policy/ExamplePolicy" + firewall_policy_change_protection: + description: + - A flag indicating whether it is possible to change which firewall + policy is used by the firewall. + type: bool + returned: success + example: false + subnet_change_protection: + description: + - A flag indicating whether it is possible to change which subnets + the firewall endpoints are in. + type: bool + returned: success + example: true + subnets: + description: A list of the subnets the firewall endpoints are in. + type: list + elements: str + example: ["subnet-12345678", "subnet-87654321"] + subnet_mappings: + description: A list representing the subnets the firewall endpoints are in. + type: list + elements: dict + contains: + subnet_id: + description: The ID of the subnet. + type: str + returned: success + example: "subnet-12345678" + tags: + description: The tags associated with the firewall. + type: dict + returned: success + example: '{"SomeTag": "SomeValue"}' + vpc_id: + description: The ID of the VPC that the firewall is used by. + type: str + returned: success + example: "vpc-0123456789abcdef0" + firewall_metadata: + description: Metadata about the firewall + type: dict + returned: success + contains: + configuration_sync_state_summary: + description: + - A short summary of the synchronization status of the + policy and rule groups. + type: str + returned: success + example: "IN_SYNC" + status: + description: + - A short summary of the status of the firewall endpoints. + type: str + returned: success + example: "READY" + sync_states: + description: + - A description, broken down by availability zone, of the status + of the firewall endpoints as well as the synchronization status + of the policies and rule groups. + type: dict + returned: success + example: + { + "us-east-1a": { + "attachment": { + "endpoint_id": "vpce-123456789abcdef01", + "status": "READY", + "subnet_id": "subnet-12345678" + }, + "config": { + "arn:aws:network-firewall:us-east-1:123456789012:firewall-policy/Ansible-Example": { + "sync_status": "IN_SYNC", + "update_token": "abcdef01-0000-0000-0000-123456789abc" + }, + "arn:aws:network-firewall:us-east-1:123456789012:stateful-rulegroup/ExampleDomainList": { + "sync_status": "IN_SYNC", + "update_token": "12345678-0000-0000-0000-abcdef012345" + } + } + } + } +''' + + +from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule +from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallManager + + +def main(): + + argument_spec = dict( + name=dict(type='str', required=False, aliases=['firewall_name']), + arn=dict(type='str', required=False, aliases=['firewall_arn']), + state=dict(type='str', required=False, default='present', choices=['present', 'absent']), + description=dict(type='str', required=False), + tags=dict(type='dict', required=False), + purge_tags=dict(type='bool', required=False, default=True), + wait=dict(type='bool', required=False, default=True), + wait_timeout=dict(type='int', required=False), + subnet_change_protection=dict(type='bool', required=False), + policy_change_protection=dict(type='bool', required=False, aliases=['firewall_policy_change_protection']), + delete_protection=dict(type='bool', required=False), + subnets=dict(type='list', elements='str', required=False), + purge_subnets=dict(type='bool', required=False, default=True), + policy=dict(type='str', required=False, aliases=['firewall_policy_arn']), + ) + + mutually_exclusive = [ + ('arn', 'name',) + ] + required_one_of = [ + ('arn', 'name',) + ] + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + mutually_exclusive=mutually_exclusive, + required_one_of=required_one_of, + ) + + arn = module.params.get('arn') + name = module.params.get('name') + state = module.params.get('state') + + manager = NetworkFirewallManager(module, name=name, arn=arn) + manager.set_wait(module.params.get('wait', None)) + manager.set_wait_timeout(module.params.get('wait_timeout', None)) + + if state == 'absent': + manager.set_delete_protection(module.params.get('delete_protection', None)) + manager.delete() + else: + if not manager.original_resource: + if not module.params.get('subnets', None): + module.fail_json('The subnets parameter must be provided on creation.') + if not module.params.get('policy', None): + module.fail_json('The policy parameter must be provided on creation.') + manager.set_description(module.params.get('description', None)) + manager.set_tags(module.params.get('tags', None), module.params.get('purge_tags', None)) + manager.set_subnet_change_protection(module.params.get('subnet_change_protection', None)) + manager.set_policy_change_protection(module.params.get('policy_change_protection', None)) + manager.set_delete_protection(module.params.get('delete_protection', None)) + manager.set_subnets(module.params.get('subnets', None), module.params.get('purge_subnets', None)) + manager.set_policy(module.params.get('policy', None)) + manager.flush_changes() + + results = dict( + changed=manager.changed, + firewall=manager.updated_resource, + ) + if manager.changed: + diff = dict( + before=manager.original_resource, + after=manager.updated_resource, + ) + results['diff'] = diff + module.exit_json(**results) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/networkfirewall_info.py b/plugins/modules/networkfirewall_info.py new file mode 100644 index 00000000000..48db97ea67a --- /dev/null +++ b/plugins/modules/networkfirewall_info.py @@ -0,0 +1,236 @@ +#!/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 + + +DOCUMENTATION = ''' +module: networkfirewall_info +short_description: describe AWS Network Firewall firewalls +version_added: 4.0.0 +description: + - A module for describing AWS Network Firewall firewalls. +options: + arn: + description: + - The ARN of the Network Firewall. + - Mutually exclusive with I(name) and I(vpc_ids). + required: false + type: str + name: + description: + - The name of the Network Firewall. + - Mutually exclusive with I(arn) and I(vpc_ids). + required: false + type: str + vpc_ids: + description: + - A List of VPCs to retrieve the firewalls for. + - Mutually exclusive with I(name) and I(arn). + required: false + type: list + elements: str + aliases: ['vpcs', 'vpc_id'] + +author: Mark Chappell (@tremble) +extends_documentation_fragment: + - amazon.aws.aws + - amazon.aws.ec2 +''' + +EXAMPLES = ''' + +# Describe all firewalls in an account +- community.aws.networkfirewall_info: {} + +# Describe a firewall by ARN +- community.aws.networkfirewall_info: + arn: arn:aws:network-firewall:us-east-1:123456789012:firewall/ExampleFirewall + +# Describe a firewall by name +- community.aws.networkfirewall_info: + name: ExampleFirewall +''' + +RETURN = ''' +firewall_list: + description: A list of ARNs of the matching firewalls. + type: list + elements: str + returned: When a firewall name isn't specified + example: ['arn:aws:network-firewall:us-east-1:123456789012:firewall/Example1', + 'arn:aws:network-firewall:us-east-1:123456789012:firewall/Example2'] + +firewalls: + description: The details of the firewalls + returned: success + type: list + elements: dict + contains: + firewall: + description: The details of the firewall + type: dict + returned: success + contains: + delete_protection: + description: A flag indicating whether it is possible to delete the firewall. + type: str + returned: success + example: true + description: + description: A description of the firewall. + type: str + returned: success + example: "Description" + firewall_arn: + description: The ARN of the firewall. + type: str + returned: success + example: "arn:aws:network-firewall:us-east-1:123456789012:firewall/ExampleFirewall" + firewall_id: + description: A unique ID for the firewall. + type: str + returned: success + example: "12345678-abcd-1234-abcd-123456789abc" + firewall_name: + description: The name of the firewall. + type: str + returned: success + example: "ExampleFirewall" + firewall_policy_arn: + description: The ARN of the firewall policy used by the firewall. + type: str + returned: success + example: "arn:aws:network-firewall:us-east-1:123456789012:firewall-policy/ExamplePolicy" + firewall_policy_change_protection: + description: + - A flag indicating whether it is possible to change which firewall + policy is used by the firewall. + type: bool + returned: success + example: false + subnet_change_protection: + description: + - A flag indicating whether it is possible to change which subnets + the firewall endpoints are in. + type: bool + returned: success + example: true + subnet_mappings: + description: A list of the subnets the firewall endpoints are in. + type: list + elements: dict + contains: + subnet_id: + description: The ID of the subnet. + type: str + returned: success + example: "subnet-12345678" + tags: + description: The tags associated with the firewall. + type: dict + returned: success + example: '{"SomeTag": "SomeValue"}' + vpc_id: + description: The ID of the VPC that the firewall is used by. + type: str + returned: success + example: "vpc-0123456789abcdef0" + firewall_metadata: + description: Metadata about the firewall + type: dict + returned: success + contains: + configuration_sync_state_summary: + description: + - A short summary of the synchronization status of the + policy and rule groups. + type: str + returned: success + example: "IN_SYNC" + status: + description: + - A short summary of the status of the firewall endpoints. + type: str + returned: success + example: "READY" + sync_states: + description: + - A description, broken down by availability zone, of the status + of the firewall endpoints as well as the synchronization status + of the policies and rule groups. + type: dict + returned: success + example: + { + "us-east-1a": { + "attachment": { + "endpoint_id": "vpce-123456789abcdef01", + "status": "READY", + "subnet_id": "subnet-12345678" + }, + "config": { + "arn:aws:network-firewall:us-east-1:123456789012:firewall-policy/Ansible-Example": { + "sync_status": "IN_SYNC", + "update_token": "abcdef01-0000-0000-0000-123456789abc" + }, + "arn:aws:network-firewall:us-east-1:123456789012:stateful-rulegroup/ExampleDomainList": { + "sync_status": "IN_SYNC", + "update_token": "12345678-0000-0000-0000-abcdef012345" + } + } + } + } +''' + + +from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule +from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallManager + + +def main(): + + argument_spec = dict( + name=dict(type='str', required=False), + arn=dict(type='str', required=False), + vpc_ids=dict(type='list', required=False, elements='str', aliases=['vpcs', 'vpc_id']), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + mutually_exclusive=[ + ('arn', 'name', 'vpc_ids',), + ], + ) + + arn = module.params.get('arn') + name = module.params.get('name') + vpcs = module.params.get('vpc_ids') + + manager = NetworkFirewallManager(module) + + results = dict(changed=False) + + if name or arn: + firewall = manager.get_firewall(name=name, arn=arn) + if firewall: + results['firewalls'] = [firewall] + else: + results['firewalls'] = [] + else: + if vpcs: + firewall_list = manager.list(vpc_ids=vpcs) + else: + firewall_list = manager.list() + results['firewall_list'] = firewall_list + firewalls = [manager.get_firewall(arn=f) for f in firewall_list] + results['firewalls'] = firewalls + + module.exit_json(**results) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/networkfirewall/aliases b/tests/integration/targets/networkfirewall/aliases new file mode 100644 index 00000000000..04ebe0ef98b --- /dev/null +++ b/tests/integration/targets/networkfirewall/aliases @@ -0,0 +1,7 @@ +cloud/aws + +# Takes around 45 minutes: deletion of resources has to be serial and is +# painfully slow +slow + +networkfirewall_info diff --git a/tests/integration/targets/networkfirewall/defaults/main.yml b/tests/integration/targets/networkfirewall/defaults/main.yml new file mode 100644 index 00000000000..d5fe55074a2 --- /dev/null +++ b/tests/integration/targets/networkfirewall/defaults/main.yml @@ -0,0 +1,35 @@ +_resource_prefix: 'AnsibleTest-{{ tiny_prefix }}-NF' +firewall_name_prefix: '{{ _resource_prefix }}' +# +# _resource_prefix: 'AnsibleTest-STATIC-NF' +# firewall_name_prefix: 'AnsibleTest-{{ tiny_prefix }}-NF' + +firewall_name: '{{ firewall_name_prefix }}' + +cidr_prefix: '10.{{ 255 | random(seed=_resource_prefix) }}' +tgw_name: '{{ _resource_prefix }}' +tgw_name_2: '{{ _resource_prefix }}-2' +vpc_name_a: '{{ _resource_prefix }}-1' +vpc_name_b: '{{ _resource_prefix }}-2' +vpc_cidr_a: '{{ cidr_prefix }}.1.0/24' +vpc_cidr_b: '{{ cidr_prefix }}.2.0/24' + +subnet_cidr_a_1: '{{ cidr_prefix }}.1.0/26' +subnet_cidr_a_2: '{{ cidr_prefix }}.1.64/26' +subnet_cidr_a_3: '{{ cidr_prefix }}.1.128/26' +subnet_cidr_a_1a: '{{ cidr_prefix }}.1.192/26' +subnet_cidr_b_1: '{{ cidr_prefix }}.2.0/26' +subnet_cidr_b_2: '{{ cidr_prefix }}.2.64/26' + +subnet_name_a_1: '{{ _resource_prefix }}-a-1' +subnet_name_a_1a: '{{ _resource_prefix }}-a-1a' +subnet_name_a_2: '{{ _resource_prefix }}-a-2' +subnet_name_a_3: '{{ _resource_prefix }}-a-3' +subnet_name_b_1: '{{ _resource_prefix }}-b-1' +subnet_name_b_2: '{{ _resource_prefix }}-b-2' + +policy_name_prefix: '{{ _resource_prefix }}' +group_name_prefix: '{{ _resource_prefix }}' +default_policy_name: '{{ policy_name_prefix }}-DefaultOrder' +default_group_name: '{{ group_name_prefix }}-DefaultOrder' +rule_group_capacity: 100 diff --git a/tests/integration/targets/networkfirewall/meta/main.yml b/tests/integration/targets/networkfirewall/meta/main.yml new file mode 100644 index 00000000000..aef5ca0ee57 --- /dev/null +++ b/tests/integration/targets/networkfirewall/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - role: setup_ec2_facts diff --git a/tests/integration/targets/networkfirewall/tasks/cleanup.yml b/tests/integration/targets/networkfirewall/tasks/cleanup.yml new file mode 100644 index 00000000000..b5797fb7edd --- /dev/null +++ b/tests/integration/targets/networkfirewall/tasks/cleanup.yml @@ -0,0 +1,123 @@ +--- +# +# We can't start deleting the other resources until the firewalls have finished +# detatching from the subnets +# +- name: 'Fetch all firewalls' + networkfirewall_info: {} + register: account_firewalls_info + ignore_errors: true + +- name: 'Get a list of all firewalls matching {{ firewall_name_prefix }}' + set_fact: + matching_firewalls: '{{ account_firewalls_info.firewall_list | select("search", firewall_name_prefix) | list }}' + ignore_errors: true + +- name: 'Delete matching firewalls' + networkfirewall: + arn: '{{ item }}' + state: absent + delete_protection: False + wait: True + ignore_errors: true + loop: '{{ matching_firewalls }}' + +# +# Policies can take a while to delete, but we can start the process, trigger the +# deletion of the Subnets/VPC and then come back and delete the Rule Groups +# +- name: 'Fetch all policies' + networkfirewall_policy_info: {} + register: account_policies_info + ignore_errors: true + +- name: 'Get a list of all rules matching {{ policy_name_prefix }}' + set_fact: + matching_policies: '{{ account_policies_info.policy_list | select("search", policy_name_prefix) | list }}' + ignore_errors: true + +- name: 'Delete matching policies' + networkfirewall_policy: + arn: '{{ item }}' + state: absent + wait: False + ignore_errors: true + loop: '{{ matching_policies }}' + +- name: 'Start deletion of subnets' + ec2_vpc_subnet: + state: absent + cidr: '{{ item.cidr }}' + vpc_id: '{{ item.vpc_id }}' + wait: False + loop: + - cidr: '{{ subnet_cidr_a_1 }}' + vpc_id: '{{ vpc_id_a }}' + - cidr: '{{ subnet_cidr_a_2 }}' + vpc_id: '{{ vpc_id_a }}' + - cidr: '{{ subnet_cidr_a_3 }}' + vpc_id: '{{ vpc_id_a }}' + - cidr: '{{ subnet_cidr_b_1 }}' + vpc_id: '{{ vpc_id_b }}' + - cidr: '{{ subnet_cidr_b_2 }}' + vpc_id: '{{ vpc_id_b }}' + - cidr: '{{ subnet_cidr_a_1a }}' + vpc_id: '{{ vpc_id_a }}' + ignore_errors: True + +- name: 'Wait for deletion of subnets' + ec2_vpc_subnet: + state: absent + cidr: '{{ item.cidr }}' + vpc_id: '{{ item.vpc_id }}' + wait: True + loop: + - cidr: '{{ subnet_cidr_a_1 }}' + vpc_id: '{{ vpc_id_a }}' + - cidr: '{{ subnet_cidr_a_2 }}' + vpc_id: '{{ vpc_id_a }}' + - cidr: '{{ subnet_cidr_a_3 }}' + vpc_id: '{{ vpc_id_a }}' + - cidr: '{{ subnet_cidr_b_1 }}' + vpc_id: '{{ vpc_id_b }}' + - cidr: '{{ subnet_cidr_b_2 }}' + vpc_id: '{{ vpc_id_b }}' + - cidr: '{{ subnet_cidr_a_1a }}' + vpc_id: '{{ vpc_id_a }}' + ignore_errors: True + +- name: 'Delete VPCs' + ec2_vpc_net: + state: absent + cidr_block: '{{ item.cidr }}' + name: '{{ item.name }}' + loop: + - cidr: '{{ vpc_cidr_a }}' + name: '{{ vpc_name_a }}' + - cidr: '{{ vpc_cidr_b }}' + name: '{{ vpc_name_b }}' + ignore_errors: True + +- name: 'Wait for policies to finish deletion' + networkfirewall_policy: + arn: '{{ item }}' + state: absent + ignore_errors: true + loop: '{{ matching_policies }}' + +- name: 'Fetch all account rule groups' + networkfirewall_rule_group_info: {} + register: account_rules_info + ignore_errors: true + +- name: 'Get a list of all rules matching {{ group_name_prefix }}' + set_fact: + matching_rules: '{{ account_rules_info.rule_list | select("search", group_name_prefix) | list }}' + ignore_errors: true + +- name: 'Delete matching rule groups' + networkfirewall_rule_group: + arn: '{{ item }}' + state: absent + ignore_errors: true + loop: '{{ matching_rules }}' diff --git a/tests/integration/targets/networkfirewall/tasks/complex.yml b/tests/integration/targets/networkfirewall/tasks/complex.yml new file mode 100644 index 00000000000..ea8378cc949 --- /dev/null +++ b/tests/integration/targets/networkfirewall/tasks/complex.yml @@ -0,0 +1,612 @@ +--- +# Tests the manipulation of networkfirewall resources one option at a time + +- vars: + complex_firewall_name: '{{ firewall_name_prefix }}-Complex' + first_tags: + CamelCaseKey: CamelCaseValue + 'Key with Spaces': Value with spaces + pascalCaseKey: pascalCaseValue + snake_case_key: snake_case_value + second_tags: + CamelCaseKey: CamelCaseValue + 'Key with Spaces': Updated Value with spaces + NewCamelCaseKey: CamelCaseValue + 'New Key with Spaces': Value with spaces + newPascalCaseKey: pascalCaseValue + new_snake_case_key: snake_case_value + pascalCaseKey: pascalCaseValue + snake_case_key: snake_case_value + block: + ################################################################### + # Creation + + - name: '(CHECK) Create a complex firewall' + check_mode: True + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + delete_protection: True + description: "An example Description" + policy: '{{ default_policy_names[0] }}' + policy_change_protection: True + subnets: + - '{{ subnet_id_a_1 }}' + - '{{ subnet_id_a_2 }}' + subnet_change_protection: True + tags: '{{ first_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An example Description' + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Create a complex firewall' + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + delete_protection: True + description: "An example Description" + policy: '{{ default_policy_names[0] }}' + policy_change_protection: True + subnets: + - '{{ subnet_id_a_1 }}' + - '{{ subnet_id_a_2 }}' + subnet_change_protection: True + tags: '{{ first_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An example Description' + - firewall_data.firewall_arn.startswith(account_arn) + - firewall_data.firewall_arn.endswith(complex_firewall_name) + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + firewall_metadata: '{{ complex_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Save Policy ID/ARN for later' + set_fact: + complex_firewall_id: '{{ firewall_data.firewall_id }}' + complex_firewall_arn: '{{ firewall_data.firewall_arn }}' + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + + - name: '(CHECK) Create a complex firewall (idempotency)' + check_mode: True + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + delete_protection: True + description: "An example Description" + policy: '{{ default_policy_names[0] }}' + policy_change_protection: True + subnets: + - '{{ subnet_id_a_1 }}' + - '{{ subnet_id_a_2 }}' + subnet_change_protection: True + tags: '{{ first_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is not changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An example Description' + - firewall_data.firewall_arn == complex_firewall_arn + - firewall_data.firewall_id == complex_firewall_id + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + firewall_metadata: '{{ complex_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Create a complex firewall (idempotency)' + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + delete_protection: True + description: "An example Description" + policy: '{{ default_policy_names[0] }}' + policy_change_protection: True + subnets: + - '{{ subnet_id_a_1 }}' + - '{{ subnet_id_a_2 }}' + subnet_change_protection: True + tags: '{{ first_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is not changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An example Description' + - firewall_data.firewall_arn == complex_firewall_arn + - firewall_data.firewall_id == complex_firewall_id + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + firewall_metadata: '{{ complex_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ################################################################### + # Update + + - name: '(CHECK) Update a complex firewall' + check_mode: True + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + description: "An updated Description" + policy: '{{ default_policy_arns[2] }}' + policy_change_protection: False + subnet_change_protection: False + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + tags: '{{ second_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == complex_firewall_arn + - firewall_data.firewall_id == complex_firewall_id + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + firewall_metadata: '{{ complex_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update a complex firewall' + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + description: "An updated Description" + policy: '{{ default_policy_arns[2] }}' + policy_change_protection: False + subnet_change_protection: False + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + tags: '{{ second_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == complex_firewall_arn + - firewall_data.firewall_id == complex_firewall_id + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + firewall_metadata: '{{ complex_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + # There's a delay of a couple of seconds between requesting a change and the + # firewall entering a PENDING/PROVISIONING state. The delay is enough to + # let the firewall enter the expected PENDING state is it's going to. + - name: 'Pause to let synchroization start' + pause: + seconds: 5 + + # Also checks that we get the info we expect + - name: 'Check firewall is not still updating' + networkfirewall_info: + arn: '{{ complex_firewall_arn }}' + register: complex_firewall_info + + - assert: + that: + - complex_firewall_info is successful + - complex_firewall_info.firewalls | length == 1 + - '"firewalls" in complex_firewall_info' + - '"firewall" in complex_firewall_info.firewalls[0]' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall_info.firewalls[0]' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == complex_firewall_arn + - firewall_data.firewall_id == complex_firewall_id + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall_info.firewalls[0].firewall }}' + firewall_metadata: '{{ complex_firewall_info.firewalls[0].firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update a complex firewall (idempotency)' + check_mode: True + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + description: "An updated Description" + policy: '{{ default_policy_arns[2] }}' + policy_change_protection: False + subnet_change_protection: False + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + tags: '{{ second_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is not changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == complex_firewall_arn + - firewall_data.firewall_id == complex_firewall_id + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + firewall_metadata: '{{ complex_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update a complex firewall (idempotency)' + networkfirewall: + name: '{{ complex_firewall_name }}' + state: present + description: "An updated Description" + policy: '{{ default_policy_arns[2] }}' + policy_change_protection: False + subnet_change_protection: False + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + tags: '{{ second_tags }}' + register: complex_firewall + + - assert: + that: + - complex_firewall is not changed + - '"firewall" in complex_firewall' + - '"firewall" in complex_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in complex_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == complex_firewall_arn + - firewall_data.firewall_id == complex_firewall_id + - firewall_data.firewall_name == complex_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == "READY" + - firewall_metadata.configuration_sync_state_summary == "IN_SYNC" + vars: + firewall_data: '{{ complex_firewall.firewall.firewall }}' + firewall_metadata: '{{ complex_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + + ################################################################### + # Delete firewall + # + # This is *very* slow, so we don't wait on this one. The simple test will + # check that waiting for deletion behaves properly. What we are however + # checking is that deletion protection updates happen prior to attempting to + # delete the firewall. + + - name: '(CHECK) Delete complex firewall - no wait' + check_mode: True + networkfirewall: + name: '{{ complex_firewall_name }}' + delete_protection: False + state: absent + wait: False + register: complex_firewall + + - name: 'Delete complex firewall - no wait' + networkfirewall: + name: '{{ complex_firewall_name }}' + delete_protection: False + state: absent + wait: False + register: complex_firewall + + - assert: + that: + - complex_firewall is changed + + # We need to wait for the state to change + - pause: + seconds: 4 + + - name: 'Check firewall is not gone (expected to be in a pending state)' + networkfirewall_info: + arn: '{{ complex_firewall_arn }}' + register: complex_firewall_info + + - assert: + that: + - complex_firewall_info is successful + - complex_firewall_info.firewalls | length == 1 + + - name: '(CHECK) Delete complex firewall (idempotency)' + check_mode: True + networkfirewall: + name: '{{ complex_firewall_name }}' + delete_protection: False + state: absent + wait: False + register: complex_firewall + + - assert: + that: + - complex_firewall is not changed + + - name: 'Delete complex firewall (idempotency)' + networkfirewall: + name: '{{ complex_firewall_name }}' + delete_protection: False + state: absent + wait: False + register: complex_firewall + + - assert: + that: + - complex_firewall is not changed + + always: + - name: 'Cleanup complex firewall' + networkfirewall: + name: '{{ complex_firewall_name }}' + state: absent + delete_protection: False + wait: False + ignore_errors: True diff --git a/tests/integration/targets/networkfirewall/tasks/main.yml b/tests/integration/targets/networkfirewall/tasks/main.yml new file mode 100644 index 00000000000..6a77d4f9355 --- /dev/null +++ b/tests/integration/targets/networkfirewall/tasks/main.yml @@ -0,0 +1,35 @@ +--- +- name: 'networkfirewall integration tests' + collections: + - amazon.aws + - community.aws + 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: + # Fetch some info about the account so we can build ARNs + - aws_caller_info: {} + register: caller_info + - name: 'Generate the ARN pattern to search for' + vars: + _caller_info: '{{ caller_info.arn.split(":") }}' + _base_arn: 'arn:{{_caller_info[1]}}:network-firewall:{{aws_region}}' + set_fact: + account_arn: '{{_base_arn}}:{{_caller_info[4]}}:firewall/' + + # Prepares various resources + - include_tasks: 'setup.yml' + + # Test manipulating multiple parameters at the same time + - include_tasks: 'complex.yml' + + # Test manipulating one parameter at a time + - include_tasks: 'simple.yml' + + always: # [] + # Cleanup after ourselves + - include_tasks: 'cleanup.yml' diff --git a/tests/integration/targets/networkfirewall/tasks/setup.yml b/tests/integration/targets/networkfirewall/tasks/setup.yml new file mode 100644 index 00000000000..17f1dde88e2 --- /dev/null +++ b/tests/integration/targets/networkfirewall/tasks/setup.yml @@ -0,0 +1,118 @@ +--- +# The simplest form of rule group +- name: 'Create Rule Groups with minimal settings (Default order)' + networkfirewall_rule_group: + name: '{{ default_group_name }}-{{ item }}' + type: 'stateful' + capacity: '{{ rule_group_capacity }}' + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + register: default_groups + loop: '{{ range(0,3,1) | list }}' + +# Store Group Names and ARNs for later +- set_fact: + default_group_names: >- + {{ default_groups.results + | map(attribute="rule_group") + | map(attribute="rule_group_metadata") + | map(attribute="rule_group_name") | list }} + default_group_arns: >- + {{ default_groups.results + | map(attribute="rule_group") + | map(attribute="rule_group_metadata") + | map(attribute="rule_group_arn") | list }} + +- name: 'Pick 2 AZs available for use' + set_fact: + subnet_az_a_1: '{{ ec2_availability_zone_names[0] }}' + subnet_az_a_1a: '{{ ec2_availability_zone_names[0] }}' + subnet_az_a_2: '{{ ec2_availability_zone_names[1] }}' + subnet_az_a_3: '{{ ec2_availability_zone_names[2] }}' + subnet_az_b_1: '{{ ec2_availability_zone_names[0] }}' + subnet_az_b_2: '{{ ec2_availability_zone_names[1] }}' + +- name: 'Create VPCs to attach to Firewall' + ec2_vpc_net: + cidr_block: '{{ item.cidr }}' + name: '{{ item.name }}' + loop: + - cidr: '{{ vpc_cidr_a }}' + name: '{{ vpc_name_a }}' + - cidr: '{{ vpc_cidr_b }}' + name: '{{ vpc_name_b }}' + register: create_vpcs + +- set_fact: + vpc_id_a: '{{ vpc_a.id }}' + vpc_id_b: '{{ vpc_b.id }}' + vpc_owner_a: '{{ vpc_a.owner_id }}' + vpc_owner_b: '{{ vpc_b.owner_id }}' + vars: + vpc_a: '{{ create_vpcs.results[0].vpc }}' + vpc_b: '{{ create_vpcs.results[1].vpc }}' + +- name: 'Create subnets' + ec2_vpc_subnet: + az: '{{ item.az }}' + cidr: '{{ item.cidr }}' + tags: + Name: '{{ item.name }}' + vpc_id: '{{ item.vpc_id }}' + loop: + - az: '{{ subnet_az_a_1 }}' + cidr: '{{ subnet_cidr_a_1 }}' + vpc_id: '{{ vpc_id_a }}' + name: '{{ subnet_name_a_1 }}' + - az: '{{ subnet_az_a_2 }}' + cidr: '{{ subnet_cidr_a_2 }}' + vpc_id: '{{ vpc_id_a }}' + name: '{{ subnet_name_a_2 }}' + - az: '{{ subnet_az_a_3 }}' + cidr: '{{ subnet_cidr_a_3 }}' + vpc_id: '{{ vpc_id_a }}' + name: '{{ subnet_name_a_3 }}' + - az: '{{ subnet_az_b_1 }}' + cidr: '{{ subnet_cidr_b_1 }}' + vpc_id: '{{ vpc_id_b }}' + name: '{{ subnet_name_b_1 }}' + - az: '{{ subnet_az_b_2 }}' + cidr: '{{ subnet_cidr_b_2 }}' + vpc_id: '{{ vpc_id_b }}' + name: '{{ subnet_name_b_2 }}' + - az: '{{ subnet_az_a_1a }}' + cidr: '{{ subnet_cidr_a_1a }}' + vpc_id: '{{ vpc_id_a }}' + name: '{{ subnet_name_a_1a }}' + register: create_subnets + +- set_fact: + subnet_id_a_1: '{{ create_subnets.results[0].subnet.id }}' + subnet_id_a_2: '{{ create_subnets.results[1].subnet.id }}' + subnet_id_a_3: '{{ create_subnets.results[2].subnet.id }}' + subnet_id_b_1: '{{ create_subnets.results[3].subnet.id }}' + subnet_id_b_2: '{{ create_subnets.results[4].subnet.id }}' + subnet_id_a_1a: '{{ create_subnets.results[5].subnet.id }}' + +- name: 'Create a simple firewall policy with `default` rule order' + networkfirewall_policy: + name: '{{ default_policy_name }}-{{ item }}' + stateful_rule_order: 'default' + stateful_rule_groups: + - '{{ default_group_names[(item)] }}' + state: present + register: default_policies + loop: '{{ range(0,3,1) | list }}' + +# Store Group Names and ARNs for later +- set_fact: + default_policy_names: >- + {{ default_policies.results + | map(attribute="policy") + | map(attribute="policy_metadata") + | map(attribute="firewall_policy_name") | list }} + default_policy_arns: >- + {{ default_policies.results + | map(attribute="policy") + | map(attribute="policy_metadata") + | map(attribute="firewall_policy_arn") | list }} diff --git a/tests/integration/targets/networkfirewall/tasks/simple.yml b/tests/integration/targets/networkfirewall/tasks/simple.yml new file mode 100644 index 00000000000..271aff17dff --- /dev/null +++ b/tests/integration/targets/networkfirewall/tasks/simple.yml @@ -0,0 +1,3893 @@ +--- +# Tests the manipulation of networkfirewall resources one option at a time + +- vars: + simple_firewall_name: '{{ firewall_name_prefix }}-Simple' + first_tags: + 'Key with Spaces': Value with spaces + CamelCaseKey: CamelCaseValue + pascalCaseKey: pascalCaseValue + snake_case_key: snake_case_value + second_tags: + 'New Key with Spaces': Value with spaces + NewCamelCaseKey: CamelCaseValue + newPascalCaseKey: pascalCaseValue + new_snake_case_key: snake_case_value + third_tags: + 'Key with Spaces': Value with spaces + CamelCaseKey: CamelCaseValue + pascalCaseKey: pascalCaseValue + snake_case_key: snake_case_value + 'New Key with Spaces': Updated Value with spaces + final_tags: + 'Key with Spaces': Value with spaces + CamelCaseKey: CamelCaseValue + pascalCaseKey: pascalCaseValue + snake_case_key: snake_case_value + 'New Key with Spaces': Updated Value with spaces + NewCamelCaseKey: CamelCaseValue + newPascalCaseKey: pascalCaseValue + new_snake_case_key: snake_case_value + block: + ################################################################### + # Creation + + - name: '(CHECK) Create a simple firewall with the minimum necessary parameters' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_names[0] }}' + subnets: + - '{{ subnet_id_a_1 }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.subnet_mappings + - firewall_data.vpc_id == vpc_id_a + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Create a simple firewall with the minimum necessary parameters' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_names[0] }}' + subnets: + - '{{ subnet_id_a_1 }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.firewall_arn.startswith(account_arn) + - firewall_data.firewall_arn.endswith(simple_firewall_name) + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Save Policy ID/ARN for later' + set_fact: + simple_firewall_id: '{{ firewall_data.firewall_id }}' + simple_firewall_arn: '{{ firewall_data.firewall_arn }}' + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + + - name: '(CHECK) Create a simple firewall with the minimum necessary parameters (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_names[0] }}' + subnets: + - '{{ subnet_id_a_1 }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Create a simple firewall with the minimum necessary parameters (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_names[0] }}' + subnets: + - '{{ subnet_id_a_1 }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Create a simple firewall with the minimum necessary parameters - test reference by ARN (idempotency)' + check_mode: True + networkfirewall: + arn: '{{ simple_firewall_arn }}' + state: present + policy: '{{ default_policy_names[0] }}' + subnets: + - '{{ subnet_id_a_1 }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Create a simple firewall with the minimum necessary parameters - test reference by ARN (idempotency)' + networkfirewall: + arn: '{{ simple_firewall_arn }}' + state: present + policy: '{{ default_policy_names[0] }}' + subnets: + - '{{ subnet_id_a_1 }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ################################################################### + # Description + + - name: '(CHECK) Set Description' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An example Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An example Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Set Description' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An example Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An example Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Set Description (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An example Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An example Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Set Description (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An example Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An example Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update Description' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An updated Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update Description' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An updated Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update Description (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An updated Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update Description (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + description: "An updated Description" + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == {} + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ################################################################### + # Tags + + - name: '(CHECK) Set Tags' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ first_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Set Tags' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ first_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Set Tags (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ first_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Set Tags (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ first_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == first_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update Tags with purge' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ second_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update Tags with purge' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ second_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update Tags with purge (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ second_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update Tags with purge (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ second_tags }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == second_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update Tags without purge' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ third_tags }}' + purge_tags: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update Tags without purge' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ third_tags }}' + purge_tags: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update Tags without purge (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ third_tags }}' + purge_tags: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update Tags without purge (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + tags: '{{ third_tags }}' + purge_tags: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ################################################################### + # Change Protection + + - name: '(CHECK) Enable deletion protection' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Enable deletion protection' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Enable deletion protection (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Enable deletion protection (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Enable firewall policy change protection' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Enable firewall policy change protection' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Enable firewall policy change protection (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Enable firewall policy change protection (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Enable subnet change protection' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Enable subnet change protection' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Enable subnet change protection (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Enable subnet change protection (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: True + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == true + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Disable firewall policy change protection' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Disable firewall policy change protection' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Disable firewall policy change protection (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Disable firewall policy change protection (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == true + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Disable subnet change protection' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Disable subnet change protection' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Disable subnet change protection (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Disable subnet change protection (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnet_change_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == true + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Disable deletion protection' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Disable deletion protection' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Disable deletion protection (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Disable deletion protection (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + delete_protection: False + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[0] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ################################################################### + # Change Firewall policy + + - name: '(CHECK) Update policy assigned to firewall - without waiting' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + wait: false + policy: '{{ default_policy_names[1] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[1] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update policy assigned to firewall - without waiting' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + wait: false + policy: '{{ default_policy_names[1] }}' + register: simple_firewall + + # There's a delay of a couple of seconds between requesting a change and the + # firewall entering a PENDING/PROVISIONING state. The delay is enough to + # let the firewall enter the expected PENDING state + - name: 'Pause to let synchroization start' + pause: + seconds: 5 + + - name: 'Check firewall state' + networkfirewall_info: + arn: '{{ simple_firewall_arn }}' + register: simple_firewall_info + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[1] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + # Because we're not waiting, this might not happen before we returned, + # so we check using _info a couple of seconds later + - simple_firewall_info.firewalls[0].firewall_metadata.configuration_sync_state_summary == 'PENDING' + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update policy assigned to firewall - without waiting (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + wait: false + policy: '{{ default_policy_names[1] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[1] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'PENDING' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update policy assigned to firewall - without waiting (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + wait: false + policy: '{{ default_policy_names[1] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[1] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'PENDING' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update policy assigned to firewall - without waiting - by arn (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + wait: false + policy: '{{ default_policy_arns[1] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[1] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'PENDING' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update policy assigned to firewall - without waiting (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + wait: false + policy: '{{ default_policy_arns[1] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[1] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'PENDING' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update policy assigned to firewall - waiting' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_arns[2] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update policy assigned to firewall - waiting' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_arns[2] }}' + register: simple_firewall + + # There's a delay of a couple of seconds between requesting a change and the + # firewall entering a PENDING/PROVISIONING state. The delay is enough to + # let the firewall enter the PENDING state if we didn't wait (because we're + # waiting, we should be back to IN_SYNC. + - name: 'Pause to let synchroization start' + pause: + seconds: 5 + + - name: 'Check firewall state' + networkfirewall_info: + arn: '{{ simple_firewall_arn }}' + register: simple_firewall_info + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - subnet_az_a_1 in firewall_metadata.sync_states + - simple_firewall_info.firewalls[0].firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update policy assigned to firewall - waiting (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_names[2] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update policy assigned to firewall - waiting (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_names[2] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update policy assigned to firewall - waiting - by name (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_names[2] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update policy assigned to firewall - waiting - by name (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + policy: '{{ default_policy_arns[2] }}' + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 1 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + - firewall_metadata.status == 'READY' + - firewall_metadata.configuration_sync_state_summary == 'IN_SYNC' + - subnet_az_a_1 in firewall_metadata.sync_states + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ################################################################### + # Change Subnets + + - name: '(CHECK) Update subnets - duplicate AZ (FAIL)' + check_mode: True + ignore_errors: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_1a }}' + purge_subnets: false + register: simple_firewall + + - assert: + that: + - simple_firewall is failed + + - name: 'Update subnets - duplicate AZ (FAIL)' + ignore_errors: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_1a }}' + purge_subnets: false + register: simple_firewall + + - assert: + that: + - simple_firewall is failed + + ### + + - name: '(CHECK) Update subnets - Different VPC (FAIL)' + check_mode: True + ignore_errors: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_b_2 }}' + purge_subnets: false + register: simple_firewall + + - assert: + that: + - simple_firewall is failed + + - name: 'Update subnets - Different VPC (FAIL)' + ignore_errors: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_b_2 }}' + purge_subnets: false + register: simple_firewall + + - assert: + that: + - simple_firewall is failed + + ### + + - name: '(CHECK) Update subnets - Different VPC with purge (FAIL)' + check_mode: True + ignore_errors: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_b_2 }}' + purge_subnets: true + register: simple_firewall + + - assert: + that: + - simple_firewall is failed + + - name: 'Update subnets - Different VPC with purge (FAIL)' + ignore_errors: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_b_2 }}' + purge_subnets: true + register: simple_firewall + + - assert: + that: + - simple_firewall is failed + + ### + + - name: '(CHECK) Update subnets - without purge' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + purge_subnets: false + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update subnets - without purge' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + purge_subnets: false + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update subnets - without purge (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + purge_subnets: false + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update subnets - without purge (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + purge_subnets: false + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1 in subnet_ids + - subnet_id_a_2 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update subnets - with purge' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + purge_subnets: true + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update subnets - with purge' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + purge_subnets: true + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update subnets - with purge (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + purge_subnets: true + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update subnets - with purge (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + purge_subnets: true + wait: false + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 2 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + # We're not waiting, so we can't assert anything about the sync states + # in the metadata + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ### + + - name: '(CHECK) Update subnets - with wait' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + wait: true + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update subnets - with wait' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + wait: true + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: '(CHECK) Update subnets - with wait (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + wait: true + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + - name: 'Update subnets - with wait (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: present + subnets: + - '{{ subnet_id_a_1a }}' + - '{{ subnet_id_a_2 }}' + - '{{ subnet_id_a_3 }}' + wait: true + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + - '"firewall" in simple_firewall' + - '"firewall" in simple_firewall.firewall' + - '"delete_protection" in firewall_data' + - '"description" in firewall_data' + - '"firewall_arn" in firewall_data' + - '"firewall_id" in firewall_data' + - '"firewall_metadata" in simple_firewall.firewall' + - '"firewall_name" in firewall_data' + - '"firewall_policy_arn" in firewall_data' + - '"firewall_policy_change_protection" in firewall_data' + - '"subnet_change_protection" in firewall_data' + - '"subnet_mappings" in firewall_data' + - '"tags" in firewall_data' + - '"vpc_id" in firewall_data' + - firewall_data.delete_protection == false + - firewall_data.description == 'An updated Description' + - firewall_data.firewall_arn == simple_firewall_arn + - firewall_data.firewall_id == simple_firewall_id + - firewall_data.firewall_name == simple_firewall_name + - firewall_data.firewall_policy_arn == default_policy_arns[2] + - firewall_data.firewall_policy_change_protection == false + - firewall_data.subnet_change_protection == false + - firewall_data.subnet_mappings | length == 3 + - '"subnet_id" in firewall_data.subnet_mappings[0]' + - subnet_id_a_1a in subnet_ids + - subnet_id_a_2 in subnet_ids + - subnet_id_a_3 in subnet_ids + - firewall_data.vpc_id == vpc_id_a + - firewall_data.tags == final_tags + - '"configuration_sync_state_summary" in firewall_metadata' + - '"status" in firewall_metadata' + - '"sync_states" in firewall_metadata' + vars: + firewall_data: '{{ simple_firewall.firewall.firewall }}' + firewall_metadata: '{{ simple_firewall.firewall.firewall_metadata }}' + subnet_ids: '{{ firewall_data.subnet_mappings | map(attribute="subnet_id") | list }}' + + ################################################################### + # Delete firewall + + - name: '(CHECK) Delete firewall' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: absent + register: simple_firewall + + - name: 'Check firewall state' + networkfirewall_info: + arn: '{{ simple_firewall_arn }}' + register: simple_firewall_info + + - assert: + that: + - simple_firewall is changed + - simple_firewall_info.firewalls[0].firewall_metadata.status == 'READY' + + - name: 'Delete firewall' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: absent + register: simple_firewall + + - assert: + that: + - simple_firewall is changed + + - name: 'Check firewall is gone' + networkfirewall_info: + arn: '{{ simple_firewall_arn }}' + register: simple_firewall_info + + - assert: + that: + - simple_firewall_info is successful + - simple_firewall_info.firewalls | length == 0 + + - name: '(CHECK) Delete firewall (idempotency)' + check_mode: True + networkfirewall: + name: '{{ simple_firewall_name }}' + state: absent + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + + - name: 'Delete firewall (idempotency)' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: absent + register: simple_firewall + + - assert: + that: + - simple_firewall is not changed + + always: + - name: 'Cleanup simple firewall' + networkfirewall: + name: '{{ simple_firewall_name }}' + state: absent + delete_protection: False + wait: False + ignore_errors: True