Using Remote Exec

With Resource Manager, you can use Terraform's remote exec functionality to execute scripts or commands on a remote computer. You can also use this technique for other provisioners that require access to the remote resource.

For more information, see remote-exec Provisioner (terraform.io).

Before You Begin

  • The location where the script is remotely executed must be an Oracle Cloud Infrastructure resource with one of the following configurations.
  • On Windows, WinRM must be enabled. On Linux or Unix, SSH must be enabled.
  • A key pair used for signing API requests, with the public key uploaded to Oracle. For more information on generating and uploading keys, see Required Keys and OCIDs.

Authenticating

We recommend using one of the following approaches, depending on whether you have access to the Vault service. For more information, see Overview of Vault.

With Vault

First, use Vault to encrypt your private key. For more information, see Managing Keys and Using Master Encryption Keys.

Next, provide the encrypted private key to Resource Manager. You can use the decrypt data source to decrypt it.

The following code sample demonstrates this process.

data "oci_kms_decrypted_data" "private_key_decrypted" {
    #Required
    ciphertext = "${file(var.encrypted_private_key_path)}"
    crypto_endpoint = "${var.decrypted_data_crypto_endpoint}"
    key_id = "${var.kms_encryption_key_id}"
}
  
  
resource "oci_core_instance" "TFInstance1" {
  availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.availability_domain - 1],"name")}"
  compartment_id      = "${var.compartment_ocid}"
  display_name        = "TFInstance"
  hostname_label      = "instance3"
  shape               = "${var.instance_shape}"
  subnet_id           = "${oci_core_subnet.ExampleSubnet.id}"
  
  source_details {
    source_type = "image"
    source_id   = "${var.instance_image_ocid[var.region]}"
  }
  
  extended_metadata {
    ssh_authorized_keys = "${var.ssh_public_key}"
  }
}
  
resource "null_resource" "remote-exec" {
  depends_on = ["oci_core_instance.TFInstance1"]
  provisioner "remote-exec" {
    connection {
      agent       = false
      timeout     = "30m"
      host        = "${oci_core_instance.TFInstance1.public_ip}"
      user        = "${var.opc_user_name}"
      private_key = "${data.oci_kms_decrypted_data.test_decrypted_data.plaintext}"
    }
  
    inline = [
      "touch ~/IMadeAFile.Right.Here"
    ]
  } 
}

Without Vault

If you do not have access to the Vault service, you can dynamically generate a key pair and store them in the state file.

  1. Generate a key pair using a TLS resource.
  2. When you launch the compute instance, use the public key from the TLS resource.
  3. When you establish the SSH connection, provide the private key.
Caution

You should not save your private key in your Terraform configuration file because that is not a secure location.

The following sample demonstrates how to use the TLS private key resource to provision a compute instance, then perform a remote execution on that instance.

resource "tls_private_key" "public_private_key_pair" {
  algorithm   = "RSA"
}
  
resource "oci_core_instance" "TFInstance1" {
  availability_domain = "${lookup(data.oci_identity_availability_domains.ADs.availability_domains[var.availability_domain - 1],"name")}"
  compartment_id      = "${var.compartment_ocid}"
  display_name        = "TFInstance"
  hostname_label      = "instance3"
  shape               = "${var.instance_shape}"
  subnet_id           = "${oci_core_subnet.ExampleSubnet.id}"
  
  source_details {
    source_type = "image"
    source_id   = "${var.instance_image_ocid[var.region]}"
  }
  
  extended_metadata {
    ssh_authorized_keys = "${tls_private_key.public_private_key_pair.public_key_openssh}"
  }
}
  
resource "null_resource" "remote-exec" {
  depends_on = ["oci_core_instance.TFInstance1"]
  provisioner "remote-exec" {
    connection {
      agent       = false
      timeout     = "30m"
      host        = "${oci_core_instance.TFInstance1.public_ip}"
      user        = "${var.opc_user_name}"
      private_key = "${tls_private_key.public_private_key_pair.private_key_pem}"
    }
  
    inline = [
      "touch ~/IMadeAFile.Right.Here"
    ]
  } 
}

Connection Construct

This example demonstrates how to use a connection construct for remote exec. Terraform uses a number of defaults when connecting to a resource, but these can be overridden using a connection block in either a resource or provisioner. For more information, see Provisioner Connections.