MSK
MSK

Reputation: 84

Adding and removing multiple IP address to AWS security group using Ansible

I was trying to use Ansible to add IP addresses to an AWS security group.

I came up with a task syntax that looks like this:

- hosts: localhost
  gather_facts: False
  vars:
    ip_addresses:
      - 1.2.3.4/32
      - 2.3.4.5/32
  tasks:
    - ec2_group:
        name: security-group-name
        description: Security group description
        vpc_id: vpc-1234567
        region: us-east-1
        profile: profile-name
        purge_rules: false
        rules:
         - proto: tcp
           from_port: 123
           to_port: 123
           cidr_ip: "{{ item }}"
      with_items: ip_addresses

This does not do exactly what I was looking for as it basically runs the ec2_group task multiple times instead of just looping over the rules.

This also does not work if I set the purge_rules to true as then it will purge all existing rules on each iteration, effectively removing all but the last IP address on the list.

I'm wondering if there is something similar to with_items that I can apply to the rules attribute to provide it a list of IP addresses but calling ec2_task only once?

Upvotes: 3

Views: 2278

Answers (2)

Bruce P
Bruce P

Reputation: 20759

This does not do exactly what I was looking for as it basically runs the ec2_group task multiple times instead of just looping over the rules.

Ansible implements loops by invoking the task once for each item in the loop, so that's expected behavior.

I'm wondering if there is something similar to with_items that I can apply to the rules attribute to provide it a list of IP addresses but calling ec2_task only once?

Since the rules property for ec2_group actually takes a list of rules, you should be able to do the following:

- ec2_group:
    name: security-group-name
    description: Security group description
    vpc_id: vpc-1234567
    region: us-east-1
    profile: profile-name
    purge_rules: true
    rules:
     - proto: tcp
       from_port: 123
       to_port: 123
       cidr_ip: 1.2.3.4/32
     - proto: tcp
       from_port: 123
       to_port: 123
       cidr_ip: 2.3.4.5/32

Or, if you want to use pre-defined vars as in your example:

vars:
  my_rules:
     - proto: tcp
       from_port: 123
       to_port: 123
       cidr_ip: 1.2.3.4/32
     - proto: tcp
       from_port: 123
       to_port: 123
       cidr_ip: 2.3.4.5/32

tasks:
  - ec2_group:
      name: security-group-name
     description: Security group description
      vpc_id: vpc-1234567
      region: us-east-1
      profile: profile-name
      purge_rules: true
      rules: my_rules

Upvotes: 3

nftw
nftw

Reputation: 624

You can achieve what you want with a custom filter plugin.

Create a directory in the root of your playbook called filter_plugins and create a file in there called make_rules.py with the following contents:

def make_rules(hosts, ports, proto):
    return [{"proto": proto,
             "from_port": port,
             "to_port": port,
             "cidr_ip": host} for host in hosts for port in map(int, ports.split(","))]

class FilterModule(object):
     def filters(self):
         return {'make_rules': make_rules}

Then you can do this:

- hosts: localhost
  gather_facts: False
  vars:
    ip_addresses:
      - 1.2.3.4/32
      - 2.3.4.5/32
  tasks:
    - ec2_group:
        name: security-group-name
        description: Security group description
        vpc_id: vpc-1234567
        region: us-east-1
        profile: profile-name
        purge_rules: true
        rules: {{ ip_addresses | make_rules('123', 'tcp') }}

Taken from: https://gist.github.com/viesti/1febe79938c09cc29501

Upvotes: 4

Related Questions