Skip to main content
To follow this guide you need a SafeDep Cloud API Key and Tenant Identifier. See Cloud Quickstart on how to onboard to SafeDep Cloud and get an API key.
This guide covers how to discover Terraform providers used in a Terraform project, synchronize the inventory (BOM) with SafeDep Cloud, and query for unofficial providers that may pose supply chain risks.

Prerequisites

  • vet installed (see quickstart for installation options)
  • SafeDep Cloud account with API key and tenant identifier
  • Terraform project with initialized providers (.terraform.lock.hcl must exist)

Scan and Discover Terraform Providers

Run vet on your Terraform project to discover providers. The project must be initialized so that .terraform.lock.hcl is present in the project directory. --report-sync uploads the provider inventory to SafeDep Cloud, so set your credentials first:
export SAFEDEP_API_KEY=your-api-key
export SAFEDEP_TENANT_ID=your-tenant-domain
Then run the scan:
vet scan -D /path/to/terraform-code \
  --report-sync \
  --report-sync-project gh/test/infra1 \
  --report-sync-project-version main

What This Command Does

1

Provider Discovery

Scans Terraform configuration files and lock files to identify all providers
2

Metadata Collection

Gathers information about provider versions, sources, and tiers (official, partner, community)
3

Cloud Synchronization

Uploads the provider inventory to SafeDep Cloud for centralized analysis
4

Project Tracking

Associates findings with specific projects and versions for tracking over time

Query Provider Inventory

Use SafeDep Cloud SQL queries to analyze your Terraform provider inventory. See SafeDep Cloud Quickstart for more details on the query interface.

Find Unofficial Terraform Providers

Query for providers that are not officially maintained by HashiCorp: Providers are surfaced as packages in your synced inventory, joined to the global Terraform provider registry. Anchor the query on an indexed column (here projects.origin_source) and join out to terraform_providers:
safedep query exec --sql "
  SELECT projects.name, packages.name, terraform_providers.tier
  FROM projects
  JOIN project_versions ON project_versions.project_id = projects.id
  JOIN boms ON boms.pv_id = project_versions.id
  JOIN packages ON packages.bom_id = boms.id
  JOIN terraform_providers ON terraform_providers.provider_name = packages.name
  WHERE projects.origin_source = 'SOURCE_GITHUB'
    AND terraform_providers.tier != 'official'
  ORDER BY packages.name"

Example Response

projects.name    packages.name                                terraform_providers.tier
gh/test/infra1   registry.terraform.io/digitalocean/do        community
gh/test/infra1   registry.terraform.io/hetznercloud/hcloud    community

Advanced Queries

Break providers down by tier across your GitHub projects:
safedep query exec --sql "
  SELECT terraform_providers.tier, COUNT(DISTINCT packages.name) AS provider_count
  FROM projects
  JOIN project_versions ON project_versions.project_id = projects.id
  JOIN boms ON boms.pv_id = project_versions.id
  JOIN packages ON packages.bom_id = boms.id
  JOIN terraform_providers ON terraform_providers.provider_name = packages.name
  WHERE projects.origin_source = 'SOURCE_GITHUB'
  GROUP BY terraform_providers.tier
  ORDER BY provider_count DESC"
For the full query language, schema, join model, and more worked examples, see the SafeDep Cloud SQL guide.

CI/CD Integration

GitHub Actions

Integrate Terraform provider auditing into your CI/CD pipeline:
name: Terraform Security Audit
on:
  push:
    paths:
      - '**/*.tf'
      - '.terraform.lock.hcl'
  pull_request:
    paths:
      - '**/*.tf'
      - '.terraform.lock.hcl'

jobs:
  terraform-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        
      - name: Terraform Init
        run: terraform init
        
      - name: Audit Terraform Providers
        run: |
          vet scan -D . \
            --report-sync \
            --report-sync-project ${{ github.repository }} \
            --report-sync-project-version ${{ github.ref_name }}
        env:
          SAFEDEP_API_KEY: ${{ secrets.SAFEDEP_CLOUD_API_KEY }}
          SAFEDEP_TENANT_ID: ${{ secrets.SAFEDEP_CLOUD_TENANT_DOMAIN }}
          
      - name: Check for Unofficial Providers
        run: |
          safedep query exec -o json --sql "
            SELECT packages.name, terraform_providers.tier
            FROM projects
            JOIN project_versions ON project_versions.project_id = projects.id
            JOIN boms ON boms.pv_id = project_versions.id
            JOIN packages ON packages.bom_id = boms.id
            JOIN terraform_providers ON terraform_providers.provider_name = packages.name
            WHERE projects.name = '${{ github.repository }}'
              AND terraform_providers.tier != 'official'
          " > unofficial-providers.json

          if [ "$(jq '.count' unofficial-providers.json)" -gt 0 ]; then
            echo "⚠️ Unofficial providers detected:"
            jq -r '.rows[] | .["packages.name"]' unofficial-providers.json
            echo "Please review these providers for security compliance."
          fi
        env:
          SAFEDEP_API_KEY: ${{ secrets.SAFEDEP_CLOUD_API_KEY }}
          SAFEDEP_TENANT_ID: ${{ secrets.SAFEDEP_CLOUD_TENANT_DOMAIN }}

GitLab CI

stages:
  - init
  - audit

terraform-init:
  stage: init
  image: hashicorp/terraform:latest
  script:
    - terraform init
  artifacts:
    paths:
      - .terraform.lock.hcl
    expire_in: 1 hour

terraform-audit:
  stage: audit
  image: ghcr.io/safedep/vet:latest
  script:
    - vet scan -D . --report-sync --report-sync-project $CI_PROJECT_PATH --report-sync-project-version $CI_COMMIT_REF_NAME
  dependencies:
    - terraform-init
  variables:
    SAFEDEP_API_KEY: $SAFEDEP_CLOUD_API_KEY
    SAFEDEP_TENANT_ID: $SAFEDEP_CLOUD_TENANT_DOMAIN

Policy Enforcement

Terraform provider tier (official, partner, community) lives in SafeDep Cloud’s query layer, not in Vet’s local --filter-suite engine, which evaluates package-level signals (vulnerabilities, licenses, OpenSSF Scorecard) and has no notion of provider tiers. To enforce provider policies, query the synced inventory and fail the build on disallowed providers. The Check for Unofficial Providers step in the GitHub Actions example above demonstrates this pattern: it queries terraform_providers.tier and exits non-zero when any non-official provider is present. Adapt that query to encode your approved-provider rules.

Schema Exploration

List all queryable columns for Terraform providers:
safedep query schema show terraform_providers
Available fields include:
  • terraform_providers.tier - Provider tier (official, partner, community)
  • terraform_providers.source - Provider source URL
  • terraform_providers.namespace - Provider namespace
  • packages.name - Full provider name
  • packages.version - Provider version

Troubleshooting

If no providers are detected:
  • Ensure .terraform.lock.hcl exists (run terraform init)
  • Verify Terraform configuration files are present
  • Check that Vet supports your Terraform version
If synchronization to SafeDep Cloud fails:
  • Verify API key and tenant ID are correct
  • Check network connectivity to SafeDep Cloud
  • Ensure project name doesn’t contain special characters

Terraform Provider Registry

Browse official and community Terraform providers

SafeDep Cloud Queries

Learn more about querying your infrastructure inventory

Supply Chain Security

Learn about Terraform in the software supply chain

Vet CLI Documentation

Complete Vet CLI documentation and examples