Reputation: 2444
How do you prevent terraform from upgrading its providers?
I have built a docker image with terraform 1.0.5 installed and a specific version of the aws provider:
# terraform -version
Terraform v1.0.5
on linux_amd64
+ provider registry.terraform.io/hashicorp/aws v3.55.0
I build this terraform docker image with this simple docker file:
FROM hashicorp/terraform:1.0.5 as terraform-provider
COPY provider.tf .
RUN terraform init
RUN mv .terraform/providers/registry.terraform.io/hashicorp/aws/3.55.0/linux_amd64/* /bin/
And the provider.tf needed for the docker build is here:
terraform {
required_providers {
aws = {
version = "3.55.0"
source = "hashicorp/aws"
}
}
}
When I run this docker image against my local terraform code, the terraform init
command insists on upgrading the aws provider to the latest version.
Here is how I run it:
TERRAFORM_BASE_IMAGE is the terraform image that I just build via docker build .
I have one main.tf in the $CURRENT_DIR/terraform/
folder containing simply:
terraform {
backend "s3" {}
}
provider "aws" {
default_tags {
tags = {
Owner = "[email protected]"
Description = "Demo"
}
}
}
And when I run the command:
docker run -v $CURRENT_DIR:$CURRENT_DIR --workdir $CURRENT_DIR/terraform \
${TERRAFORM_BASE_IMAGE} \
init -get=false \
-reconfigure \
-backend-config="bucket=XXX-tf-remote-state" \
-backend-config="key=${ENVIRONMENT}/${PROJECT_NAME}" \
-backend-config="region=us-west-2" \
-backend=true
I see in the output:
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.57.0...
- Installed hashicorp/aws v3.57.0 (signed by HashiCorp)
I don't want terraform to upgrade any providers at all. The docker image already has the 3.55.0
version of the aws provider.
How do I prevent terraform init
from upgrading any providers?
Upvotes: 1
Views: 369
Reputation: 74564
I think there are two related questions in your question here:
With no special configuration, Terraform will follow the Implied Local Mirror Directories procedure, searching each of the implied directories to see which providers are installed there. It will then behave as if you had written a provider_installation
block in your CLI configuration which excludes any of the locally-available providers from direct installation.
For example, if you have at least one version of the hashicorp/aws
under /usr/local/share/terraform/plugins
in your container image, Terraform will infer a provider installation configuration as if you'd configured it this way:
provider_installation {
filesystem_mirror {
# The contents of this directory must match one of
# the two supported directory layouts, described in
# the documentation:
# https://www.terraform.io/docs/cli/config/config-file.html#filesystem_mirror
path = "/usr/local/share/terraform/plugins"
include = ["hashicorp/aws"]
}
direct {
exclude = ["hashicorp/aws"]
}
}
One consequence of the configuration above -- which excludes hashicorp/aws
from the "direct" installation method -- is that Terraform will only be able to find plugin packages for that provider which you've already installed in the given directory. Even if there's a newer version available in the registry, Terraform's provider installer won't know about it because it won't ask the registry at all.
However, this implied strategy doesn't exclude providers that you don't already have in the local mirror directory. If you want to force Terraform to never install new providers over the network -- even for providers you haven't already included -- you can write a stricter configuration and have your image build process place it in one of the locations Terraform will search for it:
provider_installation {
filesystem_mirror {
path = "/usr/local/share/terraform/plugins"
}
# note: no "direct" here at all, so the normal registry
# installer is totally deactivated
}
The above might be sufficient for your needs because in effect it creates a closed plugin environment where Terraform can only select packages you've included in the image. Even if the Terraform configuration had no version constraints at all, Terraform would only be able to select the newest version available in your image.
However, Terraform's provider requirements and dependency lock file mechanisms do still apply in this case, so if you have a configuration which selects a version you haven't included in your image then terraform init
will fail due to not being able to resolve the dependencies.
You might consider that an advantage, in which case the problem is solved.
If you'd prefer to have the container image be the sole decider of which provider versions are in use then it could be reasonable to write your Terraform configurations with only minimal version constraints and to exclude the dependency lock file from your version control so that Terraform won't try to match the available packages against previously-recorded checksums. In your case, your container image could provide an effective replacement for the guarantees the dependency lock file typically provides, as long as your process for building the image somehow ensures that the provider packages you've included are all trustworthy.
Upvotes: 1