pre-commit-terraform

repository·master·Indexed 25 days ago

https://github.com/antonbabenko/pre-commit-terraform

A collection of Git Hooks for Terraform, OpenTofu, and Terragrunt driven by the pre-commit framework. It automates linting, formatting, and security scanning using tools such as TFLint, Checkov, Trivy, Terrascan, and Infracost to ensure infrastructure-as-code configurations remain consistent and error-free.

Tokens
10K
Snippets
30
Records
47
Agent score
86%

What's inside pre-commit-terraform

  1. Overview of pre-commit-terraform

    master

    pre-commit-terraform is a collection of Git Hooks for Terraform, OpenTofu, and Terragrunt, powered by the pre-commit framework. It automates code quality checks, formatting, and validation to ensure infrastructure-as-code configurations remain consistent and error-free.

    Key capabilities include:

    • Running checks locally and in CI environments.
    • Execution as standalone Git hooks or via Docker images.
    • Flexible scope: run against the entire repository or only on changed files (e.g., during a git stash, last commit, or Pull Request).
  2. Available Terraform and Terragrunt pre-commit hooks

    master

    This repository provides a collection of pre-commit hooks to maintain Terraform (*.tf, *.tfvars) and Terragrunt (*.hcl) configurations.

    Terraform Hooks

    • checkov / terraform_checkov: Static analysis for security issues using Checkov. Requires checkov and Ubuntu dependencies python3, python3-pip.
    • infracost_breakdown: Cost analysis using Infracost. Requires infracost, jq, and an Infracost API key.
    • terraform_docs: Inserts input/output documentation into README.md. Requires terraform-docs.
    • terraform_docs_without_aggregate_type_defaults: Similar to terraform_docs but without aggregate type defaults. Requires terraform-docs.
    • terraform_fmt: Reformats Terraform files to canonical format.
    • terraform_providers_lock: Updates provider signatures in dependency lock files.
    • terraform_tflint: Validates configurations using TFLint. Requires tflint.
    • terraform_trivy: Static analysis for security issues using Trivy. Requires trivy.
    • terraform_validate: Validates Terraform configuration files. Requires jq if using the --retry-once-with-cleanup flag.
    • terraform_wrapper_module_for_each: Generates Terraform wrappers with for_each in modules. Requires hcledit.
    • tfupdate: Updates version constraints for Terraform core, providers, and modules. Requires tfupdate.

    Terragrunt Hooks

    • terragrunt_fmt: Reformats Terragrunt (*.hcl) files. Requires terragrunt.
    • terragrunt_validate: Validates Terragrunt configuration files. Requires terragrunt.
    • terragrunt_validate_inputs: Validates unused and undefined Terragrunt inputs. Requires terragrunt.
    • terragrunt_providers_lock: Generates .terraform.lock.hcl files using Terragrunt. Requires terragrunt.

    Other Hooks

    • terrascan: Detects compliance and security violations. Requires terrascan.

    Note: terraform_docs_replace and terraform_tfsec are DEPRECATED. Use terraform_docs and terraform_trivy respectively.

  3. Install dependencies on Ubuntu 20.04+

    master

    For Ubuntu 20.04 and newer, use apt and pip3 to install the core dependencies and then use curl to download and install specific binary releases for tools like terraform-docs, tflint, tfsec, trivy, infracost, tfupdate, and hcledit.

    sudo apt update
    sudo apt install -y unzip software-properties-common python3 python3-pip python-is-python3
    python3 -m pip install --upgrade pip
    pip3 install --no-cache-dir pre-commit
    pip3 install --no-cache-dir checkov
    curl -L "$(curl -s https://api.github.com/repos/terraform-docs/terraform-docs/releases/latest | grep -o -E -m 1 "https://.+?-linux-amd64.tar.gz")" > terraform-docs.tgz && tar -xzf terraform-docs.tgz terraform-docs && rm terraform-docs.tgz && chmod +x terraform-docs && sudo mv terraform-docs /usr/bin/
    curl -L "$(curl -s https://api.github.com/repos/tenable/terrascan/releases/latest | grep -o -E -m 1 "https://.+?_Linux_x86_64.tar.gz")" > terrascan.tar.gz && tar -xzf terrascan.tar.gz terrascan && rm terrascan.tar.gz && sudo mv terrascan /usr/bin/ && terrascan init
    curl -L "$(curl -s https://api.github.com/repos/terraform-linters/tflint/releases/latest | grep -o -E -m 1 "https://.+?_linux_amd64.zip")" > tflint.zip && unzip tflint.zip && rm tflint.zip && sudo mv tflint /usr/bin/
    curl -L "$(curl -s https://api.github.com/repos/aquasecurity/tfsec/releases/latest | grep -o -E -m 1 "https://.+?tfsec-linux-amd64")" > tfsec && chmod +x tfsec && sudo mv tfsec /usr/bin/
    curl -L "$(curl -s https://api.github.com/repos/aquasecurity/trivy/releases/latest | grep -o -E -i -m 1 "https://.+?/trivy_.+?_Linux-64bit.tar.gz")" > trivy.tar.gz && tar -xzf trivy.tar.gz trivy && rm trivy.tar.gz && sudo mv trivy /usr/bin
    sudo apt install -y jq && \
    curl -L "$(curl -s https://api.github.com/repos/infracost/infracost/releases/latest | grep -o -E -m 1 "https://.+?-linux-amd64.tar.gz")" > infracost.tgz && tar -xzf infracost.tgz && rm infracost.tgz && sudo mv infracost-linux-amd64 /usr/bin/infracost && infracost auth login
    curl -L "$(curl -s https://api.github.com/repos/minamijoyo/tfupdate/releases/latest | grep -o -E -m 1 "https://.+?_linux_amd64.tar.gz")" > tfupdate.tar.gz && tar -xzf tfupdate.tar.gz tfupdate && rm tfupdate.tar.gz && sudo mv tfupdate /usr/bin/
    curl -L "$(curl -s https://api.github.com/repos/minamijoyo/hcledit/releases/latest | grep -o -E -m 1 "https://.+?_linux_amd64.tar.gz")" > hcledit.tar.gz && tar -xzf hcledit.tar.gz hcledit && rm hcledit.tar.gz && sudo mv hcledit /usr/bin/
  4. Install pre-commit hooks globally

    master

    If you are NOT using the Docker image, you can install the pre-commit hooks globally for all new git repositories by setting up a git template directory:

    DIR=~/.git-template
    git config --global init.templateDir ${DIR}
    pre-commit init-templatedir -t pre-commit ${DIR}
    DIR=~/.git-template
    git config --global init.templateDir ${DIR}
    pre-commit init-templatedir -t pre-commit ${DIR}
  5. Install dependencies via Docker

    master

    You can use a pre-built Docker image containing all necessary hooks. This avoids the need to install individual tools like terraform, tflint, or checkov on your host machine.

    To pull the latest image:

    TAG=latest
    docker pull ghcr.io/antonbabenko/pre-commit-terraform:$TAG

    Alternatively, you can build the image from scratch to customize tool versions using --build-arg.

    Build with latest versions of all tools:

    git clone git@github.com:antonbabenko/pre-commit-terraform.git
    cd pre-commit-terraform
    docker build -t pre-commit-terraform --build-arg INSTALL_ALL=true .

    Build with specific tool versions: Use --build-arg to pin specific versions for tools like TERRAFORM_VERSION, TFLINT_VERSION, or CHECKOV_VERSION.

    Note on Authentication: If the build process needs to access the GitHub API, provide a GITHUB_TOKEN:

    docker build -t pre-commit-terraform --build-arg GITHUB_TOKEN .
    TAG=latest
    docker pull ghcr.io/antonbabenko/pre-commit-terraform:$TAG
  6. Authenticate with private GitHub Terraform modules in Docker

    master

    If your Terraform modules are hosted in private GitHub repositories, you must provide authentication via a ~/.netrc file.

    1. Create a ~/.netrc file containing your GITHUB_PAT and GITHUB_SERVER_HOSTNAME (e.g., github.com or your enterprise URL).
    2. Mount this file into the Docker container at /root/.netrc using a volume mount so the auto-login process can access it.
    # 1. Create the .netrc file
    GITHUB_PAT=ghp_bl481aBlabl481aBla
    GITHUB_SERVER_HOSTNAME=github.com
    echo -e "machine $GITHUB_SERVER_HOSTNAME\n\tlogin $GITHUB_PAT" >> ~/.netrc
    
    # 2. Run docker with the .netrc volume mount
    docker run --rm -e "USERID=$(id -u):$(id -g)" -v ~/.netrc:/root/.netrc -v $(pwd):/lint -w /lint ghcr.io/antonbabenko/pre-commit-terraform:latest run -a
  7. Migrate to terraform-docs standard markers

    master

    If you are using older custom markers, you can migrate your repository to use the standard terraform-docs markers (BEGIN_TF_DOCS and END_TF_DOCS) by running the following command in your repository root:

    sed --version &> /dev/null && SED_CMD=(sed -i) || SED_CMD=(sed -i '')
    grep -rl --null 'BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK' . | xargs -0 "${SED_CMD[@]}" -e 's/BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK/BEGIN_TF_DOCS/'
    grep -rl --null 'END OF PRE-COMMIT-TERRAFORM DOCS HOOK' . | xargs -0 "${SED_CMD[@]}" -e 's/END OF PRE-COMMIT-TERRAFORM DOCS HOOK/END_TF_DOCS/'
  8. Add pre-commit-terraform hooks to a repository

    master

    To use the hooks in a specific repository, create a .pre-commit-config.yaml file in the repository root.

    Example configuration:

    repos:
    - repo: https://github.com/antonbabenko/pre-commit-terraform
      rev: <VERSION> # Replace with the latest release version
      hooks:
        - id: terraform_fmt
        - id: terraform_docs

    After creating the config, if you haven't installed the hooks globally, run pre-commit install within the repository.

    cat <<EOF > .pre-commit-config.yaml
    repos:
    - repo: https://github.com/antonbabenko/pre-commit-terraform
      rev: <VERSION>
      hooks:
        - id: terraform_fmt
        - id: terraform_docs
    EOF
  9. Replace deprecated terraform_docs_replace with terraform_docs

    master

    The terraform_docs_replace hook is deprecated. To achieve the same functionality (replacing the entire file instead of string replacement between markers) using the terraform_docs hook, follow these steps:

    1. Create a .terraform-docs.yml file in your repository root:
    formatter: "markdown"
    
    output:
        file: "README.md"
        mode: replace
        template: |-
            {{/** End of file fixer */}}
    1. Update your .pre-commit-config.yaml to use terraform_docs with that config:
        - id: terraform_docs
          args:
            - --args=--config=.terraform-docs.yml
  10. Run pre-commit-terraform using Docker

    master

    You can run the Terraform hooks using a Docker container. To avoid permission issues where files in your local repository are owned by root, use the USERID environment variable to match your current user's UID and GID.

    It is recommended to use the latest tag or pin to a specific version for reproducibility. The nightly tag is also available for the latest dependency updates.

    TAG=latest
    docker run -e "USERID=$(id -u):$(id -g)" -v $(pwd):/lint -w /lint ghcr.io/antonbabenko/pre-commit-terraform:$TAG run -a
  11. Manually test the CLI in development

    master

    To test the CLI locally, install the package in editable mode within a development virtualenv:

    pip install -e .

    Once installed, you can invoke the main CLI or specific subcommands using the python -m interface:

    # Run the main CLI
    python -m pre_commit_terraform
    
    # Run a specific subcommand
    python -m pre_commit_terraform <subcommand-name>

    You can use --help to inspect available commands and arguments.

    pip install -e .
    python -m pre_commit_terraform
    python -m pre_commit_terraform <subcommand-name>