Skip to content

Using Terraform & Ansible in a Workflow

Terraform and Ansible are both widely used technologies in the area of automating infrastructure deployments, configurations, and more. At first glance, it might seem daunting to incorporate these technologies into a Direktiv workflow; but it's actually fairly straightforward. This article seeks to explain how to structure potentially 'complex' workflows in order to support technologies that may require data that persists across multiple workflow executions.

The Workflow

This workflow consists of only 2 states. The first state runs the terraform isolate, and requires access to a variable that contains the contents of a file. This file includes all of the configuration and authorisation details required to create a new virtual machine on Google Cloud Platform. The state is configured to assign the public IP address of the resulting virtual machine as .addr

The second state uses the ansible isolate, and requires access to two different variables:

  • playbook.yml
  • Ansible playbook that will be executed to connect to the remote machine and print a 'Hello, world!' message.
  • pk.pem
  • Private key included in the variable of the previous state, used by Ansible to securely connect to the remote virtual machine.

Examples of each variable are included at the end of this article.

# This workflow uses Terraform to create an instance on 
# Google Cloud Platform, and connects to it with Ansible.
id: terraform-and-ansible
description: "This workflow uses Terraform to create an instance on Google Cloud Platform, and connects to it with Ansible."


  # Calls the standard 'terraform' isolate, providing
  # the `` file from an existing workflow variable.
  - id: terraform
    image: direktiv/terraform:v1
      - key:
        scope: workflow
        type: plain

  # Runs ansible
  - id: ansible
    image: direktiv/ansible:v1
      - key: playbook.yml
        scope: workflow
        type: plain
      - key: pk.pem
        scope: workflow


  # Create a GCP instance using Terraform
  - id: run-terraform
    type: action
      secrets: ["GCP_PROJECT"]
      function: terraform
        action: "apply"
          - "-backend-config=address=http://localhost:8001/terraform-gcp-instance"
          "state-name": "terraform-gcp-instance"
          project_id: jq(.secrets.GCP_PROJECT)
    transform: jq(.addr = .return.output["ip-address"].value | del(.return))
    transition: run-ansible

  # Use Ansible to connect to the instance using provided private key file
  - id: run-ansible
    type: action
      function: ansible
        playbook: playbook.yml
        privateKey: pk.pem
          - "-i"
          - "jq(.addr),"


The file used by the terraform isolate ensures the creation of a Virtual Machine on Google Cloud Platform with a startup script that will save a private/public key pair to the system and ensure that it is authorised for access to the machine via SSH. To change the name of the resulting virtual machine, modify the value of the name field.

terraform {
    backend "http" {}

provider "google" {
    credentials = var.service_account_key

resource "google_compute_instance" "default" {
  project = var.project_id
  name         = "direktiv-terraform-ansible"
  machine_type = "n1-standard-1"
  zone         = "australia-southeast1-a"

  tags = ["direktiv", "direktiv"]

  boot_disk {
    initialize_params {
      image = "ubuntu-os-cloud/ubuntu-2004-lts"

  network_interface {
    network = "default"

    access_config {
      // Ephemeral IP

  metadata_startup_script = <<EOT
   echo <base64-encoded contents of a pem privat key> > /pk.b64
   base64 -d /pk.b64 > /pk.pem
   echo <base64-encoded contents of an rsa public key> > /ssh.b64
   base64 -d /ssh.b64 > /ssh.key
   chmod 600 /pk.pem
   eval `ssh-agent -s`
   ssh-add /pk.pem
   cat /ssh.key >> ~/.ssh/authorized_keys

variable "service_account_key" {
  description = "the entire contents of a service account key"
  default = <<EOT
  "type": "service_account",
  "project_id": "*****",
  "private_key_id": "*****",
  "private_key": "*****",
  "client_email": "*****",
  "client_id": "*****",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": "*****"

variable "project_id" {
  description = "project_id to spawn the virtual machine on"

output "ip-address" {
    value = google_compute_instance.default.network_interface[0].access_config[0].nat_ip


This is an incredibly basic Ansible playbook. After connecting to the remote machine, it simply prints Hello, world! and returns.

- hosts: all
  name: helloworld playbook
  gather_facts: yes
  remote_user: root
  connection: ssh
    - name: run helloworld logic
          - "Hello, world!"


This is a PEM formatted private key file, provided to both the created virtual machine (via and the ansible isolate. It provides a way for the ansible isolate to securely connect to the virtual machine via SSH.