G
GuideDevOps
Lesson 4 of 14

Providers

Part of the Terraform tutorial series.

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:

  1. Authenticates with a cloud platform
  2. Translates HCL resources to API calls
  3. Manages resource lifecycle (create, read, update, delete)
  4. 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 -upgrade

Multi-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 -upgrade

Authentication 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 init

Version Conflicts

# Check provider versions
terraform version
 
# Too many versions installed?
rm -rf .terraform/
rm terraform.lock.hcl
terraform init

Best 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