diff --git a/src/terraform/NOTES.md b/src/terraform/NOTES.md index 2c1540aee..74a90639e 100644 --- a/src/terraform/NOTES.md +++ b/src/terraform/NOTES.md @@ -4,6 +4,37 @@ On August 10, 2023, HashiCorp announced a change of license for its products, including Terraform. After ~9 years of Terraform being open source under the MPL v2 license, it was to move under a non-open source BSL v1.1 license, starting from the next (1.6) version. See https://github.com/hashicorp/terraform/blob/main/LICENSE +## Custom Download Server + +The `customDownloadServer` option allows you to specify an alternative server for downloading Terraform and Sentinel packages. This is useful for organizations that maintain internal mirrors or have proxies for HashiCorp downloads. + +When using this option: +- Provide the complete URL including protocol (e.g., `https://my-mirror.example.com`) +- The server should mirror the HashiCorp releases structure + +Example: +```json +"features": { + "ghcr.io/devcontainers/features/terraform:1": { + "customDownloadServer": "https://my-mirror.example.com" + } +} +``` + +### ⚠️ Security Considerations + +When using a custom download server, be aware of the following security implications: + +- **Server Verification**: Always verify that the custom server is trustworthy and maintained by your organization or a trusted entity. Using an untrusted or compromised server could lead to downloading malicious software. + +- **Supply Chain Risks**: Malicious actors may attempt to distribute compromised versions of Terraform that contain backdoors, cryptominers, or other harmful code. + +- **Integrity Checks**: The feature performs SHA256 checks when available, but these are only as trustworthy as the source of the checksums. If both the binaries and checksums come from a compromised server, the integrity check may pass despite the software being malicious. + +- **Organizational Policy**: Ensure your custom download server adheres to your organization's security policies and implements proper access controls. + +Always use the official HashiCorp download server (https://releases.hashicorp.com) unless you have a specific need for an alternative source. + ## OS Support This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. diff --git a/src/terraform/devcontainer-feature.json b/src/terraform/devcontainer-feature.json index d022f83c1..db1bacc67 100644 --- a/src/terraform/devcontainer-feature.json +++ b/src/terraform/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "terraform", - "version": "1.3.10", + "version": "1.4.0", "name": "Terraform, tflint, and TFGrunt", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/terraform", "description": "Installs the Terraform CLI and optionally TFLint and Terragrunt. Auto-detects latest version and installs needed dependencies.", @@ -54,6 +54,11 @@ "type": "string", "default": "", "description": "Connect to a keyserver using a proxy by configuring this option" + }, + "customDownloadServer": { + "type": "string", + "default": "", + "description": "Custom server URL for downloading Terraform and Sentinel packages, including protocol (e.g., https://releases.hashicorp.com). If not provided, the default HashiCorp download server (https://releases.hashicorp.com) will be used." } }, "customizations": { diff --git a/src/terraform/install.sh b/src/terraform/install.sh index a2aace9b4..fb7abc6ee 100755 --- a/src/terraform/install.sh +++ b/src/terraform/install.sh @@ -18,6 +18,7 @@ TERRAGRUNT_VERSION="${TERRAGRUNT:-"latest"}" INSTALL_SENTINEL=${INSTALLSENTINEL:-false} INSTALL_TFSEC=${INSTALLTFSEC:-false} INSTALL_TERRAFORM_DOCS=${INSTALLTERRAFORMDOCS:-false} +CUSTOM_DOWNLOAD_SERVER="${CUSTOMDOWNLOADSERVER:-""}" TERRAFORM_SHA256="${TERRAFORM_SHA256:-"automatic"}" TFLINT_SHA256="${TFLINT_SHA256:-"automatic"}" @@ -26,6 +27,11 @@ SENTINEL_SHA256="${SENTINEL_SHA256:-"automatic"}" TFSEC_SHA256="${TFSEC_SHA256:-"automatic"}" TERRAFORM_DOCS_SHA256="${TERRAFORM_DOCS_SHA256:-"automatic"}" +HASHICORP_RELEASES_URL="https://releases.hashicorp.com" +if [ -n "${CUSTOM_DOWNLOAD_SERVER}" ]; then + HASHICORP_RELEASES_URL="${CUSTOM_DOWNLOAD_SERVER}" +fi + TERRAFORM_GPG_KEY="72D7468F" TFLINT_GPG_KEY_URI="https://raw.githubusercontent.com/terraform-linters/tflint/v0.46.1/8CE69160EB3F2FE9.key" KEYSERVER_PROXY="${HTTPPROXY:-"${HTTP_PROXY:-""}"}" @@ -357,7 +363,7 @@ find_version_from_git_tags TERRAGRUNT_VERSION "$terragrunt_url" install_terraform() { local TERRAFORM_VERSION=$1 terraform_filename="terraform_${TERRAFORM_VERSION}_linux_${architecture}.zip" - curl -sSL -o ${terraform_filename} "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/${terraform_filename}" + curl -sSL -o ${terraform_filename} "${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/${terraform_filename}" } mkdir -p /tmp/tf-downloads @@ -373,8 +379,8 @@ fi if [ "${TERRAFORM_SHA256}" != "dev-mode" ]; then if [ "${TERRAFORM_SHA256}" = "automatic" ]; then receive_gpg_keys TERRAFORM_GPG_KEY - curl -sSL -o terraform_SHA256SUMS https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS - curl -sSL -o terraform_SHA256SUMS.sig https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS.${TERRAFORM_GPG_KEY}.sig + curl -sSL -o terraform_SHA256SUMS "${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS" + curl -sSL -o terraform_SHA256SUMS.sig "${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS.${TERRAFORM_GPG_KEY}.sig" gpg --verify terraform_SHA256SUMS.sig terraform_SHA256SUMS else echo "${TERRAFORM_SHA256} *${terraform_filename}" > terraform_SHA256SUMS @@ -464,7 +470,7 @@ fi if [ "${INSTALL_SENTINEL}" = "true" ]; then SENTINEL_VERSION="latest" - sentinel_releases_url='https://releases.hashicorp.com/sentinel' + sentinel_releases_url="${HASHICORP_RELEASES_URL}/sentinel" find_sentinel_version_from_url SENTINEL_VERSION ${sentinel_releases_url} sentinel_filename="sentinel_${SENTINEL_VERSION}_linux_${architecture}.zip" echo "(*) Downloading Sentinel... ${sentinel_filename}" diff --git a/test/terraform/custom_download_server.sh b/test/terraform/custom_download_server.sh new file mode 100755 index 000000000..9f0fdd600 --- /dev/null +++ b/test/terraform/custom_download_server.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +# Import test library +source dev-container-features-test-lib + +# Check if terraform was installed correctly and it's the expected version +check "terraform installed" terraform --version +check "terraform version matches" terraform --version | grep "1.6.5" + +# Report results +reportResults diff --git a/test/terraform/custom_download_server_with_sentinel.sh b/test/terraform/custom_download_server_with_sentinel.sh new file mode 100755 index 000000000..9675b39b9 --- /dev/null +++ b/test/terraform/custom_download_server_with_sentinel.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +# Import test library +source dev-container-features-test-lib + +# Check if terraform was installed correctly and it's the expected version +check "terraform installed" terraform --version +check "terraform version matches" terraform --version | grep "1.6.5" + +# Check if sentinel was installed correctly +check "sentinel installed" sentinel --version + +# Report results +reportResults diff --git a/test/terraform/scenarios.json b/test/terraform/scenarios.json index 04693666c..ea6b35b09 100644 --- a/test/terraform/scenarios.json +++ b/test/terraform/scenarios.json @@ -70,5 +70,24 @@ "tflint": "0.40.0" } } + }, + "custom_download_server": { + "image": "mcr.microsoft.com/devcontainers/base:jammy", + "features": { + "terraform": { + "version": "1.6.5", + "customDownloadServer": "https://releases.hashicorp.com" + } + } + }, + "custom_download_server_with_sentinel": { + "image": "mcr.microsoft.com/devcontainers/base:jammy", + "features": { + "terraform": { + "version": "1.6.5", + "installSentinel": true, + "customDownloadServer": "https://releases.hashicorp.com" + } + } } } \ No newline at end of file