Ansible EC2 Example - Create EC2 instance with Ansible

Ansible Create EC2

Infrastructure as Code is getting all attention it deserves and everyone is trying to find their way to the `Completely automated Infrastructure Provisioning & Management`

While there are a lot of tools available now in the market starting from Terraform, AWS CloudFormation, Chef, Puppet, Salt Stack

There are some differences between each tool. Some of them are configuration management tools (Ansible, Chef, Saltstack) and Some of them are purely provisioning tools (terraform, cloud formation). You have to choose your judgement based on various factors like Easy to learn, easy to adopt.

Though Terraform is a wonderful cross-platform provisioning tool I feel it has a steep learning curve. while Ansible is not that complex to start with an easy to learn and adopt.

So this post is for those ( including me ) who love ansible's simplicity and structure and want to see how it works with AWS.

This is going to be a quick introduction to Ansible AWS Ec2 module.

 

How Ansible works with AWS EC2 - Setup Boto for Ansible

Ansible AWS combo is more like Hobbs and Shah ( Sorry! I am Fast & Furious Fan) while both of em have their own individual stardom they join together to create magic.

Stupid analogy right.!!!

Jokes Apart, But Ansible is a leader in configuration management tools and AWS is a leader in Cloud solutions and no doubt that they give best results as combined for the Infrastructure automation and management.

In Ansible Parlance, Everything is a module and Yes ansible provides ample amount of modules to work with AWS resource. As I am typing this post, Ansible has 194 officially listed modules for aws. here is a list

All these modules are helping us to accomplish a various level of tasks in AWS cloud resources creation, deletion, management, assessment etc

Our objective is precise, we want to create an EC2 Instance using Ansible and Ansible has a module for that named ec2

Before we jump right into the playbooks and stuff. we need to do some environment setup.

 

Environment Setup for Ansible to work with AWS EC2 module

As we all know Ansible is pythonic and their modules are written in python as well. So for AWS modules to work you need to have Certain prerequisite elements installed on your Ansible Control machine ( where you have installed ansible )

  • boto
  • boto3
  • botocore
  • python version >=  2.6

You can install python easily but what is this boto. boto is one of the Amazon supported SDK. Boto3 is the latest version of boto.

to make sure you have boto installed in your python. Just Launch your Python interactive terminal and type import boto and import boto3 if it works fine ( shows no error) you are good.

to install boto and boto3 you must have pip3 as well. If you are having python 2.7 there are chances you might have this bundled in.

Some times when you have two versions of python installed in your system you have to try them out both and make sure which one has the boto installed. by performing the `import boto` command so that you can avoid some exceptions like this

If you take my  MAC, for example, I have two python version installed, One is at /usr/local/bin/python another one is at  /usr/bin/python One comes as built-in with OS another one is installed by `homebrew` , I had to lauch them both and check the if the boto package is present in there like shown below.

You could see that my /usr/local/bin/python3 all necessary modules installed,

 Note:

It is known that Python3 may not work properly with Ansible old versions. In that case, you can  choose  to install your boto libraries in python 2.7.* version and it use it as your primary version in ansible_python_interpreter

 

This is just a method to find the right python package to use it with ansible

The path and everything could be different for you. Before executing these commands, update the paths based on your local installation.

Now I presume that you have a python with these necessary modules installed.

 

Ansible Playbook to create a new EC2 instance

Here is the playbook to create EC2 instances and also to get the list of in your AWS Cloud account.

We have used two blocks here (a block is just a group of tasks )

  • The first block is to just get the instances information
  • The second block is to create the instance

For security reasons, we made the Second block to run only when it is being explicitly called with --tags

this has been done by using the tag  never in the block

---
- name: Create Ec2 instances
  hosts: localhost
  gather_facts: false
  tasks:

  # Block is a Group of Tasks combined together
  - name: Get Info Block
    block: 
      - name: Get Running instance Info
        
        ec2_instance_info:
        register: ec2info 

      - name: Print info
        debug: var="ec2info.instances"
             

    # By specifying always on the tag, 
    # I let this block to run all the time by module_default
    # this is for security to net create ec2 instances accidentally
    tags: ['always', 'getinfoonly']

  - name: Create EC2 Block
    block: 

      - name: Launch ec2 instances
        tags: create_ec2
        ec2:
          region: us-east-1
          key_name: SaravAK-PrivateKey 
          group: app_sec_group
          instance_type: t2.medium
          image: ami-2051294a
          wait: yes
          wait_timeout: 500
          count: 2
          instance_tags:
            name: appservers
            os: ubuntu
          monitoring: no
          vpc_subnet_id: subnet-3d3ef270
          assign_public_ip: yes
        register: ec2
        delegate_to: localhost

      - name : Add instance to host group
        add_host:
          hostname: "{{ item.public_ip }}"
          groupname: launched
        loop: "{{ ec2.instances }}"

      - name: Wait for SSH to come up
        local_action:
          module: wait_for
          host: "{{ item.public_ip }}"
          port: 22
          delay: 10
          timeout: 120
        loop: "{{ ec2.instances }}"
    # By specifying never on the tag of this block, 
    # I let this block to run only when explicitely being called
    tags: ['never', 'ec2-create']

 

 

You might wonder where is my AWS Key and SECRET mentioned. How would I be able to login to my AWS account? How the authentication will be done.

I hear ya.

 

Setup AWS Authentication Before Running the Playbook with Ansible EC2

To make this article precise, I just assume that you know how to create programmatic access for your AWS account and get your AWS_ACCESS_KEY and AWS_SECRET

Once you have the keys, the easiest but an unsecured way is to save it as Environment Variables like this and we are all set.

 

Getting ready to execute the playbook - Ansible AWS EC2

Before executing the playbook you must be sure which python interpreter you are going to use which has `boto` libraries installed.

When it comes to using EC2 modules, It is always better to tell ansible explicitly which python interpreter it has to use.

In my case, as I have said before my /usr/local/bin/python3 has the necessary boto libraries and I have to tell ansible to use that python.

to do that, I can use ansible.cfg file or  ansible inventory file but I prefer to do it in a command line as a runtime variable

Here is the command I supposed to use

ansible-playbook ec2-creation.yml  \
--connection=local  \
-e "ansible_python_interpreter=/usr/local/bin/python3"

 

Here

--connection  tells Ansible to run this task locally and not look for any remote server or hosts file

--e extra args or variables where we gave the python interpreter by setting the python full location to ansible_python_interpreter variable

when I run this, I would get only the info of existing instances. it would not create the instances yet. as we have the info as the default block

Now to create the ec2 instance or to run that block, I need to call the tag of that block using --tags like shown below.

ansible-playbook ec2-creation.yml \ 
--connection=local \ 
--tags=ec2-create \ 
-e "ansible_python_interpreter=/usr/local/bin/python3"

 

 

Execution Part - Run the playbook with Ansible EC2

Here is the execution and the result of this playbook.

 

 

A Playbook with Ansible EC2 & Ansible Vault - Secure Approach

to use the Ansible vault to securely store your AWS Keys, You might need one more file on the same directory where you can save your credentials as variables and encrypt it with the vault.

The file can be imported later within the playbook.

Here is the modified playbook with a secure approach, Ansible Vault

---
- name: Create Ec2 instances
  hosts: localhost
  # import the secret file
  vars_files:
    - secrets.yml
  gather_facts: false
  tasks:

  # Block is a Group of Tasks combined together
  - name: Get Info Block
    block: 
      - name: Get Running instance Info
        
        ec2_instance_info:
        register: ec2info 

      - name: Print info
        debug: var="ec2info.instances"
             

    # By specifying always on the tag, 
    # I let this block to run all the time by module_default
    # this is for security to net create ec2 instances accidentally
    tags: ['always', 'getinfoonly']

  - name: Create EC2 Block
    block: 

      - name: Launch ec2 instances
        tags: create_ec2
        ec2:
          region: us-east-1
          key_name: SaravAK-PrivateKey
          group: app_sec_group
          instance_type: t2.medium
          image: ami-2051294a
          wait: yes
          wait_timeout: 500
          count: 2
          instance_tags:
            name: appservers
            os: ubuntu
          monitoring: no
          vpc_subnet_id: subnet-3d3ef270
          assign_public_ip: yes
        register: ec2
        delegate_to: localhost

      - name : Add instance to host group
        add_host:
          hostname: "{{ item.public_ip }}"
          groupname: launched
        loop: "{{ ec2.instances }}"

      - name: Wait for SSH to come up
        local_action:
          module: wait_for
          host: "{{ item.public_ip }}"
          port: 22
          delay: 10
          timeout: 120
        loop: "{{ ec2.instances }}"
    # By specifying never on the tag of this block, 
    # I let this block to run only when explicitely being called
    tags: ['never', 'ec2-create']

 

 

 

Saving the AWS Secrets

As we have included the secrets.yml file inside our playbook, Now we need to save our AWS KEY and SECRET

This is the content of the secret.yml file

➜ cat secrets.yml 
AWS_ACCESS_KEY_ID: AKIATQ7Q7SGKYB4TT3DX 
AWS_SECRET_ACCESS_KEY: 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

 

It is saved as clear text info within the file so whoever opens it can see what is inside.

So Encrypt it

➜ ansible-vault encrypt secrets.yml 
New Vault password: 
Confirm New Vault password: Encryption successful

 

Now you have to remember this password and use it while you are starting the playbook.

For Ansible to ask you the password you should use a startup argument named --ask-vault-pass

ansible-playbook ec2-creation.yml \ 
--connection=local \ 
--tags=ec2-create \ 
-e "ansible_python_interpreter=/usr/local/bin/python3" \ 
--ask-vault-pass

 

It would prompt you for the password as it runs.

See the following Screen record if you want to see how it works in realtime.

 

Execution of Ansible AWS Playbook example

 

I know this is just a first step, Now you have got better things to do with that newly created server and install and configure it. you might have further questions on how to use these servers and configure them properly on the same playbook.

Please stay connected and Lookup for my next article. I am already drafting it.

hope this helps.

Rate this article [ratings] if you would like to

 

Cheers
Sarav AK

Follow me on Linkedin My Profile
Follow DevopsJunction onFacebook orTwitter
For more practical videos and tutorials. Subscribe to our channel

Buy Me a Coffee at ko-fi.com

Signup for Exclusive "Subscriber-only" Content

Loading