We will use Terraform to stand up an environment to use Ansible from and on. The Ansible control node, which is where Ansible runs from, needs to be a Linux system with Python installed. We will create 3 target systems that we will configure using Ansible. Those systems will have the web server ports exposed to the public internet, but will otherwise only be accessible from the control node and other targets.
The variables that need to be populated are listed in the documentation at the bottom of this file. This documentation is generated from the Terraform code itself using terraform-docs.
$ terraform-docs markdown table --output-file README.md --output-mode inject .
README.md updated successfully
Create terraform.tfvars
:
aws_region = "us-east-2"
owner_email = "[email protected]"
key_name = "gene-test-us-east-2"
private_key_file = "/home/ggotimer/.ssh/gene-test-us-east-2.pem"
Then we can use Terraform to create the environment. The remote_exec
provisioner will
make it take longer that we've seen.
$ terraform init
...
$ terraform apply
...
Outputs:
target_instance_ids = [
"i-063e6e1b8ac71119d",
"i-035125762cbce935d",
"i-00fbe57ff4efea08a",
]
target_private_ips = [
"10.8.0.10",
"10.8.0.41",
"10.8.0.178",
]
target_public_ips = [
"18.117.70.148",
"18.188.98.141",
"18.116.43.247",
]
workstation_instance_id = "i-02890a16937a7af84"
workstation_private_ip = "10.8.0.26"
workstation_public_ip = "3.142.171.59"
We'll need to use these output values in this and later lessons. If the values scroll
off the screen, we can use terraform output
to extract them from the state
file again. That means we have to run the commands in this directory so Terraform finds
the right state, or we'll have to use the -state=path
option to point to the
correct terraform.tfstate
file.
$ terraform output
target_instance_ids = [
"i-063e6e1b8ac71119d",
"i-035125762cbce935d",
"i-00fbe57ff4efea08a",
]
target_private_ips = [
"10.8.0.10",
"10.8.0.41",
"10.8.0.178",
]
target_public_ips = [
"18.117.70.148",
"18.188.98.141",
"18.116.43.247",
]
workstation_instance_id = "i-02890a16937a7af84"
workstation_private_ip = "10.8.0.26"
workstation_public_ip = "3.142.171.59"
$ terraform output target_private_ips
[
"10.8.0.10",
"10.8.0.41",
"10.8.0.178",
]
$ cd ..
$ terraform output -state=lesson-04/terraform.tfstate workstation_public_ip
"3.142.171.59"
SSH into the Ansible workstation using the workstation_public_ip
and the key file
we specified. The username is ubuntu
.
$ ssh -i /home/ggotimer/.ssh/gene-test-us-east-2.pem [email protected]
The authenticity of host '3.142.171.59 (3.142.171.59)' can't be established.
ED25519 key fingerprint is SHA256:s14sJUQRjUGCD5/9SE9SeVcfsV0f3qDocxrwrSPSMbM.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '3.142.171.59' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.19.0-1026-aws x86_64)
...
ubuntu@ip-10-8-0-26:~$
On the Ansible workstation, we'll run our first Ansible command to verify it is installed correctly.
ubuntu@ip-10-8-0-26:~$ ansible localhost -m ping
[WARNING]: No inventory was parsed, only implicit localhost is available
localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}
If we get a pong
back from our ping
, then Ansible was able to log onto
the target (localhost
in this case) and run a command.
We'll leave the environment running for now since we'll be using it for the upcoming lessons. We can destroy it later (and recreate it again if we need to).
It might be easier in a lot of ways if we used our laptop as our Ansible control node instead of creating a workstation in AWS and working remotely. But there are reasons we aren't doing that. Some of them are:
- Installing the correct version of Python is generally easy, but only if another version of Python isn't already installed.
- Set up and configuration on different OSes and platforms sometimes has subtle or non-subtle differences.
- Use of the command line (e.g., escaping special characters) differs between shells.
- It is safer to work in a sandbox as closed off from the public internet as possible, especially while we are learning.
- Using a system near the target network as a bastion host or workstation is not an uncommon pattern.
- SSH tunneling can be non-trivial to set up and troubleshoot, especially on multiple platforms and SSH clients.
- We aren't using this environment for an extended period.
So in the interest of simplifying the workshop, I chose to use a remote control node. It just makes for a smoother, more homogeneous workshop experience.
That said, we could do the rest of the exercises with some changes to the security groups on the targets, eliminating the workstation, and making sure Ansible is installed and configured correctly on our laptop. If you choose to go that route, caveat lector. The necessary changes are left as an exercise for the reader.
In the next lesson, we'll start looking at some Ansible basics.
Name | Version |
---|---|
terraform | >= 1.8.3 |
aws | ~> 5.49.0 |
Name | Version |
---|---|
aws | 5.49.0 |
No modules.
Name | Type |
---|---|
aws_default_security_group.default | resource |
aws_instance.target | resource |
aws_instance.workstation | resource |
aws_internet_gateway.sandbox_gateway | resource |
aws_route_table.rtb_public | resource |
aws_route_table_association.rta_subnet_public | resource |
aws_security_group.target_sg | resource |
aws_security_group.workstation_sg | resource |
aws_security_group_rule.target_sg_allow_all_outgoing | resource |
aws_security_group_rule.target_sg_allow_internal_mongodb | resource |
aws_security_group_rule.target_sg_allow_public_http | resource |
aws_security_group_rule.target_sg_allow_public_https | resource |
aws_security_group_rule.target_sg_allow_workstation_mongodb | resource |
aws_security_group_rule.target_sg_allow_workstation_ssh | resource |
aws_subnet.public_subnet | resource |
aws_vpc.sandbox_vpc | resource |
aws_ami.ubuntu_focal | data source |
aws_ami.ubuntu_jammy | data source |
Name | Description | Type | Default | Required |
---|---|---|---|---|
aws_profile | Local AWS profile to use for AWS credentials | string |
"default" |
no |
aws_region | AWS region to build in | string |
n/a | yes |
key_name | Name of an already-installed AWS keypair | string |
n/a | yes |
owner_email | Email address to tag resources with | string |
n/a | yes |
private_key_file | Path to the private key of the already-installed AWS keypair | string |
n/a | yes |
project_tag | Project name to tag resources with for grouping | string |
"IntroToTerraformAndAnsible" |
no |
Name | Description |
---|---|
target_instance_ids | IDs of the Ansible target instances |
target_private_ips | Private IP addresses of the Ansible targets |
target_public_ips | Public IP addresses of the Ansible targets |
workstation_instance_id | ID of the Ansible workstation instance |
workstation_private_ip | Private IP address of the Ansible workstation |
workstation_public_ip | Public IP address of the Ansible workstation |