我正在尝试使用Ansible设置AWS EC2安全组。
我希望其中一些小组有多个规则。有些规则仅适用于我的内部VPC,而另一些则向世界公开。
我想在一个从列表变量读取配置的循环中创建安全组,但是我不想为内部VPC硬编码CIDR。我希望从我的VPC事实中获取CIDR,但是我还没有找到一种令人满意的方法来将CIDR替换为规则。
为了使这一点更加清楚,这是一个(人为)示例。我的原始组列表对所有CIDR都进行了硬编码:
aws_security_groups:
- name: Webservers
description: Security group for webservers
region: my_aws_region
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: 0.0.0.0/0
- name: Databases
description: Security group for internal database access
region: my_aws_region
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: 0.0.0.0/0
- proto: tcp
from_port: 3306
to_port: 3306
cidr_ip: <vpc.cidr.hard.coded/16>
原始剧本非常简单:
- name: Provision EC2 security groups
ec2_group:
name: "{{ item.name }}"
description: "{{ item.description }}"
region: "{{ item.region }}"
state: present
rules: "{{ item.rules }}"
with_items: "{{ aws_security_groups }}"
我可以添加或减去规则,并且知道组将被同步。但是,我不想对CIDR进行硬编码...我希望组列表如下所示:
aws_security_groups:
- name: Webservers
description: Security group for webservers
region: my_aws_region
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: all
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: all
- name: Databases
description: Security group for internal database access
region: my_aws_region
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: all
- proto: tcp
from_port: 3306
to_port: 3306
cidr_ip: internal
我当前的策略是使用
with_subelements
分别为每个规则运行一堆ec2_group
命令:- name: Gather EC2 VPC facts
ec2_vpc_net_facts:
region: my_aws_region
register: vpcs
- name: Provision EC2 security groups
ec2_group:
name: "{{ item.0.name }}"
description: "{{ item.0.description }}"
region: "{{ item.0.region }}"
state: present
purge_rules: false
rules:
- from_port: "{{ item.1.from_port }}"
to_port: "{{ item.1.to_port }}"
proto: "{{ item.1.proto }}"
cidr_ip: "{{ (item.1.cidr_ip == 'internal') | ternary(vpcs.vpcs.0.cidr_block, (item.1.cidr_ip == 'all') | ternary('0.0.0.0/0', item.1.cidr_ip)) }}"
with_subelements:
- "{{ aws_security_groups }}"
- rules
换人可以用,但我会遇到一些不利的折衷。
首先,我必须关闭
purge_rules
,因为如果不这样做,每个循环只会删除以前的规则。因此,如果我对规则进行更改,我可能会被旧的规则困住,需要跟踪并清理它们。其次,嵌套的三进制很尴尬,不容易扩展。
第三,当一个电话足够时,我会打多个电话。
我感觉自己缺少明显的东西,或者使这个过程变得过于复杂。如何在Ansible剧本中完成CIDR替代,或更一般地说,完成任何此类替代?替代是可取的还是有更好的方法来完成相同的任务?
在此方面的任何帮助将不胜感激。
最佳答案
通过以下方式避免purge_rules
问题,它更干净,恕我直言。
任务:
- set_fact:
from_template: "{{ lookup('template', './template.j2') }}"
vars:
to_template_aws_security_groups: "{{ aws_security_groups }}"
to_template_vpcs: "{{ vpcs }}"
- name: Provision EC2 security groups
ec2_group:
name: "{{ item.name }}"
description: "{{ item.description }}"
region: "{{ item.region }}"
state: present
rules: "{{ item.rules }}"
with_items: "{{ from_template.aws_security_groups }}"
template.j2
:{
"aws_security_groups": [
{% for aws_security_group in to_template_aws_security_groups %}
{
"description": "{{ aws_security_group.description }}",
"name": "{{ aws_security_group.name }}",
"region": "{{ aws_security_group.region }}",
"rules": [
{% for rule in aws_security_group.rules %}
{
"cidr_ip": "{{ (rule.cidr_ip == 'internal') | ternary(to_template_vpcs.vpcs.0.cidr_block, (rule.cidr_ip == 'all') | ternary('0.0.0.0/0', rule.cidr_ip)) }}",
"from_port": "{{ rule.from_port }}",
"proto": "{{ rule.proto }}",
"to_port": {{ rule.to_port }}
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}