Migrate from Terraform to Crossplane or Upbound

Crossplane and Terraform are powerful tools for managing and provisioning cloud resources. Both offer consistent infrastructure provisioning through declarative configurations and support multiple cloud providers for more resilient multi-cloud strategies. Both tools also extend beyond traditional infrastructure management and allow users to create and manage various resource types with provider plugins.

Why Crossplane?

While both Crossplane and Terraform help teams manage resources, Crossplane has several features that may fit better with your deployment workflow.

The Control Plane is the centralized management layer that orchestrates and coordinates the provisioning and lifecycle management of cloud resources. Crossplane leverages Kubernetes as its control plane, utilizing the Kubernetes API to manage infrastructure and resources. If your organization already uses Kubernetes, Crossplane allows you to simplify your workflow and minimizes tool sprawl.

Crossplane also manages state for you as a Kubernetes Controller. If your external resource changes outside of the desired Crossplane configuration, Crossplane automatically reconciles the resource for you.

Migration prerequisites

If you have resources in Terraform and want to migrate to Crossplane, make sure you have the following prerequisites:

  • A Kubernetes cluster
  • Crossplane installed
  • A cloud provider account

Configure your kind cluster

To follow this guide with a kind cluster, create a new cluster with a new namespace.

kind create cluster

kind create namespace upbound-system

Remember to install Crossplane into your new cluster.

Review the Terraform configuration

This guide reviews a small Terraform configuration using AWS and use Crossplane’s provider-terraform to migrate the resources to a new control plane.

The Terraform configuration you’ll work with creates a new virtual machine:

resource "aws_instance" "my_vm" {
  ami           = "ami-065deacbcaac64cf2"
  instance_type = "t2.micro"
  tags = {
    Name = var.vmName
  }
}

variable "vmName" {
  description = "VM name"
  type        = string
}

provider-terraform is a Crossplane provider that parses and executes your Terraform configurations as a Crossplane Managed Resource (MR). You don’t have to rewrite all your Terraform configurations to begin working with Crossplane.

Create a managed resource

Crossplane managed resources are declarative specifications that define your desired infrastructure and resources. These configurations are a Kubernetes manifest YAML file. Crossplane uses them to create and manage resources within your Kubernetes cluster.

apiVersion: tf.upbound.io/v1beta1
kind: Workspace
metadata:
  name: tf-vm
spec:
  forProvider:
    source: Inline
    module: |
      vars:
        - key:
            value:      

The apiVersion field is a standard field in Kubernetes manifests and references the API group of the Terraform provider plugin installed in a later step.

The kind field identifies the schema type for the configuration. Workspace is a Managed Resource type defined in the provider. The Workspace kind expects certain values for the configuration to deploy.

The metadata is a standard, required Kubernetes field that contains information about the resource, like the name or other identifying values.

The spec field defines the parameters of the Workspace you want to create. The provider defines the fields inside the spec.

The forProvider sub-field lets you define the source of the Terraform configuration you want to deploy with Crossplane. In this example, the source is Inline meaning you define the HashiCorp Configuration Language (HCL) in this file with themodule field.

The module field refers to the root module of your Terraform configuration. For an Inline source, you can write the contents of the main module directly in the file.

The vars field allows you to create configuration variables to pass to your Terraform configuration.

Create a new file called terraform-configuration.yaml. Your complete configuration file should match the following:

apiVersion: tf.upbound.io/v1beta1
kind: Workspace
metadata:
  name: tf-vm
spec:
  forProvider:
    source: Inline
    module: |
      resource "aws_instance" "my_vm" {
        ami           = "ami-065deacbcaac64cf2"
        instance_type = "t2.micro"
        tags = {
          Name = var.vmName
        }
      }

      variable "vmName" {
        description = "VM name"
        type        = string
      }      

    vars:
      - key: vmName
        value: crossplanevm
Warning
This configuration will not work if applied now.

Authenticate with your cloud provider

The provider configuration handles authentication. You must create a Kubernetes secret file to authenticate with your AWS account.

The provider supports AWS authentication with: The provider supports AWS authentication with:

Note
For more information on cloud provider authentication, read the Provider Azure or Provider GCP authentication documentation.

This guide uses the authentication key method. Download your AWS credentials and save them to a new file called aws-credentials.

Create a new Kubernetes secret.

kubectl -n upbound-system create secret generic aws-creds --from-file=credentials=aws-credentials

Verify your secret with kubectl describe secret.

kubectl describe secret aws-creds -n upbound-system

Name:         aws-creds
Namespace:    upbound-system
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
creds:  114 bytes

Install the provider

You wrote a managed resource in the previous step. Next, install the provider-terraform into your Kubernetes cluster with a Kubernetes configuration file.

Create a new file called provider-terraform-install.yaml.

Copy and paste the configuration below.

apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-terraform
spec:
  package: xpkg.upbound.io/upbound/provider-terraform:v0.13.0
  credentials:
    source: Secret
    secretRef:
      namespace: upbound-system
      name: aws-credentials
      key: credentials

Crossplane uses this Kubernetes manifest file to download and install the provider package into your cluster.

Deploy the configuration file with kubectl apply -f

$ kubectl apply -f provider-terraform-install.yaml

Verify the provider with kubectl get pods.

$ kubectl get pods -n upbound-system
NAME                                                              READY   STATUS    RESTARTS   AGE
crossplane-6979f579f9-x7nkr                                       2/2     Running   0

Crossplane uses this Kubernetes manifest file to download and install the provider package into your cluster.

Deploy the configuration file with kubectl apply -f

$ kubectl apply -f provider-terraform-install.yaml

Verify the provider with kubectl get providers.

$ kubectl get providers
NAME                 READY       STATUS    PACKAGE                                              AGE
provider-terraform   True        True      xpkg.upbound.io/upbound/provider-terraform:v0.13.0   15s

Deploy your configuration

Next, apply the manifest.

kubectl apply -f terraform-configuration.yaml

State management

For greenfield deployments, this approach works well for users who are already familiar with Terraform. To maintain state with a remote Terraform state file, you can use a ProviderConfig to point your Crossplane-controlled Terraform provider to the correct backend.

The example below uses the kubernetes backend:

apiVersion: tf.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: aws-tf-config
spec:
  credentials:
    - filename: aws-creds.ini
      source: Secret
      secretRef:
        namespace: upbound-system
        name: aws-creds
        key: credentials
  configuration: |
    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "5.6.1"
        }
      }
      backend "kubernetes" {
        secret_suffix    = "providerconfig"
        namespace        = "upbound-system"
        in_cluster_config = true
      }
    }
    provider "aws" {
      shared_credentials_files = ["${path.module}/aws-creds.ini"]
      region = "us-east-1"
    }    
Warning
This configuration won’t work as is. Review the example backend configuration and the Terraform File documentation

You can apply this ProviderConfig and let Crossplane continuously reconcile the resources in your cloud provider and update the state file.

Next steps

You created a resource with the Crossplane provider-terraform! For more information on advanced migration tactics, watch this Upbound sponsored webinar with the team behind the Crossplane provider-terraform.

In the next guide, you’ll create a functional Crossplane configuration with a definition, composition, and claim.