๐Ÿถ
Terraform

Terraform Output to Ansible: Using vars_files

By Filip on 11/14/2024

Learn how to streamline your infrastructure automation by seamlessly passing Terraform output variables into Ansible playbooks as vars_files for efficient and dynamic configuration management.

Terraform Output to Ansible: Using vars_files

Table of Contents

Introduction

This document outlines the process of passing variables from Terraform to Ansible, enabling seamless integration between infrastructure provisioning and configuration management. The process involves defining outputs in Terraform, capturing these outputs, and then referencing them as variables within your Ansible playbooks.

Step-by-Step Guide

  1. Output Terraform Variables: In your Terraform code, define outputs for the variables you want to pass to Ansible.

    output "subnet_id" {
      value = aws_subnet.example.id
    }
  2. Capture Terraform Outputs: Use a tool like terraform output or jq to capture the output values and store them in a JSON or YAML file.

    terraform output -json > terraform.json
  3. Create Ansible Vars File: Create a YAML file (e.g., vars.yml) to store the Terraform outputs as Ansible variables.

    subnet_id: "{{ lookup('file', 'terraform.json') | from_json | json_query('subnet_id') }}"
  4. Use Variables in Ansible Playbook: In your Ansible playbook, reference the variables defined in the vars.yml file.

    - name: Create EC2 instance
      hosts: all
      tasks:
        - name: Launch instance
          amazon.aws.ec2_instance:
            subnet_id: "{{ subnet_id }}"
  5. Run Ansible Playbook: Execute your Ansible playbook, passing the vars.yml file using the -e or --extra-vars flag.

    ansible-playbook -i inventory.ini playbook.yml -e @vars.yml

Explanation:

  • Terraform outputs are captured and stored in a JSON file.
  • Ansible uses lookup and json_query to extract specific values from the JSON file.
  • These values are assigned to Ansible variables in vars.yml.
  • The Ansible playbook then references these variables during execution.
  • The -e flag passes the vars.yml file to the playbook, making the variables available.

Code Example

This setup uses Terraform to create an AWS VPC and subnet, saving the subnet ID to a JSON file. An Ansible playbook then references this file to dynamically retrieve the subnet ID and launch an EC2 instance within the provisioned subnet, demonstrating infrastructure-as-code collaboration.

# Configure the AWS Provider
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

provider "aws" {
  region = "us-west-2" # Replace with your desired region
}

# Create a VPC
resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
}

# Create a Subnet
resource "aws_subnet" "example" {
  vpc_id     = aws_vpc.example.id
  cidr_block = "10.0.1.0/24"
}

# Output the Subnet ID
output "subnet_id" {
  value = aws_subnet.example.id
}

Ansible Playbook (playbook.yml)

---
- name: Create EC2 instance
  hosts: all
  tasks:
    - name: Launch instance
      amazon.aws.ec2_instance:
        key_name: your_key_pair_name # Replace with your key pair name
        instance_type: t2.micro
        image_id: ami-0c55b159c2d5wi538e # Replace with your desired AMI ID
        subnet_id: "{{ subnet_id }}"
        assign_public_ip: true
        security_groups:
          - default

Ansible Vars File (vars.yml)

---
subnet_id: "{{ lookup('file', 'terraform.json') | from_json | json_query('subnet_id') }}"

Execution Steps:

  1. Deploy Terraform Infrastructure:

    terraform init
    terraform apply -auto-approve
  2. Capture Terraform Outputs:

    terraform output -json > terraform.json
  3. Run Ansible Playbook:

    ansible-playbook -i inventory.ini playbook.yml -e @vars.yml 

Explanation:

  • Terraform: Defines the AWS resources (VPC and Subnet) and outputs the Subnet ID.
  • Ansible Playbook: Defines the task to create an EC2 instance using the subnet_id variable.
  • Ansible Vars File: Extracts the subnet_id value from the terraform.json file using lookup, from_json, and json_query.
  • Execution: First, Terraform deploys the infrastructure. Then, Terraform outputs are captured in a JSON file. Finally, the Ansible playbook is executed, using the vars.yml file to access the Terraform output.

Note:

  • Replace placeholders like region, key pair name, AMI ID with your actual values.
  • Ensure you have properly configured AWS credentials for both Terraform and Ansible.
  • This example assumes you have an inventory file (inventory.ini) configured for your target environment.

Additional Notes

Flexibility and Reusability:

  • Parameterization: This approach promotes infrastructure-as-code best practices by parameterizing your deployments. You can easily modify the Terraform code to create different environments (e.g., development, staging, production) and reuse the same Ansible playbook by adjusting the input variables.
  • Modularity: You can extend this pattern to pass multiple variables from Terraform to Ansible, allowing for more complex configurations. For example, you could pass security group IDs, VPC IDs, or even custom tags.

Alternative Approaches:

  • Terraform Provisioners: Terraform offers provisioners that can execute scripts (including Ansible playbooks) after resource creation. However, using separate Terraform and Ansible stages often provides better separation of concerns and debugging capabilities.
  • Configuration Management Tools: While this example focuses on Ansible, you can adapt the principles to other configuration management tools like Puppet, Chef, or SaltStack.

Security Considerations:

  • Sensitive Data: Be cautious about storing sensitive information (like API keys or passwords) directly in Terraform output files. Consider using tools like Ansible Vault or HashiCorp Vault to manage secrets securely.

Best Practices:

  • Descriptive Naming: Use clear and descriptive names for your Terraform outputs and Ansible variables to improve code readability and maintainability.
  • Error Handling: Implement error handling in your Ansible playbooks to gracefully handle situations where Terraform outputs might be missing or invalid.
  • Version Control: Store both your Terraform code and Ansible playbooks in a version control system (like Git) to track changes and facilitate collaboration.

Additional Tips:

  • terraform output Filtering: You can use the -raw flag with terraform output to get a specific output value without any formatting, making it easier to parse in Ansible.
  • JSON Parsing in Ansible: Ansible provides various filters for working with JSON data, such as json_query for extracting specific values and to_json for converting data structures to JSON format.

By understanding these concepts and best practices, you can effectively bridge the gap between Terraform and Ansible, enabling a robust and automated workflow for infrastructure provisioning and configuration management.

Summary

This document outlines the process of passing variables from Terraform to Ansible, enabling seamless infrastructure provisioning and configuration.

Steps:

  1. Define Terraform Outputs:

    • Within your Terraform code, use the output directive to specify the variables you want to pass to Ansible. For example:
      output "subnet_id" {
        value = aws_subnet.example.id
      }
  2. Capture Terraform Outputs:

    • After running terraform apply, capture the output values using tools like terraform output or jq. Store these values in a structured format like JSON or YAML:
      terraform output -json > terraform.json
  3. Create Ansible Variables File:

    • Create a YAML file (e.g., vars.yml) to store the captured Terraform outputs as Ansible variables. Utilize lookup and json_query to extract specific values from the JSON file:
      subnet_id: "{{ lookup('file', 'terraform.json') | from_json | json_query('subnet_id') }}"
  4. Utilize Variables in Ansible Playbook:

    • In your Ansible playbook, reference the variables defined in vars.yml within your tasks:
      - name: Create EC2 instance
        hosts: all
        tasks:
          - name: Launch instance
            amazon.aws.ec2_instance:
              subnet_id: "{{ subnet_id }}"
  5. Execute Ansible Playbook:

    • Run your Ansible playbook, passing the vars.yml file using the -e or --extra-vars flag to make the variables available during execution:
      ansible-playbook -i inventory.ini playbook.yml -e @vars.yml

Benefits:

  • Dynamic Infrastructure: Enables Ansible to work with dynamically provisioned resources from Terraform.
  • Clean Separation: Maintains a clear separation between infrastructure provisioning (Terraform) and configuration management (Ansible).
  • Improved Reusability: Promotes code reusability by allowing Ansible playbooks to adapt to different environments based on Terraform outputs.

Conclusion

This approach effectively bridges the gap between Terraform and Ansible, enabling a robust and automated workflow for infrastructure provisioning and configuration management. By defining outputs in Terraform and referencing them as variables within Ansible playbooks, you can create a seamless process for deploying and configuring your infrastructure. This method ensures that Ansible has access to the latest infrastructure details, promoting consistency and reducing manual errors. Remember to handle sensitive data with care and follow security best practices when passing variables between these tools.

References

Were You Able to Follow the Instructions?

๐Ÿ˜Love it!
๐Ÿ˜ŠYes
๐Ÿ˜Meh-gical
๐Ÿ˜žNo
๐ŸคฎClickbait