EC2_group module refactor (formerly pr/37255) (#38678)
* Refactor ec2_group Replace nested for loops with list comprehensions Purge rules before adding new ones in case sg has maximum permitted rules * Add check mode tests for ec2_group * add tests * Remove dead code * Fix integration test assertions for old boto versions * Add waiter for security group that is autocreated * Add support for in-account group rules * Add common util to get AWS account ID Fixes #31383 * Fix protocol number and add separate tests for egress rule handling * Return egress rule treatment to be backwards compatible * Remove functions that were obsoleted by `Rule` namedtuple * IP tests * Move description updates to a function * Fix string formatting missing index * Add tests for auto-creation of the same group in quick succession * Resolve use of brand-new group in a rule without a description * Clean up duplicated get-security-group function * Add reverse cleanup in case of dependency issues * Add crossaccount ELB group support * Deal with non-STS calls to account API * Add filtering of owner IDs that match the current account
This commit is contained in:
parent
49f569d915
commit
858a1b09bb
11 changed files with 1844 additions and 651 deletions
46
lib/ansible/module_utils/aws/iam.py
Normal file
46
lib/ansible/module_utils/aws/iam.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Copyright (c) 2017 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
import traceback
|
||||
|
||||
try:
|
||||
from botocore.exceptions import ClientError, NoCredentialsError
|
||||
except ImportError:
|
||||
pass # caught by HAS_BOTO3
|
||||
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
def get_aws_account_id(module):
|
||||
""" Given AnsibleAWSModule instance, get the active AWS account ID
|
||||
|
||||
get_account_id tries too find out the account that we are working
|
||||
on. It's not guaranteed that this will be easy so we try in
|
||||
several different ways. Giving either IAM or STS privilages to
|
||||
the account should be enough to permit this.
|
||||
"""
|
||||
account_id = None
|
||||
try:
|
||||
sts_client = module.client('sts')
|
||||
account_id = sts_client.get_caller_identity().get('Account')
|
||||
# non-STS sessions may also get NoCredentialsError from this STS call, so
|
||||
# we must catch that too and try the IAM version
|
||||
except (ClientError, NoCredentialsError):
|
||||
try:
|
||||
iam_client = module.client('iam')
|
||||
account_id = iam_client.get_user()['User']['Arn'].split(':')[4]
|
||||
except ClientError as e:
|
||||
if (e.response['Error']['Code'] == 'AccessDenied'):
|
||||
except_msg = to_native(e)
|
||||
# don't match on `arn:aws` because of China region `arn:aws-cn` and similar
|
||||
account_id = except_msg.search(r"arn:\w+:iam::([0-9]{12,32}):\w+/").group(1)
|
||||
if account_id is None:
|
||||
module.fail_json_aws(e, msg="Could not get AWS account information")
|
||||
except Exception as e:
|
||||
module.fail_json(
|
||||
msg="Failed to get AWS account information, Try allowing sts:GetCallerIdentity or iam:GetUser permissions.",
|
||||
exception=traceback.format_exc()
|
||||
)
|
||||
if not account_id:
|
||||
module.fail_json(msg="Failed while determining AWS account ID. Try allowing sts:GetCallerIdentity or iam:GetUser permissions.")
|
||||
return to_native(account_id)
|
|
@ -27,6 +27,24 @@ ec2_data = {
|
|||
},
|
||||
]
|
||||
},
|
||||
"SecurityGroupExists": {
|
||||
"delay": 5,
|
||||
"maxAttempts": 40,
|
||||
"operation": "DescribeSecurityGroups",
|
||||
"acceptors": [
|
||||
{
|
||||
"matcher": "path",
|
||||
"expected": True,
|
||||
"argument": "length(SecurityGroups[]) > `0`",
|
||||
"state": "success"
|
||||
},
|
||||
{
|
||||
"matcher": "error",
|
||||
"expected": "InvalidGroup.NotFound",
|
||||
"state": "retry"
|
||||
},
|
||||
]
|
||||
},
|
||||
"SubnetExists": {
|
||||
"delay": 5,
|
||||
"maxAttempts": 40,
|
||||
|
@ -179,6 +197,12 @@ waiters_by_name = {
|
|||
core_waiter.NormalizedOperationMethod(
|
||||
ec2.describe_route_tables
|
||||
)),
|
||||
('EC2', 'security_group_exists'): lambda ec2: core_waiter.Waiter(
|
||||
'security_group_exists',
|
||||
ec2_model('SecurityGroupExists'),
|
||||
core_waiter.NormalizedOperationMethod(
|
||||
ec2.describe_security_groups
|
||||
)),
|
||||
('EC2', 'subnet_exists'): lambda ec2: core_waiter.Waiter(
|
||||
'subnet_exists',
|
||||
ec2_model('SubnetExists'),
|
||||
|
|
File diff suppressed because it is too large
Load diff
161
test/integration/targets/ec2_group/tasks/credential_tests.yml
Normal file
161
test/integration/targets/ec2_group/tasks/credential_tests.yml
Normal file
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
# A Note about ec2 environment variable name preference:
|
||||
# - EC2_URL -> AWS_URL
|
||||
# - EC2_ACCESS_KEY -> AWS_ACCESS_KEY_ID -> AWS_ACCESS_KEY
|
||||
# - EC2_SECRET_KEY -> AWS_SECRET_ACCESS_KEY -> AWX_SECRET_KEY
|
||||
# - EC2_REGION -> AWS_REGION
|
||||
#
|
||||
|
||||
# - include: ../../setup_ec2/tasks/common.yml module_name: ec2_group
|
||||
|
||||
- block:
|
||||
# ============================================================
|
||||
- name: test failure with no parameters
|
||||
ec2_group:
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert failure with no parameters
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- 'result.msg == "one of the following is required: name, group_id"'
|
||||
|
||||
# ============================================================
|
||||
- name: test failure with only name
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert failure with only name
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- 'result.msg == "Must provide description when state is present."'
|
||||
|
||||
# ============================================================
|
||||
- name: test failure with only description
|
||||
ec2_group:
|
||||
description: '{{ec2_group_description}}'
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert failure with only description
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- 'result.msg == "one of the following is required: name, group_id"'
|
||||
|
||||
# ============================================================
|
||||
- name: test failure with empty description (AWS API requires non-empty string desc)
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: ''
|
||||
region: '{{ec2_region}}'
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert failure with empty description
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- 'result.msg == "Must provide description when state is present."'
|
||||
|
||||
# ============================================================
|
||||
- name: test valid region parameter
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
region: '{{ec2_region}}'
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert valid region parameter
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- '"Unable to locate credentials" in result.msg'
|
||||
|
||||
# ============================================================
|
||||
- name: test environment variable EC2_REGION
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
environment:
|
||||
EC2_REGION: '{{ec2_region}}'
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert environment variable EC2_REGION
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- '"Unable to locate credentials" in result.msg'
|
||||
|
||||
# ============================================================
|
||||
- name: test invalid ec2_url parameter
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
environment:
|
||||
EC2_URL: bogus.example.com
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert invalid ec2_url parameter
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- 'result.msg.startswith("The ec2_group module requires a region")'
|
||||
|
||||
# ============================================================
|
||||
- name: test valid ec2_url parameter
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
environment:
|
||||
EC2_URL: '{{ec2_url}}'
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert valid ec2_url parameter
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- 'result.msg.startswith("The ec2_group module requires a region")'
|
||||
|
||||
# ============================================================
|
||||
- name: test credentials from environment
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
environment:
|
||||
EC2_REGION: '{{ec2_region}}'
|
||||
EC2_ACCESS_KEY: bogus_access_key
|
||||
EC2_SECRET_KEY: bogus_secret_key
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert ec2_group with valid ec2_url
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- '"validate the provided access credentials" in result.msg'
|
||||
|
||||
# ============================================================
|
||||
- name: test credential parameters
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
ec2_region: '{{ec2_region}}'
|
||||
ec2_access_key: 'bogus_access_key'
|
||||
ec2_secret_key: 'bogus_secret_key'
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert credential parameters
|
||||
assert:
|
||||
that:
|
||||
- 'result.failed'
|
||||
- '"validate the provided access credentials" in result.msg'
|
44
test/integration/targets/ec2_group/tasks/data_validation.yml
Normal file
44
test/integration/targets/ec2_group/tasks/data_validation.yml
Normal file
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
- block:
|
||||
- name: set up aws connection info
|
||||
set_fact:
|
||||
aws_connection_info: &aws_connection_info
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
region: "{{ aws_region }}"
|
||||
no_log: yes
|
||||
- name: Create a group with only the default rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-input-tests'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
|
||||
- name: Run through some common weird port specs
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-input-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
rules:
|
||||
- "{{ item }}"
|
||||
with_items:
|
||||
- proto: tcp
|
||||
from_port: "8182"
|
||||
to_port: 8182
|
||||
cidr_ipv6: "64:ff9b::/96"
|
||||
rule_desc: Mixed string and non-string ports
|
||||
- proto: tcp
|
||||
ports:
|
||||
- "9000"
|
||||
- 9001
|
||||
- 9002-9005
|
||||
cidr_ip: "1.2.3.0/24"
|
||||
always:
|
||||
- name: tidy up input testing group
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-input-tests'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
state: absent
|
||||
<<: *aws_connection_info
|
||||
ignore_errors: yes
|
175
test/integration/targets/ec2_group/tasks/egress_tests.yml
Normal file
175
test/integration/targets/ec2_group/tasks/egress_tests.yml
Normal file
|
@ -0,0 +1,175 @@
|
|||
---
|
||||
- block:
|
||||
- name: set up aws connection info
|
||||
set_fact:
|
||||
aws_connection_info: &aws_connection_info
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
region: "{{ aws_region }}"
|
||||
no_log: yes
|
||||
|
||||
|
||||
- name: Create a group with only the default rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert default rule is in place (expected changed=true)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.ip_permissions|length == 0
|
||||
- result.ip_permissions_egress|length == 1
|
||||
- result.ip_permissions_egress[0].ip_ranges[0].cidr_ip == '0.0.0.0/0'
|
||||
|
||||
- name: Create a group with only the default rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
purge_rules_egress: false
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert default rule is not purged (expected changed=false)
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.ip_permissions|length == 0
|
||||
- result.ip_permissions_egress|length == 1
|
||||
- result.ip_permissions_egress[0].ip_ranges[0].cidr_ip == '0.0.0.0/0'
|
||||
|
||||
- name: Pass empty egress rules without purging, should leave default rule in place
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
purge_rules_egress: false
|
||||
rules_egress: []
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert default rule is not purged (expected changed=false)
|
||||
assert:
|
||||
that:
|
||||
- result is not changed
|
||||
- result.ip_permissions|length == 0
|
||||
- result.ip_permissions_egress|length == 1
|
||||
- result.ip_permissions_egress[0].ip_ranges[0].cidr_ip == '0.0.0.0/0'
|
||||
|
||||
- name: Purge rules, including the default
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
purge_rules_egress: true
|
||||
rules_egress: []
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert default rule is not purged (expected changed=false)
|
||||
assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.ip_permissions|length == 0
|
||||
- result.ip_permissions_egress|length == 0
|
||||
|
||||
- name: Add a custom egress rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
rules_egress:
|
||||
- proto: tcp
|
||||
ports:
|
||||
- 1212
|
||||
cidr_ip: 1.2.1.2/32
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert first rule is here
|
||||
assert:
|
||||
that:
|
||||
- result.ip_permissions_egress|length == 1
|
||||
|
||||
- name: Add a second custom egress rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
purge_rules_egress: false
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
rules_egress:
|
||||
- proto: tcp
|
||||
ports:
|
||||
- 2323
|
||||
cidr_ip: 2.3.2.3/32
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert the first rule is not purged
|
||||
assert:
|
||||
that:
|
||||
- result.ip_permissions_egress|length == 2
|
||||
|
||||
- name: Purge the second rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
rules_egress:
|
||||
- proto: tcp
|
||||
ports:
|
||||
- 1212
|
||||
cidr_ip: 1.2.1.2/32
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: assert first rule is here
|
||||
assert:
|
||||
that:
|
||||
- result.ip_permissions_egress|length == 1
|
||||
- result.ip_permissions_egress[0].ip_ranges[0].cidr_ip == '1.2.1.2/32'
|
||||
|
||||
- name: add a rule for all TCP ports
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
rules_egress:
|
||||
- proto: tcp
|
||||
ports: 0-65535
|
||||
cidr_ip: 0.0.0.0/0
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
register: result
|
||||
|
||||
- name: Re-add the default rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
description: '{{ec2_group_description}}'
|
||||
rules_egress:
|
||||
- proto: -1
|
||||
cidr_ip: 0.0.0.0/0
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
register: result
|
||||
always:
|
||||
- name: tidy up egress rule test security group
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-egress-tests'
|
||||
state: absent
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
<<: *aws_connection_info
|
||||
ignore_errors: yes
|
103
test/integration/targets/ec2_group/tasks/ipv6_default_tests.yml
Normal file
103
test/integration/targets/ec2_group/tasks/ipv6_default_tests.yml
Normal file
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
- name: set up aws connection info
|
||||
set_fact:
|
||||
aws_connection_info: &aws_connection_info
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
region: "{{ aws_region }}"
|
||||
no_log: yes
|
||||
# ============================================================
|
||||
- name: test state=present for ipv6 (expected changed=true) (CHECK MODE)
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
rules:
|
||||
- proto: "tcp"
|
||||
from_port: 8182
|
||||
to_port: 8182
|
||||
cidr_ipv6: "64:ff9b::/96"
|
||||
check_mode: true
|
||||
register: result
|
||||
|
||||
- name: assert state=present (expected changed=true)
|
||||
assert:
|
||||
that:
|
||||
- 'result.changed'
|
||||
|
||||
# ============================================================
|
||||
- name: test state=present for ipv6 (expected changed=true)
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
rules:
|
||||
- proto: "tcp"
|
||||
from_port: 8182
|
||||
to_port: 8182
|
||||
cidr_ipv6: "64:ff9b::/96"
|
||||
register: result
|
||||
|
||||
- name: assert state=present (expected changed=true)
|
||||
assert:
|
||||
that:
|
||||
- 'result.changed'
|
||||
- 'result.group_id.startswith("sg-")'
|
||||
|
||||
# ============================================================
|
||||
- name: test rules_egress state=present for ipv6 (expected changed=true) (CHECK MODE)
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
rules:
|
||||
- proto: "tcp"
|
||||
from_port: 8182
|
||||
to_port: 8182
|
||||
cidr_ipv6: "64:ff9b::/96"
|
||||
rules_egress:
|
||||
- proto: "tcp"
|
||||
from_port: 8181
|
||||
to_port: 8181
|
||||
cidr_ipv6: "64:ff9b::/96"
|
||||
check_mode: true
|
||||
register: result
|
||||
|
||||
- name: assert state=present (expected changed=true)
|
||||
assert:
|
||||
that:
|
||||
- 'result.changed'
|
||||
|
||||
# ============================================================
|
||||
- name: test rules_egress state=present for ipv6 (expected changed=true)
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
rules:
|
||||
- proto: "tcp"
|
||||
from_port: 8182
|
||||
to_port: 8182
|
||||
cidr_ipv6: "64:ff9b::/96"
|
||||
rules_egress:
|
||||
- proto: "tcp"
|
||||
from_port: 8181
|
||||
to_port: 8181
|
||||
cidr_ipv6: "64:ff9b::/96"
|
||||
register: result
|
||||
|
||||
- name: assert state=present (expected changed=true)
|
||||
assert:
|
||||
that:
|
||||
- 'result.changed'
|
||||
- 'result.group_id.startswith("sg-")'
|
||||
- name: delete it
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}'
|
||||
<<: *aws_connection_info
|
||||
state: absent
|
File diff suppressed because it is too large
Load diff
132
test/integration/targets/ec2_group/tasks/rule_group_create.yml
Normal file
132
test/integration/targets/ec2_group/tasks/rule_group_create.yml
Normal file
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
- block:
|
||||
- name: set up aws connection info
|
||||
set_fact:
|
||||
aws_connection_info: &aws_connection_info
|
||||
aws_access_key: "{{ aws_access_key }}"
|
||||
aws_secret_key: "{{ aws_secret_key }}"
|
||||
security_token: "{{ security_token }}"
|
||||
region: "{{ aws_region }}"
|
||||
no_log: yes
|
||||
|
||||
- name: Create a group with self-referring rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-1'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
rules:
|
||||
- proto: "tcp"
|
||||
from_port: 8000
|
||||
to_port: 8100
|
||||
group_name: '{{ec2_group_name}}-auto-create-1'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Create a second group rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-2'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
|
||||
- name: Create a series of rules with a recently created group as target
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-1'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
purge_rules: false
|
||||
rules:
|
||||
- proto: "tcp"
|
||||
from_port: "{{ item }}"
|
||||
to_port: "{{ item }}"
|
||||
group_name: '{{ec2_group_name}}-auto-create-2'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
with_items:
|
||||
- 20
|
||||
- 40
|
||||
- 60
|
||||
- 80
|
||||
|
||||
- name: Create a group with only the default rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-1'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
rules:
|
||||
- proto: "tcp"
|
||||
from_port: 8182
|
||||
to_port: 8182
|
||||
group_name: '{{ec2_group_name}}-auto-create-3'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
ignore_errors: true
|
||||
|
||||
- name: assert you can't create a new group from a rule target with no description
|
||||
assert:
|
||||
that:
|
||||
- result is failed
|
||||
|
||||
- name: Create a group with a target of a separate group
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-1'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
rules:
|
||||
- proto: tcp
|
||||
ports:
|
||||
- 22
|
||||
- 80
|
||||
group_name: '{{ec2_group_name}}-auto-create-3'
|
||||
group_desc: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
register: result
|
||||
|
||||
- name: Create a 4th group
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-4'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
rules:
|
||||
- proto: tcp
|
||||
ports:
|
||||
- 22
|
||||
cidr_ip: 0.0.0.0/0
|
||||
|
||||
- name: use recently created group in a rule
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-5'
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
description: '{{ec2_group_description}}'
|
||||
rules:
|
||||
- proto: tcp
|
||||
ports:
|
||||
- 443
|
||||
group_name: '{{ec2_group_name}}-auto-create-4'
|
||||
<<: *aws_connection_info
|
||||
state: present
|
||||
|
||||
always:
|
||||
- name: tidy up egress rule test security group
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-{{ item }}'
|
||||
state: absent
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
<<: *aws_connection_info
|
||||
ignore_errors: yes
|
||||
with_items: [5, 4, 3, 2, 1]
|
||||
- name: tidy up egress rule test security group
|
||||
ec2_group:
|
||||
name: '{{ec2_group_name}}-auto-create-{{ item }}'
|
||||
state: absent
|
||||
vpc_id: '{{ vpc_result.vpc.id }}'
|
||||
<<: *aws_connection_info
|
||||
ignore_errors: yes
|
||||
with_items: [1, 2, 3, 4, 5]
|
|
@ -2,7 +2,6 @@ lib/ansible/module_utils/network/iosxr/iosxr.py ansible-format-automatic-specifi
|
|||
lib/ansible/modules/cloud/amazon/aws_api_gateway.py ansible-format-automatic-specification
|
||||
lib/ansible/modules/cloud/amazon/aws_kms.py ansible-format-automatic-specification
|
||||
lib/ansible/modules/cloud/amazon/ec2_eip.py ansible-format-automatic-specification
|
||||
lib/ansible/modules/cloud/amazon/ec2_group.py ansible-format-automatic-specification
|
||||
lib/ansible/modules/cloud/amazon/ecs_ecr.py ansible-format-automatic-specification
|
||||
lib/ansible/modules/cloud/amazon/sns.py ansible-format-automatic-specification
|
||||
lib/ansible/modules/cloud/azure/azure_rm_acs.py ansible-format-automatic-specification
|
||||
|
|
80
test/units/modules/cloud/amazon/test_ec2_group.py
Normal file
80
test/units/modules/cloud/amazon/test_ec2_group.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
import pytest
|
||||
|
||||
from ansible.modules.cloud.amazon import ec2_group as group_module
|
||||
|
||||
|
||||
def test_from_permission():
|
||||
internal_http = {
|
||||
u'FromPort': 80,
|
||||
u'IpProtocol': 'tcp',
|
||||
u'IpRanges': [
|
||||
{
|
||||
u'CidrIp': '10.0.0.0/8',
|
||||
u'Description': 'Foo Bar Baz'
|
||||
},
|
||||
],
|
||||
u'Ipv6Ranges': [
|
||||
{u'CidrIpv6': 'fe80::94cc:8aff:fef6:9cc/64'},
|
||||
],
|
||||
u'PrefixListIds': [],
|
||||
u'ToPort': 80,
|
||||
u'UserIdGroupPairs': [],
|
||||
}
|
||||
perms = list(group_module.rule_from_group_permission(internal_http))
|
||||
assert len(perms) == 2
|
||||
assert perms[0].target == '10.0.0.0/8'
|
||||
assert perms[0].target_type == 'ipv4'
|
||||
assert perms[0].description == 'Foo Bar Baz'
|
||||
assert perms[1].target == 'fe80::94cc:8aff:fef6:9cc/64'
|
||||
|
||||
global_egress = {
|
||||
'IpProtocol': '-1',
|
||||
'IpRanges': [{'CidrIp': '0.0.0.0/0'}],
|
||||
'Ipv6Ranges': [],
|
||||
'PrefixListIds': [],
|
||||
'UserIdGroupPairs': []
|
||||
}
|
||||
perms = list(group_module.rule_from_group_permission(global_egress))
|
||||
assert len(perms) == 1
|
||||
assert perms[0].target == '0.0.0.0/0'
|
||||
assert perms[0].port_range == (None, None)
|
||||
|
||||
internal_prefix_http = {
|
||||
u'FromPort': 80,
|
||||
u'IpProtocol': 'tcp',
|
||||
u'PrefixListIds': [
|
||||
{'PrefixListId': 'p-1234'}
|
||||
],
|
||||
u'ToPort': 80,
|
||||
u'UserIdGroupPairs': [],
|
||||
}
|
||||
perms = list(group_module.rule_from_group_permission(internal_prefix_http))
|
||||
assert len(perms) == 1
|
||||
assert perms[0].target == 'p-1234'
|
||||
|
||||
|
||||
def test_rule_to_permission():
|
||||
tests = [
|
||||
group_module.Rule((22, 22), 'udp', 'sg-1234567890', 'group', None),
|
||||
group_module.Rule((1, 65535), 'tcp', '0.0.0.0/0', 'ipv4', "All TCP from everywhere"),
|
||||
group_module.Rule((443, 443), 'tcp', 'ip-123456', 'ip_prefix', "Traffic to privatelink IPs"),
|
||||
group_module.Rule((443, 443), 'tcp', 'feed:dead:::beef/64', 'ipv6', None),
|
||||
]
|
||||
for test in tests:
|
||||
perm = group_module.to_permission(test)
|
||||
assert perm['FromPort'], perm['ToPort'] == test.port_range
|
||||
assert perm['IpProtocol'] == test.protocol
|
||||
|
||||
|
||||
def test_validate_ip():
|
||||
class Warner(object):
|
||||
def warn(self, msg):
|
||||
return
|
||||
ips = [
|
||||
('1.1.1.1/24', '1.1.1.0/24'),
|
||||
('192.168.56.101/16', '192.168.0.0/16'),
|
||||
('1203:8fe0:fe80:b897:8990:8a7c:99bf:323d/64', '1203:8fe0:fe80::/64'),
|
||||
]
|
||||
|
||||
for ip, net in ips:
|
||||
assert group_module.validate_ip(Warner(), ip) == net
|
Loading…
Reference in a new issue