From a4528fd0c9f2a62e4e42b14a69e1598facf7c215 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Thu, 10 Mar 2022 10:00:04 +0100 Subject: [PATCH 1/2] Some additional helper classes, example modules with full integration tests to follow. --- plugins/module_utils/base.py | 349 +++++++++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 plugins/module_utils/base.py diff --git a/plugins/module_utils/base.py b/plugins/module_utils/base.py new file mode 100644 index 00000000000..c3c94ada3b2 --- /dev/null +++ b/plugins/module_utils/base.py @@ -0,0 +1,349 @@ +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# +# Note: This code should probably live in amazon.aws rather than community.aws. +# However, for the sake of getting something into a useful shape first, it makes +# sense for it to start life in community.aws. +# + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +from copy import deepcopy +from functools import wraps + +try: + import botocore +except ImportError: + pass # Handled by AnsibleAWSModule + +from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict + +from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict + + +class BaseWaiterFactory(): + """ + A helper class used for creating additional waiters. + Unlike the waiters available directly from botocore these waiters will + automatically retry on common (temporary) AWS failures. + + This class should be treated as an abstract class and subclassed before use. + A subclass should: + - create the necessary client to pass to BaseWaiterFactory.__init__ + - override _BaseWaiterFactory._waiter_model_data to return the data defining + the waiter + + Usage: + waiter_factory = BaseWaiterFactory(module, client) + waiter = waiters.get_waiter('my_waiter_name') + waiter.wait(**params) + """ + module = None + client = None + + def __init__(self, module, client): + self.module = module + self.client = client + # While it would be nice to supliment this with the upstream data, + # unfortunately client doesn't have a public method for getting the + # waiter configs. + data = self._inject_ratelimit_retries(self._waiter_model_data) + self._model = botocore.waiter.WaiterModel( + waiter_config=dict(version=2, waiters=data), + ) + + @property + def _waiter_model_data(self): + r""" + Subclasses should override this method to return a dictionary mapping + waiter names to the waiter definition. + + This data is similar to the data found in botocore's waiters-2.json + files (for example: botocore/botocore/data/ec2/2016-11-15/waiters-2.json) + with two differences: + 1) Waiter names do not have transformations applied during lookup + 2) Only the 'waiters' data is required, the data is assumed to be + version 2 + + for example: + + @property + def _waiter_model_data(self): + return dict( + tgw_attachment_deleted=dict( + operation='DescribeTransitGatewayAttachments', + delay=5, maxAttempts=120, + acceptors=[ + dict(state='retry', matcher='pathAll', expected='deleting', argument='TransitGatewayAttachments[].State'), + dict(state='success', matcher='pathAll', expected='deleted', argument='TransitGatewayAttachments[].State'), + dict(state='success', matcher='path', expected=True, argument='length(TransitGatewayAttachments[]) == `0`'), + dict(state='success', matcher='error', expected='InvalidRouteTableID.NotFound'), + ] + ), + ) + + or + + @property + def _waiter_model_data(self): + return { + "instance_exists": { + "delay": 5, + "maxAttempts": 40, + "operation": "DescribeInstances", + "acceptors": [ + { + "matcher": "path", + "expected": true, + "argument": "length(Reservations[]) > `0`", + "state": "success" + }, + { + "matcher": "error", + "expected": "InvalidInstanceID.NotFound", + "state": "retry" + } + ] + }, + } + """ + + return dict() + + def _inject_ratelimit_retries(self, model): + extra_retries = [ + 'RequestLimitExceeded', 'Unavailable', 'ServiceUnavailable', + 'InternalFailure', 'InternalError', 'TooManyRequestsException', + 'Throttling'] + + acceptors = [] + for error in extra_retries: + acceptors.append(dict(state="retry", matcher="error", expected=error)) + + _model = deepcopy(model) + for waiter in _model: + _model[waiter]["acceptors"].extend(acceptors) + + return _model + + def get_waiter(self, waiter_name): + waiters = self._model.waiter_names + if waiter_name not in waiters: + self.module.fail_json( + 'Unable to find waiter {0}. Available_waiters: {1}' + .format(waiter_name, waiters)) + return botocore.waiter.create_waiter_with_client( + waiter_name, self._model, self.client, + ) + + +class Boto3Mixin(): + @staticmethod + def aws_error_handler(description): + r""" + A simple wrapper that handles the usual botocore exceptions and exits + with module.fail_json_aws. Designed to be used with BaseResourceManager. + Assumptions: + 1) First argument (usually `self` of method being wrapped will have a + 'module' attribute which is an AnsibleAWSModule + 2) First argument of method being wrapped will have an + _extra_error_output() method which takes no arguments and returns a + dictionary of extra parameters to be returned in the event of a + botocore exception. + Parameters: + description (string): In the event of a botocore exception the error + message will be 'Failed to {DESCRIPTION}'. + + Example Usage: + class ExampleClass(Boto3Mixin): + def __init__(self, module) + self.module = module + self._get_client() + + @Boto3Mixin.aws_error_handler("connect to AWS") + def _get_client(self): + self.client = self.module.client('ec2') + + @Boto3Mixin.aws_error_handler("describe EC2 instances") + def _do_something(**params): + return self.client.describe_instances(**params) + """ + + def wrapper(func): + @wraps(func) + def handler(_self, *args, **kwargs): + extra_ouput = _self._extra_error_output() + try: + return func(_self, *args, **kwargs) + except (botocore.exceptions.WaiterError) as e: + _self.module.fail_json_aws(e, msg='Failed waiting for {DESC}'.format(DESC=description), **extra_ouput) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + _self.module.fail_json_aws(e, msg='Failed to {DESC}'.format(DESC=description), **extra_ouput) + return handler + return wrapper + + def _normalize_boto3_resource(self, resource, add_tags=False): + r""" + Performs common boto3 resource to Ansible resource conversion. + `resource['Tags']` will by default be converted from the boto3 tag list + format to a simple dictionary. + Parameters: + resource (dict): The boto3 style resource to convert to the normal Ansible + format (snake_case). + add_tags (bool): When `true`, if a resource does not have 'Tags' property + the returned resource will have tags set to an empty + dictionary. + """ + if resource is None: + return None + + tags = resource.get('Tags', None) + if tags: + tags = boto3_tag_list_to_ansible_dict(tags) + elif add_tags or tags is not None: + tags = {} + + normalized_resource = camel_dict_to_snake_dict(resource) + if tags is not None: + normalized_resource['tags'] = tags + return normalized_resource + + def _extra_error_output(self): + # In the event of an error it can be helpful to ouput things like the + # 'name'/'arn' of a resource. + return dict() + + +class BaseResourceManager(Boto3Mixin): + def __init__(self, module): + r""" + Parameters: + module (AnsibleAWSModule): An Ansible module. + """ + self.module = module + self.changed = False + self.original_resource = dict() + self.updated_resource = dict() + self._resource_updates = dict() + self._preupdate_resource = dict() + self._wait = True + self._wait_timeout = None + super(BaseResourceManager, self).__init__() + + def _merge_resource_changes(self, filter_immutable=True, creation=False): + """ + Merges the contents of the 'pre_update' resource and metadata variables + with the pending updates + """ + resource = deepcopy(self._preupdate_resource) + resource.update(self._resource_updates) + + if filter_immutable: + resource = self._filter_immutable_resource_attributes(resource) + + return resource + + def _filter_immutable_resource_attributes(self, resource): + return deepcopy(resource) + + def _do_creation_wait(self, **params): + pass + + def _do_deletion_wait(self, **params): + pass + + def _do_update_wait(self, **params): + pass + + @property + def _waiter_config(self): + params = dict() + if self._wait_timeout: + delay = min(5, self._wait_timeout) + max_attempts = (self._wait_timeout // delay) + config = dict(Delay=delay, MaxAttempts=max_attempts) + params['WaiterConfig'] = config + return params + + def _wait_for_deletion(self): + if not self._wait: + return + params = self._waiter_config + self._do_deletion_wait(**params) + + def _wait_for_creation(self): + if not self._wait: + return + params = self._waiter_config + self._do_creation_wait(**params) + + def _wait_for_update(self): + if not self._wait: + return + params = self._waiter_config + self._do_update_wait(**params) + + def _generate_updated_resource(self): + """ + Merges all pending changes into self.updated_resource + Used during check mode where it's not possible to get and + refresh the resource + """ + return self._merge_resource_changes(filter_immutable=False) + + def _flush_create(self): + changed = True + + if not self.module.check_mode: + changed = self._do_create_resource() + self._wait_for_creation() + self._do_creation_wait() + self.updated_resource = self.get_resource() + else: # (CHECK MODE) + self.updated_resource = self._normalize_resource(self._generate_updated_resource()) + + self._resource_updates = dict() + self.changed = changed + return True + + def _check_updates_pending(self): + if self._resource_updates: + return True + return False + + def _flush_update(self): + if not self._check_updates_pending(): + self.updated_resource = self.original_resource + return False + + if not self.module.check_mode: + self._do_update_resource() + response = self._wait_for_update() + self.updated_resource = self.get_resource() + else: # (CHECK_MODE) + self.updated_resource = self._normalize_resource(self._generate_updated_resource()) + + self._resource_updates = dict() + return True + + def flush_changes(self): + if self.original_resource: + return self._flush_update() + else: + return self._flush_create() + + def _set_resource_value(self, key, value, description=None, immutable=False): + if value is None: + return False + if value == self._preupdate_resource.get(key, None): + return False + if immutable and self.original_resource: + if description is None: + description = key + self.module.fail_json(msg='{0} can not be updated after creation' + .format(description)) + self._resource_updates[key] = value + self.changed = True + return True From 8af9875e64cc3b795f086a2457c3d1fa60f93325 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Thu, 10 Mar 2022 10:09:38 +0100 Subject: [PATCH 2/2] Network Firewall --- meta/runtime.yml | 2 + plugins/module_utils/networkfirewall.py | 727 +++++++ plugins/modules/networkfirewall_rule_group.py | 818 ++++++++ .../networkfirewall_rule_group_info.py | 446 +++++ .../networkfirewall_rule_group/aliases | 3 + .../defaults/main.yml | 2 + .../networkfirewall_rule_group/meta/main.yml | 4 + .../tasks/5-tuple.yml | 579 ++++++ .../tasks/cleanup.yml | 19 + .../tasks/domain_list.yml | 1662 +++++++++++++++++ .../networkfirewall_rule_group/tasks/main.yml | 49 + .../tasks/managed.yml | 10 + .../tasks/minimal.yml | 771 ++++++++ .../tasks/rule_strings.yml | 480 +++++ .../tasks/stateful.yml | 1362 ++++++++++++++ 15 files changed, 6934 insertions(+) create mode 100644 plugins/module_utils/networkfirewall.py create mode 100644 plugins/modules/networkfirewall_rule_group.py create mode 100644 plugins/modules/networkfirewall_rule_group_info.py create mode 100644 tests/integration/targets/networkfirewall_rule_group/aliases create mode 100644 tests/integration/targets/networkfirewall_rule_group/defaults/main.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/meta/main.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/5-tuple.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/cleanup.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/domain_list.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/main.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/managed.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/minimal.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/rule_strings.yml create mode 100644 tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml diff --git a/meta/runtime.yml b/meta/runtime.yml index ab5bb4e0bb8..2d1710c06d6 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -147,6 +147,8 @@ action_groups: - lambda_info - lambda_policy - lightsail + - networkfirewall_rule_group + - networkfirewall_rule_group_info - rds_instance - rds_instance_info - rds_instance_snapshot diff --git a/plugins/module_utils/networkfirewall.py b/plugins/module_utils/networkfirewall.py new file mode 100644 index 00000000000..569f28a42a0 --- /dev/null +++ b/plugins/module_utils/networkfirewall.py @@ -0,0 +1,727 @@ +# 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 + +from copy import deepcopy + +from ansible.module_utils._text import to_text +from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict +from ansible.module_utils.six import string_types + +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry +from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict +from ansible_collections.amazon.aws.plugins.module_utils.tagging import ansible_dict_to_boto3_tag_list +from ansible_collections.amazon.aws.plugins.module_utils.tagging import compare_aws_tags + +from ansible_collections.community.aws.plugins.module_utils.base import Boto3Mixin +from ansible_collections.community.aws.plugins.module_utils.base import BaseResourceManager +from ansible_collections.community.aws.plugins.module_utils.base import BaseWaiterFactory + + +def _merge_set(current, new, purge): + _current = set(current) + _new = set(new) + if purge: + final = _new + else: + final = _new | _current + + return final + + +def _merge_dict(current, new, purge): + _current = deepcopy(current) + if purge: + final = dict() + else: + final = _current + final.update(new) + + return final + + +def _string_list(value): + if isinstance(value, string_types): + value = [value] + elif isinstance(value, bool): + value = [to_text(value).lower()] + elif isinstance(value, list): + value = [to_text(v) for v in value] + else: + value = [to_text(value)] + return value + + +class NetworkFirewallWaiterFactory(BaseWaiterFactory): + def __init__(self, module): + # the AWSRetry wrapper doesn't support the wait functions (there's no + # public call we can cleanly wrap) + client = module.client('network-firewall') + super(NetworkFirewallWaiterFactory, self).__init__(module, client) + + @property + def _waiter_model_data(self): + data = super(NetworkFirewallWaiterFactory, self)._waiter_model_data + nw_data = dict( + rule_group_active=dict( + operation='DescribeRuleGroup', + delay=5, maxAttempts=120, + acceptors=[ + dict(state='success', matcher='path', expected='ACTIVE', argument='RuleGroupResponse.RuleGroupStatus'), + ] + ), + rule_group_deleted=dict( + operation='DescribeRuleGroup', + delay=5, maxAttempts=120, + acceptors=[ + dict(state='retry', matcher='path', expected='DELETING', argument='RuleGroupResponse.RuleGroupStatus'), + dict(state='success', matcher='error', expected='ResourceNotFoundException'), + ] + ), + ) + data.update(nw_data) + return data + + +class NFRuleGroupBoto3Mixin(Boto3Mixin): + def __init__(self, module): + r""" + Parameters: + module (AnsibleAWSModule): An Ansible module. + """ + self.nf_waiter_factory = NetworkFirewallWaiterFactory(module) + super(NFRuleGroupBoto3Mixin, self).__init__(module) + self._update_token = None + + # 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_rule_groups(self, **params): + paginator = self.client.get_paginator('list_rule_groups') + result = paginator.paginate(**params).build_full_result() + return result.get('RuleGroups', None) + + @Boto3Mixin.aws_error_handler('listing all rule groups') + def _list_rule_groups(self, **params): + return self._paginated_list_rule_groups(**params) + + @Boto3Mixin.aws_error_handler('describe rule group') + def _describe_rule_group(self, **params): + try: + result = self.client.describe_rule_group(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 + rule_group = result.get('RuleGroup', None) + metadata = result.get('RuleGroupResponse', None) + return dict(RuleGroup=rule_group, RuleGroupMetadata=metadata) + + @Boto3Mixin.aws_error_handler('create rule group') + def _create_rule_group(self, **params): + result = self.client.create_rule_group(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('RuleGroupResponse', None) + + @Boto3Mixin.aws_error_handler('update rule group') + def _update_rule_group(self, **params): + if self._update_token and 'UpdateToken' not in params: + params['UpdateToken'] = self._update_token + result = self.client.update_rule_group(aws_retry=True, **params) + + update_token = result.get('UpdateToken', None) + if update_token: + self._update_token = update_token + return result.get('RuleGroupResponse', None) + + @Boto3Mixin.aws_error_handler('update rule group') + def _delete_rule_group(self, **params): + try: + result = self.client.delete_rule_group(aws_retry=True, **params) + except is_boto3_error_code('ResourceNotFoundException'): + return None + + return result.get('RuleGroupResponse', None) + + @Boto3Mixin.aws_error_handler('firewall rule to finish deleting') + def _wait_rule_group_deleted(self, **params): + waiter = self.nf_waiter_factory.get_waiter('rule_group_deleted') + waiter.wait(**params) + + @Boto3Mixin.aws_error_handler('firewall rule to become active') + def _wait_rule_group_active(self, **params): + waiter = self.nf_waiter_factory.get_waiter('rule_group_active') + waiter.wait(**params) + + +class BaseNetworkFirewallManager(BaseResourceManager): + def __init__(self, module): + r""" + Parameters: + module (AnsibleAWSModule): An Ansible module. + """ + super().__init__(module) + + self.client = self._create_client() + + # Network Firewall returns a token when you perform create/get/update + # actions + self._preupdate_metadata = dict() + self._metadata_updates = dict() + self._tagging_updates = dict() + + @Boto3Mixin.aws_error_handler('connect to AWS') + def _create_client(self, client_name='network-firewall'): + client = self.module.client(client_name, retry_decorator=AWSRetry.jittered_backoff()) + return client + + def _get_id_params(self): + return dict() + + def _check_updates_pending(self): + if self._metadata_updates: + return True + return super(BaseNetworkFirewallManager, self)._check_updates_pending() + + def _merge_metadata_changes(self, filter_immutable=True): + """ + Merges the contents of the 'pre_update' metadata variables + with the pending updates + """ + metadata = deepcopy(self._preupdate_metadata) + metadata.update(self._metadata_updates) + + if filter_immutable: + metadata = self._filter_immutable_metadata_attributes(metadata) + + return metadata + + def _merge_changes(self, filter_metadata=True): + """ + Merges the contents of the 'pre_update' resource and metadata variables + with the pending updates + """ + metadata = self._merge_metadata_changes(filter_metadata) + resource = self._merge_resource_changes() + return metadata, resource + + def _filter_immutable_metadata_attributes(self, metadata): + """ + Removes information from the metadata which can't be updated. + Returns a *copy* of the metadata dictionary. + """ + return deepcopy(metadata) + + def _flush_create(self): + changed = super(BaseNetworkFirewallManager, self)._flush_create() + self._metadata_updates = dict() + return changed + + def _flush_update(self): + changed = super(BaseNetworkFirewallManager, self)._flush_update() + self._metadata_updates = dict() + return changed + + @BaseResourceManager.aws_error_handler('set tags on resource') + def _add_tags(self, **params): + self.client.tag_resource(aws_retry=True, **params) + return True + + @BaseResourceManager.aws_error_handler('unset tags on resource') + def _remove_tags(self, **params): + self.client.untag_resource(aws_retry=True, **params) + return True + + def _get_preupdate_arn(self): + return self._preupdate_metadata.get('Arn') + + def _set_metadata_value(self, key, value, description=None, immutable=False): + if value is None: + return False + if value == self._preupdate_metadata.get(key, None): + return False + if immutable and self.original_resource: + if description is None: + description = key + self.module.fail_json(msg='{0} can not be updated after creation' + .format(description)) + self._metadata_updates[key] = value + self.changed = True + return True + + def _do_tagging(self): + changed = False + tags_to_add = self._tagging_updates.get('add') + tags_to_remove = self._tagging_updates.get('remove') + + resource_arn = self._get_preupdate_arn() + if not resource_arn: + return False + + if tags_to_add: + changed = True + tags = ansible_dict_to_boto3_tag_list(tags_to_add) + if not self.module.check_mode: + self._add_tags(ResourceArn=resource_arn, Tags=tags) + if tags_to_remove: + changed = True + if not self.module.check_mode: + self._remove_tags(ResourceArn=resource_arn, TagKeys=tags_to_remove) + + return changed + + def set_tags(self, tags, purge_tags): + + if tags is None: + return False + changed = False + + # 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._preupdate_metadata.get('Tags', [])) + + # So that diff works in check mode we need to know the full target state + if purge_tags: + desired_tags = deepcopy(tags) + else: + desired_tags = deepcopy(current_tags) + desired_tags.update(tags) + + tags_to_add, tags_to_remove = compare_aws_tags(current_tags, tags, purge_tags) + + if tags_to_add: + self._tagging_updates['add'] = tags_to_add + changed = True + if tags_to_remove: + self._tagging_updates['remove'] = tags_to_remove + changed = True + + if changed: + # 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 False + + +class NetworkFirewallRuleManager(NFRuleGroupBoto3Mixin, BaseNetworkFirewallManager): + + RULE_TYPES = frozenset(['StatelessRulesAndCustomActions', 'StatefulRules', + 'RulesSourceList', 'RulesString']) + + name = None + rule_type = None + arn = None + + def __init__(self, module, name=None, rule_type=None, arn=None): + super().__init__(module) + # Name parameter is unique (by region) and can not be modified. + self.name = name + self.rule_type = rule_type + self.arn = arn + if self.name or self.arn: + rule_group = deepcopy(self.get_rule_group()) + self.original_resource = rule_group + + def _extra_error_output(self): + output = super(NetworkFirewallRuleManager, self)._extra_error_output() + if self.name: + output['RuleGroupName'] = self.name + if self.rule_type: + output['Type'] = self.rule_type + if self.arn: + output['RuleGroupArn'] = self.arn + return output + + def _filter_immutable_metadata_attributes(self, metadata): + metadata = super(NetworkFirewallRuleManager, self)._filter_immutable_metadata_attributes(metadata) + metadata.pop('RuleGroupArn', None) + metadata.pop('RuleGroupName', None) + metadata.pop('RuleGroupId', None) + metadata.pop('Type', None) + metadata.pop('Capacity', None) + metadata.pop('RuleGroupStatus', None) + metadata.pop('Tags', None) + metadata.pop('ConsumedCapacity', None) + metadata.pop('NumberOfAssociations', None) + return metadata + + def _get_preupdate_arn(self): + return self._preupdate_metadata.get('RuleGroupArn') + + def _get_id_params(self, name=None, rule_type=None, arn=None): + if arn: + return dict(RuleGroupArn=arn) + if self.arn: + return dict(RuleGroupArn=self.arn) + if not name: + name = self.name + if not rule_type: + rule_type = self.rule_type + if rule_type: + rule_type = rule_type.upper() + if not rule_type or not name: + # Users should never see this, but let's cover ourself + self.module.fail_json(msg='Rule identifier parameters missing') + return dict(RuleGroupName=name, Type=rule_type) + + @staticmethod + def _empty_rule_variables(): + return dict(IPSets=dict(), PortSets=dict()) + + @staticmethod + def _transform_rule_variables(variables): + return {k: dict(Definition=_string_list(v)) for (k, v) in variables.items()} + + def delete(self, name=None, rule_type=None, arn=None): + + id_params = self._get_id_params(name=name, rule_type=rule_type, arn=None) + result = self._get_rule_group(**id_params) + + if not result: + return False + + self.updated_resource = dict() + + # Rule Group is already in the process of being deleted (takes time) + rule_status = self._preupdate_metadata.get('RuleGroupStatus', '').upper() + if rule_status == 'DELETING': + self._wait_for_deletion() + return False + + if self.module.check_mode: + self.changed = True + return True + + result = self._delete_rule_group(**id_params) + self._wait_for_deletion() + self.changed |= bool(result) + return bool(result) + + def list(self, scope=None): + params = dict() + if scope: + scope = scope.upper() + params['Scope'] = scope + rule_groups = self._list_rule_groups(**params) + if not rule_groups: + return list() + + return [r.get('Arn', None) for r in rule_groups] + + def _normalize_rule_variable(self, variable): + if variable is None: + return None + return {k: variable.get(k, dict()).get('Definition', []) for k in variable.keys()} + + def _normalize_rule_variables(self, variables): + if variables is None: + return None + result = dict() + ip_sets = self._normalize_rule_variable(variables.get('IPSets', None)) + if ip_sets: + result['ip_sets'] = ip_sets + port_sets = self._normalize_rule_variable(variables.get('PortSets', None)) + if port_sets: + result['port_sets'] = port_sets + return result + + def _normalize_rule_group(self, rule_group): + if rule_group is None: + return None + rule_variables = self._normalize_rule_variables(rule_group.get('RuleVariables', None)) + rule_group = self._normalize_boto3_resource(rule_group) + if rule_variables is not None: + rule_group['rule_variables'] = rule_variables + return rule_group + + def _normalize_rule_group_metadata(self, rule_group_metadata): + return self._normalize_boto3_resource(rule_group_metadata, add_tags=True) + + def _normalize_rule_group_result(self, result): + if result is None: + return None + rule_group = self._normalize_rule_group(result.get('RuleGroup', None)) + rule_group_metadata = self._normalize_rule_group_metadata(result.get('RuleGroupMetadata', None)) + result = camel_dict_to_snake_dict(result) + if rule_group: + result['rule_group'] = rule_group + if rule_group_metadata: + result['rule_group_metadata'] = rule_group_metadata + return result + + def _normalize_resource(self, resource): + return self._normalize_rule_group_result(resource) + + def get_rule_group(self, name=None, rule_type=None, 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: + return None + + rule_group = self._normalize_rule_group_result(result) + return rule_group + + def set_description(self, description): + return self._set_metadata_value('Description', description) + + def set_capacity(self, capacity): + return self._set_metadata_value( + 'Capacity', capacity, + description="Reserved Capacity", immutable=True) + + def _set_rule_option(self, option_name, description, value, immutable=False, default_value=None): + if value is None: + return False + + rule_options = deepcopy(self._preupdate_resource.get('StatefulRuleOptions', dict())) + if value == rule_options.get(option_name, default_value): + return False + if immutable and self.original_resource: + self.module.fail_json(msg='{0} can not be updated after creation' + .format(description)) + + # The first time, we grab StatefulRuleOptions from the preupdate state (above), + # afterwards we grab it from _resource_updates + rule_option_updates = self._resource_updates.get('StatefulRuleOptions', rule_options) + rule_option_updates[option_name] = value + + return self._set_resource_value('StatefulRuleOptions', rule_option_updates) + + def set_rule_order(self, order): + RULE_ORDER_MAP = { + 'default': 'DEFAULT_ACTION_ORDER', + 'strict': 'STRICT_ORDER', + } + value = RULE_ORDER_MAP.get(order) + changed = self._set_rule_option('RuleOrder', 'Rule order', value, True, 'DEFAULT_ACTION_ORDER') + self.changed |= changed + return changed + + def _set_rule_variables(self, set_name, variables, purge): + if variables is None: + return False + + variables = self._transform_rule_variables(variables) + + all_variables = self._preupdate_resource.get('RuleVariables', self._empty_rule_variables()) + current_variables = all_variables.get(set_name, dict()) + + updated_variables = _merge_dict(current_variables, variables, purge) + + if current_variables == updated_variables: + return False + + # The first time we grab RuleVariables from preupdate stata (above), + # afterwards we grab it from _resource_updates + current_updates = deepcopy(self._resource_updates.get('RuleVariables', all_variables)) + current_updates[set_name] = updated_variables + + return self._set_resource_value('RuleVariables', current_updates) + + def set_ip_variables(self, variables, purge): + return self._set_rule_variables('IPSets', variables, purge) + + def set_port_variables(self, variables, purge): + return self._set_rule_variables('PortSets', variables, purge) + + def _set_rule_source(self, rule_type, rules): + if not rules: + return False + conflicting_types = self.RULE_TYPES.difference({rule_type}) + original_source = self._preupdate_resource.get('RulesSource', dict()) + pending_updates = self._resource_updates.get('RulesSource', dict()) + current_keys = set(original_source.keys()) + current_keys.union(pending_updates.keys()) + conflicting_rule_type = conflicting_types.intersection(current_keys) + if conflicting_rule_type: + self.module.fail_json('Unable to add {0} rules, {1} rules already set' + .format(rule_type, " and ".join(conflicting_rule_type))) + + original_rules = original_source.get(rule_type) + if rules == original_rules: + return False + + rules_source = dict() + rules_source[rule_type] = rules + return self._set_resource_value('RulesSource', rules_source) + + def set_rule_string(self, rule): + if rule is None: + return False + if not rule: + self.module.fail_json('Rule string must include at least one rule') + + rule = "\n".join(_string_list(rule)) + return self._set_rule_source('RulesString', rule) + + def set_domain_list(self, options): + if not options: + return False + changed = False + domain_names = options.get('domain_names') + home_net = options.get('source_ips', None) + action = options.get('action') + filter_http = options.get('filter_http', False) + filter_https = options.get('filter_https', False) + + if home_net: + # Seems a little kludgy but the HOME_NET ip variable is how you + # configure which source CIDRs the traffic should be filtered for. + changed |= self.set_ip_variables(dict(HOME_NET=home_net), purge=True) + else: + self.set_ip_variables(dict(), purge=True) + + # Perform some transformations + target_types = [] + if filter_http: + target_types.append('HTTP_HOST') + if filter_https: + target_types.append('TLS_SNI') + + if action == 'allow': + action = 'ALLOWLIST' + else: + action = 'DENYLIST' + + # Finally build the 'rule' + rule = dict( + Targets=domain_names, + TargetTypes=target_types, + GeneratedRulesType=action, + ) + changed |= self._set_rule_source('RulesSourceList', rule) + return changed + + def _format_rule_options(self, options, sid): + formatted_options = [] + opt = dict(Keyword='sid:{0}'.format(sid)) + formatted_options.append(opt) + if options: + for option in sorted(options.keys()): + opt = dict(Keyword=option) + settings = options.get(option) + if settings: + opt['Settings'] = _string_list(settings) + formatted_options.append(opt) + return formatted_options + + def _format_stateful_rule(self, rule): + options = self._format_rule_options( + rule.get('rule_options', dict()), + rule.get('sid'), + ) + formatted_rule = dict( + Action=rule.get('action').upper(), + RuleOptions=options, + Header=dict( + Protocol=rule.get('protocol').upper(), + Source=rule.get('source'), + SourcePort=rule.get('source_port'), + Direction=rule.get('direction').upper(), + Destination=rule.get('destination'), + DestinationPort=rule.get('destination_port'), + ), + ) + return formatted_rule + + def set_rule_list(self, rules): + if rules is None: + return False + if not rules: + self.module.fail_json(msg='Rule list must include at least one rule') + + formatted_rules = [self._format_stateful_rule(r) for r in rules] + return self._set_rule_source('StatefulRules', formatted_rules) + + def _do_create_resource(self): + metadata, resource = self._merge_changes(filter_metadata=False) + params = metadata + params.update(self._get_id_params()) + params['RuleGroup'] = resource + response = self._create_rule_group(**params) + return bool(response) + + def _generate_updated_resource(self): + metadata, resource = self._merge_changes(filter_metadata=False) + metadata.update(self._get_id_params()) + updated_resource = dict( + RuleGroup=resource, + RuleGroupMetadata=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') + + rules_source = self._resource_updates.get('RulesSource') + rule_type = self.RULE_TYPES.intersection(set(rules_source.keys())) + if len(rule_type) != 1: + self.module.fail_json('Exactly one of rule strings, domain list or rule list' + ' must be provided when creating a new rule group', + rule_type=rule_type, keys=self._resource_updates.keys(), + types=self.RULE_TYPES) + + return super(NetworkFirewallRuleManager, self)._flush_create() + + def _do_update_resource(self): + filtered_metadata_updates = self._filter_immutable_metadata_attributes(self._metadata_updates) + filtered_resource_updates = self._resource_updates + + if not filtered_resource_updates and not filtered_metadata_updates: + return False + + metadata, resource = self._merge_changes() + + params = metadata + params.update(self._get_id_params()) + params['RuleGroup'] = resource + + if not self.module.check_mode: + response = self._update_rule_group(**params) + + return True + + def _flush_update(self): + changed = False + changed |= self._do_tagging() + changed |= super(NetworkFirewallRuleManager, self)._flush_update() + return changed + + def _get_rule_group(self, **params): + result = self._describe_rule_group(**params) + if not result: + return None + + rule_group = result.get('RuleGroup', None) + metadata = result.get('RuleGroupMetadata', None) + self._preupdate_resource = deepcopy(rule_group) + self._preupdate_metadata = deepcopy(metadata) + 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): + all_params = self._get_id_params() + all_params.update(params) + return self._wait_rule_group_active(**all_params) + + def _do_deletion_wait(self, **params): + all_params = self._get_id_params() + all_params.update(params) + return self._wait_rule_group_deleted(**all_params) diff --git a/plugins/modules/networkfirewall_rule_group.py b/plugins/modules/networkfirewall_rule_group.py new file mode 100644 index 00000000000..116c5249b3f --- /dev/null +++ b/plugins/modules/networkfirewall_rule_group.py @@ -0,0 +1,818 @@ +#!/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_rule_group +short_description: create, delete and modify AWS Network Firewall rule groups +version_added: 4.0.0 +description: + - A module for managing AWS Network Firewall rule groups. + - U(https://docs.aws.amazon.com/network-firewall/latest/developerguide/index.html) + - Currently only supports C(stateful) firewall groups. +options: + arn: + description: + - The ARN of the Network Firewall rule group. + - Exactly one of I(arn) and I(name) must be provided. + required: false + type: str + name: + description: + - The name of the Network Firewall rule group. + - When I(name) is set, I(rule_type) must also be set. + required: false + type: str + rule_type: + description: + - Indicates whether the rule group is stateless or stateful. + - Stateless rulesets are currently not supported. + - Required if I(name) is set. + required: false + aliases: ['type' ] + choices: ['stateful'] +# choices: ['stateful', 'stateless'] + type: str + state: + description: + - Create or remove the Network Firewall rule group. + required: false + choices: ['present', 'absent'] + default: 'present' + type: str + capacity: + description: + - The maximum operating resources that this rule group can use. + - Once a rule group is created this parameter is immutable. + - See also the AWS documentation about how capacityis calculated + U(https://docs.aws.amazon.com/network-firewall/latest/developerguide/nwfw-rule-group-capacity.html) + - This option is mandatory when creating a new rule group. + type: int + required: false + rule_order: + description: + - Indicates how to manage the order of the rule evaluation for the rule group. + - Once a rule group is created this parameter is immutable. + - Mutually exclusive with I(rule_type=stateless). + - For more information on how rules are evaluated read the AWS documentation + U(https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-rule-evaluation-order.html). + - I(rule_order) requires botocore>=1.23.23. + type: str + required: false + choices: ['default', 'strict'] + aliases: ['stateful_rule_order'] + description: + description: + - A description of the AWS Network Firewall rule group. + type: str + ip_variables: + description: + - A dictionary mapping variable names to a list of IP addresses and address ranges, in CIDR notation. + - For example C({EXAMPLE_HOSTS:["192.0.2.0/24", "203.0.113.42"]}). + - Mutually exclusive with I(domain_list). + type: dict + required: false + aliases: ['ip_set_variables'] + purge_ip_variables: + description: + - Whether to purge variable names not mentioned in the I(ip_variables) + dictionary. + - To remove all IP Set Variables it is necessary to explicitly set I(ip_variables={}) + and I(purge_port_variables=true). + type: bool + default: true + required: false + aliases: ['purge_ip_set_variables'] + port_variables: + description: + - A dictionary mapping variable names to a list of ports. + - For example C({SECURE_PORTS:["22", "443"]}). + type: dict + required: false + aliases: ['port_set_variables'] + purge_port_variables: + description: + - Whether to purge variable names not mentioned in the I(port_variables) + dictionary. + - To remove all Port Set Variables it is necessary to explicitly set I(port_variables={}) + and I(purge_port_variables=true). + type: bool + required: false + default: true + aliases: ['purge_port_set_variables'] + rule_strings: + description: + - Rules in Suricata format. + - If I(rule_strings) is specified, it must include at least one entry. + - For more information read the AWS documentation + U(https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-limitations-caveats.html) + and the Suricata documentation + U(https://suricata.readthedocs.io/en/suricata-6.0.0/rules/intro.html). + - Mutually exclusive with I(rule_type=stateless). + - Mutually exclusive with I(domain_list) and I(rule_list). + - Exactly one of I(rule_strings), I(domain_list) or I(rule_list) must be + specified at creation time. + type: list + elements: str + required: false + domain_list: + description: + - Inspection criteria for a domain list rule group. + - When set overwrites all Domain List settings with the new configuration. + - For more information about domain name based filtering + read the AWS documentation + U(https://docs.aws.amazon.com/network-firewall/latest/developerguide/stateful-rule-groups-domain-names.html). + - Mutually exclusive with I(rule_type=stateless). + - Mutually exclusive with I(ip_variables), I(rule_list) and I(rule_strings). + - Exactly one of I(rule_strings), I(domain_list) or I(rule_list) must be + specified at creation time. + type: dict + required: false + suboptions: + domain_names: + description: + - A list of domain names to look for in the traffic flow. + type: list + elements: str + required: true + filter_http: + description: + - Whether HTTP traffic should be inspected (uses the host header). + type: bool + required: false + default: false + filter_https: + description: + - Whether HTTPS traffic should be inspected (uses the SNI). + type: bool + required: false + default: false + action: + description: + - Action to perform on traffic that matches the rule match settings. + type: str + required: true + choices: ['allow', 'deny'] + source_ips: + description: + - Used to expand the local network definition beyond the CIDR range + of the VPC where you deploy Network Firewall. + type: list + elements: str + required: false + rule_list: + description: + - Inspection criteria to be used for a 5-tuple based rule group. + - When set overwrites all existing 5-tuple rules with the new configuration. + - Mutually exclusive with I(domain_list) and I(rule_strings). + - Mutually exclusive with I(rule_type=stateless). + - Exactly one of I(rule_strings), I(domain_list) or I(rule_list) must be + specified at creation time. + - For more information about valid values see the AWS documentation + U(https://docs.aws.amazon.com/network-firewall/latest/APIReference/API_StatefulRule.html) + and + U(https://docs.aws.amazon.com/network-firewall/latest/APIReference/API_Header.html). + - 'Note: Idempotency when comparing AWS Web UI and Ansiible managed rules can not be guaranteed' + type: list + elements: dict + required: false + aliases: ['stateful_rule_list'] + suboptions: + action: + description: + - What Network Firewall should do with the packets in a traffic flow when the flow matches. + type: str + required: true + choices: ['pass', 'drop', 'alert'] + protocol: + description: + - The protocol to inspect for. To specify all, you can use C(IP), because all traffic on AWS is C(IP). + type: str + required: true + source: + description: + - The source IP address or address range to inspect for, in CIDR notation. + - To match with any address, specify C(ANY). + type: str + required: true + source_port: + description: + - The source port to inspect for. + - To match with any port, specify C(ANY). + type: str + required: true + direction: + description: + - The direction of traffic flow to inspect. + - If set to C(any), the inspection matches both traffic going from the + I(source) to the I(destination) and from the I(destination) to the + I(source). + - If set to C(forward), the inspection only matches traffic going from the + I(source) to the I(destination). + type: str + required: false + default: 'forward' + choices: ['forward', 'any'] + destination: + description: + - The destination IP address or address range to inspect for, in CIDR notation. + - To match with any address, specify C(ANY). + type: str + required: true + destination_port: + description: + - The source port to inspect for. + - To match with any port, specify C(ANY). + type: str + required: true + sid: + description: + - The signature ID of the rule. + - A unique I(sid) must be passed for all rules. + type: int + required: true + rule_options: + description: + - Additional options for the rule. + - 5-tuple based rules are converted by AWS into Suricata rules, for more + complex options requirements where order matters consider using I(rule_strings). + - A dictionary mapping Suricata RuleOptions names to a list of values. + - The examples section contains some examples of using rule_options. + - For more information read the AWS documentation + U(https://docs.aws.amazon.com/network-firewall/latest/developerguide/suricata-limitations-caveats.html) + and the Suricata documentation + U(https://suricata.readthedocs.io/en/suricata-6.0.0/rules/intro.html). + type: dict + required: false + tags: + description: + - A dictionary representing the tags associated with the rule group. + - 'For example C({"Example Tag": "some example value"})' + - Unless I(purge_tags=False) all other tags will be removed from the rule + group. + type: dict + required: false + purge_tags: + description: + - If I(purge_tags=true), existing tags will be purged from the resource to match exactly what is defined by I(tags) parameter. + type: bool + required: false + default: True + +author: Mark Chappell (@tremble) +extends_documentation_fragment: + - amazon.aws.aws + - amazon.aws.ec2 +''' + +EXAMPLES = ''' +# Create a rule group +- name: Create a minimal AWS Network Firewall Rule Group + community.aws.networkfirewall_rule_group: + name: 'MinimalGroup' + type: 'stateful' + capacity: 200 + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + +# Create an example rule group using rule_list +- name: Create 5-tuple Rule List based rule group + community.aws.networkfirewall_rule_group: + name: 'ExampleGroup' + type: 'stateful' + description: 'My description' + rule_order: default + capacity: 100 + rule_list: + - sid: 1 + direction: forward + action: pass + protocol: IP + source: any + source_port: any + destination: any + destination_port: any + +# Create an example rule group using rule_list +- name: Create 5-tuple Rule List based rule group + community.aws.networkfirewall_rule_group: + name: 'ExampleGroup' + type: 'stateful' + description: 'My description' + ip_variables: + SOURCE_IPS: ['203.0.113.0/24', '198.51.100.42'] + DESTINATION_IPS: ['192.0.2.0/24', '198.51.100.48'] + port_variables: + HTTP_PORTS: [80, 8080] + rule_order: default + capacity: 100 + rule_list: + # Allow 'Destination Unreachable' traffic + - sid: 1 + action: pass + protocol: icmp + source: any + source_port: any + destination: any + destination_port: any + rule_options: + itype: 3 + - sid: 2 + action: drop + protocol: tcp + source: "$SOURCE_IPS" + source_port: any + destination: "$DESTINATION_IPS" + destination_port: "$HTTP_PORTS" + rule_options: + urilen: ["20<>40"] + # Where only a keyword is needed, add the keword, but no value + http_uri: + # Settings where Suricata expects raw strings (like the content + # keyword) will need to have the double-quotes explicitly escaped and + # passed because there's no practical way to distinguish between them + # and flags. + content: '"index.php"' + +# Create an example rule group using Suricata rule strings +- name: Create Suricata rule string based rule group + community.aws.networkfirewall_rule_group: + name: 'ExampleSuricata' + type: 'stateful' + description: 'My description' + capacity: 200 + ip_variables: + EXAMPLE_IP: ['203.0.113.0/24', '198.51.100.42'] + ANOTHER_EXAMPLE: ['192.0.2.0/24', '198.51.100.48'] + port_variables: + EXAMPLE_PORT: [443, 22] + rule_strings: + - 'pass tcp any any -> $EXAMPLE_IP $EXAMPLE_PORT (sid:1000001;)' + - 'pass udp any any -> $ANOTHER_EXAMPLE any (sid:1000002;)' + +# Create an example Domain List based rule group +- name: Create Domain List based rule group + community.aws.networkfirewall_rule_group: + name: 'ExampleDomainList' + type: 'stateful' + description: 'My description' + capacity: 100 + domain_list: + domain_names: + - 'example.com' + - '.example.net' + filter_https: True + filter_http: True + action: allow + source_ips: '192.0.2.0/24' + +# Update the description of a rule group +- name: Update the description of a rule group + community.aws.networkfirewall_rule_group: + name: 'MinimalGroup' + type: 'stateful' + description: 'Another description' + +# Update IP Variables for a rule group +- name: Update IP Variables + community.aws.networkfirewall_rule_group: + name: 'ExampleGroup' + type: 'stateful' + ip_variables: + EXAMPLE_IP: ['192.0.2.0/24', '203.0.113.0/24', '198.51.100.42'] + purge_ip_variables: false + +# Delete a rule group +- name: Delete a rule group + community.aws.networkfirewall_rule_group: + name: 'MinimalGroup' + type: 'stateful' + state: absent + +''' + +RETURN = ''' +rule_group: + description: Details of the rules in the rule group + type: dict + returned: success + contains: + rule_variables: + description: Settings that are available for use in the rules in the rule group. + returned: When rule variables are attached to the rule group. + type: complex + contains: + ip_sets: + description: A dictionary mapping variable names to IP addresses in CIDR format. + returned: success + type: dict + example: ['192.0.2.0/24'] + port_sets: + description: A dictionary mapping variable names to ports + returned: success + type: dict + example: ['42'] + stateful_rule_options: + description: Additional options governing how Network Firewall handles stateful rules. + returned: When the rule group is either "rules string" or "rules list" based. + type: dict + contains: + rule_order: + description: The order in which rules will be evaluated. + returned: success + type: str + example: 'DEFAULT_ACTION_ORDER' + rules_source: + description: Inspection criteria used for a 5-tuple based rule group. + returned: success + type: dict + contains: + stateful_rules: + description: A list of dictionaries describing the rules that the rule group is comprised of. + returned: When the rule group is "rules list" based. + type: list + elements: dict + contains: + action: + description: What action to perform when a flow matches the rule criteria. + returned: success + type: str + example: 'PASS' + header: + description: A description of the criteria used for the rule. + returned: success + type: dict + contains: + protocol: + description: The protocol to inspect for. + returned: success + type: str + example: 'IP' + source: + description: The source address or range of addresses to inspect for. + returned: success + type: str + example: '203.0.113.98' + source_port: + description: The source port to inspect for. + returned: success + type: str + example: '42' + destination: + description: The destination address or range of addresses to inspect for. + returned: success + type: str + example: '198.51.100.0/24' + destination_port: + description: The destination port to inspect for. + returned: success + type: str + example: '6666:6667' + direction: + description: The direction of traffic flow to inspect. + returned: success + type: str + example: 'FORWARD' + rule_options: + description: Additional Suricata RuleOptions settings for the rule. + returned: success + type: list + elements: dict + contains: + keyword: + description: The keyword for the setting. + returned: success + type: str + example: 'sid:1' + settings: + description: A list of values passed to the setting. + returned: When values are available + type: list + elements: str + rules_string: + description: A string describing the rules that the rule group is comprised of. + returned: When the rule group is "rules string" based. + type: str + rules_source_list: + description: A description of the criteria for a domain list rule group. + returned: When the rule group is "domain list" based. + type: dict + contains: + targets: + description: A list of domain names to be inspected for. + returned: success + type: list + elements: str + example: ['abc.example.com', '.example.net'] + target_types: + description: The protocols to be inspected by the rule group. + returned: success + type: list + elements: str + example: ['TLS_SNI', 'HTTP_HOST'] + generated_rules_type: + description: Whether the rule group allows or denies access to the domains in the list. + returned: success + type: str + example: 'ALLOWLIST' + stateless_rules_and_custom_actions: + description: A description of the criteria for a stateless rule group. + returned: When the rule group is a stateless rule group. + type: dict + contains: + stateless_rules: + description: A list of stateless rules for use in a stateless rule group. + type: list + elements: dict + contains: + rule_definition: + description: Describes the stateless 5-tuple inspection criteria and actions for the rule. + returned: success + type: dict + contains: + match_attributes: + description: Describes the stateless 5-tuple inspection criteria for the rule. + returned: success + type: dict + contains: + sources: + description: The source IP addresses and address ranges to inspect for. + returned: success + type: list + elements: dict + contains: + address_definition: + description: An IP address or a block of IP addresses in CIDR notation. + returned: success + type: str + example: '192.0.2.3' + destinations: + description: The destination IP addresses and address ranges to inspect for. + returned: success + type: list + elements: dict + contains: + address_definition: + description: An IP address or a block of IP addresses in CIDR notation. + returned: success + type: str + example: '192.0.2.3' + source_ports: + description: The source port ranges to inspect for. + returned: success + type: list + elements: dict + contains: + from_port: + description: The lower limit of the port range. + returned: success + type: int + to_port: + description: The upper limit of the port range. + returned: success + type: int + destination_ports: + description: The destination port ranges to inspect for. + returned: success + type: list + elements: dict + contains: + from_port: + description: The lower limit of the port range. + returned: success + type: int + to_port: + description: The upper limit of the port range. + returned: success + type: int + protocols: + description: The IANA protocol numbers of the protocols to inspect for. + returned: success + type: list + elements: int + example: [6] + tcp_flags: + description: The TCP flags and masks to inspect for. + returned: success + type: list + elements: dict + contains: + flags: + description: Used with masks to define the TCP flags that flows are inspected for. + returned: success + type: list + elements: str + masks: + description: The set of flags considered during inspection. + returned: success + type: list + elements: str + actions: + description: The actions to take when a flow matches the rule. + returned: success + type: list + elements: str + example: ['aws:pass', 'CustomActionName'] + priority: + description: Indicates the order in which to run this rule relative to all of the rules that are defined for a stateless rule group. + returned: success + type: int + custom_actions: + description: A list of individual custom action definitions that are available for use in stateless rules. + type: list + elements: dict + contains: + action_name: + description: The name for the custom action. + returned: success + type: str + action_definition: + description: The custom action associated with the action name. + returned: success + type: dict + contains: + publish_metric_action: + description: The description of an action which publishes to CloudWatch. + returned: When the action publishes to CloudWatch. + type: dict + contains: + dimensions: + description: The value to use in an Amazon CloudWatch custom metric dimension. + returned: success + type: list + elements: dict + contains: + value: + description: The value to use in the custom metric dimension. + returned: success + type: str +rule_group_metadata: + description: Details of the rules in the rule group + type: dict + returned: success + contains: + capacity: + description: The maximum operating resources that this rule group can use. + type: int + returned: success + consumed_capacity: + description: The number of capacity units currently consumed by the rule group rules. + type: int + returned: success + description: + description: A description of the rule group. + type: str + returned: success + number_of_associations: + description: The number of firewall policies that use this rule group. + type: int + returned: success + rule_group_arn: + description: The ARN for the rule group + type: int + returned: success + example: 'arn:aws:network-firewall:us-east-1:123456789012:stateful-rulegroup/ExampleGroup' + rule_group_id: + description: A unique identifier for the rule group. + type: int + returned: success + example: '12345678-abcd-1234-abcd-123456789abc' + rule_group_name: + description: The name of the rule group. + type: str + returned: success + rule_group_status: + description: The current status of a rule group. + type: str + returned: success + example: 'DELETING' + tags: + description: A dictionary representing the tags associated with the rule group. + type: dict + returned: success + type: + description: Whether the rule group is stateless or stateful. + type: str + returned: success + example: 'STATEFUL' +''' + + +from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule +from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallRuleManager + + +def main(): + + domain_list_spec = dict( + domain_names=dict(type='list', elements='str', required=True), + filter_http=dict(type='bool', required=False, default=False), + filter_https=dict(type='bool', required=False, default=False), + action=dict(type='str', required=True, choices=['allow', 'deny']), + source_ips=dict(type='list', elements='str', required=False), + ) + + rule_list_spec = dict( + action=dict(type='str', required=True, choices=['pass', 'drop', 'alert']), + protocol=dict(type='str', required=True), + source=dict(type='str', required=True), + source_port=dict(type='str', required=True), + direction=dict(type='str', required=False, default='forward', choices=['forward', 'any']), + destination=dict(type='str', required=True), + destination_port=dict(type='str', required=True), + sid=dict(type='int', required=True), + rule_options=dict(type='dict', required=False), + ) + + argument_spec = dict( + arn=dict(type='str', required=False), + name=dict(type='str', required=False), + rule_type=dict(type='str', required=False, aliases=['type'], choices=['stateful']), + # rule_type=dict(type='str', required=True, aliases=['type'], choices=['stateless', 'stateful']), + state=dict(type='str', required=False, choices=['present', 'absent'], default='present'), + capacity=dict(type='int', required=False), + rule_order=dict(type='str', required=False, aliases=['stateful_rule_order'], choices=['default', 'strict']), + description=dict(type='str', required=False), + ip_variables=dict(type='dict', required=False, aliases=['ip_set_variables']), + purge_ip_variables=dict(type='bool', required=False, aliases=['purge_ip_set_variables'], default=True), + port_variables=dict(type='dict', required=False, aliases=['port_set_variables']), + purge_port_variables=dict(type='bool', required=False, aliases=['purge_port_set_variables'], default=True), + rule_strings=dict(type='list', elements='str', required=False), + domain_list=dict(type='dict', options=domain_list_spec, required=False), + rule_list=dict(type='list', elements='dict', aliases=['stateful_rule_list'], options=rule_list_spec, required=False), + tags=dict(type='dict', required=False), + purge_tags=dict(type='bool', required=False, default=True), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + mutually_exclusive=[ + ('name', 'arn'), + ('rule_strings', 'domain_list', 'rule_list'), + ('domain_list', 'ip_variables'), + ], + required_together=[ + ('name', 'rule_type'), + ], + required_one_of=[ + ('name', 'arn'), + ], + ) + + module.require_botocore_at_least('1.19.20') + + state = module.params.get('state') + name = module.params.get('name') + arn = module.params.get('arn') + rule_type = module.params.get('rule_type') + + if rule_type == 'stateless': + if module.params.get('rule_order'): + module.fail_json('rule_order can not be set for stateless rule groups') + if module.params.get('rule_strings'): + module.fail_json('rule_strings can only be used for stateful rule groups') + if module.params.get('rule_list'): + module.fail_json('rule_list can only be used for stateful rule groups') + if module.params.get('domain_list'): + module.fail_json('domain_list can only be used for stateful rule groups') + + if module.params.get('rule_order'): + module.require_botocore_at_least('1.23.23', reason='to set the rule order') + + manager = NetworkFirewallRuleManager(module, arn=arn, name=name, rule_type=rule_type) + + if state == 'absent': + manager.delete() + else: + manager.set_description(module.params.get('description')) + manager.set_capacity(module.params.get('capacity')) + manager.set_rule_order(module.params.get('rule_order')) + manager.set_ip_variables(module.params.get('ip_variables'), module.params.get('purge_ip_variables')) + manager.set_port_variables(module.params.get('port_variables'), module.params.get('purge_port_variables')) + manager.set_rule_string(module.params.get('rule_strings')) + manager.set_domain_list(module.params.get('domain_list')) + manager.set_rule_list(module.params.get('rule_list')) + manager.set_tags(module.params.get('tags'), module.params.get('purge_tags')) + + manager.flush_changes() + + results = dict( + changed=manager.changed, + rule_group=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_rule_group_info.py b/plugins/modules/networkfirewall_rule_group_info.py new file mode 100644 index 00000000000..ae9f43bd28b --- /dev/null +++ b/plugins/modules/networkfirewall_rule_group_info.py @@ -0,0 +1,446 @@ +#!/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_rule_group_info +short_description: describe AWS Network Firewall rule groups +version_added: 4.0.0 +description: + - A module for describing AWS Network Firewall rule groups. +options: + arn: + description: + - The ARN of the Network Firewall rule group. + - At time of writing AWS does not support describing Managed Rules. + required: false + type: str + name: + description: + - The name of the Network Firewall rule group. + required: false + type: str + rule_type: + description: + - Indicates whether the rule group is stateless or stateful. + - Required if I(name) is provided. + required: false + aliases: ['type' ] + choices: ['stateful', 'stateless'] + type: str + scope: + description: + - The scope of the request. + - When I(scope='account') returns a description of all rule groups in the account. + - When I(scope='managed') returns a list of available managed rule group arns. + - By default searches only at the account scope. + - I(scope='managed') requires botocore>=1.23.23. + required: false + choices: ['managed', 'account'] + type: str + +author: Mark Chappell (@tremble) +extends_documentation_fragment: + - amazon.aws.aws + - amazon.aws.ec2 +''' + +EXAMPLES = ''' + +# Describe all Rule Groups in an account (excludes managed groups) +- community.aws.networkfirewall_rule_group_info: {} + +# List the available Managed Rule groups (AWS doesn't support describing the +# groups) +- community.aws.networkfirewall_rule_group_info: + scope: managed + +# Describe a Rule Group by ARN +- community.aws.networkfirewall_rule_group_info: + arn: arn:aws:network-firewall:us-east-1:123456789012:stateful-rulegroup/ExampleRuleGroup + +# Describe a Rule Group by name +- community.aws.networkfirewall_rule_group_info: + name: ExampleRuleGroup + type: stateful + +''' + +RETURN = ''' +rule_list: + description: A list of ARNs of the matching rule groups. + type: list + elements: str + returned: When a rule name isn't specified + +rule_groups: + description: The details of the rule groups + returned: success + type: list + elements: dict + contains: + rule_group: + description: Details of the rules in the rule group + type: dict + returned: success + contains: + rule_variables: + description: Settings that are available for use in the rules in the rule group. + returned: When rule variables are attached to the rule group. + type: complex + contains: + ip_sets: + description: A dictionary mapping variable names to IP addresses in CIDR format. + returned: success + type: dict + example: ['192.0.2.0/24'] + port_sets: + description: A dictionary mapping variable names to ports + returned: success + type: dict + example: ['42'] + stateful_rule_options: + description: Additional options governing how Network Firewall handles stateful rules. + returned: When the rule group is either "rules string" or "rules list" based. + type: dict + contains: + rule_order: + description: The order in which rules will be evaluated. + returned: success + type: str + example: 'DEFAULT_ACTION_ORDER' + rules_source: + description: DEFAULT_ACTION_ORDER + returned: success + type: dict + contains: + stateful_rules: + description: A list of dictionaries describing the rules that the rule group is comprised of. + returned: When the rule group is "rules list" based. + type: list + elements: dict + contains: + action: + description: What action to perform when a flow matches the rule criteria. + returned: success + type: str + example: 'PASS' + header: + description: A description of the criteria used for the rule. + returned: success + type: dict + contains: + protocol: + description: The protocol to inspect for. + returned: success + type: str + example: 'IP' + source: + description: The source address or range of addresses to inspect for. + returned: success + type: str + example: '203.0.113.98' + source_port: + description: The source port to inspect for. + returned: success + type: str + example: '42' + destination: + description: The destination address or range of addresses to inspect for. + returned: success + type: str + example: '198.51.100.0/24' + destination_port: + description: The destination port to inspect for. + returned: success + type: str + example: '6666:6667' + direction: + description: The direction of traffic flow to inspect. + returned: success + type: str + example: 'FORWARD' + rule_options: + description: Additional Suricata RuleOptions settings for the rule. + returned: success + type: list + elements: dict + contains: + keyword: + description: The keyword for the setting. + returned: success + type: str + example: 'sid:1' + settings: + description: A list of values passed to the setting. + returned: When values are available + type: list + elements: str + rules_string: + description: A string describing the rules that the rule group is comprised of. + returned: When the rule group is "rules string" based. + type: str + rules_source_list: + description: A description of the criteria for a domain list rule group. + returned: When the rule group is "domain list" based. + type: dict + contains: + targets: + description: A list of domain names to be inspected for. + returned: success + type: list + elements: str + example: ['abc.example.com', '.example.net'] + target_types: + description: The protocols to be inspected by the rule group. + returned: success + type: list + elements: str + example: ['TLS_SNI', 'HTTP_HOST'] + generated_rules_type: + description: Whether the rule group allows or denies access to the domains in the list. + returned: success + type: str + example: 'ALLOWLIST' + stateless_rules_and_custom_actions: + description: A description of the criteria for a stateless rule group. + returned: When the rule group is a stateless rule group. + type: dict + contains: + stateless_rules: + description: A list of stateless rules for use in a stateless rule group. + type: list + elements: dict + contains: + rule_definition: + description: Describes the stateless 5-tuple inspection criteria and actions for the rule. + returned: success + type: dict + contains: + match_attributes: + description: Describes the stateless 5-tuple inspection criteria for the rule. + returned: success + type: dict + contains: + sources: + description: The source IP addresses and address ranges to inspect for. + returned: success + type: list + elements: dict + contains: + address_definition: + description: An IP address or a block of IP addresses in CIDR notation. + returned: success + type: str + example: '192.0.2.3' + destinations: + description: The destination IP addresses and address ranges to inspect for. + returned: success + type: list + elements: dict + contains: + address_definition: + description: An IP address or a block of IP addresses in CIDR notation. + returned: success + type: str + example: '192.0.2.3' + source_ports: + description: The source port ranges to inspect for. + returned: success + type: list + elements: dict + contains: + from_port: + description: The lower limit of the port range. + returned: success + type: int + to_port: + description: The upper limit of the port range. + returned: success + type: int + destination_ports: + description: The destination port ranges to inspect for. + returned: success + type: list + elements: dict + contains: + from_port: + description: The lower limit of the port range. + returned: success + type: int + to_port: + description: The upper limit of the port range. + returned: success + type: int + protocols: + description: The IANA protocol numbers of the protocols to inspect for. + returned: success + type: list + elements: int + example: [6] + tcp_flags: + description: The TCP flags and masks to inspect for. + returned: success + type: list + elements: dict + contains: + flags: + description: Used with masks to define the TCP flags that flows are inspected for. + returned: success + type: list + elements: str + masks: + description: The set of flags considered during inspection. + returned: success + type: list + elements: str + actions: + description: The actions to take when a flow matches the rule. + returned: success + type: list + elements: str + example: ['aws:pass', 'CustomActionName'] + priority: + description: Indicates the order in which to run this rule relative to all of the rules that are defined for a stateless rule group. + returned: success + type: int + custom_actions: + description: A list of individual custom action definitions that are available for use in stateless rules. + type: list + elements: dict + contains: + action_name: + description: The name for the custom action. + returned: success + type: str + action_definition: + description: The custom action associated with the action name. + returned: success + type: dict + contains: + publish_metric_action: + description: The description of an action which publishes to CloudWatch. + returned: When the action publishes to CloudWatch. + type: dict + contains: + dimensions: + description: The value to use in an Amazon CloudWatch custom metric dimension. + returned: success + type: list + elements: dict + contains: + value: + description: The value to use in the custom metric dimension. + returned: success + type: str + rule_group_metadata: + description: Details of the rules in the rule group + type: dict + returned: success + contains: + capacity: + description: The maximum operating resources that this rule group can use. + type: int + returned: success + consumed_capacity: + description: The number of capacity units currently consumed by the rule group rules. + type: int + returned: success + description: + description: A description of the rule group. + type: str + returned: success + number_of_associations: + description: The number of firewall policies that use this rule group. + type: int + returned: success + rule_group_arn: + description: The ARN for the rule group + type: int + returned: success + example: 'arn:aws:network-firewall:us-east-1:123456789012:stateful-rulegroup/ExampleGroup' + rule_group_id: + description: A unique identifier for the rule group. + type: int + returned: success + example: '12345678-abcd-1234-abcd-123456789abc' + rule_group_name: + description: The name of the rule group. + type: str + returned: success + rule_group_status: + description: The current status of a rule group. + type: str + returned: success + example: 'DELETING' + tags: + description: A dcitionary representing the tags associated with the rule group. + type: dict + returned: success + type: + description: Whether the rule group is stateless or stateful. + type: str + returned: success + example: 'STATEFUL' +''' + + +from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule +from ansible_collections.community.aws.plugins.module_utils.networkfirewall import NetworkFirewallRuleManager + + +def main(): + + argument_spec = dict( + name=dict(type='str', required=False), + rule_type=dict(type='str', required=False, aliases=['type'], choices=['stateless', 'stateful']), + arn=dict(type='str', required=False), + scope=dict(type='str', required=False, choices=['managed', 'account']), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + mutually_exclusive=[ + ('arn', 'name',), + ('arn', 'rule_type'), + ], + required_together=[ + ('name', 'rule_type'), + ] + ) + + module.require_botocore_at_least('1.19.20') + + arn = module.params.get('arn') + name = module.params.get('name') + rule_type = module.params.get('rule_type') + scope = module.params.get('scope') + + if module.params.get('scope') == 'managed': + module.require_botocore_at_least('1.23.23', reason='to list managed rules') + + manager = NetworkFirewallRuleManager(module, name=name, rule_type=rule_type) + + results = dict(changed=False) + + if name or arn: + rule = manager.get_rule_group(name=name, rule_type=rule_type, arn=arn) + rules = [rule] + results['rule_groups'] = rules + else: + rule_list = manager.list(scope=scope) + results['rule_list'] = rule_list + if scope != 'managed': + rules = [manager.get_rule_group(arn=r) for r in rule_list] + results['rule_groups'] = rules + + module.exit_json(**results) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/networkfirewall_rule_group/aliases b/tests/integration/targets/networkfirewall_rule_group/aliases new file mode 100644 index 00000000000..dd36cb2db92 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/aliases @@ -0,0 +1,3 @@ +cloud/aws + +networkfirewall_rule_group_info diff --git a/tests/integration/targets/networkfirewall_rule_group/defaults/main.yml b/tests/integration/targets/networkfirewall_rule_group/defaults/main.yml new file mode 100644 index 00000000000..fa49aa20c20 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/defaults/main.yml @@ -0,0 +1,2 @@ +--- +group_name_prefix: 'AnsibleTest-{{ tiny_prefix }}' diff --git a/tests/integration/targets/networkfirewall_rule_group/meta/main.yml b/tests/integration/targets/networkfirewall_rule_group/meta/main.yml new file mode 100644 index 00000000000..f09ab4af198 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/meta/main.yml @@ -0,0 +1,4 @@ +dependencies: + - role: setup_botocore_pip + vars: + botocore_version: "1.23.23" diff --git a/tests/integration/targets/networkfirewall_rule_group/tasks/5-tuple.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/5-tuple.yml new file mode 100644 index 00000000000..a74c8886f24 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/5-tuple.yml @@ -0,0 +1,579 @@ +--- +# +# Basic manipulation of 5-Tuple based rule groups +# - Creation +# - Deletion +# - Updating Rules +- vars: + tuple_group_name: '{{ group_name_prefix }}-5TupleGroup' + rule_one: + source: '192.0.2.74' + destination: '198.51.100.0/24' + source_port: 'any' + destination_port: 22 + action: 'pass' + protocol: 'TCP' + sid: '10001' + rule_two: + action: 'pass' + direction: 'any' + source: 'any' + destination: 'any' + source_port: 'any' + destination_port: 'any' + protocol: 'icmp' + sid: '10002' + rule_options: + itype: [3] + rule_three: + action: 'drop' + direction: 'forward' + source: '$EXAMPLE_SOURCE' + destination: '$EXAMPLE_DEST' + source_port: 'any' + destination_port: '$HTTPS_PORT' + protocol: 'http' + sid: '10003' + rule_options: + # Raw strings need the extra quotes + content: '"index.php"' + # Empty == no 'setting' (is valid) + http_uri: + ip_variables: + EXAMPLE_SOURCE: '203.0.113.0/24' + EXAMPLE_DEST: '192.0.2.117' + port_variables: + HTTPS_PORT: '8443' + # Formatted version of the options + rule_one_options: + - keyword: 'sid:10001' + rule_two_options: + - keyword: 'sid:10002' + - keyword: 'itype' + settings: ['3'] + rule_three_options: + - keyword: 'sid:10003' + - keyword: 'content' + # Ẽxtra quotes are deliberate + settings: ['"index.php"'] + - keyword: 'http_uri' + block: + ################################################################### + # Creation + + # Bare minimum rule, wouldn't actually check anything since neither HTTP not + # HTTPS traffic is being inspected + - name: '(CHECK) Create a 5-Tuple Rule Group' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + capacity: 50 + rule_list: + - '{{ rule_one }}' + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - '"rules_source" in tuple_group.rule_group.rule_group' + - '"stateful_rules" in tuple_group.rule_group.rule_group.rules_source' + - tuple_group.rule_group.rule_group.rules_source.stateful_rules | length == 1 + - '"action" in first_rule' + - '"header" in first_rule' + - '"rule_options" in first_rule' + - first_rule.action == 'PASS' + - '"destination" in first_rule.header' + - '"destination_port" in first_rule.header' + - '"direction" in first_rule.header' + - '"protocol" in first_rule.header' + - '"source" in first_rule.header' + - '"source_port" in first_rule.header' + - first_rule.header.destination == '198.51.100.0/24' + - first_rule.header.destination_port == '22' + - first_rule.header.source == '192.0.2.74' + - first_rule.header.source_port == 'any' + - first_rule.header.protocol == 'TCP' + - first_rule.header.direction == 'FORWARD' + - first_rule.rule_options == rule_one_options + vars: + first_rule: '{{ tuple_group.rule_group.rule_group.rules_source.stateful_rules[0] }}' + + - name: 'Create a 5-Tuple Rule Group' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + capacity: 50 + rule_list: + - '{{ rule_one }}' + register: tuple_group + + - assert: + that: + - tuple_group is changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_id" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn.startswith(account_arn) + - tuple_group.rule_group.rule_group_metadata.rule_group_arn.endswith(tuple_group_name) + - '"rules_source" in tuple_group.rule_group.rule_group' + + - name: Save RuleGroup ID/ARN for later + set_fact: + minimal_rule_group_id: '{{ tuple_group.rule_group.rule_group_metadata.rule_group_id }}' + minimal_rule_group_arn: '{{ tuple_group.rule_group.rule_group_metadata.rule_group_arn }}' + + - name: '(CHECK) Create a 5-Tuple Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + capacity: 50 + rule_list: + - '{{ rule_one }}' + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is not changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + - name: 'Create a 5-Tuple Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + capacity: 50 + rule_list: + - '{{ rule_one }}' + register: tuple_group + + - assert: + that: + - tuple_group is not changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + ################################################################### + # Add some extra variables, properly tested in stateful.yml + + - name: 'Set IP and Port variables' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variables }}' + port_variables: '{{ port_variables }}' + register: port_variables + + - assert: + that: + - port_variables is changed + + ################################################################### + # Update + + - name: '(CHECK) Update a 5-Tuple Rule Group with new rules' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + - '"stateful_rules" in tuple_group.rule_group.rule_group.rules_source' + - tuple_group.rule_group.rule_group.rules_source.stateful_rules | length == 3 + - '"action" in first_rule' + - '"header" in first_rule' + - '"rule_options" in first_rule' + - first_rule.action == 'PASS' + - '"destination" in first_rule.header' + - '"destination_port" in first_rule.header' + - '"direction" in first_rule.header' + - '"protocol" in first_rule.header' + - '"source" in first_rule.header' + - '"source_port" in first_rule.header' + - first_rule.header.destination == '198.51.100.0/24' + - first_rule.header.destination_port == '22' + - first_rule.header.source == '192.0.2.74' + - first_rule.header.source_port == 'any' + - first_rule.header.protocol == 'TCP' + - first_rule.header.direction == 'FORWARD' + - first_rule.rule_options == rule_one_options + - '"action" in second_rule' + - '"header" in second_rule' + - '"rule_options" in second_rule' + - second_rule.action == 'PASS' + - '"destination" in second_rule.header' + - '"destination_port" in second_rule.header' + - '"direction" in second_rule.header' + - '"protocol" in second_rule.header' + - '"source" in second_rule.header' + - '"source_port" in second_rule.header' + - second_rule.header.destination == 'any' + - second_rule.header.destination_port == 'any' + - second_rule.header.source == 'any' + - second_rule.header.source_port == 'any' + - second_rule.header.protocol == 'ICMP' + - second_rule.header.direction == 'ANY' + - second_rule.rule_options == rule_two_options + - '"action" in third_rule' + - '"header" in third_rule' + - '"rule_options" in third_rule' + - third_rule.action == 'DROP' + - '"destination" in third_rule.header' + - '"destination_port" in third_rule.header' + - '"direction" in third_rule.header' + - '"protocol" in third_rule.header' + - '"source" in third_rule.header' + - '"source_port" in third_rule.header' + - third_rule.header.destination == '$EXAMPLE_DEST' + - third_rule.header.destination_port == '$HTTPS_PORT' + - third_rule.header.source == '$EXAMPLE_SOURCE' + - third_rule.header.source_port == 'any' + - third_rule.header.protocol == 'HTTP' + - third_rule.header.direction == 'FORWARD' + - third_rule.rule_options == rule_three_options + vars: + first_rule: '{{ tuple_group.rule_group.rule_group.rules_source.stateful_rules[0] }}' + second_rule: '{{ tuple_group.rule_group.rule_group.rules_source.stateful_rules[1] }}' + third_rule: '{{ tuple_group.rule_group.rule_group.rules_source.stateful_rules[2] }}' + + - name: 'Update a 5-Tuple Rule Group with new rules' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + + - assert: + that: + - tuple_group is changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_id" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + - name: '(CHECK) Update a 5-Tuple Rule Group with new rules (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is not changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + - name: 'Update a 5-Tuple Rule Group with new rules (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + + - assert: + that: + - tuple_group is not changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + ##### + + - name: '(CHECK) Update a 5-Tuple Rule Group by removing first rule' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + - '"stateful_rules" in tuple_group.rule_group.rule_group.rules_source' + - tuple_group.rule_group.rule_group.rules_source.stateful_rules | length == 2 + - '"action" in first_rule' + - '"header" in first_rule' + - '"rule_options" in first_rule' + - first_rule.action == 'PASS' + - '"destination" in first_rule.header' + - '"destination_port" in first_rule.header' + - '"direction" in first_rule.header' + - '"protocol" in first_rule.header' + - '"source" in first_rule.header' + - '"source_port" in first_rule.header' + - first_rule.header.destination == 'any' + - first_rule.header.destination_port == 'any' + - first_rule.header.source == 'any' + - first_rule.header.source_port == 'any' + - first_rule.header.protocol == 'ICMP' + - first_rule.header.direction == 'ANY' + - first_rule.rule_options == rule_two_options + - '"action" in second_rule' + - '"header" in second_rule' + - '"rule_options" in second_rule' + - second_rule.action == 'DROP' + - '"destination" in second_rule.header' + - '"destination_port" in second_rule.header' + - '"direction" in second_rule.header' + - '"protocol" in second_rule.header' + - '"source" in second_rule.header' + - '"source_port" in second_rule.header' + - second_rule.header.destination == '$EXAMPLE_DEST' + - second_rule.header.destination_port == '$HTTPS_PORT' + - second_rule.header.source == '$EXAMPLE_SOURCE' + - second_rule.header.source_port == 'any' + - second_rule.header.protocol == 'HTTP' + - second_rule.header.direction == 'FORWARD' + - second_rule.rule_options == rule_three_options + vars: + first_rule: '{{ tuple_group.rule_group.rule_group.rules_source.stateful_rules[0] }}' + second_rule: '{{ tuple_group.rule_group.rule_group.rules_source.stateful_rules[1] }}' + + - name: 'Update a 5-Tuple Rule Group by removing first rule' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + + - assert: + that: + - tuple_group is changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_id" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + - name: '(CHECK) Update a 5-Tuple Rule Group by removing first rule (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is not changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + - name: 'Update a 5-Tuple Rule Group by removing first rule (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + rule_list: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: tuple_group + + - assert: + that: + - tuple_group is not changed + - '"rule_group" in tuple_group' + - '"rule_group" in tuple_group.rule_group' + - '"rule_group_metadata" in tuple_group.rule_group' + - '"capacity" in tuple_group.rule_group.rule_group_metadata' + - '"rule_group_name" in tuple_group.rule_group.rule_group_metadata' + - '"type" in tuple_group.rule_group.rule_group_metadata' + - tuple_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - tuple_group.rule_group.rule_group_metadata.capacity == 50 + - tuple_group.rule_group.rule_group_metadata.rule_group_name == tuple_group_name + - tuple_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - tuple_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in tuple_group.rule_group.rule_group' + + ################################################################### + # Deletion + + - name: '(CHECK) Delete Domain List rule group' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + state: absent + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is changed + + - name: 'Delete Domain List rule group' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + state: absent + register: tuple_group + + - assert: + that: + - tuple_group is changed + + # The Rule Group may still exist in a "DELETING" state, we should still + # return not changed + - name: 'Delete Domain List rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + state: absent + register: tuple_group + check_mode: true + + - assert: + that: + - tuple_group is not changed + + - name: '(CHECK) Delete Domain List rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + state: absent + register: tuple_group + + - assert: + that: + - tuple_group is not changed + + always: + - name: '(always) Delete Domain List rule group' + networkfirewall_rule_group: + name: '{{ tuple_group_name }}' + type: 'stateful' + state: absent + ignore_errors: true diff --git a/tests/integration/targets/networkfirewall_rule_group/tasks/cleanup.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/cleanup.yml new file mode 100644 index 00000000000..7bcd3fab081 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/cleanup.yml @@ -0,0 +1,19 @@ +--- +- 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 + +# These should just be "no-ops" caused by the deletion being in-progress. +# Waiters are not supported at this time. +- 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_rule_group/tasks/domain_list.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/domain_list.yml new file mode 100644 index 00000000000..e4f797f6618 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/domain_list.yml @@ -0,0 +1,1662 @@ +--- +# +# Basic manipulation of Domain List based rule groups +# - Creation +# - Deletion +# - Updating Rules +# -- Domain list +# -- Inspected Protocols +# -- Action +# -- Source IPs +- vars: + domains_group_name: '{{ group_name_prefix }}-DomainListGroup' + block: + ################################################################### + # Creation + + # Bare minimum rule, wouldn't actually check anything since neither HTTP not + # HTTPS traffic is being inspected + - name: '(CHECK) Create a Domain List Rule Group' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + capacity: 50 + domain_list: + domain_names: 'example.com' + action: allow + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com'] + + - name: 'Create a Domain List Rule Group' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + capacity: 50 + domain_list: + domain_names: 'example.com' + action: allow + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn.startswith(account_arn) + - domain_group.rule_group.rule_group_metadata.rule_group_arn.endswith(domains_group_name) + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com'] + + - name: Save RuleGroup ID/ARN for later + set_fact: + minimal_rule_group_id: '{{ domain_group.rule_group.rule_group_metadata.rule_group_id }}' + minimal_rule_group_arn: '{{ domain_group.rule_group.rule_group_metadata.rule_group_arn }}' + + - name: '(CHECK) Create a Domain List Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + capacity: 50 + domain_list: + domain_names: 'example.com' + action: allow + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com'] + + - name: 'Create a Domain List Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + capacity: 50 + domain_list: + domain_names: 'example.com' + action: allow + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com'] + + ##### + + - name: '(CHECK) Create a Domain List Rule Group - List instead of string (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + capacity: 50 + domain_list: + domain_names: + - 'example.com' + action: allow + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com'] + + - name: 'Create a Domain List Rule Group List - instead of string (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + capacity: 50 + domain_list: + domain_names: + - 'example.com' + action: allow + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com'] + + + ################################################################### + # Update + + - name: '(CHECK) Update a Domain List Rule Group with new domains' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: allow + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with new domains' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: allow + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: '(CHECK) Update a Domain List Rule Group with new domains (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: allow + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with new domains (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: allow + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'ALLOWLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with new action' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with new action' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: '(CHECK) Update a Domain List Rule Group with new action (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with new action (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with HTTP only' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with HTTP only' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: '(CHECK) Update a Domain List Rule Group with HTTP only (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with HTTP only (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with HTTPS only' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_https: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with HTTPS only' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_https: true + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: '(CHECK) Update a Domain List Rule Group with HTTPS only (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_https: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with HTTPS only (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_https: true + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with HTTP and HTTPS' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with HTTP and HTTPS' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: '(CHECK) Update a Domain List Rule Group with HTTP and HTTPS (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with HTTP and HTTPS (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with Source IP list' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: '203.0.113.0/24' + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24'] + + - name: 'Update a Domain List Rule Group with Source IP list' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: '203.0.113.0/24' + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24'] + + - name: '(CHECK) Update a Domain List Rule Group with Source IP list (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: '203.0.113.0/24' + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24'] + + - name: 'Update a Domain List Rule Group with Source IP list (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: '203.0.113.0/24' + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24'] + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with updated Source IP list' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: + - '203.0.113.0/24' + - '198.51.100.248' + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24', '198.51.100.248'] + + - name: 'Update a Domain List Rule Group with updated Source IP list' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: + - '203.0.113.0/24' + - '198.51.100.248' + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24', '198.51.100.248'] + + - name: '(CHECK) Update a Domain List Rule Group with updated Source IP list (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: + - '203.0.113.0/24' + - '198.51.100.248' + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24', '198.51.100.248'] + + - name: 'Update a Domain List Rule Group with updated Source IP list (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + source_ips: + - '203.0.113.0/24' + - '198.51.100.248' + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - '"ip_sets" in domain_group.rule_group.rule_group.rule_variables' + - '"HOME_NET" in domain_group.rule_group.rule_group.rule_variables.ip_sets' + - domain_group.rule_group.rule_group.rule_variables.ip_sets['HOME_NET'] == ['203.0.113.0/24', '198.51.100.248'] + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with removed Source IP list' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - domain_group.rule_group.rule_group.rule_variables == {} + + - name: 'Update a Domain List Rule Group with removed Source IP list' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - domain_group.rule_group.rule_group.rule_variables == {} + + - name: '(CHECK) Update a Domain List Rule Group with removed Source IP list (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - domain_group.rule_group.rule_group.rule_variables == {} + + - name: 'Update a Domain List Rule Group with removed Source IP list (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + filter_http: true + filter_https: true + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == ['HTTP_HOST', 'TLS_SNI'] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + - '"rule_variables" in domain_group.rule_group.rule_group' + - domain_group.rule_group.rule_group.rule_variables == {} + + ##### + + - name: '(CHECK) Update a Domain List Rule Group with no protocols' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with no protocols' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + + - assert: + that: + - domain_group is changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_id" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: '(CHECK) Update a Domain List Rule Group with no protocols (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + - name: 'Update a Domain List Rule Group with no protocols (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + domain_list: + domain_names: + - 'example.com' + - '.example.net' + action: deny + register: domain_group + + - assert: + that: + - domain_group is not changed + - '"rule_group" in domain_group' + - '"rule_group" in domain_group.rule_group' + - '"rule_group_metadata" in domain_group.rule_group' + - '"capacity" in domain_group.rule_group.rule_group_metadata' + - '"rule_group_name" in domain_group.rule_group.rule_group_metadata' + - '"type" in domain_group.rule_group.rule_group_metadata' + - domain_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - domain_group.rule_group.rule_group_metadata.capacity == 50 + - domain_group.rule_group.rule_group_metadata.rule_group_name == domains_group_name + - domain_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - domain_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in domain_group.rule_group.rule_group' + - '"rules_source_list" in domain_group.rule_group.rule_group.rules_source' + - '"generated_rules_type" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"target_types" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - '"targets" in domain_group.rule_group.rule_group.rules_source.rules_source_list' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.generated_rules_type == 'DENYLIST' + - domain_group.rule_group.rule_group.rules_source.rules_source_list.target_types == [] + - domain_group.rule_group.rule_group.rules_source.rules_source_list.targets == ['example.com', '.example.net'] + + ################################################################### + # Deletion + + - name: '(CHECK) Delete Domain List rule group' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + state: absent + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is changed + + - name: 'Delete Domain List rule group' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + state: absent + register: domain_group + + - assert: + that: + - domain_group is changed + + # The Rule Group may still exist in a "DELETING" state, we should still + # return not changed + - name: 'Delete Domain List rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + state: absent + register: domain_group + check_mode: true + + - assert: + that: + - domain_group is not changed + + - name: '(CHECK) Delete Domain List rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + state: absent + register: domain_group + + - assert: + that: + - domain_group is not changed + + always: + - name: '(always) Delete Domain List rule group' + networkfirewall_rule_group: + name: '{{ domains_group_name }}' + type: 'stateful' + state: absent + ignore_errors: true diff --git a/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml new file mode 100644 index 00000000000..596f839c8e5 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/main.yml @@ -0,0 +1,49 @@ +--- +- module_defaults: + group/aws: + aws_access_key: '{{ aws_access_key | default(omit) }}' + aws_secret_key: '{{ aws_secret_key | default(omit) }}' + security_token: '{{ security_token | default(omit) }}' + region: '{{ aws_region | default(omit) }}' + collections: + - amazon.aws + - community.aws + # We have a base need of botocore >= 1.19.20 which should be fulfilled by the + # time we release 4.0.0, this has been locally tested against 1.20.0 only + # bumping the requirements for specific tests to 1.23.23 + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + 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]}}:stateful-rulegroup/' + managed_arn: '{{_base_arn}}:aws-managed:stateful-rulegroup/' + + # List the Managed Rule Groups (there's no access to the rules themselves) + - include_tasks: 'managed.yml' + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + # Minimal tests and manipulation of common metadata + - include_tasks: 'minimal.yml' + + # Tests Manipulation of common Stateful settings + - include_tasks: 'stateful.yml' + + # Tests Manipulation of Suricata formatted rule strings + - include_tasks: 'rule_strings.yml' + + # Tests Manipulation of DomainList rule groups + - include_tasks: 'domain_list.yml' + + # Tests Manipulation of 5-Tuple rule groups + - include_tasks: '5-tuple.yml' + + always: + - include_tasks: 'cleanup.yml' diff --git a/tests/integration/targets/networkfirewall_rule_group/tasks/managed.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/managed.yml new file mode 100644 index 00000000000..a79a5d9bac6 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/managed.yml @@ -0,0 +1,10 @@ +--- +# Tests related to the Managed Firewall rules +- networkfirewall_rule_group_info: + scope: managed + register: managed_rules_info + +- assert: + that: + - '"rule_list" in managed_rules_info' + - managed_rules_info.rule_list | length > 0 diff --git a/tests/integration/targets/networkfirewall_rule_group/tasks/minimal.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/minimal.yml new file mode 100644 index 00000000000..63de71dbba3 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/minimal.yml @@ -0,0 +1,771 @@ +--- +# +# Basic manipulation of a Firewall Group +# - Minimal Creation +# - Deletion +# - Updating Metadata +# -- description +# -- tags +# +# Uses an 'allow all' string based rule, but doesn't attempt to manipulate the +# rule itself +# +- vars: + minimal_group_name: '{{ group_name_prefix }}-MinimalGroup' + missing_group_name: '{{ group_name_prefix }}-MissingGroup' + 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: + # Test basic functionality of the modules + - name: 'Fetch all account rule groups' + networkfirewall_rule_group_info: {} + register: account_rules_info + + - assert: + that: + - '"rule_list" in account_rules_info' + - '"rule_groups" in account_rules_info' + # We've not created anything yet, so there's no guarantee anything will be here + + ################################################################### + # Creation + + # The simplest form of rule group + - name: '(CHECK) Create a Rule Group with minimal settings' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + # Needed for creation + capacity: 100 + # Needed for creation - We'll test manipulating them later + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + + # The simplest form of rule group + - name: 'Create a Rule Group with minimal settings' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + # Needed for creation + capacity: 100 + # Needed for creation - We'll test manipulating them later + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + register: minimal_group + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_id" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn.startswith(account_arn) + - minimal_group.rule_group.rule_group_metadata.rule_group_arn.endswith(minimal_group_name) + + - name: Save RuleGroup ID/ARN for later + set_fact: + minimal_rule_group_id: '{{ minimal_group.rule_group.rule_group_metadata.rule_group_id }}' + minimal_rule_group_arn: '{{ minimal_group.rule_group.rule_group_metadata.rule_group_arn }}' + + - name: '(CHECK) Create a Rule Group with minimal settings (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + capacity: 100 + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + + - name: 'Create a Rule Group with minimal settings (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + capacity: 100 + register: minimal_group + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + + ################################################################### + # Capacity + + # Capacity can't be changed after creation + - name: '(CHECK) Attempt to change capacity' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + capacity: 200 + register: minimal_group + ignore_errors: true + check_mode: true + + - assert: + that: + - minimal_group is failed + + - name: 'Attempt to change capacity' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + capacity: 200 + register: minimal_group + ignore_errors: true + + - assert: + that: + - minimal_group is failed + + ################################################################### + # Description + + - name: '(CHECK) Add a description' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Example Description' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Example Description' + + - name: 'Add a description' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Example Description' + register: minimal_group + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Example Description' + + - name: '(CHECK) Add a description (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Example Description' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Example Description' + + - name: 'Add a description (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Example Description' + register: minimal_group + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Example Description' + + ##### + + - name: '(CHECK) Update a description' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Updated description' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + + - name: 'Update a description' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Updated description' + register: minimal_group + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + + - name: '(CHECK) Update a description (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Updated description' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + + - name: 'Update a description (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + description: 'Updated description' + register: minimal_group + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + + ################################################################### + # Tags + + - name: '(CHECK) Tag Rule Group' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ first_tags }}' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - '"tags" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == first_tags + + - name: 'Tag Rule Group' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ first_tags }}' + register: minimal_group + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == first_tags + + - name: '(CHECK) Tag Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ first_tags }}' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == first_tags + + - name: 'Tag Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ first_tags }}' + register: minimal_group + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == first_tags + + ##### + + - name: '(CHECK) Update tags with purge' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ second_tags }}' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - '"tags" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == second_tags + + - name: 'Update tags with purge' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ second_tags }}' + register: minimal_group + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == second_tags + + - name: '(CHECK) Update tags with purge (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ second_tags }}' + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == second_tags + + - name: 'Update tags with purge (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ second_tags }}' + register: minimal_group + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == second_tags + + ##### + + - name: '(CHECK) Update tags with no purge' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ third_tags }}' + purge_tags: false + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - '"tags" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == final_tags + + - name: 'Update tags with no purge' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ third_tags }}' + purge_tags: false + register: minimal_group + + - assert: + that: + - minimal_group is changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == final_tags + + - name: '(CHECK) Update tags with no purge (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ third_tags }}' + purge_tags: false + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == final_tags + + - name: 'Update tags with no purge (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + tags: '{{ third_tags }}' + purge_tags: false + register: minimal_group + + - assert: + that: + - minimal_group is not changed + - '"rule_group" in minimal_group' + - '"rule_group" in minimal_group.rule_group' + - '"rule_group_metadata" in minimal_group.rule_group' + - '"capacity" in minimal_group.rule_group.rule_group_metadata' + - '"rule_group_name" in minimal_group.rule_group.rule_group_metadata' + - '"type" in minimal_group.rule_group.rule_group_metadata' + - minimal_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - minimal_group.rule_group.rule_group_metadata.capacity == 100 + - minimal_group.rule_group.rule_group_metadata.rule_group_name == minimal_group_name + - minimal_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - minimal_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - minimal_group.rule_group.rule_group_metadata.description == 'Updated description' + - minimal_group.rule_group.rule_group_metadata.tags == final_tags + + ################################################################### + # Deletion + + - name: '(CHECK) Delete minimal rule group' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + state: absent + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is changed + + - name: 'Delete minimal rule group' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + state: absent + register: minimal_group + + - assert: + that: + - minimal_group is changed + + # The Rule Group may still exist in a "DELETING" state, we should still + # return not changed + - name: 'Delete minimal rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + state: absent + register: minimal_group + check_mode: true + + - assert: + that: + - minimal_group is not changed + + - name: '(CHECK) Delete minimal rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + state: absent + register: minimal_group + + - assert: + that: + - minimal_group is not changed + + ##### + - name: '(CHECK) Delete missing rule group' + networkfirewall_rule_group: + name: '{{ missing_group_name }}' + type: 'stateful' + state: absent + register: missing_group + check_mode: true + + - assert: + that: + - missing_group is not changed + + - name: 'Delete missing rule group' + networkfirewall_rule_group: + name: '{{ missing_group_name }}' + type: 'stateful' + state: absent + + - assert: + that: + - missing_group is not changed + + always: + - name: '(always) Delete minimal rule group' + networkfirewall_rule_group: + name: '{{ minimal_group_name }}' + type: 'stateful' + state: absent + ignore_errors: true diff --git a/tests/integration/targets/networkfirewall_rule_group/tasks/rule_strings.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/rule_strings.yml new file mode 100644 index 00000000000..b536d039bc1 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/rule_strings.yml @@ -0,0 +1,480 @@ +--- +# +# Basic manipulation of Suricata String based rule groups +# - Minimal Creation +# - Deletion +# - Updating Rules +# +- vars: + strings_group_name: '{{ group_name_prefix }}-SuricataGroup' + rule_one: 'pass tcp any any -> any any (sid:1000001;)' + rule_two: 'drop tcp any any -> any any (sid:1000002;)' + rule_three: 'alert tcp any any -> any any (sid:1000003;)' + all_rules: |- + {{ rule_one }} + {{ rule_two }} + {{ rule_three }} + last_rules: |- + {{ rule_two }} + {{ rule_three }} + block: + ################################################################### + # Creation + + - name: '(CHECK) Create a rule_strings Rule Group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: '{{ rule_one }}' + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == rule_one + + - name: 'Create a rule_strings Rule Group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: '{{ rule_one }}' + register: strings_group + + - assert: + that: + - strings_group is changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_id" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn.startswith(account_arn) + - strings_group.rule_group.rule_group_metadata.rule_group_arn.endswith(strings_group_name) + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == rule_one + + - name: Save RuleGroup ID/ARN for later + set_fact: + minimal_rule_group_id: '{{ strings_group.rule_group.rule_group_metadata.rule_group_id }}' + minimal_rule_group_arn: '{{ strings_group.rule_group.rule_group_metadata.rule_group_arn }}' + + - name: '(CHECK) Create a rule_strings Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: '{{ rule_one }}' + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == rule_one + + - name: 'Create a rule_strings Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: '{{ rule_one }}' + register: strings_group + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == rule_one + + ##### + + - name: '(CHECK) Test that rule_strings as a list with one element behaves the same as a single string' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_one }}' + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == rule_one + + - name: 'Test that rule_strings as a list with one element behaves the same as a single string' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_one }}' + register: strings_group + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == rule_one + + ################################################################### + # Update + + - name: '(CHECK) Update a rule_strings Rule Group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == all_rules + + - name: 'Update a rule_strings Rule Group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + + - assert: + that: + - strings_group is changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_id" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == all_rules + + - name: '(CHECK) Update a rule_strings Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == all_rules + + - name: 'Update a rule_strings Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_one }}' + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == all_rules + + ##### + + - name: '(CHECK) Update(2) a rule_strings Rule Group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == last_rules + + - name: 'Update(2) a rule_strings Rule Group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + + - assert: + that: + - strings_group is changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_id" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == last_rules + + - name: '(CHECK) Update(2) a rule_strings Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == last_rules + + - name: 'Update(2) a rule_strings Rule Group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + rule_strings: + - '{{ rule_two }}' + - '{{ rule_three }}' + register: strings_group + + - assert: + that: + - strings_group is not changed + - '"rule_group" in strings_group' + - '"rule_group" in strings_group.rule_group' + - '"rule_group_metadata" in strings_group.rule_group' + - '"capacity" in strings_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strings_group.rule_group.rule_group_metadata' + - '"type" in strings_group.rule_group.rule_group_metadata' + - strings_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strings_group.rule_group.rule_group_metadata.capacity == 100 + - strings_group.rule_group.rule_group_metadata.rule_group_name == strings_group_name + - strings_group.rule_group.rule_group_metadata.rule_group_arn == minimal_rule_group_arn + - strings_group.rule_group.rule_group_metadata.rule_group_id == minimal_rule_group_id + - '"rules_source" in strings_group.rule_group.rule_group' + - '"rules_string" in strings_group.rule_group.rule_group.rules_source' + - strings_group.rule_group.rule_group.rules_source.rules_string == last_rules + + ################################################################### + # Deletion + + - name: '(CHECK) Delete rule_strings rule group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + state: absent + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is changed + + - name: 'Delete rule_strings rule group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + state: absent + register: strings_group + + - assert: + that: + - strings_group is changed + + # The Rule Group may still exist in a "DELETING" state, we should still + # return not changed + - name: 'Delete rule_strings rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + state: absent + register: strings_group + check_mode: true + + - assert: + that: + - strings_group is not changed + + - name: '(CHECK) Delete rule_strings rule group (idempotency)' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + state: absent + register: strings_group + + - assert: + that: + - strings_group is not changed + + always: + - name: '(always) Delete rule_strings rule group' + networkfirewall_rule_group: + name: '{{ strings_group_name }}' + type: 'stateful' + state: absent + ignore_errors: true diff --git a/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml b/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml new file mode 100644 index 00000000000..cd2ea4a3081 --- /dev/null +++ b/tests/integration/targets/networkfirewall_rule_group/tasks/stateful.yml @@ -0,0 +1,1362 @@ +--- +# +# Manipulation of options common to stateful rules +# - Minimal Creation +# - Updating IP Variables +# - Updating Port Variables +# - Setting RuleOrder +# +- vars: + strict_ro_group_name: '{{ group_name_prefix }}-StrictROGroup' + default_ro_group_name: '{{ group_name_prefix }}-DefaultROGroup' + stateful_group_name: '{{ group_name_prefix }}-StatefulGroup' + rule_one: 'pass tcp any any -> any any (sid:1000001;)' + ip_variable_one: + EXAMPLE_IP: '192.0.2.5' + ip_variable_one_list: + EXAMPLE_IP: ['192.0.2.5'] + ip_variable_two: + ANOTHER_EXAMPLE: ['198.51.100.13', '198.51.100.235', '203.0.113.0/24'] + ip_variable_both: + EXAMPLE_IP: ['192.0.2.5'] + ANOTHER_EXAMPLE: ['198.51.100.13', '198.51.100.235', '203.0.113.0/24'] + port_variable_one: + EXAMPLE_PORT: '22' + port_variable_one_list: + EXAMPLE_PORT: ['22'] + port_variable_two: + ANOTHER_PORT: ['443', '8443'] + port_variable_both: + EXAMPLE_PORT: ['22'] + ANOTHER_PORT: ['443', '8443'] + block: + ################################################################### + # Creation + + - name: 'Create a Stateful Rule Group' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: '{{ rule_one }}' + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn.startswith(account_arn) + - stateful_group.rule_group.rule_group_metadata.rule_group_arn.endswith(stateful_group_name) + # Check that we've defaulted to the DEFAULT rule order + + - name: Save RuleGroup ID/ARN for later + set_fact: + stateful_rule_group_id: '{{ stateful_group.rule_group.rule_group_metadata.rule_group_id }}' + stateful_rule_group_arn: '{{ stateful_group.rule_group.rule_group_metadata.rule_group_arn }}' + + ################################################################### + # Update IP Variables + + - name: '(CHECK) Add IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one }}' + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_one_list + + - name: 'Add IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one }}' + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_one_list + + - name: '(CHECK) Add IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one }}' + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_one_list + + - name: 'Add IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one }}' + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_one_list + + ##### + + - name: '(CHECK) Ensure IP Variable string/list equivalence (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one_list }}' + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_one_list + + - name: 'Ensure IP Variable string/list equivalence (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one_list }}' + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_one_list + + ##### + + - name: '(CHECK) Replace IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_two }}' + purge_ip_variables: true + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_two + + - name: 'Replace IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_two }}' + purge_ip_variables: true + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_two + + - name: '(CHECK) Replace IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_two }}' + purge_ip_variables: true + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_two + + - name: 'Replace IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_two }}' + purge_ip_variables: true + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_two + + ##### + + - name: '(CHECK) Add extra IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one_list }}' + purge_ip_variables: false + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + - name: 'Add extra IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one_list }}' + purge_ip_variables: false + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + - name: '(CHECK) Add extra IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one_list }}' + purge_ip_variables: false + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + - name: 'Add extra IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: '{{ ip_variable_one_list }}' + purge_ip_variables: false + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + ################################################################### + # Update Port Variables + + - name: '(CHECK) Add IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one }}' + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_one_list + + - name: 'Add IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one }}' + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_one_list + + - name: '(CHECK) Add IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one }}' + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_one_list + + - name: 'Add IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one }}' + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_one_list + + ##### + + - name: '(CHECK) Ensure IP Variable string/list equivalence (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one_list }}' + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_one_list + + - name: 'Ensure IP Variable string/list equivalence (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one_list }}' + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_one_list + + ##### + + - name: '(CHECK) Replace IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_two }}' + purge_port_variables: true + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_two + + - name: 'Replace IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_two }}' + purge_port_variables: true + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_two + + - name: '(CHECK) Replace IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_two }}' + purge_port_variables: true + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_two + + - name: 'Replace IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_two }}' + purge_port_variables: true + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_two + + ##### + + - name: '(CHECK) Add extra IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one_list }}' + purge_port_variables: false + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_both + + - name: 'Add extra IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one_list }}' + purge_port_variables: false + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_both + + - name: '(CHECK) Add extra IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one_list }}' + purge_port_variables: false + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_both + + - name: 'Add extra IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: '{{ port_variable_one_list }}' + purge_port_variables: false + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + - stateful_group.rule_group.rule_group.rule_variables.port_sets == port_variable_both + + ##### + + - name: '(CHECK) Remove Port Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: {} + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + - name: 'Remove Port Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: {} + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + - name: '(CHECK) Remove Port Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: {} + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + - name: 'Remove Port Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + port_variables: {} + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" in stateful_group.rule_group.rule_group.rule_variables' + - stateful_group.rule_group.rule_group.rule_variables.ip_sets == ip_variable_both + + ##### + + - name: '(CHECK) Remove IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: {} + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" not in stateful_group.rule_group.rule_group.rule_variables' + + - name: 'Remove IP Variable' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: {} + register: stateful_group + + - assert: + that: + - stateful_group is changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_id" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" not in stateful_group.rule_group.rule_group.rule_variables' + + - name: '(CHECK) Remove IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: {} + register: stateful_group + check_mode: true + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" not in stateful_group.rule_group.rule_group.rule_variables' + + - name: 'Remove IP Variable (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + ip_variables: {} + register: stateful_group + + - assert: + that: + - stateful_group is not changed + - '"rule_group" in stateful_group' + - '"rule_group" in stateful_group.rule_group' + - '"rule_group_metadata" in stateful_group.rule_group' + - '"capacity" in stateful_group.rule_group.rule_group_metadata' + - '"rule_group_name" in stateful_group.rule_group.rule_group_metadata' + - '"type" in stateful_group.rule_group.rule_group_metadata' + - stateful_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - stateful_group.rule_group.rule_group_metadata.capacity == 100 + - stateful_group.rule_group.rule_group_metadata.rule_group_name == stateful_group_name + - stateful_group.rule_group.rule_group_metadata.rule_group_arn == stateful_rule_group_arn + - stateful_group.rule_group.rule_group_metadata.rule_group_id == stateful_rule_group_id + - '"rule_variables" in stateful_group.rule_group.rule_group' + - '"port_sets" not in stateful_group.rule_group.rule_group.rule_variables' + - '"ip_sets" not in stateful_group.rule_group.rule_group.rule_variables' + + ################################################################### + # Rule Order + + - name: '(CHECK) Attempt to update the Default Rule Order' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + rule_order: 'strict' + register: stateful_group + ignore_errors: True + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - stateful_group is failed + + - name: 'Attempt to update the Default Rule Order' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + rule_order: 'strict' + register: stateful_group + ignore_errors: True + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - stateful_group is failed + + ##### + + - name: '(CHECK) Attempt to update the Default Rule Order (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + rule_order: 'default' + register: stateful_group + ignore_errors: True + + # Because the default rule order doesn't necessitate the setting of + # RuleOptions, for 'default' the existence of statefule_rule_options (and specifically rule_order) + # isn't guaranteed, so we don't explicitly test for it here, instead we rely + # on 'changed' doing the right thing. + - assert: + that: + - stateful_group is not changed + + - name: 'Attempt to update the Default Rule Order (idempotency)' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + rule_order: 'default' + register: stateful_group + ignore_errors: True + + - assert: + that: + - stateful_group is not changed + + ################################################################### + # Creation with 'strict' rule ordering + + - name: '(CHECK) Create a Rule Group with strict order' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + rule_order: strict + register: strict_group + check_mode: true + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is changed + - '"rule_group" in strict_group' + - '"rule_group" in strict_group.rule_group' + - '"rule_group_metadata" in strict_group.rule_group' + - '"capacity" in strict_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strict_group.rule_group.rule_group_metadata' + - '"type" in strict_group.rule_group.rule_group_metadata' + - strict_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strict_group.rule_group.rule_group_metadata.capacity == 100 + - strict_group.rule_group.rule_group_metadata.rule_group_name == strict_ro_group_name + - '"stateful_rule_options" in strict_group.rule_group.rule_group' + - '"rule_order" in strict_group.rule_group.rule_group.stateful_rule_options' + - strict_group.rule_group.rule_group.stateful_rule_options.rule_order == 'STRICT_ORDER' + + - name: 'Create a Rule Group with strict order' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + rule_order: strict + register: strict_group + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is changed + - '"rule_group" in strict_group' + - '"rule_group" in strict_group.rule_group' + - '"rule_group_metadata" in strict_group.rule_group' + - '"capacity" in strict_group.rule_group.rule_group_metadata' + - '"rule_group_arn" in strict_group.rule_group.rule_group_metadata' + - '"rule_group_id" in strict_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strict_group.rule_group.rule_group_metadata' + - '"type" in strict_group.rule_group.rule_group_metadata' + - strict_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strict_group.rule_group.rule_group_metadata.capacity == 100 + - strict_group.rule_group.rule_group_metadata.rule_group_name == strict_ro_group_name + - strict_group.rule_group.rule_group_metadata.rule_group_arn.startswith(account_arn) + - strict_group.rule_group.rule_group_metadata.rule_group_arn.endswith(strict_ro_group_name) + - '"stateful_rule_options" in strict_group.rule_group.rule_group' + - '"rule_order" in strict_group.rule_group.rule_group.stateful_rule_options' + - strict_group.rule_group.rule_group.stateful_rule_options.rule_order == 'STRICT_ORDER' + + - name: Save RuleGroup ID/ARN for later + set_fact: + strict_rule_group_id: '{{ strict_group.rule_group.rule_group_metadata.rule_group_id }}' + strict_rule_group_arn: '{{ strict_group.rule_group.rule_group_metadata.rule_group_arn }}' + + - name: '(CHECK) Create a Rule Group with strict order (idempotency)' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + rule_order: strict + register: strict_group + check_mode: true + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is not changed + - '"rule_group" in strict_group' + - '"rule_group" in strict_group.rule_group' + - '"rule_group_metadata" in strict_group.rule_group' + - '"capacity" in strict_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strict_group.rule_group.rule_group_metadata' + - '"type" in strict_group.rule_group.rule_group_metadata' + - strict_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strict_group.rule_group.rule_group_metadata.capacity == 100 + - strict_group.rule_group.rule_group_metadata.rule_group_name == strict_ro_group_name + - strict_group.rule_group.rule_group_metadata.rule_group_arn == strict_rule_group_arn + - strict_group.rule_group.rule_group_metadata.rule_group_id == strict_rule_group_id + - '"stateful_rule_options" in strict_group.rule_group.rule_group' + - '"rule_order" in strict_group.rule_group.rule_group.stateful_rule_options' + - strict_group.rule_group.rule_group.stateful_rule_options.rule_order == 'STRICT_ORDER' + + - name: 'Create a Rule Group with strict order (idempotency)' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + capacity: 100 + rule_strings: + - 'pass tcp any any -> any any (sid:1000001;)' + rule_order: strict + register: strict_group + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is not changed + - '"rule_group" in strict_group' + - '"rule_group" in strict_group.rule_group' + - '"rule_group_metadata" in strict_group.rule_group' + - '"capacity" in strict_group.rule_group.rule_group_metadata' + - '"rule_group_name" in strict_group.rule_group.rule_group_metadata' + - '"type" in strict_group.rule_group.rule_group_metadata' + - strict_group.rule_group.rule_group_metadata.type == 'STATEFUL' + - strict_group.rule_group.rule_group_metadata.capacity == 100 + - strict_group.rule_group.rule_group_metadata.rule_group_name == strict_ro_group_name + - strict_group.rule_group.rule_group_metadata.rule_group_arn == strict_rule_group_arn + - strict_group.rule_group.rule_group_metadata.rule_group_id == strict_rule_group_id + - '"stateful_rule_options" in strict_group.rule_group.rule_group' + - '"rule_order" in strict_group.rule_group.rule_group.stateful_rule_options' + - strict_group.rule_group.rule_group.stateful_rule_options.rule_order == 'STRICT_ORDER' + + ################################################################### + # Rule Order + + - name: '(CHECK) Attempt to update the Default Rule Order from strict' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + rule_order: 'default' + register: strict_group + ignore_errors: True + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is failed + + - name: 'Attempt to update the Default Rule Order from strict' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + rule_order: 'default' + register: strict_group + ignore_errors: True + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is failed + + ##### + + - name: '(CHECK) Attempt to update the Default Rule Order from strict (idempotency)' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + rule_order: 'strict' + register: strict_group + ignore_errors: True + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is not changed + + - name: 'Attempt to update the Default Rule Order from strict (idempotency)' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + rule_order: 'strict' + register: strict_group + ignore_errors: True + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + + - assert: + that: + - strict_group is not changed + + + ################################################################### + # Deletion + + - name: 'Delete Stateful rule group' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + state: absent + register: stateful_group + + - assert: + that: + - stateful_group is changed + + - name: 'Delete Strict rule group' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + state: absent + register: strict_group + + - assert: + that: + - strict_group is changed + + always: + - name: '(always) Delete Stateful rule group' + networkfirewall_rule_group: + name: '{{ stateful_group_name }}' + type: 'stateful' + state: absent + ignore_errors: true + + - name: '(always) Delete Strict rule group' + networkfirewall_rule_group: + name: '{{ strict_ro_group_name }}' + type: 'stateful' + state: absent + ignore_errors: true