Enabling FIPS Compatibility

You can use Terraform and a special FIPS compatible version of the Oracle Cloud Infrastructure (OCI) Terraform provider, as long as a few specific requirements and best practices are employed. This topic provides guidance on these requirements and practices.

FIPS encryption

To ensure the highest security standards, traffic from Terraform to OCI endpoints should transit over a TLS connection established with an HTTP client using FIPS certified encryption.

The standard OCI Terraform provider is implemented in Go. Go’s native cryptography implementations, while fully capable of establishing secure TLS connections with OCI endpoints, have not been FIPS certified.

For Terraform traffic to transit to OCI endpoints over FIPS-compliant connections, you must use a special version of the Terraform provider that uses FIPS certified cryptography. This version of the OCI Terraform provider uses the FIPS 140-2 certified Oracle Cloud Infrastructure Cryptographic Library for Kubernetes instead of Go’s native cryptography implementation. Read more about the Oracle Cloud Infrastructure Cryptographic Library for Kubernetes here.

Installing the FIPS-Compliant Terraform Provider

The FIPS-compliant OCI Terraform provider is only available for Oracle Linux. You can install the provider using yum.

Tip

Before installing the OCI Terraform provider, download and install Terraform from HashiCorp, or install Terraform using yum.

If any existing OCI Terraform provider packages are already installed on the Oracle Linux machine, remove them first:

yum remove terraform-provider-oci

Install the FIPS-compatible OCI Terraform provider by running the following yum command from an Oracle Linux machine:

yum install terraform-provider-oci-fips

Configuring the Terraform Provider

  1. Add an environment variable to set the target region for Terraform:

    echo "export TF_VAR_region='<your_region>'" >> ${HOME}/.bash_profile
  2. Add an environment variable to disable interprocess traffic encryption between Terraform and the OCI Terraform provider:

    echo "export TF_DISABLE_PLUGIN_TLS=1" >> ${HOME}/.bash_profile
  3. Add an environment variable to prevent Terraform from accessing the HashiCorp Checkpoint service:

    echo "export CHECKPOINT_DISABLE=1" >> ${HOME}/.bash_profile
  4. Configure the authentication method for the Terraform provider. See Authentication for more information.

Operating Terraform in a Single Region

To ensure that traffic between Terraform and OCI services does not transit over public internet infrastructure, we recommend that you run Terraform and the OCI Terraform provider from a Compute instance that is hosted in the same region as the resources they create and manage.

Creating a Compute Instance

After Terraform and the OCI Terraform provider are installed on an Oracle Linux machine, you can use Terraform and the following sample Terraform configuration file to:

  • Create a designated Compute instance you can use to provision additional infrastructure within the same region.
  • Install Terraform and the latest FIPS compliant OCI Terraform provider on the new instance.
  • Restrict communication with the instance to OCI endpoints and HTTPS using a service gateway.
  • Enable instance principal authentication.

See Authoring Configurations for more information.

To create the compute instance:

  1. Copy the main.tf file to your Oracle Linux machine.
  2. Gather the information required to populate the Terraform configuration file's variables.
  3. Refer to Platform Images to locate the Oracle Linux image OCID value for your region. Modify the oel-image value in the Terraform configuration file.
  4. Initialize Terraform in the directory that contains the Terraform configuration file:

    terraform init
  5. Apply the Terraform configuration:

    terraform plan
    terraform apply
Important

The instance-ip output variable provides the IP address you will need to use to sign in to the new Compute instance.

main.tf
variable "tenancy_ocid" {
}
 
variable "user_ocid" {
}
 
variable "fingerprint" {
}
 
variable "private_key_path" {
}
 
variable "region" {
}
 
variable "compartment_ocid" {
}
 
variable "ssh_public_key" {
}
 
variable "ssh_private_key" {
}
 
locals {
  prefix    = "terraform"
  oel-image = "<Oracle_Linux_image_OCID>"
  vm-shape  = "VM.Standard2.1"
 
  user-data = <<EOF
#!/bin/bash -x
echo "export TF_VAR_auth='InstancePrincipal'" >> ~/.bash_profile
echo "export TF_VAR_region='${var.region}'" >> ~/.bash_profile
yum install -y terraform terraform-provider-oci-fips
EOF
 
}
 
provider "oci" {
  tenancy_ocid     = var.tenancy_ocid
  user_ocid        = var.user_ocid
  fingerprint      = var.fingerprint
  private_key_path = var.private_key_path
  region           = var.region
}
 
resource "oci_core_vcn" "vcn1" {
  compartment_id = var.compartment_ocid
  display_name   = "${local.prefix}Vcn"
  cidr_block     = "10.0.0.0/16"
}
 
resource "oci_core_subnet" "subnet1" {
  compartment_id    = var.compartment_ocid
  vcn_id            = oci_core_vcn.vcn1.id
  cidr_block        = "10.0.0.0/24"
  display_name      = "${local.prefix}Subnet"
  security_list_ids = [oci_core_vcn.vcn1.default_security_list_id]
  route_table_id    = oci_core_vcn.vcn1.default_route_table_id
  dhcp_options_id   = oci_core_vcn.vcn1.default_dhcp_options_id
}
 
resource "oci_core_internet_gateway" "internet-gateway1" {
  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.vcn1.id
  display_name   = "${local.prefix}InternetGateway"
}
 
resource "oci_core_default_route_table" "route-table1" {
  manage_default_resource_id = oci_core_vcn.vcn1.default_route_table_id
  display_name               = "${local.prefix}RouteTable"
 
  route_rules {
    destination       = "0.0.0.0/0"
    destination_type  = "CIDR_BLOCK"
    network_entity_id = oci_core_internet_gateway.internet-gateway1.id
  }
}
 
data "oci_core_services" "service-gateway-services" {
  filter {
    name   = "name"
    values = ["All .* Services In Oracle Services Network"]
    regex  = true
  }
}
 
resource "oci_core_service_gateway" "service-gateway1" {
  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.vcn1.id
  display_name   = "${local.prefix}ServiceGateway"
 
  services {
    service_id = data.oci_core_services.service-gateway-services.services[0]["id"]
  }
}
 
resource "oci_core_default_security_list" "security-list1" {
  manage_default_resource_id = oci_core_vcn.vcn1.default_security_list_id
  display_name               = "${local.prefix}SecurityList"
 
  // inbound ssh traffic
  ingress_security_rules {
    protocol  = "6" // tcp
    source    = "0.0.0.0/0"
    stateless = false
 
    tcp_options {
      min = 22
      max = 22
    }
  }
 
  // outbound traffic to OCI services
  egress_security_rules {
    destination      = data.oci_core_services.service-gateway-services.services[0]["cidr_block"]
    destination_type = "SERVICE_CIDR_BLOCK"
    protocol         = "6"
 
    tcp_options {
      max = "443"
      min = "443"
    }
  }
 
  // outbound tcp traffic on all ports
  egress_security_rules {
    destination = "0.0.0.0/0"
    protocol    = "6"
  }
}
 
data "oci_identity_compartment" "compartment1" {
  id = var.compartment_ocid
}
 
resource "oci_identity_dynamic_group" "dynamic-group1" {
  compartment_id = var.tenancy_ocid
  name           = "${local.prefix}DynamicGroup"
  description    = "Dynamic Group for executing Terraform with Instance Principal authentication"
  matching_rule  = "ANY {instance.compartment.id = '${var.compartment_ocid}'}"
}
 
resource "oci_identity_policy" "instance-principal-policy1" {
  compartment_id = var.compartment_ocid
  name           = "${local.prefix}Policy"
  description    = "Policy to allow Instance Principal Terraform execution"
  statements     = ["ALLOW dynamic-group ${oci_identity_dynamic_group.dynamic-group1.name} to manage all-resources IN compartment ${data.oci_identity_compartment.compartment1.name}"]
}
 
data "oci_identity_availability_domain" "ad" {
  compartment_id = var.tenancy_ocid
  ad_number      = 1
}
 
resource "oci_core_instance" "instance1" {
  availability_domain = data.oci_identity_availability_domain.ad.name
  compartment_id      = var.compartment_ocid
  display_name        = "${local.prefix}Instance"
  shape               = local.vm-shape
 
  source_details {
    source_type = "image"
    source_id   = local.oel-image
  }
 
  metadata = {
    ssh_authorized_keys = var.ssh_public_key
    user_data           = base64encode(local.user-data)
    tenancy_ocid        = var.tenancy_ocid
  }
 
  create_vnic_details {
    subnet_id        = oci_core_subnet.subnet1.id
    assign_public_ip = true
  }
}
 
output "instance-ip" {
  value = [oci_core_instance.instance1.public_ip]
}

Signing in to the Instance

Use the following SSH command to access the instance:

$ ssh –i <private_key_path> <username>@<instance_ip_address>

<private_key_path> is the full path and name of the file that contains the private key associated with the instance you want to access.

<username> is the default username for the instance. For Oracle Linux images, the default username is opc.

<instance_ip_address> is the instance IP address that was the output of the Terraform commands.

Installing and Configuring Terraform on the Instance

  1. Use yum to install Terraform and the FIPS compatible OCI Terraform provider on the instance:

    yum install -y terraform terraform-provider-oci-fips
  2. Add an environment variable to enable instance principal authentication to the bash profile:

    echo "export TF_VAR_auth='InstancePrincipal'" >> ${HOME}/.bash_profile
  3. Add an environment variable to set the target region for Terraform:

    echo "export TF_VAR_region='<your_region>'" >> ${HOME}/.bash_profile
  4. Add an environment variable to disable interprocess traffic encryption between Terraform and the OCI Terraform provider:

    echo "export TF_DISABLE_PLUGIN_TLS=1" >> ${HOME}/.bash_profile
  5. Add an environment variable to prevent Terraform from accessing the HashiCorp Checkpoint service:

    echo "export CHECKPOINT_DISABLE=1" >> ${HOME}/.bash_profile
  6. Exit the instance:

    exit

Implementing Security Rules

Before using the new instance to run Terraform, you should update the security rules to prevent egress traffic to any third-party endpoints other than OCI services. You can do this by removing the following egress rule from the Terraform configuration file's security-list1 resource and running terraform apply from the Oracle Linux machine:

// outbound tcp traffic on all ports
// remove this rule or comment it out to prevent egress traffic to third-party endpoints
#egress_security_rules {
#  destination = "0.0.0.0/0"
#  protocol    = "6"
#}
Tip

You can also use the OCI Console to update your security rules on the new instance.

Running Terraform from the Instance

After creating the instance, installing and configuring Terraform on the instance, and updating the security rules, you can use Terraform to provision additional OCI infrastructure within the same region. Copy any additional Terraform configuration files to your instance, sign in to the instance, and run your Terraform commands like any other Terraform provider:

ssh -i <private_key_path> opc@<instance_ip_address>
terraform init
terraform apply