What are Terraform Providers?
Terraform providers are plugins that Terraform uses to manage resources. They act as translators between Terraform's configuration language and the APIs of various services, enabling you to manage infrastructure across multiple cloud providers and services.
Provider Architecture
Providers are written in Go and implement a standard interface that Terraform uses to:
- Discover available resources and data sources
- Read and update resource state
- Plan and apply changes
- Handle authentication and API communication
How Providers Work
Provider Lifecycle
- 1Initialization: Terraform downloads and configures providers
- 2Schema Exchange: Terraform requests resource schemas
- 3Planning: Provider calculates changes needed
- 4Application: Provider executes API calls
- 5State Update: Provider returns new state to Terraform
Communication Flow
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Terraform │ ────────▶│ Provider │ ────────▶│ API │
│ Core │ ◀─────── │ Plugin │ ◀─────── │ Endpoint │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
└─────────────────────────┘
State ManagementInstalling and Configuring Providers
Provider Source
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}Provider Sources Breakdown
- hashicorp/aws: Official HashiCorp AWS provider
- hashicorp/azurerm: Official HashiCorp Azure provider
- google-beta: Google provider with beta features
- kreuzwerker/docker: Community Docker provider
Version Constraints
terraform {
required_providers {
# Exact version
aws = {
version = "5.0.0"
}
# Minimum version
azurerm = {
version = ">= 3.0"
}
# Pessimistic version constraint
google = {
version = "~> 4.0" # >= 4.0, < 5.0
}
# Range
docker = {
version = ">= 2.0, < 4.0"
}
}
}Provider Initialization
terraform initOutput:
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.0.0...
- Installed hashicorp/aws v5.0.0 (signed by HashiCorp)
Terraform has created a lock file...AWS Provider
Basic Configuration
provider "aws" {
region = "us-east-1"
}Authentication Methods
1. Environment Variables:
export AWS_ACCESS_KEY_ID="your_access_key"
export AWS_SECRET_ACCESS_KEY="your_secret_key"
export AWS_DEFAULT_REGION="us-east-1"2. Shared Credentials File:
~/.aws/credentials
[default]
aws_access_key_id = your_access_key
aws_secret_access_key = your_secret_key
[production]
aws_access_key_id = prod_access_key
aws_secret_access_key = prod_secret_keyprovider "aws" {
region = "us-east-1"
profile = "production"
}3. Static Credentials (Not Recommended):
provider "aws" {
region = "us-east-1"
access_key = "your_access_key"
secret_key = "your_secret_key"
}4. Assume Role:
provider "aws" {
region = "us-east-1"
assume_role {
role_arn = "arn:aws:iam::123456789012:role/TerraformRole"
session_name = "terraform-session"
external_id = "unique_external_id"
}
}5. Web Identity (EKS, ECS):
provider "aws" {
region = "us-east-1"
assume_role_with_web_identity {
role_arn = "arn:aws:iam::123456789012:role/EKSRole"
session_name = "terraform-session"
web_identity_token_file = "/var/run/secrets/eks.amazonaws.com/serviceaccount/token"
}
}Multiple AWS Providers
provider "aws" {
alias = "us_east_1"
region = "us-east-1"
}
provider "aws" {
alias = "eu_west_1"
region = "eu-west-1"
}
resource "aws_instance" "east" {
provider = aws.us_east_1
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
resource "aws_instance" "west" {
provider = aws.eu_west_1
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}AWS Provider Features
provider "aws" {
region = "us-east-1"
# Default tags for all resources
default_tags {
tags = {
Environment = "production"
ManagedBy = "Terraform"
Project = "my-app"
}
}
# Ignore tags
ignore_tags {
keys = ["GitCommit"]
}
# Max retries
max_retries = 10
# HTTP settings
http_proxy = "http://proxy.example.com:8080"
https_proxy = "https://proxy.example.com:8080"
# S3 force path style
s3_force_path_style = true
# Skip credentials validation
skip_credentials_validation = true
# Skip metadata API check
skip_metadata_api_check = true
# Skip region validation
skip_region_validation = true
# Retry modes
retry_mode = "adaptive"
}Azure Provider
Basic Configuration
provider "azurerm" {
features {}
}Authentication Methods
1. Service Principal:
export ARM_CLIENT_ID="your_client_id"
export ARM_CLIENT_SECRET="your_client_secret"
export ARM_SUBSCRIPTION_ID="your_subscription_id"
export ARM_TENANT_ID="your_tenant_id"2. Managed Identity:
provider "azurerm" {
features {}
use_msi = true
}3. Azure CLI:
az login
az account set --subscription "your_subscription_id"terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
skip_provider_registration = true
}Azure Provider Features
provider "azurerm" {
features {
# API Management
api_management {
purge_soft_delete_on_destroy = true
}
# Key Vault
key_vault {
purge_soft_delete_on_destroy = true
purge_soft_deleted_certificates_on_destroy = true
}
# Virtual Machine
virtual_machine {
delete_os_disk_on_deletion = true
}
# Virtual Network
virtual_network {
soft_delete_enabled = false
}
}
# Storage account settings
storage_use_azuread = true
# Disable Terraform partner ID
disable_terraform_partner_id = true
}Google Provider
Basic Configuration
provider "google" {
project = "my-project-id"
region = "us-central1"
zone = "us-central1-a"
}Authentication Methods
1. Service Account JSON:
provider "google" {
project = "my-project-id"
region = "us-central1"
credentials = file("account.json")
}2. Application Default Credentials:
gcloud auth application-default login3. Service Account Impersonation:
provider "google" {
project = "my-project-id"
region = "us-central1"
impersonate_service_account = "terraform@my-project-id.iam.gserviceaccount.com"
}Google Provider Features
provider "google" {
project = "my-project-id"
region = "us-central1"
# User project overrides
billing_project = "billing-project-id"
# Request timeout
timeout = 60
# Request retry
retry_errors = ["UNAVAILABLE", "INTERNAL"]
# Scopes
scopes = ["https://www.googleapis.com/auth/cloud-platform"]
# Zone
zone = "us-central1-a"
}
provider "google-beta" {
project = "my-project-id"
region = "us-central1"
}Kubernetes Provider
Basic Configuration
provider "kubernetes" {
config_path = "~/.kube/config"
config_context = "my-context"
}Authentication Methods
1. Exec Plugin (AWS EKS):
provider "kubernetes" {
host = data.aws_eks_cluster.main.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.main.certificate_authority[0].data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", data.aws_eks_cluster.main.name]
}
}2. Static Token:
provider "kubernetes" {
host = "https://kubernetes.default.svc"
token = data.vault_generic_secret.kubernetes_token.data["token"]
}3. Client Certificate:
provider "kubernetes" {
host = var.kubernetes_host
cluster_ca_certificate = base64decode(var.kubernetes_ca_cert)
client_certificate = base64decode(var.kubernetes_client_cert)
client_key = base64decode(var.kubernetes_client_key)
}Kubernetes Provider Resources
resource "kubernetes_deployment" "nginx" {
metadata {
name = "nginx-deployment"
labels = {
app = "nginx"
}
}
spec {
replicas = 3
selector {
match_labels = {
app = "nginx"
}
}
template {
metadata {
labels = {
app = "nginx"
}
}
spec {
container {
name = "nginx"
image = "nginx:1.21.0"
port {
container_port = 80
}
}
}
}
}
}
resource "kubernetes_service" "nginx" {
metadata {
name = "nginx-service"
}
spec {
selector = {
app = "nginx"
}
port {
port = 80
target_port = 80
}
type = "LoadBalancer"
}
}Custom Providers
Using Community Providers
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.0"
}
github = {
source = "integrations/github"
version = "~> 5.0"
}
}
}Docker Provider Example
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
}
resource "docker_container" "nginx" {
image = docker_image.nginx.image_id
name = "nginx-server"
ports {
internal = 80
external = 8080
}
}Helm Provider Example
provider "helm" {
kubernetes {
host = data.aws_eks_cluster.main.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.main.certificate_authority[0].data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", data.aws_eks_cluster.main.name]
}
}
}
resource "helm_release" "nginx" {
name = "nginx-ingress"
repository = "https://kubernetes.github.io/ingress-nginx"
chart = "ingress-nginx"
namespace = "ingress-nginx"
set {
name = "controller.service.type"
value = "LoadBalancer"
}
}Provider Development
Creating a Custom Provider
1. Provider Structure:
my-provider/
├── provider/
│ ├── provider.go
│ ├── resource_example.go
│ └── data_source_example.go
├── main.go
└── go.mod2. Provider Interface:
package provider
func New() *schema.Provider {
return &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
"myprovider_example": resourceExample(),
},
DataSourcesMap: map[string]*schema.Resource{
"myprovider_example": dataSourceExample(),
},
}
}3. Building:
go build -o terraform-provider-myprovider
mkdir -p ~/.terraform.d/plugins/localhost/myorg/myprovider/1.0.0/darwin_arm64
mv terraform-provider-myprovider ~/.terraform.d/plugins/localhost/myorg/myprovider/1.0.0/darwin_arm64/4. Using:
terraform {
required_providers {
myprovider = {
source = "localhost/myorg/myprovider"
version = "1.0.0"
}
}
}Provider Best Practices
1. Version Management
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # Lock major version
}
}
}2. Provider Pinning
# .terraform.lock.hcl
provider "hashicorp/aws" {
version = "5.0.0"
hashes = [
"h1:abc123...",
]
}3. Separate Provider Files
providers/
├── aws.tf
├── google.tf
└── kubernetes.tf4. Provider Aliases for Multiple Regions
provider "aws" {
alias = "virginia"
region = "us-east-1"
}
provider "aws" {
alias = "oregon"
region = "us-west-2"
}5. Use Environment-Specific Providers
variable "environment" {
type = string
default = "dev"
}
locals {
aws_regions = {
dev = "us-east-1"
prod = "us-west-2"
}
}
provider "aws" {
region = local.aws_regions[var.environment]
}Provider Troubleshooting
Common Issues
1. Provider Not Downloaded:
terraform init -upgrade2. Version Conflicts:
terraform providers3. Provider Timeout:
provider "aws" {
region = "us-east-1"
timeout = "60s"
max_retries = 5
}4. Authentication Issues:
terraform loginDebug Mode
TF_LOG=DEBUG terraform applyProvider Configuration Validation
terraform init
terraform validate
terraform planAdvanced Provider Features
Provider Functions
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# Use provider functions
locals {
ami_id = provider::aws::region("ami-0c55b159cbfafe1f0")
}Provider Schema Validation
variable "region" {
type = string
description = "AWS region"
validation {
condition = can(regex("^us-[a-z]+-[0-9]+$", var.region))
error_message = "Region must be a valid AWS region."
}
}
provider "aws" {
region = var.region
}Provider Retry Logic
provider "aws" {
region = "us-east-1"
# Custom retry configuration
max_retries = 10
# Exponential backoff
retry_mode = "adaptive"
}Provider and Terraform Cloud
Terraform Cloud Providers
terraform {
cloud {
organization = "my-org"
workspaces {
name = "my-workspace"
}
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.0.0"
}
}
}
provider "aws" {
region = "us-east-1"
}Environment Variables in Cloud
Set in Terraform Cloud workspace:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGIONConclusion
Terraform providers are the bridge between your configuration and the infrastructure you manage. Understanding how to configure, authenticate, and optimize providers is essential for successful IaC implementations.
Key takeaways:
- Providers enable multi-cloud and multi-service management
- Authentication methods vary by provider
- Version management is critical
- Multiple providers enable complex architectures
- Community providers extend Terraform's capabilities
Master providers to unlock Terraform's full potential across your entire infrastructure.