Introducing the Loft Terraform Provider
Tags: kubernetes, vcluster, devspace, loft
Published: 2022-06-15 15:02:56

By Russ Centanni

We’re proud to announce our new terraform provider for Loft. For customers already managing infrastructure using Terraform, the terraform-provider-loft allows configuring Loft spaces and virtual clusters as terraform resources. Here’s a quick look at what’s in the release. For more details, head over to the [provider’s documentation](https://registry.terraform.io/providers/loft-sh/loft/latest/docs).

## Prerequisites

If you'd like to follow along with these examples, or test drive the provider for your own infrastructure, you'll need the following installed:

* A Kubernetes Cluster: [Docker Desktop](https://docs.docker.com/desktop/kubernetes/) or [KinD](https://kind.sigs.k8s.io/) are great for running Kubernetes locally)
* Terraform version 1.0 or greater
* [Loft Installed](https://loft.sh/docs/getting-started/install/cli) and a working login

## Getting Started

The first step is to add the provider to your terraform file.

```Python
terraform {
  required_providers {
    loft = {t
      source = "registry.terraform.io/loft-sh/loft"
    }
  }
}

provider "loft" {}
```

From your terminal, run terraform init. Terraform will download the provider to your system.

```Bash
$ terraform init
```

### Configuring Loft Authentication

By default, the provider will use your current Loft credentials if you’ve logged in to loft using the loft login command. This is convenient for getting started, but this can be difficult to manage, especially if you frequently switch between different environments and don’t use the same credentials in each environment.

#### Loft Configuration

One option for managing this is to create a config file for each environment. This can be done with the `--config` option and the `loft login` command.

First, log in to Loft with a custom configuration file path:

```Bash
$ loft login https://localhost:8443 --insecure --config dev.config.json
```

Then refer to this file path using the `config_path` attribute:

```Python
provider "loft" {
  config_path = "dev.config.json"
}
```

This option works as long as everyone uses the same file paths for their configuration, but can lead to accidentally leaking credentials if the files aren’t managed properly.

#### Access Keys

Another option for authentication is to configure the provider using access keys. This allows the credentials to be passed in through Terraform variables and managed as you would any other secrets. This is the recommended option for CI/CD environments. 

First, here’s how you might configure Terraform to use variables:

```Python
variable "loft_host" {
  type        = string
  description = "The loft instance host (e.g. https://loft.example.com)"
}

variable "loft_access_key" {
  type        = string
  description = "The Loft access key."
  sensitive   = true
}

variable "loft_insecure" {
  type        = bool
  description = "Allow login into an insecure Loft instance"
}

provider "loft" {
  host       = var.loft_host
  access_key = var.loft_access_key
  insecure   = var.loft_insecure
}
```

Next we'll create a Loft access key for the provider to use. Head over to the "Users" page in the Loft UI: 

![Loft User Management screen](https://loft.sh/blog/images/content/loft-terraform-provider-1.png)

Select the user you wish to create an access key for, and click "Create Access Key": 

![Click the Create Access Key button](https://loft.sh/blog/images/content/loft-terraform-provider-2.png)

In the form, add a description for the Access Key's intended purpose and click create: 

![Add a description for the new access key](https://loft.sh/blog/images/content/loft-terraform-provider-3.png)

A dialog with the newly generated access key will be shown. This can be copied and then passed to terraform through the [command line](https://www.terraform.io/language/values/variables#variables-on-the-command-line), [environment variables](https://www.terraform.io/language/values/variables#environment-variables), or [.tfvars files](https://www.terraform.io/language/values/variables#variable-definitions-tfvars-files)

Once the provider is configured to connect to Loft, it's time to manage resources.

### Manage a Space

Creating a Loft space using terraform is as simple as providing the cluster and name of the space to a `loft_space` resource.

```Python
resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}
```

#### Sleep Mode

One of the benefits of using Loft is the cost savings of using [sleep mode](https://loft.sh/docs/getting-started/explore/sleep-mode). Configuring sleep mode on a space is done by using the `sleep_after` attribute.

```Python
resource "loft_space" "basic" {
  name        = "basic-space"
  cluster     = "loft-cluster"
  sleep_after = "1h" # Sleep after one hour of inactivity
}
```

The `sleep_after` attribute accepts any Golang style duration string. You may already be familiar with this format from [kubectl](https://kubernetes.io/docs/reference/kubectl/).

#### Space Objects

A convenient way to manage resources inside a space is by using space objects. Objects are Kubernetes resources that are synchronized by Loft. Here's an example of creating a space with some example config maps:

```Python
resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
  objects = <<YAML
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-map-1
data:
  key1: "value1"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-map-2
data:
  key2: "value2"
YAML
}
```

As you can see, multiple resources can be synced by using the YAML document separator --- in the `objects` attribute.

#### Import

If you've been using Loft for a while, you likely have existing spaces that you'd like to start managing with Terraform. To enable this, the provider supports importing existing spaces into your Terraform state.

To import an existing space, add a `loft_space` resource with the `cluster` and `name` attributes:

```Python
resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}
```

Next, run the `terraform import` command to import the resource into terraform.

```Bash
$ terraform import loft_space.basic loft-cluster/basic-space
```

Finally, run terraform plan to see a diff of other attributes that should be added to your *.tf files to start managing the existing space's configuration.

```Bash
$ terraform plan
```

### Manage a Virtual Cluster

The `loft_virtual_cluster` resource enables declarative management of Loft virtual clusters. Here's an example of creating a virtual cluster in the space we created earlier:

```Python
resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}

resource "loft_virtual_cluster" "basic" {
  name      = "basic-virtual-cluster"
  namespace = resource.loft_space.basic.name
  cluster   = resource.loft_space.basic.cluster
}
```

By using `loft_virtual_cluster` with the l`oft_space resource`, virtual clusters can take advantage of sleep mode too.

#### Virtual Cluster Objects

Similar to spaces, it's also possible to synchronize Kubernetes resources to a virtual cluster. One difference to keep in mind is that you'll also need to create namespaces in the Virtual Cluster since you're not already scoped to one. Here's an example of adding a namespace and config map to the example virtual cluster above.

```Python
resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}

resource "loft_virtual_cluster" "basic" {
  name      = "basic-virtual-cluster"
  namespace = resource.loft_space.basic.name
  cluster   = resource.loft_space.basic.cluster
  objects   = <<YAML
apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config-map
  namespace: my-namespace
data:
  key: "value"
YAML
}
```

#### Import

Importing an existing virtual cluster so it can be managed with Terraform looks very similar to spaces. The key difference is that you'll need to provide the name of the virtual cluster. As an example, here's a command to import the virtual cluster from the previous examples:

```Bash
$ terraform import loft_virtual_cluster.basic loft-cluster/basic-space/basic-virtual-cluster
```

For more advanced configuration options, see the [loft_virtual_cluster documentation](https://registry.terraform.io/providers/loft-sh/loft/latest/docs/resources/virtual_cluster) and the [VCluster Helm charts](https://github.com/loft-sh/vcluster/tree/main/charts).

## Conclusion

If you're a Loft customer using Terraform, this provider enables a more seamless approach to managing Loft spaces and virtual clusters. We're just getting started and we hope you'll give it a try and reach out to us with feature requests:

* Open issues in the [terraform-provider-loft](https://github.com/loft-sh/terraform-provider-loft/issues) GitHub repo
* Join us on [Slack](https://slack.loft.sh/)
* Follow [@loft_sh](https://twitter.com/loft_sh) on Twitter