Introduction to Providers
Providers are Terraform plugins that act as translators between Terraform and cloud platforms or services. Every resource you want to manage—whether it's an EC2 instance, S3 bucket, database, Kubernetes cluster, or Docker container—requires a provider.
Terraform has 3,000+ providers available, including:
- Cloud providers: AWS, Azure, Google Cloud, DigitalOcean, Linode
- Container platforms: Docker, Kubernetes, Helm
- Databases: PostgreSQL, MySQL, MongoDB
- SaaS platforms: GitHub, GitLab, Datadog, PagerDuty, Slack
- Infrastructure: Vault, Consul, Proxmox
Understanding Providers
What Does a Provider Do?
Terraform Code (HCL)
↓
Provider Plugin (AWS, Azure, etc.)
↓
Cloud API Calls
↓
Actual Infrastructure Created
A provider:
- Authenticates with a cloud platform
- Translates HCL resources to API calls
- Manages resource lifecycle (create, read, update, delete)
- Returns state of resources
Provider Architecture
# Source: Where the provider comes from
# Version: Which version to use
# Configuration: How to authenticate and configure
terraform {
required_providers {
aws = {
source = "hashicorp/aws" # Registry path
version = "~> 5.0" # Version constraint
}
}
}
provider "aws" {
region = "us-east-1" # Configuration
}Declaring Providers
Basic Provider Declaration
# Minimal AWS provider
provider "aws" {
region = "us-east-1"
}
# Minimal Azure provider
provider "azurerm" {
features {}
}
# Minimal Google Cloud provider
provider "google" {
project = "my-project"
region = "us-central1"
}Required Providers Block
Specifies which providers are needed and from where:
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # 5.x but not 6.x
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "= 2.25.0" # Exact version
}
}
}
# Provider configurations must appear after required_providers
provider "aws" {
region = "us-east-1"
}
provider "azurerm" {
features {}
}
provider "kubernetes" {
host = aws_eks_cluster.main.endpoint
cluster_ca_certificate = base64decode(aws_eks_cluster.main.certificate_authority[0].data)
token = data.aws_eks_auth.main.token
}Provider Authentication
AWS
provider "aws" {
region = "us-east-1"
# Method 1: From environment variables
# export AWS_ACCESS_KEY_ID=...
# export AWS_SECRET_ACCESS_KEY=...
}
provider "aws" {
# Method 2: Explicit credentials (not recommended)
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = "us-east-1"
}
provider "aws" {
# Method 3: Using AWS profiles
profile = "production"
region = "us-east-1"
}
provider "aws" {
# Method 4: Assume role
assume_role {
role_arn = "arn:aws:iam::ACCOUNT_ID:role/TerraformRole"
}
region = "us-east-1"
}Azure
provider "azurerm" {
# Method 1: Service Principal with environment variables
# export ARM_CLIENT_ID=...
# export ARM_CLIENT_SECRET=...
# export ARM_TENANT_ID=...
# export ARM_SUBSCRIPTION_ID=...
features {}
}
provider "azurerm" {
# Method 2: Managed Identity (in Azure VMs)
features {}
# Authenticate using VM's managed identity
}
provider "azurerm" {
# Method 3: Azure CLI authentication
features {}
# Uses `az login`
}Google Cloud
provider "google" {
# Method 1: Service account file
credentials = file("~/terraform-sa.json")
project = "my-project"
region = "us-central1"
}
provider "google" {
# Method 2: From environment variable
# export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
project = "my-project"
region = "us-central1"
}Kubernetes
provider "kubernetes" {
# Method 1: From kubeconfig file
config_path = "~/.kube/config"
config_context = "my-cluster"
}
provider "kubernetes" {
# Method 2: Direct connection details
host = "https://kubernetes.example.com:6443"
token = var.kube_token
cluster_ca_certificate = base64decode(var.cluster_ca)
}
provider "kubernetes" {
# Method 3: From AWS EKS
host = aws_eks_cluster.main.endpoint
cluster_ca_certificate = base64decode(aws_eks_cluster.main.certificate_authority[0].data)
token = data.aws_eks_auth.main.token
}Provider Configuration
Region/Location Selection
# AWS: Single region
provider "aws" {
region = "us-east-1"
}
# AWS: Multi-region (multiple providers)
provider "aws" {
alias = "us_east"
region = "us-east-1"
}
provider "aws" {
alias = "us_west"
region = "us-west-2"
}
provider "aws" {
alias = "eu"
region = "eu-west-1"
}
# Use specific provider
resource "aws_instance" "us_server" {
provider = aws.us_east
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
resource "aws_instance" "eu_server" {
provider = aws.eu
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}Provider Features and Options
provider "azurerm" {
features {
# Allow deleting resources with attached locks
key_vault {
purge_soft_delete_on_destroy = true
}
virtual_machine {
delete_os_disk_on_deletion = true
graceful_shutdown = true
skip_shutdown_and_force_delete = false
}
}
}
provider "aws" {
region = "us-east-1"
skip_region_validation = false
skip_credentials_validation = false
skip_metadata_api_check = false
# For custom endpoints (e.g., Terraform Cloud)
dynamodb_endpoint = "http://localhost:8000"
s3_endpoint = "http://localhost:9000"
}Provider Versioning
Version Constraints
terraform {
required_providers {
# Exact version
aws = {
source = "hashicorp/aws"
version = "5.0.0"
}
# Any 5.x version >= 5.0
azurerm = {
source = "hashicorp/azurerm"
version = ">= 5.0"
}
# Pessimistic constraint (5.x but not 6.x)
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 5.0"
}
# Any compatible version
github = {
source = "integrations/github"
version = ">= 5.0, < 7.0"
}
# Latest version (not recommended for production)
random = {
source = "hashicorp/random"
version = "*"
}
}
}Version Lock File
terraform.lock.hcl locks provider versions:
# Create lock (terraform init)
terraform init # Generates terraform.lock.hcl
# View lock file
cat terraform.lock.hcl
# Share with team
git add terraform.lock.hcl
git commit -m "Lock provider versions"
# Update to latest allowable version
terraform init -upgradeMulti-Provider Scenarios
Cross-Cloud Deployment
Deploy the same infrastructure across multiple clouds:
# AWS resources
resource "aws_instance" "web" {
provider = aws.us_east
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
# Azure resources
resource "azurerm_virtual_machine" "web" {
provider = azurerm.primary
name = "web-vm"
location = "East US"
resource_group_name = azurerm_resource_group.main.name
}
# Google Cloud resources
resource "google_compute_instance" "web" {
provider = google.us_central
name = "web-vm"
machine_type = "e2-micro"
zone = "us-central1-a"
}Multi-Region AWS Deployment
provider "aws" {
alias = "primary"
region = "us-east-1"
}
provider "aws" {
alias = "secondary"
region = "us-west-2"
}
provider "aws" {
alias = "disaster_recovery"
region = "eu-west-1"
profile = "dr-account" # Different AWS account
}
# Primary region
resource "aws_instance" "primary" {
provider = aws.primary
instance_type = "t3.large"
availability_zone = "us-east-1a"
}
# Secondary region
resource "aws_instance" "secondary" {
provider = aws.secondary
instance_type = "t3.medium"
availability_zone = "us-west-2a"
}
# Disaster recovery (different account)
resource "aws_instance" "dr" {
provider = aws.disaster_recovery
instance_type = "t3.small"
availability_zone = "eu-west-1a"
}Finding and Using Providers
Terraform Registry
Visit registry.terraform.io to:
- Search for providers
- View documentation and examples
- Check version history
- See available resources
Popular Providers Directory
Infrastructure:
- aws (Amazon Web Services)
- azurerm (Azure)
- google (Google Cloud)
- digitalocean
- linode
- proxmox
Containers:
- docker
- kubernetes
- helm
Configuration Management:
- null
- local
- random
SaaS:
- github
- gitlab
- datadog
- pagerduty
- slack
Networking:
- dns
- http
Installing Custom Providers
For third-party or custom providers:
terraform {
required_providers {
custom = {
source = "example.com/company/custom"
version = "1.0.0"
}
}
}Place provider binary at:
~/.terraform.d/plugins/example.com/company/custom/1.0.0/linux_amd64/
Provider Data Sources
Providers offer data sources to query existing infrastructure:
# Query existing AWS VPC
data "aws_vpc" "default" {
default = true
}
# Query existing security group
data "aws_security_group" "web" {
name = "web-tier"
}
# Use in resources
resource "aws_instance" "app" {
subnet_id = data.aws_vpc.default.main_route_table_id
security_groups = [data.aws_security_group.web.id]
}Troubleshooting Provider Issues
Provider Not Found
# Error: `provider not installed`
terraform init # Re-initialize to download providers
# Check installed providers
terraform providers
# Upgrade providers
terraform init -upgradeAuthentication Errors
# AWS: Check credentials
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
terraform init
# Azure: Check login
az login
terraform init
# Kubernetes: Check kubeconfig
export KUBECONFIG=~/.kube/config
terraform initVersion Conflicts
# Check provider versions
terraform version
# Too many versions installed?
rm -rf .terraform/
rm terraform.lock.hcl
terraform initBest Practices for Providers
✅ Pin provider versions in production (use terraform.lock.hcl) ✅ Use separate provider instances for multi-region/multi-account ✅ Authenticate using managed identities when possible ✅ Rotate credentials regularly ✅ Use appropriate IAM roles/permissions (least privilege) ✅ Document provider requirements in your module ✅ Test provider changes in non-production environments first ✅ Monitor provider deprecations in changelogs
Summary
- Providers are plugins that let Terraform manage cloud infrastructure
- Declaration specifies which providers you need and where they come from
- Authentication varies by cloud platform (environment variables, service accounts, profiles)
- Versioning ensures reproducible deployments across teams
- Multi-provider setups enable cross-cloud and multi-region deployments
- Registry is the central source for discovering and learning providers