
There are plenty of ways to deploy and manage what runs inside a Kubernetes cluster: a Helm chart, raw manifests, Kustomize, and so on. But in my experience, if your organization already uses Terraform (or OpenTofu), reaching for the Terraform Kubernetes provider to handle the full lifecycle of your cluster resources is usually the better call. It keeps the experience consistent for the people on your team today and for anyone who joins later. The HashiCorp configuration language (HCL) gives you one common language for describing and building any service or resource in your organization.
This post covers configuring the official Kubernetes provider to build out services across your environment no matter which cloud sits underneath, which is one of the main selling points of Kubernetes in the first place.
The Terraform registry is where you'll find the most up to date information about the Kubernetes Provider. One thing that sets the Kubernetes provider apart is that its resources and data sources are versioned. Those versions line up with the Kubernetes API version itself, which gives you strong backwards compatibility. The kubernetes secrets resources below are one example:
Additional information can be found out about the Kubernetes API and its versions here.
The provider gives you several ways to configure it, and they fall into two groups: explicit and implicit. Explicit means you supply configuration arguments directly in the provider block. Implicit means you rely on environment variables. Either way, you really need to think about sensitive information like keys and tokens so you don't open up a security issue. I'd strongly encourage passing those sensitive details in via the CLI or environment variables. With those two groups in mind, here are some examples of authenticating the provider against a cluster:
File configuration is a great way to set up the provider when you're working locally with Terraform, since it just takes a path to the Kubeconf that holds all the relevant details. You can also constrain it to a given context, otherwise the default context is used.
This would grab the relevant details from the Kubeconf to authenticate the provider with that particular cluster. Alternatively the environment variables KUBE_CONFIG_PATH and CONFIG_CONTEXT can be used.
This method lets you pass the file contents in directly for the authentication arguments. It's powerful when your Terraform orchestrator hands you those files dynamically, whether for a single environment or several, so you can apply the same configuration across multiple clusters. Here are those arguments:
These arguments do what they say. We're passing the paths to the file builtin function, which reads the contents as a UTF-8 encoded string. You can also do this with data sources from a given cloud platform, which makes the provider configuration fully dynamic.
If you're running your Terraform commands within a Kubernetes cluster and it is that cluster you wish to execute on, the in-cluster configuration is perfect. This configuration is done via the KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT environment variables allowing Terraform to configure resources within the cluster.
When it comes to Kubernetes, cloud providers all let you pull the Kubeconf from their managed clusters with CLI utilities. The Exec plugin type of configuration is built for exactly that case, where you want to run an external command to grab the right details at runtime. The below example uses AWS' EKS service.
The contents of the exec block could easily be subbed out for the Azure variant:
In my opinion this is another unique feature of the Kubernetes Terraform provider, and a genuinely valuable one. It lets you reach external authentication mechanisms from inside the provider declaration itself.
The example below deploys a simple service into its own namespace using Terraform.
That config creates a service that distributes traffic across the three pods the deployment spins up, as the diagram below shows.

The advantage of provisioning Kubernetes services with OpenTofu/Terraform is that it's a common language teams understand regardless of what they happen to be deploying. You also get the features of OpenTofu/Terraform itself. The example above references the namespace instead of typing it out by hand, and it uses locals for the labels.
This post walked through the Kubernetes provider and how to set it up. We covered four ways to authenticate it: file configuration, credential configuration, in-cluster configuration, and exec plugins. Between them, engineers have enough flexibility to wire up Kubernetes however a given situation demands. We then finished with an example of using Terraform to deploy something into a cluster.
