# Manage FusionAuth With Terraform

Learn how to create and change FusionAuth configuration with the FusionAuth Terraform provider.

> For the index of this section of the site, see [llms.txt](https://fusionauth.io/docs/llms.txt)

The [FusionAuth Terraform provider](https://registry.terraform.io/providers/fusionauth/fusionauth/latest) manages FusionAuth configuration as Terraform resources. This guide creates a Tenant and an Application with Terraform. Then the guide brings the default Tenant and the FusionAuth Application under Terraform management. To decide what belongs in Terraform, see [Manage FusionAuth Configuration Across Environments](https://fusionauth.io/docs/deploy.md).

Before you begin, install or set up:

*   A running FusionAuth instance. To start an instance locally, see [Docker](https://fusionauth.io/docs/get-started/install.md).
*   [Terraform](https://developer.hashicorp.com/terraform/install) 1.5 or later, or [OpenTofu](https://opentofu.org/docs/intro/install/) 1.6 or later.

The [example repository](https://github.com/fusionauth/fusionauth-example-terraform) contains the configuration from this guide.

## Create Resources

### Get an API Key

Terraform calls the FusionAuth API with an API key. Terraform can't create the first key.

Create the key at Settings -> API Keys . A key with no endpoints selected can call every API. To limit what Terraform can change, select only the endpoints for the resources that Terraform manages. See [Managing API Keys](https://fusionauth.io/docs/apis/authentication.md#managing-api-keys).

On a new instance, [Kickstart](https://fusionauth.io/docs/get-started/develop/kickstart.md) can create the key instead:

Kickstart file that creates an API key

```json
{
  "apiKeys": [
    {
      "key": "4737ea8520bd454caabb7cb3d36e14bc1832c0d3f70a4189b82598670f11b1bd"
    }
  ]
}
```

### Configure the Provider

Create a directory for the configuration. Add a `main.tf` file that requires the provider:

main.tf

```hcl
terraform {
  required_providers {
    fusionauth = {
      source  = "fusionauth/fusionauth"
      version = "~> 1.3"
    }
  }
}

# reads the API key and URL from FA_API_KEY and FA_DOMAIN
provider "fusionauth" {}
```

The provider reads the instance URL and the API key from environment variables. Set both variables, so neither value appears in the configuration:

```shell-session
$ export FA_DOMAIN="https://auth.example.com" && export FA_API_KEY="<api-key>"
```

Download the provider:

```shell-session
$ terraform init
```

### Define the Resources

Add a Tenant and a signing key to `main.tf`:

A Tenant and a signing key

```hcl
resource "fusionauth_tenant" "forum" {
  name = "Forum"
  lifecycle {
    prevent_destroy = true
  }
}

resource "fusionauth_key" "forum" {
  algorithm = "RS256"
  length    = 2048
  name      = "Forum access token key"
}
```

The `prevent_destroy` setting stops Terraform from deleting the Tenant. Deleting a Tenant deletes every user, Application, and group in the Tenant.

Add an Application to the Tenant, with an `admin` role and a `user` role:

An Application with two roles

```hcl
resource "fusionauth_application" "forum" {
  tenant_id = fusionauth_tenant.forum.id
  name      = "Forum"
  jwt_configuration {
    enabled         = true
    access_token_id = fusionauth_key.forum.id
  }
  lifecycle {
    # the forum app writes its own settings to this field through the API
    ignore_changes = [data]
  }
}

resource "fusionauth_application_role" "admin" {
  application_id = fusionauth_application.forum.id
  name           = "admin"
  is_super_role  = true
}

resource "fusionauth_application_role" "user" {
  application_id = fusionauth_application.forum.id
  name           = "user"
  is_default     = true
}
```

The Application signs access tokens with the signing key. [Handle Changes Made Outside Terraform](#handle-changes-made-outside-terraform) explains the `lifecycle` block.

The [provider documentation](https://registry.terraform.io/providers/fusionauth/fusionauth/latest/docs) lists every resource and argument.

### Apply the Configuration

Preview the changes, then apply the changes:

```shell-session
$ terraform plan && terraform apply
```

Terraform lists the five resources to create and asks for confirmation. After the apply finishes, the `Forum` Application appears at Applications .

To change a resource later, edit `main.tf`. Then run `terraform plan` and `terraform apply` again. To delete a resource, remove the resource from `main.tf` and apply.

## Manage the Default Resources

The default Tenant and the FusionAuth Application exist before Terraform runs, so Terraform can't create these resources. To change the settings of a default resource, import the resource. To use a default resource without changing the resource, [reference the resource with a data source](#reference-a-resource-without-managing-it).

### Import the Default Resources

1.  Find the Id of the default Tenant at Tenants . The FusionAuth Application has the Id `3c219e58-ed0e-4b18-ad48-f4f92793ae32` on every instance.
    
    ![The details of the default Tenant, with the Tenant Id.](https://fusionauth.io/img/docs/screenshots/operate-default-tenant-id.png)
    
2.  Add an [import block](https://developer.hashicorp.com/terraform/language/import) and a resource for the default Tenant and for the FusionAuth Application. Give each resource only the required arguments. Replace `<default-tenant-id>` with the Id of the default Tenant:
    
    Import the default resources
    
    ```hcl
    import {
      to = fusionauth_tenant.default
      id = "<default-tenant-id>"
    }
    
    resource "fusionauth_tenant" "default" {
      name = "Default"
      lifecycle {
        prevent_destroy = true
      }
    }
    
    import {
      to = fusionauth_application.fusionauth
      id = "3c219e58-ed0e-4b18-ad48-f4f92793ae32"
    }
    
    resource "fusionauth_application" "fusionauth" {
      tenant_id = fusionauth_tenant.default.id
      name      = "FusionAuth"
      lifecycle {
        prevent_destroy = true
      }
    }
    ```
    
3.  Run `terraform plan`. For each setting the configuration leaves out, the provider plans a change to a default value. The plan lists every value that differs from the instance:
    
    Output
    
    ```plaintext
      # fusionauth_tenant.default will be updated in-place
      # (imported from "d7d09513-a3f5-401c-9685-34ab6c552453")
      ~ resource "fusionauth_tenant" "default" {
      ...
          ~ email_configuration {
      ...
              - default_from_name                                = "FusionAuth" -> null
      ...
              - implicit_email_verification_allowed              = true -> null
      ...
    Plan: 2 to import, 0 to add, 2 to change, 0 to destroy.
    ```
    
4.  Copy each current value into the configuration. The current value is on the left of the arrow.
5.  Run `terraform plan` again. Repeat the previous step until the plan shows `0 to change`. On a new instance, the configuration looks like this:
    
    Import the default resources with the current values
    
    ```hcl
    import {
      to = fusionauth_tenant.default
      id = "<default-tenant-id>"
    }
    
    resource "fusionauth_tenant" "default" {
      name = "Default"
      email_configuration {
        default_from_name                   = "FusionAuth"
        implicit_email_verification_allowed = true
      }
      jwt_configuration {
        refresh_token_revocation_policy_on_login_prevented = true
        refresh_token_revocation_policy_on_password_change = true
      }
      phone_configuration {
        implicit_phone_verification_allowed = true
      }
      lifecycle {
        prevent_destroy = true
      }
    }
    
    import {
      to = fusionauth_application.fusionauth
      id = "3c219e58-ed0e-4b18-ad48-f4f92793ae32"
    }
    
    resource "fusionauth_application" "fusionauth" {
      tenant_id = fusionauth_tenant.default.id
      name      = "FusionAuth"
      jwt_configuration {
        enabled                         = true
        refresh_token_expiration_policy = "SlidingWindow"
        refresh_token_ttl_minutes       = 60
        refresh_token_usage_policy      = "OneTimeUse"
        ttl_seconds                     = 60
      }
      lifecycle {
        prevent_destroy = true
      }
    }
    ```
    
6.  Run `terraform apply` to finish the import.

The values depend on the FusionAuth version and on any changes made in the Admin UI. Copy the values from the plan for your instance, not from the example.

Caution

FusionAuth doesn't allow deleting the default Tenant or the FusionAuth Application. With `prevent_destroy` set, Terraform stops at the plan. Without `prevent_destroy`, the apply fails partway through.

Keep the import blocks in the configuration. The blocks record that these resources came from FusionAuth, not from Terraform.

### Reference a Resource Without Managing It

A [data source](https://developer.hashicorp.com/terraform/language/data-sources) looks up an existing resource without managing the resource. This example creates an Application in the default Tenant without importing the Tenant:

Create an Application in the default Tenant

```hcl
data "fusionauth_tenant" "default" {
  name = "Default"
}

resource "fusionauth_application" "forum" {
  tenant_id = data.fusionauth_tenant.default.id
  name      = "Forum"
}
```

The provider documentation lists the available data sources.

## Handle Changes Made Outside Terraform

A change made in the Admin UI or through the API doesn't update the Terraform configuration. The next `terraform apply` reverts the change. Run `terraform plan` first to see what the apply reverts.

To keep all changes in Terraform, limit who can change configuration in the Admin UI. See [Admin UI roles](https://fusionauth.io/docs/concepts/types/roles.md#admin-ui-roles).

Some changes are expected. For example, an app might store settings in the **data** field of the FusionAuth Application that represents the app. List fields like **data** in [ignorechanges](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#ignore_changes), as the `Forum` Application does:

Ignore changes to the data field

```hcl
lifecycle {
  ignore_changes = [data]
}
```

To create a resource with Terraform but never update the resource, use `ignore_changes = all`.

## Protect Secrets

Terraform state contains secrets, such as OAuth client secrets and API keys. Before sharing state with a team, store the state in an encrypted backend with restricted access. See [Secrets](https://fusionauth.io/docs/deploy.md#secrets).

To create more API keys with Terraform, use the `fusionauth_api_key` resource. With Terraform 1.11 or later, set the key with the [write-only](https://developer.hashicorp.com/terraform/language/manage-sensitive-data/write-only) `key_wo` argument. Terraform doesn't store write-only values in state.

## Limitations

Terraform can't create the first API key. Create the first key in the Admin UI or with [Kickstart](https://fusionauth.io/docs/get-started/develop/kickstart.md).

The provider supports most of the FusionAuth API. Support for a new feature can arrive a few weeks after the FusionAuth release. To request a missing resource or argument, open an issue in the [provider repository](https://github.com/fusionauth/terraform-provider-fusionauth). Until then, manage that part of the configuration with a [script](https://fusionauth.io/docs/deploy.md#scripts).

Related

[Deploy Manage FusionAuth Configuration Across Environments Learn how to keep FusionAuth configuration in code and promote changes from one environment to another. configuration managementinfrastructure as codedevops](https://fusionauth.io/docs/deploy.md)

[Deploy FusionAuth CLI Learn about the FusionAuth CLI tool. configuration management](https://fusionauth.io/docs/deploy/production/cli.md)

[Deploy Test Learn how to run FusionAuth instances for local development, automated tests, and staging. terraform](https://fusionauth.io/docs/deploy/test.md)
---

## Other pages in Production

> For the full index of this section, see [Deploy](https://fusionauth.io/docs/llms-deploy.txt).

- [FusionAuth CLI](https://fusionauth.io/docs/deploy/production/cli.md): Learn about the FusionAuth CLI tool.
- [Configure a FusionAuth sCluster](https://fusionauth.io/docs/deploy/production/cluster.md): Learn how to set up a multi-node FusionAuth cluster.
- [Configuration Reference](https://fusionauth.io/docs/deploy/production/configuration.md): Learn about the configuration options for FusionAuth.
- [Air-gapping](https://fusionauth.io/docs/deploy/production/install/air-gapping.md): Run FusionAuth with no network access (air-gapped).
- [Install a Database](https://fusionauth.io/docs/deploy/production/install/database.md): Learn how to install the database that FusionAuth will use to store user data.
- [Customize Docker Images](https://fusionauth.io/docs/deploy/production/install/docker-configuration.md): Learn how to configure a Docker image containing FusionAuth to meet the needs of your application.
- [Install FusionAuth App](https://fusionauth.io/docs/deploy/production/install/fusionauth-app.md): Learn how to install FusionAuth App on a production server with Docker or from a package.
- [Packages](https://fusionauth.io/docs/deploy/production/install/packages.md): Learn how to determine which installation packages you need.
- [Install a Search Engine](https://fusionauth.io/docs/deploy/production/install/search.md): Learn how to install a search engine for your FusionAuth instance.
- [Silent Mode](https://fusionauth.io/docs/deploy/production/install/silent-mode.md): This is a guide to using silent mode during FusionAuth install and updates.
- [Microsoft Azure Kubernetes Service (AKS)](https://fusionauth.io/docs/deploy/production/kubernetes/aks.md): Learn how to provision an AKS cluster in Microsoft Azure.
- [Elastic Kubernetes Service (EKS)](https://fusionauth.io/docs/deploy/production/kubernetes/eks.md): Learn how to provision an EKS cluster in AWS.
- [Deploy with k8s](https://fusionauth.io/docs/deploy/production/kubernetes/fusionauth-deployment.md): Learn how to deploy FusionAuth in a Kubernetes Cluster.
- [Google Kubernetes Engine (GKE)](https://fusionauth.io/docs/deploy/production/kubernetes/gke.md): Learn how to provision a GKE cluster in Google Cloud (GCP).
- [Kubernetes](https://fusionauth.io/docs/deploy/production/kubernetes.md): Learn how to deploy and test FusionAuth using Kubernetes.
- [Local Cluster with minikube](https://fusionauth.io/docs/deploy/production/kubernetes/minikube.md): Learn how to provision minikube for local development and testing of FusionAuth kubernetes deployments.
- [AWS](https://fusionauth.io/docs/deploy/production/marketplaces/aws.md): Learn how to use FusionAuth with the AWS Marketplace.
- [DigitalOcean](https://fusionauth.io/docs/deploy/production/marketplaces/digitalocean.md): Learn how to use FusionAuth with the DigitalOcean Marketplace.
- [Google Cloud](https://fusionauth.io/docs/deploy/production/marketplaces/google-cloud.md): Learn how to use FusionAuth with the GCP Marketplace.
- [Install from a Marketplace](https://fusionauth.io/docs/deploy/production/marketplaces.md): Learn how to install FusionAuth using cloud marketplaces or templates.
- [Render](https://fusionauth.io/docs/deploy/production/marketplaces/render.md): Set FusionAuth up on Render from a Blueprint.
- [Proxy FusionAuth](https://fusionauth.io/docs/deploy/production/proxy-setup.md): Learn more about HTTP proxies and FusionAuth.
- [Server Layout](https://fusionauth.io/docs/deploy/production/server-layout.md): Learn about the different server layouts that FusionAuth can be installed with to optimize performance and security.
- [Start and Stop a Production Instance](https://fusionauth.io/docs/deploy/production/start-and-stop.md): Learn how to start and stop the FusionAuth services on a production server, in Docker, and in Kubernetes.
- [System Requirements](https://fusionauth.io/docs/deploy/production/system-requirements.md): Learn the minimum system requirements required to install and run FusionAuth.
