【问题标题】:Substituting variables in Ansible playbook for EC2 security group rules用 Ansible playbook 中的变量替换 EC2 安全组规则
【发布时间】:2017-04-30 12:34:07
【问题描述】:

我正在尝试使用 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 替换,或者更一般地说,任何此类替换?替代更可取还是有更好的方法来完成相同的任务?

非常感谢您对此的任何帮助。

【问题讨论】:

    标签: amazon-web-services ansible


    【解决方案1】:

    以下方法可以避免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 %}
      ]
    }
    

    【讨论】:

    • 在真实的 AWS 中运行良好。哇。一个非常好的解决方案,它汇集了一些文档稀少的 Ansible 概念:查找的强大功能,在任务级别使用 vars,在文件传输之外使用模板......这种技术对于解决其他类似问题将很有价值。谢谢你,我从你的回答中学到了很多。
    猜你喜欢
    • 2015-07-27
    • 2018-01-01
    • 1970-01-01
    • 2015-10-08
    • 2016-04-08
    • 2023-03-09
    • 2018-04-14
    • 1970-01-01
    • 2021-10-30
    相关资源
    最近更新 更多