Deploy to AWS
Deploy an Ansible development environment to AWS.
The Ansible development environment in AWS
will comprise the following:
- A Virtual Private Cloud(VPC)
- A subnet
- An internet gateway
- A route for public traffic into the VPC
- Windows EC2 instance with
Windows Server 2019
Amazon Machine Image(AMI) - Linux EC2 instance with
Red Hat Enterprise Linux 8
Amazon Machine Image(AMI)
Free Tier
Both the
AMIs
used are within the free tier.
Ansible Modules
The following Ansible Modules
can be used to deploy the resources on AWS
using Ansible playbooks:
AWS Resource | Ansible Module |
---|---|
VPC | ec2_vpc_net |
Subnet | ec2_vpc_subnet |
Internet Gateway | ec2_vpc_igw |
Route Table | ec2_vpc_route_table |
Security Group | ec2_group |
Key Pair | ec2_key |
EC2 Instance | ec2 |
Elastic IP Address | ec2_eip |
Ansible codifies your infrastructure in YAML files called Ansible playbooks. You will use pre-written Ansible playbooks to deploy the Ansible development environment to AWS.
Resource Dependency
Several of theAWS
resources depend on other resources. These dependencies mean that you have to run the playbooks in the right order.
Let’s start exploring the playbooks we will cover in this lesson one by one:
Create a VPC
Before you can deploy an Elastic Compute Cloud(EC2) instance, you have to provision a VPC
. You will provision a VPC
with a subnet, an internet gateway, and a route table entry for public traffic. Review the aws_create_vpc.yaml
playbook below:
--- - hosts: localhost gather_facts: false connection: local tasks: - name: create vpc ec2_vpc_net: name: ansible cidr_block: 10.0.0.0/16 region: us-east-1 tags: Name: ansible-vpc app: ansible env: dev state: present register: ansible_vpc - name: create subnet ec2_vpc_subnet: region: us-east-1 vpc_id: "{{ ansible_vpc.vpc.id }}" cidr: 10.0.1.0/24 map_public: yes tags: Name: ansible-subnet app: ansible env: dev state: present register: ansible_subnet - name: create internet gateway ec2_vpc_igw: vpc_id: "{{ ansible_vpc.vpc.id }}" region: us-east-1 state: present tags: Name: "ansible-igw" app: ansible env: dev register: igw - name: Route IGW ec2_vpc_route_table: vpc_id: "{{ ansible_vpc.vpc.id }}" region: us-east-1 subnets: - "{{ ansible_subnet.subnet.id }}" routes: - dest: 0.0.0.0/0 gateway_id: "{{ igw.gateway_id }}" tags: Name: ansible-public
Ansible playbook
Ansible playbooks are written in YAML
and have two main sections:
- Hosts
- Tasks
Hosts
Hosts determine which hosts are targeted by the playbook. Refer to Line 2-4 for hosts in the above playbook.
Tasks
Tasks define what Ansible will execute sequentially. From Line 6 onwards, you can observe all the tasks
that the Ansible will perform.
You have four tasks in the playbook. create vpc
is the first task’s name. It uses the Ansible module ec2_vpc_net
to create a VPC
in AWS
. This Ansible module provides an interface to configure the VPC
using parameters and arguments. Line 10 in the playbook represents the argument passed to the ec2_vpc_net
module.
Ansible Modules Ansible modules are reusable, standalone scripts that Ansible executes. A module provides a defined interface, accepting arguments, and returning information to Ansible through a JSON string to stdout as output.
You can execute the playbook by clicking on the Run button. The Run button executes the following command in the environment:
ansible-playbook aws_create_vpc.yaml
Deploy a Windows EC2 instance
Before you can create a Windows Server 2019 EC2
instance, you need the following AWS
resources:
- Virtual Private Cloud
- Previously created by executing the
aws_create_vpc.yaml
.
- Previously created by executing the
- Security Group
- Virtual firewall for your instance to control inbound and outbound traffic.
- Key Pair
- To encrypt and decrypt login information.
- EC2 Instance
- Virtual machine running Windows Server 2019 Operating System.
- Ami Id
- The id of
Microsoft Windows Server 2019 Core
image from the AWS marketplace.
- The id of
Note: If we want to use the latest or a different image, we can find it here.
Each of these AWS
resources correlates to an Ansible Module. Review the aws_create_windows_ec2_instance.yaml
playbook below:
--- - hosts: localhost gather_facts: false connection: local tasks: - pause: prompt: "Enter password" echo: no when: password is undefined register: password_input - set_fact: password: "{{ password_input.user_input }}" when: password is undefined - ec2_vpc_net_info: region: us-east-1 filters: "tag:Name": ansible register: ansible_vpc - ec2_vpc_subnet_info: region: us-east-1 filters: vpc-id: "{{ ansible_vpc.vpcs[0].id }}" register: ansible_subnet - name: webserver security group ec2_group: name: windows description: windows sg vpc_id: "{{ ansible_vpc.vpcs[0].id }}" region: us-east-1 tags: Name: windows app: ansible env: dev rules: - proto: tcp from_port: 80 to_port: 80 cidr_ip: 0.0.0.0/0 rule_desc: allow all on port 80 - proto: tcp from_port: 3389 to_port: 3389 cidr_ip: 0.0.0.0/0 rule_desc: allow all RDP on port 3389 - proto: tcp from_port: 5986 to_port: 5986 cidr_ip: 0.0.0.0/0 rule_desc: allow all HTTPS via WinRM on 5986 - proto: tcp from_port: 5985 to_port: 5985 cidr_ip: 0.0.0.0/0 rule_desc: allow all HTTP via WinRM on 5985 - name: create a new ec2 key ec2_key: name: aws-ansible-key region: us-east-1 state: present register: ec2_key - name: Save private key to disk copy: content="{{ ec2_key.key.private_key }}" dest="./aws-ansible-key.pem" mode=0600 when: ec2_key.changed - name: windows - create ec2 instance ec2: key_name: aws-ansible-key instance_type: t2.micro image: {{Ami_Id}} region: us-east-1 group: windows count: 1 vpc_subnet_id: "{{ ansible_subnet.subnets[0].id }}" user_data: | <powershell> $content = (Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1' -UseBasicParsing).content iex $content $password = "{{ password }}" | ConvertTo-SecureString -AsPlainText -Force New-LocalUser 'ansible' -Password $password Add-LocalGroupMember -Group 'Administrators' -Member 'ansible' </powershell> <persist>true</persist> wait: yes assign_public_ip: yes instance_tags: Name: winweb01 app: ansible env: dev os: windows register: ec2 - name: associate new elastic IPs with each of the instances ec2_eip: device_id: "{{ item }}" release_on_disassociation: yes region: us-east-1 loop: "{{ ec2.instance_ids }}" # - name: get the Administrator password # ec2_win_password: # profile: my-boto-profile # instance_id: i-XXXXXX # region: us-east-1 # key_file: "~/aws-creds/my_test_key.pem"
Once again, you can execute the playbook by clicking on the Run
button.
aws-ansible-key.pem
When the aws_create_windows_ec2_instance.yaml
playbook ends, it will output a file called aws-ansible-key.pem
. This is the private key for the ansible_key key pair in AWS
. The private key is used to get the login information for the EC2
instance.
The Run
button executes the following command,
ansible-playbook aws_create_windows_ec2_instance.yaml
Once run, you will be prompted for a password. You can use a password of your own choice.
Password Strength
By default, there is a password policy on all Windows servers. Use a strong password with at least 8 characters that are a mixture of the following:
- English uppercase characters (A through Z).
- English lowercase characters (a through z).
- Base 10 digits (0 through 9).
- Non-alphabetic characters (for example, !, $, #, %).
The password provided will be used later to connect to the virtual machine.
Gather Information
The
ec2_vpc_net_info
andec2_vpc_subnet_info
are used to gather information about theVPC
. You will learn more about this technique in the upcoming chapters.
Deploy a Linux EC2 instance
Deploying a Linux EC2 instance with Ansible is identical to that of a Windows EC2 instance. Review the aws_create_linux_ec2_instance.yaml
playbook below. It uses the same modules as before and only requires the arguments
to be changed:
- The
AMI
number - Security Group Rules
--- - hosts: localhost gather_facts: false connection: local tasks: - pause: prompt: "Enter password" echo: no when: password is undefined register: password_input - set_fact: password: "{{ password_input.user_input }}" when: password is undefined - ec2_vpc_net_info: region: us-east-1 filters: "tag:Name": ansible register: ansible_vpc - ec2_vpc_subnet_info: region: us-east-1 filters: vpc-id: "{{ ansible_vpc.vpcs[0].id }}" register: ansible_subnet - name: linux security group ec2_group: name: linux description: linux sg vpc_id: "{{ ansible_vpc.vpcs[0].id }}" region: us-east-1 tags: Name: linux app: ansible env: dev rules: - proto: tcp from_port: 22 to_port: 22 cidr_ip: 0.0.0.0/0 rule_desc: allow all on port 22 - proto: tcp from_port: 80 to_port: 80 cidr_ip: 0.0.0.0/0 rule_desc: allow all on port 80 - name: create a new ec2 key ec2_key: name: aws-ansible-key region: us-east-1 state: present register: ec2_key - name: Save private key to disk copy: content="{{ ec2_key.key.private_key }}" dest="./aws-ansible-key.pem" mode=0600 when: ec2_key.changed - name: linux - create ec2 instance ec2: key_name: aws-ansible-key instance_type: t2.micro image: ami-0c322300a1dd5dc79 region: us-east-1 group: linux count: 1 vpc_subnet_id: "{{ ansible_subnet.subnets[0].id }}" user_data: | #!/bin/bash sudo adduser ansible sudo echo "{{ password }}" | passwd --stdin ansible echo 'ansible ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers sudo sed -n 'H;${x;s/\PasswordAuthentication no/PasswordAuthentication yes/;p;}' /etc/ssh/sshd_config > tmp_sshd_config sudo cat tmp_sshd_config > /etc/ssh/sshd_config rm -f tmp_sshd_config sudo service sshd restart wait: yes assign_public_ip: yes instance_tags: Name: linuxweb01 app: ansible env: dev os: linux register: ec2 - name: associate new elastic IPs with each of the instances ec2_eip: device_id: "{{ item }}" region: us-east-1 release_on_disassociation: yes loop: "{{ ec2.instance_ids }}"
Execute the playbook by clicking on the Run
button. Once again, use the password of your own choice when prompted. The following command is executed when you click the Run
button:
ansible-playbook aws_create_linux_ec2_instance.yaml
Delete the environment
All the above infrastructure lies in the free tier. You will be using these resources in the upcoming lessons and chapters. In case you are going to visit the next lessons later, you can take down the resources to avoid any unexpected bills.
You can take these resources down by executing the playbook below.
Disclaimer: _Run the playbook at your own risk!
It is highly recommended you use a development AWS account.
Review the playbook:
--- - hosts: localhost gather_facts: false connection: local vars: ec2_ids: [] sg_ids: [] tasks: - ec2_vpc_net_info: region: us-east-1 filters: "tag:Name": ansible register: ansible_vpc - name: get ec2 instance info ec2_instance_info: region: us-east-1 filters: "tag:app": ansible "tag:env": dev instance-state-name: [ "running" ] register: ec2 - set_fact: ec2_ids: "{{ ec2_ids }} + [ '{{ item.instance_id }}' ]" loop: "{{ ec2['instances'] }}" loop_control: label: "{{ item.instance_id }}" - name: disassociate an elastic IP from an instance ec2_eip: region: us-east-1 release_on_disassociation: yes device_id: "{{ item }}" state: absent with_items: "{{ ec2_ids }}" - name: terminate ec2 instances ec2: state: 'absent' region: us-east-1 instance_ids: "{{ item.instance_id }}" with_items: "{{ ec2.instances }}" - name: sleep for 30 seconds wait_for: timeout: 30 delegate_to: localhost - ec2_group_info: region: us-east-1 filters: group_name: - linux - windows vpc-id: "{{ ansible_vpc.vpcs[0].id }}" register: sgs - set_fact: sg_ids: "{{ sg_ids }} + [ '{{ item.group_id }}' ]" loop: "{{ sgs['security_groups'] }}" loop_control: label: "{{ item.group_id }}" - name: delete security groups ec2_group: region: us-east-1 group_id: "{{ item }}" state: absent loop: "{{ sg_ids }}" - name: delete internet gateway ec2_vpc_igw: vpc_id: "{{ ansible_vpc.vpcs[0].id }}" region: us-east-1 state: absent tags: Name: "ansible-igw" app: ansible env: dev - name: delete subnet ec2_vpc_subnet: region: us-east-1 cidr: 10.0.1.0/24 vpc_id: "{{ ansible_vpc.vpcs[0].id }}" tags: Name: ansible-subnet app: ansible env: dev state: absent - name: delete route IGW ec2_vpc_route_table: vpc_id: "{{ ansible_vpc.vpcs[0].id }}" region: us-east-1 tags: Name: ansible-public state: absent - name: delete VPC ec2_vpc_net: name: ansible region: us-east-1 cidr_block: 10.0.0.0/16 tags: Name: ansible-vpc app: ansible env: dev state: absent
Execute the playbook by clicking on the Run
button. It will execute the following command:
ansible-playbook aws_delete_ansible_env.yaml
In this lesson, we introduced Ansible playbooks and modules to create the VPC
and the EC2
instances with Linux and Windows operating systems.
Download the Source Code
You can download the playbooks for this lesson from the Github repository, become Ansible.
Get hands-on with 1300+ tech skills courses.