Introduction
The kubectl provider for Terraform exists to close a gap that the official HashiCorp Kubernetes provider cannot fully cover. The official provider covers most standard resources such as deployments, services and config maps. Kubernetes is extensible, and the ecosystem contains Custom Resource Definitions, operator managed resources and complex manifests that the official provider does not support natively. The kubectl provider lets you apply arbitrary YAML manifests through Terraform, similar to running kubectl apply -f. It handles CRDs, custom resources, multi document YAML files and anything else you can express in a Kubernetes manifest.
The core of this provider is the kubectl_manifest resource, allowing free form yaml to be processed and applied against Kubernetes. This yaml object is then tracked and handles creation, updates and deleted seamlessly, including drift detection. A set of helpful data resources to process directories of yaml files and inline templating is available. This terraform-provider-kubectl provider has been used by many large Kubernetes installations to completely manage the lifecycle of Kubernetes resources. The provider can be installed and managed automatically by Terraform.
The provider is described as the best way of managing Kubernetes resources in Terraform, by allowing you to use the thing Kubernetes loves best - yaml. The basic workflow from YAML manifest to deployed Kubernetes resource is demonstrated through a simple walkthrough of creating your first kubectlmanifest resource using the terraform-provider-kubectl. The guide covers the fundamental usage pattern of the provider: defining a Kubernetes resource using raw YAML within a Terraform configuration and applying it to a cluster. This example focuses on the core kubectlmanifest resource which is the primary interface for managing Kubernetes resources with this provider.
Basic Usage Workflow and YAML to Resource Pipeline
The diagram shows how the provider processes a kubectlmanifest resource. The yamlbody content is parsed into a structured manifest. Code Entity Relationships for kubectlmanifest map user configuration elements to specific code entities in the provider. The mapping involves kubectlManifestSchema, variable Manifest, and objects. After applying the example ConfigMap, Terraform state includes computed attributes that are automatically extracted from the yamlbody during the CustomizeDiff function and stored in Terraform state for drift detection and planning.
The workflow has real world consequences for teams that want Terraform state to reflect the actual Kubernetes API objects. Because the provider parses yaml_body at plan time, Terraform can compare the desired manifest with the live object. When a change is made outside of Terraform, for example a manual kubectl edit, the provider detects drift on the next plan. This prevents configuration drift from persisting unnoticed in production clusters.
The provider automatically extracts values from the yamlbody during the CustomizeDiff function and stores them in Terraform state for drift detection and planning. Once you have this basic example working, the kubectlmanifest resource supports the full Kubernetes resource lifecycle and provides extensive configuration options for production use cases.
Provider Installation and Configuration
Installing the kubectl Provider begins with adding the provider to your Terraform configuration. The provider uses the same kubeconfig as the official Kubernetes provider. You can configure both to point at the same cluster.
A minimal versions.tf with provider requirements is:
terraform
terraform {
required_version = ">= 1.5.0"
required_providers {
kubectl = {
source = "gavinbunney/kubectl"
version = "~> 1.14"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.25"
}
}
}
The kubectl provider is configured with kubeconfig settings:
terraform
provider "kubectl" {
config_path = "~/.kube/config"
config_context = "my-cluster"
}
The configuration choice of configpath and configcontext determines which cluster the provider targets. Using the same kubeconfig file as other tools reduces credential duplication and allows operators to switch contexts without modifying Terraform code. This alignment with standard kubeconfig behavior lowers adoption friction for teams already using kubectl.
kubectl_manifest Resource Definition
The basic resource is kubectl_manifest. The fundamental usage pattern is defining a Kubernetes resource using raw YAML within a Terraform configuration and applying it to a cluster.
This configuration demonstrates the essential components:
- kubectl_manifest resource type
- yaml_body attribute
The resource type yaml_body attribute is the primary input. The provider does not require you to translate YAML into HCL structures. You supply the manifest as a string and the provider submits it to the API server.
A minimal example that creates a Kubernetes ConfigMap is described in the reference walkthrough. The essential components are present in any resource block: the resource type kubectlmanifest and the yamlbody attribute containing the raw manifest.
The impact of this design is that platform teams can copy manifests from existing clusters or Helm charts directly into Terraform without rewriting them. This preserves comments, ordering and custom fields that HCL abstractions would otherwise lose.
Computed Attributes and State Tracking
After applying the example ConfigMap, Terraform state includes these computed attributes:
| Attribute | Example Value | Description |
|---|---|---|
| api_version | v1 | Extracted from YAML |
| kind | ConfigMap | Resource type |
| name | my-config | Resource name |
| namespace | default | Target namespace |
| uid | a1b2c3d4-.. | Kubernetes UID |
| yamlbodyparsed | Obfuscated YAML | Safe for display |
The provider automatically extracts these values from the yaml_body during the CustomizeDiff function and stores them in Terraform state for drift detection and planning.
The apiversion, kind, name and namespace values form a unique identity for the resource. Terraform uses these to locate the object in the API server. The uid is the immutable server assigned identifier and is used to verify that the object in state matches the object in the cluster. The yamlbody_parsed value is obfuscated for safe display while still allowing the provider to compare content.
Tracking these attributes in state enables the provider to report accurate plans when the manifest changes, when labels are added by operators, or when the API server injects default fields. The real world consequence is that operators receive clear messages about what changed and why, rather than opaque diffs.
Drift Detection and Lifecycle Management
The core of this provider is the kubectl_manifest resource, allowing free form yaml to be processed and applied against Kubernetes. This yaml object is then tracked and handles creation, updates and deleted seamlessly, including drift detection.
Drift detection means that if an administrator edits a manifest with kubectl, or an operator mutates fields, Terraform will detect the difference on the next plan. The provider compares the desired yaml_body with the live object representation stored in state. This is distinct from providers that only track the fields the user explicitly wrote.
The provider supports the full Kubernetes resource lifecycle. Creation is performed via the API server apply logic. Updates are performed by applying the new yaml_body. Deletion is performed when the resource is removed from configuration. The seamless handling reduces the need for manual state manipulation.
Handling CRDs, Custom Resources and Multi Document YAML
The official Kubernetes provider for Terraform covers most standard resources. But Kubernetes is extensible, and the ecosystem is full of Custom Resource Definitions, operator managed resources and complex manifests that the official provider does not support natively. That is where the kubectl provider comes in.
The kubectl provider lets you apply arbitrary YAML manifests through Terraform, similar to running kubectl apply -f. It handles CRDs, custom resources, multi document YAML files and anything else you can express in a Kubernetes manifest.
Multi document YAML files are a common pattern in GitOps repositories where a single file contains a namespace, RBAC objects and workloads. The provider can process these without splitting them into separate resources. This preserves author intent and reduces repository fragmentation.
For CRDs, the provider applies the definition and then subsequent resources that depend on it. The provider does not require a separate data source for CRD existence. The ability to manage custom resources means teams using operators such as Prometheus, cert-manager or custom controllers can manage the operator managed resources with the same Terraform workflow used for native resources.
Data Resources and Inline Templating
A set of helpful data resources to process directories of yaml files and inline templating is available. These data resources complement the kubectl_manifest resource by allowing bulk loading of manifests from a directory and performing limited templating before application.
Processing directories of yaml files is useful when a team maintains a library of reusable manifests in version control. The data resource reads the files, aggregates them and feeds them to the provider. Inline templating allows substitution of variables such as image tags or namespace names without requiring external preprocessing tools.
The impact is reduced boilerplate. Teams can keep manifests in their native format and still benefit from Terraform dependency ordering and state tracking.
Migration Between Provider Namespaces
The provider has been published under different namespaces. Migration from gavinbunney/kubectl to alekc/kubectl is performed with a moved block.
Pick a transitional address:
terraform
terraform {
required_providers {
kubectl = {
source = "alekc/kubectl"
}
}
}
Define a moved block:
terraform
moved {
from = kubectl_manifest.my_app
to = kubectl_manifest.my_app_v3
}
Define the resource with the new address:
```terraform
resource "kubectlmanifest" "myapp_v3" {
... same yaml_body / attributes as before
}
```
Run the migration:
bash
terraform init -upgrade
bash
terraform plan
The plan reports the resource as moved with no in place changes:
```bash
kubectlmanifest.myapp has moved to kubectlmanifest.myapp_v3
resource "kubectlmanifest" "myapp_v3" {
(N unchanged attributes hidden)
}
Plan: 0 to add, 0 to change, 0 to destroy.
```
Run apply to commit the move:
bash
terraform apply
After the move applies you can either keep the new name or rename back. The 20 attributes shared with gavinbunney carry over unchanged. The provider state remains consistent because the underlying API interactions are identical. The migration preserves history and avoids recreation of resources in the cluster.
Note that terraform plan -detailed-exitcode returns 2 on the first plan because moved annotations count as changes present even when the resource summary is 0 to add, 0 to change, 0 to destroy. The second plan after apply returns 0 cleanly. Treat the summary line as authoritative.
Comparison With HashiCorp kubernetes_manifest
The reference material also discusses the HashiCorp kubernetes provider tutorial. The tutorial shows kubernetes_manifest resource usage for CRD creation and custom resources.
When the configuration is applied to create a CRD, Terraform creates a resource with two attributes:
- manifest
- object
The manifest attribute is your desired configuration, and object is the end state returned by the Kubernetes API server after Terraform created the resource. The object attribute contains many more fields than you specified in manifest because Terraform generated a schema containing all of the possible resource attributes that the Kubernetes API server could add. When referencing the kubernetes_manifest resource from outputs or other resources, always use the object attribute.
Confirm that Terraform created the CRD using kubectl:
bash
kubectl get crds crontabs.stable.example.com
The output shows NAME and CREATED AT. The resource definition now exists in Kubernetes, but you have not used it to define any Kubernetes resources yet. Check for the resource definition with kubectl, which would return error: the server doesn't have a resource type "crontab" if the CRD didn't exist.
bash
kubectl get crontabs
No resources found in default namespace.
This distinction is important. The kubectl provider’s kubectlmanifest resource uses yamlbody as input and tracks extracted attributes for drift detection. The HashiCorp kubernetes_manifest resource uses manifest as input and exposes object as the server returned state. Teams choosing between the two weigh native YAML fidelity and provider maintenance against first class schema generation and object attribute access.
Production Use Considerations
The provider has been used by many large Kubernetes installations to completely manage the lifecycle of Kubernetes resources. Production use benefits from the provider’s ability to apply arbitrary YAML, which means security policies, network policies, and custom operator resources can be versioned alongside application manifests.
Because the provider tracks yamlbodyparsed in state, teams can audit what was applied without exposing sensitive values in plan output. The automatic extraction of api_version, kind, name, namespace and uid provides stable identifiers for dependencies.
Using the same kubeconfig as the official Kubernetes provider allows a single authentication configuration to serve both providers. This reduces secret sprawl and simplifies rotation.
When migrating provider namespaces, keeping the moved block in place for one apply cycle and then cleaning it up prevents state drift. The 20 shared attributes ensure that attribute semantics remain stable across namespace changes.
Conclusion
The kubectl provider for Terraform delivers a direct bridge between raw Kubernetes YAML and Terraform state. The kubectlmanifest resource accepts yamlbody, parses it into a structured manifest, applies it to the cluster, and tracks computed attributes such as apiversion, kind, name, namespace, uid and yamlbody_parsed for drift detection and planning.
The provider fills the gap left by the official Kubernetes provider when dealing with CRDs, operator managed resources and multi document manifests. It supports creation, updates and deletion with seamless drift detection, and it can be installed automatically by Terraform with a simple required_providers block and kubeconfig configuration.
Migration between provider namespaces is supported via moved blocks with no resource recreation. Data resources for directory processing and inline templating extend the core resource for bulk workflows. The provider’s design preserves YAML fidelity, reduces translation effort, and enables large installations to manage the full lifecycle of Kubernetes resources declaratively.