From 0c733ff299d246a5e733c5ad4532a2a8d245e429 Mon Sep 17 00:00:00 2001 From: Justin Wind Date: Mon, 13 Mar 2017 10:32:09 -0700 Subject: [PATCH] add vpcaccess role --- init_vpcaccess.yml | 7 ++ roles/vpcaccess-infrastructure/meta/main.yml | 5 + roles/vpcaccess-infrastructure/tasks/main.yml | 93 +++++++++++++++++++ roles/vpcaccess/files/ec2-pat.sh | 43 +++++++++ roles/vpcaccess/files/routeUpdater.py | 64 +++++++++++++ roles/vpcaccess/files/vpcaccess-policy.json | 19 ++++ roles/vpcaccess/handlers/main.yml | 10 ++ roles/vpcaccess/meta/main.yml | 3 + roles/vpcaccess/tasks/main.yml | 90 ++++++++++++++++++ roles/vpcaccess/templates/ripd.conf.j2 | 25 +++++ roles/vpcaccess/templates/zebra.conf.j2 | 11 +++ vpcaccess.yml | 6 ++ 12 files changed, 376 insertions(+) create mode 100644 init_vpcaccess.yml create mode 100644 roles/vpcaccess-infrastructure/meta/main.yml create mode 100644 roles/vpcaccess-infrastructure/tasks/main.yml create mode 100644 roles/vpcaccess/files/ec2-pat.sh create mode 100644 roles/vpcaccess/files/routeUpdater.py create mode 100644 roles/vpcaccess/files/vpcaccess-policy.json create mode 100644 roles/vpcaccess/handlers/main.yml create mode 100644 roles/vpcaccess/meta/main.yml create mode 100644 roles/vpcaccess/tasks/main.yml create mode 100644 roles/vpcaccess/templates/ripd.conf.j2 create mode 100644 roles/vpcaccess/templates/zebra.conf.j2 create mode 100644 vpcaccess.yml diff --git a/init_vpcaccess.yml b/init_vpcaccess.yml new file mode 100644 index 0000000..3b9d624 --- /dev/null +++ b/init_vpcaccess.yml @@ -0,0 +1,7 @@ +--- +- hosts: localhost + connection: local + gather_facts: False + become: no + roles: + - vpcaccess-infrastructure diff --git a/roles/vpcaccess-infrastructure/meta/main.yml b/roles/vpcaccess-infrastructure/meta/main.yml new file mode 100644 index 0000000..492ebf1 --- /dev/null +++ b/roles/vpcaccess-infrastructure/meta/main.yml @@ -0,0 +1,5 @@ +--- +dependencies: + - { role: aws-vpc } + - { role: aws-management-queues } + - { role: common-infrastructure } diff --git a/roles/vpcaccess-infrastructure/tasks/main.yml b/roles/vpcaccess-infrastructure/tasks/main.yml new file mode 100644 index 0000000..5149ad0 --- /dev/null +++ b/roles/vpcaccess-infrastructure/tasks/main.yml @@ -0,0 +1,93 @@ +--- +- assert: + that: + tags: ['check_vars'] + +- name: vpcaccess iam + iam: + name: vpcaccess + iam_type: role + state: present + +- name: sg vpcaccess + ec2_group: + vpc_id: "{{ vpc.vpc.id }}" + region: "{{ vpc_region }}" + state: present + name: vpcaccess + description: "vpcaccess rules" + purge_rules: false + rules: + rules_egress: + - proto: all + cidr_ip: 0.0.0.0/0 + register: sg_vpcaccess + +- name: vpcaccess lc + ec2_lc: + region: "{{ vpc_region }}" + name: vpcaccess-0000 + image_id: "{{ DEFAULT_AMI }}" + key_name: "{{ MANAGEMENT_KEY_NAME }}" + instance_profile_name: vpcaccess + security_groups: + - "{{ sg_vpcaccess.group_id }}" + - "{{ sg_ssh.group_id }}" + instance_type: m4.large + volumes: +# setting the root volume seems to prevent instances from launching +# - device_name: /dev/sda1 +# volume_size: 8 +# volume_type: gp2 +# delete_on_termination: true + - device_name: /dev/sdb + ephemeral: ephemeral0 + - device_name: /dev/sdc + ephemeral: ephemeral1 + - device_name: /dev/sdd + ephemeral: ephemeral2 + - device_name: /dev/sde + ephemeral: ephemeral3 + register: vpcaccess_lc + +- name: suss out our subnets + ec2_vpc_subnet_facts: + region: "{{ vpc_region }}" + filters: + vpc_id: "{{ vpc.vpc.id }}" + "tag:zone": pub + register: public_subnet_ids + +- debug: + var: public_subnet_ids + +- name: vpcaccess asg + ec2_asg: + region: "{{ vpc_region }}" + name: vpcaccess + min_size: 1 + max_size: 1 + desired_capacity: 1 + default_cooldown: 10 + vpc_zone_identifier: "{{ public_subnet_ids.subnets|map(attribute='id')|list }}" + launch_config_name: "{{ vpcaccess_lc.name|default('checkmode') }}" + notification_topic: "{{ management_topic.sns_arn }}" + notification_types: + - autoscaling:EC2_INSTANCE_LAUNCH + load_balancers: + tags: + - account: "{{ ACCT_NAME }}" + propagate_at_launch: yes + - module: vpcaccess + propagate_at_launch: yes + - stack: "" + propagate_at_launch: yes + - country: "" + propagate_at_launch: yes + - phase: dev + propagate_at_launch: yes + +- name: not implemented yet + debug: + msg: | + attach policies to iam role diff --git a/roles/vpcaccess/files/ec2-pat.sh b/roles/vpcaccess/files/ec2-pat.sh new file mode 100644 index 0000000..6e119cc --- /dev/null +++ b/roles/vpcaccess/files/ec2-pat.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# Configure the instance to run as a Port Address Translator (PAT) to provide +# Internet connectivity to private instances. +# + +IF='eth0' + +set -o pipefail + +function log(){ + echo "$@" | /usr/bin/logger -t 'ec2-pat' +} + +echo "Determining the MAC address on ${IF}" +if ! IF_MAC=$(/sbin/ip address show dev ${IF} | + /bin/grep 'link/ether' | + /bin/awk '{print tolower($2)}') +then + log "Unable to determine MAC address on eth0" + exit 1 +fi +log "Found MAC: ${IF_MAC} on ${IF}" + +VPC_CIDR_URI="http://169.254.169.254/latest/meta-data/network/interfaces/macs/${IF_MAC}/vpc-ipv4-cidr-block" +if ! VPC_CIDR_RANGE=$(/usr/bin/curl --retry 3 --retry-delay 1 --silent --fail "${VPC_CIDR_URI}") +then + VPC_CIDR_RANGE="0.0.0.0/0" + log "Unable to retrive VPC CIDR range from meta-data. Using ${VPC_CIDR_RANGE} instead. PAT may not function correctly!" +else + log "Retrived the VPC CIDR range: ${VPC_CIDR_RANGE} from meta-data" +fi + +if ! /sbin/sysctl -w 'net.ipv4.ip_forward=1' && + /sbin/sysctl -w "net.ipv4.conf.${IF}.send_redirects=0" && + /sbin/iptables -t nat -A POSTROUTING -o ${IF} -s ${VPC_CIDR_RANGE} -j MASQUERADE +then + log "Configuration of PAT failed" + exit 1 +fi + +log "Configuration of PAT complete" +/sbin/iptables-save > /etc/sysconfig/iptables diff --git a/roles/vpcaccess/files/routeUpdater.py b/roles/vpcaccess/files/routeUpdater.py new file mode 100644 index 0000000..8901179 --- /dev/null +++ b/roles/vpcaccess/files/routeUpdater.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +import boto.utils +import boto.ec2 +import boto.vpc +import sys + +dry_run = False + +# AWS access/secret keys +aws_access = None +aws_secret = None + +# Get all of the instance info e.g. curl 169.254.169.254/latest/meta-data/ +try: + instance_info = boto.utils.get_instance_metadata() +except: + print "Could not get EC2 instance ID!" + sys.exit(1) + +instance_id = instance_info['instance-id'] +region_name = instance_info['placement']['availability-zone'][:-1] +vpc_id = instance_info['network']['interfaces']['macs'][instance_info['mac']]['vpc-id'] + +vpc_conn = boto.vpc.connect_to_region(region_name, aws_access_key_id=aws_access, aws_secret_access_key=aws_secret) +ec2_conn = boto.ec2.connect_to_region(region_name, aws_access_key_id=aws_access, aws_secret_access_key=aws_secret) + +# Turn off Source/Destination checking if it's on +source_dest_check = ec2_conn.get_instance_attribute(instance_id, 'sourceDestCheck')['sourceDestCheck'] +print "Source/Dest check: %s" % (source_dest_check,) + +if source_dest_check: + print "Instance must have source/dest checking disabled to NAT properly!" + try: + ec2_conn.modify_instance_attribute(instance_id, 'sourceDestCheck', False, dry_run=dry_run) + except Exception, e: + print "Could not modify source/dest check: %s" % (e,) + sys.exit(1) + +# Get the managed route tables for my VPC +rt = vpc_conn.get_all_route_tables(filters={'vpc_id':vpc_id,'tag:managed':'yes'}) + +# Just in case there's more than one +for table in rt: + # See if there's a default route (0.0.0.0/0) + gw_route = next((route for route in table.routes if route.destination_cidr_block == '0.0.0.0/0'), None) + if not gw_route: + print "Could not find default gw route in routing table!" + else: + print "Found a gateway route: %s, %s, %s" % (table.id, gw_route.destination_cidr_block, instance_id) + try: + # If there is delete it, because I'm taking it over + vpc_conn.delete_route(table.id, '0.0.0.0/0', dry_run=dry_run) + except Exception, e: + print "Could not delete gw route! %s" % (e,) + sys.exit(1) + try: + # Make me the default route, I'm the router now! + vpc_conn.create_route(table.id, '0.0.0.0/0', instance_id=instance_id, dry_run=dry_run) + except Exception, e: + print "Could not replace gw route! %s" % (e,) + sys.exit(1) + + diff --git a/roles/vpcaccess/files/vpcaccess-policy.json b/roles/vpcaccess/files/vpcaccess-policy.json new file mode 100644 index 0000000..acd5795 --- /dev/null +++ b/roles/vpcaccess/files/vpcaccess-policy.json @@ -0,0 +1,19 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Stmt1489423268000", + "Effect": "Allow", + "Action": [ + "ec2:AssociateAddress", + "ec2:CreateRoute", + "ec2:DeleteRoute", + "ec2:DescribeRouteTables", + "ec2:ModifyNetworkInterfaceAttribute" + ], + "Resource": [ + "*" + ] + } + ] +} \ No newline at end of file diff --git a/roles/vpcaccess/handlers/main.yml b/roles/vpcaccess/handlers/main.yml new file mode 100644 index 0000000..9c76715 --- /dev/null +++ b/roles/vpcaccess/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: restart ripd + service: + name: ripd + state: restarted + +- name: restart zebra + service: + name: zebra + state: restarted diff --git a/roles/vpcaccess/meta/main.yml b/roles/vpcaccess/meta/main.yml new file mode 100644 index 0000000..96ecf5e --- /dev/null +++ b/roles/vpcaccess/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: aws-vpc } \ No newline at end of file diff --git a/roles/vpcaccess/tasks/main.yml b/roles/vpcaccess/tasks/main.yml new file mode 100644 index 0000000..10c394a --- /dev/null +++ b/roles/vpcaccess/tasks/main.yml @@ -0,0 +1,90 @@ +--- +- action: ec2_facts + +- name: Enable IP Forwarding + with_items: + - { "var": "net.ipv4.ip_forward", "val": 1 } + - { "var": "net.ipv4.conf.eth0.send_redirects", "val": 0 } + sysctl: + state: present + name: "{{ item.var }}" + value: "{{ item.val }}" + sysctl_set: yes + reload: yes + ignoreerrors: yes + +- name: naming things + set_fact: + environment_name: "{{ ACCT_NAME }}" +- name: Find CIDR + set_fact: + subnet_to_announce: "{{ vpc.vpc.cidr_block }}" + +- name: enable PAT + iptables: + table: nat + chain: POSTROUTING + out_interface: eth0 + source: "{{ vpc.vpc.cidr_block }}" + jump: MASQUERADE +- command: /etc/init.d/iptables save + args: + creates: /etc/sysconfig/iptables + +- name: Attach EIP + delegate_to: localhost + become: no + ec2_eip: + state: present + in_vpc: true + device_id: "{{ ansible_ec2_instance_id }}" + region: "{{ ansible_ec2_placement_region }}" + reuse_existing_ip_allowed: yes + register: eip_attachment + +- name: Refresh inventory + when: eip_attachment|changed + meta: refresh_inventory + +- name: Install support scripts + with_items: + - routeUpdater.py + copy: + src: "{{ item }}" + dest: "/usr/local/bin/{{ item }}" + owner: root + group: root + mode: "0755" + +- name: Take over private VPC routing + command: /usr/local/bin/routeUpdater.py + +- name: Install Quagga + yum: + name: quagga + state: present + +- name: Configure Quagga + with_items: + - ripd.conf + - zebra.conf + template: + src: "{{ item }}.j2" + dest: "/etc/quagga/{{ item }}" + owner: quagga + group: quagga + mode: "0640" + notify: + - restart ripd + - restart zebra + +- name: Enable Quagga + with_items: + - ripd + - zebra + service: + name: "{{ item }}" + enabled: yes + notify: + - restart ripd + - restart zebra diff --git a/roles/vpcaccess/templates/ripd.conf.j2 b/roles/vpcaccess/templates/ripd.conf.j2 new file mode 100644 index 0000000..cfc5ac6 --- /dev/null +++ b/roles/vpcaccess/templates/ripd.conf.j2 @@ -0,0 +1,25 @@ +! -*- rip -*- +! +! RIPd configuration file +! + +hostname {{ ansible_ec2_hostname }} +password {{ QUAGGA_PASSWORD }} + +router rip + network tap0 + +default-information originate +route {{ subnet_to_announce }} + +version 2 + +key chain {{ environment_name }} + key 1 + key-string FVeKWpAUkTZPMZjyKXljIJy + +interface tap0 + ip rip authentication mode md5 + ip rip authentication key-chain {{ environment_name }} + +log stdout diff --git a/roles/vpcaccess/templates/zebra.conf.j2 b/roles/vpcaccess/templates/zebra.conf.j2 new file mode 100644 index 0000000..4e27500 --- /dev/null +++ b/roles/vpcaccess/templates/zebra.conf.j2 @@ -0,0 +1,11 @@ +! -*- zebra -*- +! +! zebra configuration file +! + +hostname {{ ansible_ec2_hostname }} +password {{ QUAGGA_PASSWORD }} +enable password {{ QUAGGA_PASSWORD }} + +interface tap0 + description vpn interface diff --git a/vpcaccess.yml b/vpcaccess.yml new file mode 100644 index 0000000..1abeed9 --- /dev/null +++ b/vpcaccess.yml @@ -0,0 +1,6 @@ +--- +- hosts: vpcaccess + become: true + roles: + - common + - vpcaccess -- 2.45.2