Using Ansible to create AWS instances
EC2 modules for Ansible require the boto python library to work
The only other prerequisite is setting up 2 environment variables:
AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
Our tasks will use a couple of variables:
env: "staging" # env name, this will be used as an inventory file name app_code_user: "ubuntu" # remote user aws_region: eu-central-1 # AWS region, where instance will be created instance_type: t2.micro # AWS instance type ami: ami-b83c0aa5 # AMI id, example uses Ubuntu 14.04.1 LTS
With that completed we can write the first task, which will create the security group for our instance:
- name: Create security group ec2_group: name: "{{ project_name }}_security_group" description: "{{ project_name }} security group" region: "{{ aws_region }}" rules: - proto: tcp type: ssh from_port: 22 to_port: 22 cidr_ip: 0.0.0.0/0 - proto: tcp type: http from_port: 80 to_port: 80 cidr_ip: 0.0.0.0/0 - proto: tcp type: https from_port: 443 to_port: 443 cidr_ip: 0.0.0.0/0 rules_egress: - proto: all type: all cidr_ip: 0.0.0.0/0 register: basic_firewall
We allow ssh, http, and https traffic, then register
the output of that command for later use. After that we need to create a new ssh key pair to use for logging in.
- name: Create an EC2 key ec2_key: name: "{{ project_name }}-{{ env }}-key" region: "{{ aws_region }}" register: ec2_key
After we save the private key contents to a file (this should never be committed into VCS, I’d recommend updating the ignore list to include *.pem files) to use later when we log in to add public developer keys to the instance.
- name: save private key copy: content="{{ ec2_key.private_key }}" dest="./aws-{{ env }}-private.pem" mode=0600 when: ec2_key.changed
Now we can create an EC2 instance.
- name: Create an EC2 instance ec2: key_name: "{{ project_name }}-{{ env }}-key" region: "{{ aws_region }}" group_id: "{{ basic_firewall.group_id }}" instance_type: "{{ instance_type }}" image: "{{ ami }}" wait: yes instance_tags: env: "{{ env }}" count_tag: env exact_count: 1 register: ec2
After that we save the instance IP as a new inventory file. Ansible Dynamic Inventory could be used to access IPs dynamically, but would require setting up AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
every time the deployment playbook is run, which is inconvenient. We also create a new group, which we will be using in the task to copy developers’ public keys.
- name: save IP to inventory file copy: content="[webservers]{{'n'}}{{ item.public_ip }}" dest=./{{ env }} with_items: ec2.tagged_instances - name: Add IP to ec2_hosts group add_host: hostname={{ item.public_ip }} groups=ec2_hosts with_items: ec2.tagged_instances
This is the end of the create task. We’ll need another one to add developer keys to the instance.
- name: Make sure user is on server and generate ssh key for it user: name={{ app_code_user }} generate_ssh_key=yes - name: Add public keys for developers authorized_key: user={{ app_code_user }} key="{{ lookup('file', item) }}" with_fileglob: - ../public_keys/*.pub
First we make sure the user is on the server, then we update authorized_keys
for the user with all the developer keys found in the public_keys
directory. This is an example directory structure of the users
role:
├── users │ ├── public_keys │ │ └── bruce-wayne.pub │ │ └── tony-stark.pub │ │ └── clark-kent.pub │ └── tasks │ └── main.yml
Finally we create the playbook, where we run previously-created tasks.
- name: Create AWS instance hosts: 127.0.0.1 connection: local gather_facts: False remote_user: ubuntu roles: - create - name: Add user keys hosts: ec2_hosts sudo: yes sudo_user: root remote_user: ubuntu roles: - users
After you verify everything is working properly (you can ssh into the instance, etc.), the private key can be deleted and the inventory file created by the role can be committed to VCS so everyone working on the project can deploy to new instance.
This is a simple configuration that creates a single instance. EC2 modules for Ansible have many more possible uses, like batch creation of multiple instances, allocating RDS resources, etc. I highly recommend taking the time to learn and set up Ansible in your projects, as the initial time investment ends up paying for itself fast.