DEV Community

Simplified Retrieval of Terraform Output for Ansible via AWS SSM Parameter Store πŸš€

I recently had to work with Ansible for the first time. I needed to install software on several EC2 instances, and I was given an Ansible playbook that I needed to execute.

When examining the structure of the Ansible folder, I noticed that I had to update certain variables within a file named 'specifics.yml.' These variables were formatted as follows:

nfs_mounts:
  - src: "myNfsDNSname:/"

my_super_infra:
  hosts:
    10.10.10.10:
Enter fullscreen mode Exit fullscreen mode

I initially began working with it. However, as I continued testing, I found myself making numerous deployments with Terraform. Each time, I had to modify my code to include the new EFS DNS name, which proved to be quite a hassle.

For context, I had established a CI/CD pipeline using Gitlab-CI for this project, which had the following structure:

Gitlab CI structure

From that point on, I needed to discover a way to dynamically obtain values generated during the Terraform 'apply' stage. Initially, I considered using Terraform to create a file at the end of the 'apply' stage containing the output of my modules. While this approach would work, it would also make the execution of the Ansible job dependent on the completion of the Terraform 'apply' stage. This was not what I wanted; I aimed to run the Ansible playbook without having to go through Terraform each time.

So, I came up with this idea: introduce a Terraform module that stores the necessary variables in the AWS SSM Parameter Store. This module takes certain variables as input, which are the outputs of my modules that I wish to retrieve in Ansible, such as the EFS DNS name. To achieve this, you only need to include the following code snippet for each of your variables:

resource "aws_ssm_parameter" "efs_dns_url" {
  name  = "OUTPUT_EFS_DNS_URL"
  type  = "String"
  value = var.efs_dns_url
}
Enter fullscreen mode Exit fullscreen mode

You can also use count if you have a list (for example a list of IPs) :

resource "aws_ssm_parameter" "my_ip" {
  count = length(var.my_ip)
  name  = "OUTPUT_MY_IP_${count.index}"
  type  = "String"
  value = var.my_ip[count.index]
}
Enter fullscreen mode Exit fullscreen mode

With this step, the initial part of my strategy was set up. The next challenge was to retrieve these values within my Ansible 'specifics.yml' file. As I delved into the documentation, I came across a page in the Ansible documentation that was precisely what I needed! The first step was to include the requirements in the 'requirements.yml' file:

  - name: amazon.aws
    version: 6.5.0
Enter fullscreen mode Exit fullscreen mode

Then, you remember the specifics.yml ? it now looks like this :

nfs_mounts:
    - src: "{{ lookup('amazon.aws.aws_ssm', 'OUTPUT_EFS_DNS_URL', region='eu-central-1' ) }}:/"
Enter fullscreen mode Exit fullscreen mode

It's as straightforward as that! You can now fetch specific values from Terraform directly into your Ansible playbook. This is incredibly convenient. The only drawback I've encountered here is the output when you execute the playbook, particularly when you utilize it for the host section, like:

my_block:
  hosts:
    "{{ lookup('amazon.aws.aws_ssm', 'OUTPUT_MY_IP_0', region='eu-central-1' )}}":
    "{{ lookup('amazon.aws.aws_ssm', 'OUTPUT_MY_IP_1', region='eu-central-1' )}}":
Enter fullscreen mode Exit fullscreen mode

When you run the playbook with this kind of setup, you get an output which looks like this :

Ansible host ugly output

This is not ideal, you can change it using variables, but I haven’t found a way yet to get the IP here instead of a placeholder. If you have an idea, feel free to reach out to me via the comments or on my socials.

Top comments (0)