# Manage Union through Terraform
> This bundle contains all pages in the Manage Union through Terraform section.
> Source: https://www.union.ai/docs/latest/union/deployment/terraform/

=== PAGE: https://www.union.ai/docs/latest/union/deployment/terraform ===

# Managing Union with Terraform

Union provides a Terraform provider that enables infrastructure-as-code management of your Union deployment. With the Union Terraform provider, you can define, deploy, and manage Union resources using declarative configuration files.

## Overview

The Union Terraform provider allows you to manage Union resources programmatically, including:

- **Projects**: Create and manage Union projects
- **Access control**: Configure users, roles, and policies
- **API keys**: Generate and manage API keys for automation
- **OAuth applications**: Set up OAuth applications for external integrations
- **Access assignments**: Assign users and applications to resources

## Why use Terraform?

Using Terraform to manage Union provides several benefits:

- **Version control**: Track changes to your Union configuration over time
- **Reproducibility**: Easily replicate configurations across environments
- **Automation**: Integrate Union management into your CI/CD pipelines
- **Consistency**: Ensure consistent configuration across your organization
- **Documentation**: Your Terraform files serve as living documentation

## Getting started

To get started with the Union Terraform provider:

1. **Installation**: Set up the Terraform provider in your environment
2. **Management**: Learn about the available resources and data sources for managing Union

### **Managing Union with Terraform > Installing the Union Terraform provider**

Install and configure the Union Terraform provider

### **Managing Union with Terraform > Managing Union resources with Terraform**

Learn about available resources and data sources

### **Managing Union with Terraform > Security best practices**

Securely manage API keys and credentials

## Requirements

- Terraform >= 1.0
- Union API key (generated using the [Flyte CLI](https://www.union.ai/docs/latest/union/api-reference/flyte-cli/page.md))
- Access to a Union deployment

=== PAGE: https://www.union.ai/docs/latest/union/deployment/terraform/installation ===

# Installing the Union Terraform provider

The Union Terraform provider is distributed through the [Terraform Registry](https://registry.terraform.io/providers/unionai/unionai/latest/docs). Terraform installs it automatically when you declare it in your configuration and run `terraform init`, so there is no separate download step. Add the provider block below, then run `terraform init` to fetch it.

## Quick start

To use the Union Terraform provider, add it to your Terraform configuration:

```hcl
terraform {
  required_providers {
    unionai = {
      source  = "unionai/unionai"
      version = "~> 0.2"
    }
  }
}

provider "unionai" {
  api_key = var.unionai_api_key
}
```

> **Security note:** Never hardcode API keys in your Terraform files. See [Security best practices](./security) for recommended approaches to securely manage your API keys.

## Versioning

To choose the appropriate version of the provider (likely you should choose latest):

1. Visit the Provider Registry site and observe the latest version number
2. Use that version number in the provider declaration above

For detailed installation instructions, please refer to the [Terraform Registry documentation](https://registry.terraform.io/providers/unionai/unionai/latest/docs).

=== PAGE: https://www.union.ai/docs/latest/union/deployment/terraform/management ===

# Managing Union resources with Terraform

The Union Terraform provider enables you to manage Union resources using infrastructure-as-code principles. This page provides an overview of the provider's capabilities, including authentication, available resources, and data sources.

## Provider configuration

### Basic configuration

Configure the Union provider in your Terraform configuration:

```hcl
terraform {
  required_providers {
    unionai = {
      source  = "unionai/unionai"
      version = "~> 0.2"
    }
  }
}

provider "unionai" {
  api_key      = var.unionai_api_key
  allowed_orgs = ["your-org-name"]
}
```

### Configuration parameters

- **`api_key`** (Required): Your Union API key for authentication
- **`allowed_orgs`** (Optional): List of organization names to restrict operations to, preventing unintended operations across multiple organizations

## Authentication

The Union Terraform provider uses API key authentication. You can provide your API key in two ways:

### 1. Provider configuration

Specify the API key directly in the provider block (use variables to avoid hardcoding):

```hcl
provider "unionai" {
  api_key = var.unionai_api_key
}
```

### 2. Environment variable

Set the `UNIONAI_API_KEY` environment variable:

```bash
export UNIONAI_API_KEY="your-api-key"
```

### Generating an API key

Create an API key using the `flyte` CLI:

```bash
flyte create api-key --name "terraform-api-key"
```

For more information on creating API keys, see the [Flyte CLI documentation](https://www.union.ai/docs/latest/union/api-reference/flyte-cli).

Save the generated key securely, as it will be used to authenticate all Terraform operations against your Union deployment.

## Available resources

The Union Terraform provider supports the following resources for managing your Union deployment:

### Projects

Create and manage Union projects:

```hcl
resource "unionai_project" "example" {
  name        = "my-project"
  description = "Example project managed by Terraform"
}
```

Projects are the primary organizational unit in Union, containing workflows, tasks, and executions.

### Users

Manage user accounts:

```hcl
resource "unionai_user" "example" {
  email      = "user@example.com"
  first_name = "John"
  last_name  = "Doe"
}
```

### Roles

Define custom roles for access control:

```hcl
resource "unionai_role" "example" {
  name        = "custom-role"
  description = "Custom role with specific permissions"
  actions = [
    "create_flyte_executions",
    "view_flyte_inventory",
  ]
}
```

The `actions` argument is required: it is the set of actions the role grants (for example, `create_flyte_executions`, `register_flyte_inventory`, `administer_project`).

### Policies

Create access policies that define permissions:

```hcl
resource "unionai_policy" "example" {
  name        = "project-access-policy"
  description = "Policy for project access"

  project {
    id      = unionai_project.example.id
    role_id = unionai_role.example.id
    domains = ["development", "staging"]
  }
}
```

A policy binds a role to a subject at a given scope. Use an `organization`, `project`, or `domain` block (each takes an `id` and a `role_id`); the `project` block also accepts an optional `domains` set.

### API keys

Generate and manage API keys programmatically:

```hcl
resource "unionai_api_key" "example" {
  id = "automation-key"
}
```

The `id` is the only argument; it must be unique within your organization. The generated `secret` is a read-only, sensitive attribute stored in state, available only at creation time.

### OAuth applications

Configure OAuth applications for external integrations:

```hcl
resource "unionai_application" "example" {
  client_id   = "external-app"
  client_name = "External Application"

  grant_types   = ["AUTHORIZATION_CODE"]
  redirect_uris = ["https://example.com/callback"]
}
```

The required arguments are `client_id` and `client_name`. `redirect_uris` is a set of strings (not a single value). The client `secret` is a read-only, sensitive attribute available only at creation time.

### Access assignments

Access is policy-based: a policy carries the role-to-scope binding, and an access resource assigns that policy to a user or an application. Each access resource takes just two arguments.

```hcl
# Assign a policy to a user
resource "unionai_user_access" "example" {
  user_id   = unionai_user.example.id
  policy_id = unionai_policy.example.id
}

# Assign a policy to an application
resource "unionai_application_access" "example" {
  app_id    = unionai_application.example.id
  policy_id = unionai_policy.example.id
}
```

## Available data sources

Data sources allow you to query existing Union resources for use in your Terraform configuration. Each is looked up by its `id`; attributes such as `name` and `email` are read-only outputs, not lookup keys.

### Projects

Query an existing project:

```hcl
data "unionai_project" "existing" {
  id = "my-project-id"
}
```

### Users

Look up user information:

```hcl
data "unionai_user" "existing" {
  id = "user-id"
}
```

### Roles

Reference an existing role:

```hcl
data "unionai_role" "admin" {
  id = "admin-role-id"
}
```

### Policies

Query an existing policy:

```hcl
data "unionai_policy" "existing" {
  id = "policy-id"
}
```

### API keys

Reference an existing API key:

```hcl
data "unionai_api_key" "existing" {
  id = "api-key-id"
}
```

### Applications

Look up an OAuth application:

```hcl
data "unionai_application" "existing" {
  id = "app-client-id"
}
```

### Data plane information

Query information about the data plane:

```hcl
data "unionai_dataplane" "current" {
  id = "dataplane-id"
}
```

### Control plane information

Access control plane details:

```hcl
data "unionai_controlplane" "current" {
  # Control plane data source
}
```

### Data plane listings

List all available data planes:

```hcl
data "unionai_dataplanes" "all" {
  # Returns list of all data planes
}
```

## Best practices

### Use variables for sensitive data

Never hardcode sensitive information like API keys in your Terraform files:

```hcl
variable "unionai_api_key" {
  description = "Union API key"
  type        = string
  sensitive   = true
}

provider "unionai" {
  api_key = var.unionai_api_key
}
```

### Organize resources with modules

Structure your Terraform code using modules for reusability:

```
terraform/
├── modules/
│   ├── project/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   └── access-control/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── main.tf
```

### Use organization restrictions

Prevent accidental operations across multiple organizations:

```hcl
provider "unionai" {
  api_key      = var.unionai_api_key
  allowed_orgs = ["production-org"]
}
```

### Version control your configuration

Store your Terraform configuration in version control to track changes over time, but ensure sensitive files are excluded:

```gitignore
# .gitignore
*.tfvars
*.tfstate
*.tfstate.backup
.terraform/
```

### Use remote state

For team environments, use remote state storage:

```hcl
terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "union/terraform.tfstate"
    region = "us-west-2"
  }
}
```

## Example: complete setup

Here's a complete example that creates a project with access control:

```hcl
terraform {
  required_providers {
    unionai = {
      source  = "unionai/unionai"
      version = "~> 0.2"
    }
  }
}

provider "unionai" {
  api_key      = var.unionai_api_key
  allowed_orgs = ["my-organization"]
}

# Create a project
resource "unionai_project" "ml_pipeline" {
  name        = "ml-pipeline"
  description = "Machine learning pipeline project"
}

# Create a custom role
resource "unionai_role" "ml_engineer" {
  name        = "ml-engineer"
  description = "Role for ML engineers"
  actions = [
    "create_flyte_executions",
    "view_flyte_inventory",
  ]
}

# Create a user
resource "unionai_user" "data_scientist" {
  first_name = "Jane"
  last_name  = "Smith"
  email      = "data.scientist@example.com"
}

# Bind the role to the project with a policy
resource "unionai_policy" "ml_pipeline_access" {
  name        = "ml-pipeline-access"
  description = "Grant the ML engineer role on the ML pipeline project"

  project {
    id      = unionai_project.ml_pipeline.id
    role_id = unionai_role.ml_engineer.id
  }
}

# Assign the policy to the user
resource "unionai_user_access" "scientist_access" {
  user_id   = unionai_user.data_scientist.id
  policy_id = unionai_policy.ml_pipeline_access.id
}

# Create an API key for automation
resource "unionai_api_key" "ci_cd" {
  id = "ci-cd-pipeline-key"
}
```

## Additional resources

- [Union Terraform Provider Documentation](https://registry.terraform.io/providers/unionai/unionai/latest/docs)
- [Terraform Documentation](https://www.terraform.io/docs)
- [Flyte CLI Documentation](https://www.union.ai/docs/latest/union/api-reference/flyte-cli)

## Requirements

- **Terraform**: >= 1.0
- **Union API key**: Generated via the `flyte` CLI
- **Go**: >= 1.24 (for development only)

## Support and contributions

The Union Terraform provider is open source and licensed under the Mozilla Public License 2.0. For the complete provider documentation, visit the [Terraform Registry](https://registry.terraform.io/providers/unionai/unionai/latest/docs).

=== PAGE: https://www.union.ai/docs/latest/union/deployment/terraform/security ===

# Security best practices

**Never hardcode API keys directly in your Terraform configuration files.** API keys are sensitive credentials that should be stored securely and never committed to version control.

## Recommended approaches

### 1. Use cloud secret managers

Store your Union API key in a cloud-based secret manager and retrieve it dynamically:

#### AWS Secrets Manager

```hcl
data "aws_secretsmanager_secret" "unionai_api_key" {
  name = "unionai/terraform-api-key"
}

data "aws_secretsmanager_secret_version" "unionai_api_key" {
  secret_id = data.aws_secretsmanager_secret.unionai_api_key.id
}

provider "unionai" {
  api_key = data.aws_secretsmanager_secret_version.unionai_api_key.secret_string
}
```

#### Google Cloud Secret Manager

```hcl
data "google_secret_manager_secret_version" "unionai_api_key" {
  secret  = "unionai-terraform-api-key"
  project = "your-project-id"
}

provider "unionai" {
  api_key = data.google_secret_manager_secret_version.unionai_api_key.secret_data
}
```

#### Azure Key Vault

```hcl
data "azurerm_key_vault" "main" {
  name                = "your-keyvault-name"
  resource_group_name = "your-resource-group"
}

data "azurerm_key_vault_secret" "unionai_api_key" {
  name         = "unionai-api-key"
  key_vault_id = data.azurerm_key_vault.main.id
}

provider "unionai" {
  api_key = data.azurerm_key_vault_secret.unionai_api_key.value
}
```

### 2. Use HashiCorp Vault

For multi-cloud or on-premises deployments, HashiCorp Vault provides centralized secret management:

```hcl
data "vault_generic_secret" "unionai_api_key" {
  path = "secret/terraform/unionai"
}

provider "unionai" {
  api_key = data.vault_generic_secret.unionai_api_key.data["api_key"]
}
```

### 3. Use environment variables

For local development or CI/CD pipelines, use environment variables:

```bash
export UNIONAI_API_KEY="your-api-key-here"
```

The provider will automatically read from the `UNIONAI_API_KEY` environment variable:

```hcl
provider "unionai" {
  # api_key is read from UNIONAI_API_KEY environment variable
}
```

### 4. Use Terraform variables with `.tfvars` files

If using variable files, ensure they are excluded from version control:

```hcl
# variables.tf
variable "unionai_api_key" {
  description = "Union API key"
  type        = string
  sensitive   = true
}

# main.tf
provider "unionai" {
  api_key = var.unionai_api_key
}
```

Create a `terraform.tfvars` file (add to `.gitignore`):

```hcl
unionai_api_key = "your-api-key-here"
```

## Additional security measures

### Encrypt Terraform state

Always use encrypted remote state backends to protect sensitive data:

```hcl
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "union/terraform.tfstate"
    region         = "us-west-2"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}
```

### Use state locking

Enable state locking to prevent concurrent modifications:

- **AWS S3**: Use DynamoDB for state locking
- **Google Cloud Storage**: Automatic state locking
- **Azure Blob Storage**: Automatic state locking

### Rotate API keys regularly

Implement a rotation schedule for your API keys:

1. Generate a new API key using the Flyte CLI
2. Update the key in your secret manager
3. Verify Terraform can authenticate with the new key
4. Delete the old API key

### Restrict provider permissions

Use the `allowed_orgs` parameter to limit which organizations the provider can access:

```hcl
provider "unionai" {
  api_key      = var.unionai_api_key
  allowed_orgs = ["production-org"]
}
```

This prevents accidental operations on the wrong organization.

### Use separate API keys per environment

Create different API keys for each environment (development, staging, production):

```hcl
# Development
provider "unionai" {
  alias   = "dev"
  api_key = var.dev_api_key
}

# Production
provider "unionai" {
  alias   = "prod"
  api_key = var.prod_api_key
}
```

## Security checklist

- ✅ Store API keys in a secret manager or secure vault
- ✅ Use environment variables for local development
- ✅ Mark variables containing secrets as `sensitive = true`
- ✅ Add `*.tfvars`, `*.tfstate`, and `*.tfstate.backup` to `.gitignore`
- ✅ Use remote state backends with encryption enabled
- ✅ Enable state locking to prevent concurrent modifications
- ✅ Rotate API keys regularly
- ✅ Use separate API keys per environment
- ✅ Restrict provider access with `allowed_orgs`
- ✅ Review Terraform plans before applying changes
- ❌ Never commit API keys to version control
- ❌ Never hardcode API keys in `.tf` files
- ❌ Never share API keys in plain text (chat, email, etc.)
- ❌ Never use production API keys in development environments

## CI/CD pipeline security

When using Terraform in CI/CD pipelines:

### GitHub Actions

```yaml
name: Terraform

on:
  push:
    branches: [main]

jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2

      - name: Terraform Init
        env:
          UNIONAI_API_KEY: ${{ secrets.UNIONAI_API_KEY }}
        run: terraform init

      - name: Terraform Apply
        env:
          UNIONAI_API_KEY: ${{ secrets.UNIONAI_API_KEY }}
        run: terraform apply -auto-approve
```

### GitLab CI

```yaml
terraform:
  image: hashicorp/terraform:latest
  variables:
    UNIONAI_API_KEY: $UNIONAI_API_KEY
  script:
    - terraform init
    - terraform apply -auto-approve
  only:
    - main
```

### Best practices for CI/CD

- Store API keys as encrypted secrets in your CI/CD platform
- Use separate API keys for CI/CD (not personal keys)
- Implement approval gates for production deployments
- Enable audit logging for all Terraform operations
- Restrict who can view/modify CI/CD secrets

## Additional resources

- [Terraform Security Best Practices](https://developer.hashicorp.com/terraform/tutorials/configuration-language/sensitive-variables)
- [HashiCorp Vault Documentation](https://developer.hashicorp.com/vault/docs)
- [Flyte CLI Documentation](https://www.union.ai/docs/latest/union/api-reference/flyte-cli)

