Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hashicorp/terraform/llms.txt

Use this file to discover all available pages before exploring further.

Kubernetes Backend

The Kubernetes backend stores state in Kubernetes Secrets and uses Lease objects for state locking.

Implementation

Location: /internal/backend/remote-state/kubernetes/backend.go

Use Cases

  • Managing Kubernetes infrastructure from within the cluster
  • GitOps workflows with ArgoCD or Flux
  • Kubernetes-native CI/CD pipelines
  • Multi-tenancy with namespace isolation

Basic Configuration

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    namespace     = "terraform"
  }
}

Required Configuration

secret_suffix

  • Type: String
  • Required: Yes
  • Description: Suffix used when creating the secret
The secret is named: tfstate-{workspace}-{secret_suffix} Important: The suffix must not end with -<number>. The backend appends numeric indices when chunking large state files.
terraform {
  backend "kubernetes" {
    secret_suffix = "prod"  # Valid
    # secret_suffix = "prod-1"  # Invalid - ends with -<number>
  }
}

Optional Configuration

namespace

  • Type: String
  • Optional: Yes
  • Default: "default"
  • Environment Variable: KUBE_NAMESPACE
  • Description: Namespace where the secret will be stored
terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    namespace     = "infrastructure"
  }
}

labels

  • Type: Map of strings
  • Optional: Yes
  • Description: Additional labels to apply to the secret
terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    labels = {
      "app"         = "terraform"
      "environment" = "production"
      "managed-by"  = "terraform"
    }
  }
}

Authentication Methods

The Kubernetes backend supports multiple authentication methods:

1. In-Cluster Configuration

For pods running inside Kubernetes:
terraform {
  backend "kubernetes" {
    secret_suffix      = "state"
    in_cluster_config  = true
  }
}
Environment Variable: KUBE_IN_CLUSTER_CONFIG

2. Kubeconfig File

terraform {
  backend "kubernetes" {
    secret_suffix    = "state"
    load_config_file = true
    config_path      = "~/.kube/config"
  }
}
Environment Variables:
  • KUBE_LOAD_CONFIG_FILE (default: true)
  • KUBE_CONFIG_PATH
  • KUBE_CONFIG_PATHS (colon-separated list)

3. Multiple Config Files

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    config_paths  = [
      "/path/to/config1",
      "/path/to/config2"
    ]
  }
}
Environment Variable: KUBE_CONFIG_PATHS

4. Direct Configuration

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    
    host                   = "https://kubernetes.example.com:6443"
    token                  = "<service-account-token>"
    cluster_ca_certificate = file("/path/to/ca.pem")
  }
}

5. Client Certificate Authentication

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    
    host               = "https://kubernetes.example.com:6443"
    client_certificate = file("/path/to/client.pem")
    client_key         = file("/path/to/client-key.pem")
  }
}
Environment Variables:
  • KUBE_CLIENT_CERT_DATA
  • KUBE_CLIENT_KEY_DATA

6. Username/Password Authentication

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    
    host     = "https://kubernetes.example.com:6443"
    username = "admin"
    password = "password"
  }
}
Environment Variables:
  • KUBE_USER
  • KUBE_PASSWORD

Advanced Configuration

Context Selection

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    
    config_context         = "production"
    config_context_cluster = "prod-cluster"
    config_context_auth_info = "prod-admin"
  }
}
Environment Variables:
  • KUBE_CTX
  • KUBE_CTX_CLUSTER
  • KUBE_CTX_AUTH_INFO

Exec Plugin Authentication

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    
    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      command     = "aws"
      args        = ["eks", "get-token", "--cluster-name", "my-cluster"]
      env = {
        AWS_PROFILE = "production"
      }
    }
  }
}

Insecure TLS

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    host          = "https://kubernetes.example.com:6443"
    insecure      = true
  }
}
Environment Variable: KUBE_INSECURE (default: false) Warning: Only use in development environments.

Proxy Configuration

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    proxy_url     = "http://proxy.example.com:8080"
  }
}
Environment Variable: KUBE_PROXY_URL

State Storage

State is stored in Kubernetes Secrets:
  • Secret name: tfstate-{workspace}-{secret_suffix}
  • Default workspace: tfstate-default-{secret_suffix}
  • Other workspaces: tfstate-{workspace}-{secret_suffix}

Chunking

Large state files are automatically chunked into multiple secrets:
  • tfstate-{workspace}-{secret_suffix}-0
  • tfstate-{workspace}-{secret_suffix}-1
  • tfstate-{workspace}-{secret_suffix}-2
This is why secret_suffix cannot end with -<number>.

State Locking

The backend uses Kubernetes Lease objects for locking:
  • Lease name: Matches the secret name
  • Namespace: Same as the secret
  • Automatic renewal: Leases are renewed during long operations

Configuration Options Summary

OptionTypeRequiredDefaultDescription
secret_suffixstringYes-Suffix for secret name
namespacestringNodefaultKubernetes namespace
labelsmap(string)No{}Labels for the secret
in_cluster_configboolNofalseUse in-cluster config
load_config_fileboolNotrueLoad kubeconfig file
config_pathstringNo-Path to kubeconfig
config_pathslist(string)No-Multiple kubeconfig paths
config_contextstringNo-Kubeconfig context
config_context_auth_infostringNo-Auth info name
config_context_clusterstringNo-Cluster name
hoststringNo-Kubernetes API server URL
usernamestringNo-Basic auth username
passwordstringNo-Basic auth password
tokenstringNo-Service account token
client_certificatestringNo-Client certificate PEM
client_keystringNo-Client key PEM
cluster_ca_certificatestringNo-CA certificate PEM
insecureboolNofalseSkip TLS verification
proxy_urlstringNo-Proxy server URL

Example: In-Cluster with Service Account

terraform {
  backend "kubernetes" {
    secret_suffix     = "state"
    in_cluster_config = true
    namespace         = "terraform"
    
    labels = {
      "app" = "terraform"
    }
  }
}

Example: EKS with AWS IAM Authenticator

terraform {
  backend "kubernetes" {
    secret_suffix = "state"
    namespace     = "terraform"
    
    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      command     = "aws"
      args = [
        "eks",
        "get-token",
        "--cluster-name",
        "my-eks-cluster"
      ]
    }
  }
}

RBAC Requirements

The service account or user needs these permissions:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: terraform-backend
  namespace: terraform
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list", "create", "update", "delete"]
- apiGroups: ["coordination.k8s.io"]
  resources: ["leases"]
  verbs: ["get", "create", "update", "delete"]

Best Practices

  1. Use namespaces to isolate different teams or environments
  2. Apply labels for organization and filtering
  3. RBAC policies with minimal required permissions
  4. In-cluster config for pods, kubeconfig for external access
  5. Service accounts instead of user credentials
  6. Monitor secret size - Kubernetes secrets have a 1MB limit
  7. Descriptive suffixes to identify state purposes

Limitations

  1. Secret size limit - 1MB per secret (handled via chunking)
  2. No built-in encryption - Use encryption at rest in etcd
  3. RBAC required - Must have proper permissions
  4. Namespace scoped - Cannot share across namespaces easily

Build docs developers (and LLMs) love