From 2fc2f3ae4089c9c05ff098bb699335358de3c9e1 Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 09:57:32 +0000 Subject: [PATCH 1/9] Add custom download server option to download terraform --- src/terraform/NOTES.md | 20 +++++++++++++++++-- src/terraform/README.md | 2 +- src/terraform/devcontainer-feature.json | 7 ++++++- src/terraform/install.sh | 16 +++++++++++---- test/terraform/custom_download_server.sh | 13 ++++++++++++ .../custom_download_server_with_sentinel.sh | 15 ++++++++++++++ test/terraform/scenarios.json | 19 ++++++++++++++++++ 7 files changed, 84 insertions(+), 8 deletions(-) create mode 100755 test/terraform/custom_download_server.sh create mode 100755 test/terraform/custom_download_server_with_sentinel.sh diff --git a/src/terraform/NOTES.md b/src/terraform/NOTES.md index 2c1540aee..92a651560 100644 --- a/src/terraform/NOTES.md +++ b/src/terraform/NOTES.md @@ -1,9 +1,25 @@ - - ## Licensing 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 hostname without protocol (e.g., `my-mirror.example.com` not `https://my-mirror.example.com`) +- The server should mirror the HashiCorp releases structure +- For Sentinel with custom servers, specifying an exact version is recommended instead of "latest" + +Example: +```json +"features": { + "ghcr.io/devcontainers/features/terraform:1": { + "customDownloadServer": "my-mirror.example.com" + } +} +``` + ## 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/README.md b/src/terraform/README.md index f6f5c9636..a64a0b0ca 100644 --- a/src/terraform/README.md +++ b/src/terraform/README.md @@ -1,4 +1,3 @@ - # Terraform, tflint, and TFGrunt (terraform) Installs the Terraform CLI and optionally TFLint and Terragrunt. Auto-detects latest version and installs needed dependencies. @@ -22,6 +21,7 @@ Installs the Terraform CLI and optionally TFLint and Terragrunt. Auto-detects la | installTFsec | Install tfsec, a tool to spot potential misconfigurations for your terraform code | boolean | false | | installTerraformDocs | Install terraform-docs, a utility to generate documentation from Terraform modules | boolean | false | | httpProxy | Connect to a keyserver using a proxy by configuring this option | string | - | +| customDownloadServer | Custom server URL for downloading Terraform and Sentinel packages (default is releases.hashicorp.com) | string | - | ## Customizations diff --git a/src/terraform/devcontainer-feature.json b/src/terraform/devcontainer-feature.json index d022f83c1..e5ae71ce8 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.3.11", "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 (default is releases.hashicorp.com)" } }, "customizations": { diff --git a/src/terraform/install.sh b/src/terraform/install.sh index a2aace9b4..aaafd231b 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,13 @@ SENTINEL_SHA256="${SENTINEL_SHA256:-"automatic"}" TFSEC_SHA256="${TFSEC_SHA256:-"automatic"}" TERRAFORM_DOCS_SHA256="${TERRAFORM_DOCS_SHA256:-"automatic"}" +# Set the default HashiCorp download server +HASHICORP_RELEASES_URL="releases.hashicorp.com" +# Use custom download server if provided +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 +365,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} "https://${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/${terraform_filename}" } mkdir -p /tmp/tf-downloads @@ -373,8 +381,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 "https://${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS" + curl -sSL -o terraform_SHA256SUMS.sig "https://${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 +472,7 @@ fi if [ "${INSTALL_SENTINEL}" = "true" ]; then SENTINEL_VERSION="latest" - sentinel_releases_url='https://releases.hashicorp.com/sentinel' + sentinel_releases_url="https://${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..694c716d8 --- /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 \ No newline at end of file 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..c4c32e43a --- /dev/null +++ b/test/terraform/custom_download_server_with_sentinel.sh @@ -0,0 +1,15 @@ +#!/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 \ No newline at end of file diff --git a/test/terraform/scenarios.json b/test/terraform/scenarios.json index 04693666c..5dc02ced1 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": "releases.hashicorp.com" + } + } + }, + "custom_download_server_with_sentinel": { + "image": "mcr.microsoft.com/devcontainers/base:jammy", + "features": { + "terraform": { + "version": "1.6.5", + "installSentinel": true, + "customDownloadServer": "releases.hashicorp.com" + } + } } } \ No newline at end of file From c4bd98af67475f7842a65954c7f57106880e1901 Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 09:59:34 +0000 Subject: [PATCH 2/9] Bump Terraform version to 1.4.0 in devcontainer feature configuration --- src/terraform/devcontainer-feature.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/terraform/devcontainer-feature.json b/src/terraform/devcontainer-feature.json index e5ae71ce8..ce8780d78 100644 --- a/src/terraform/devcontainer-feature.json +++ b/src/terraform/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "terraform", - "version": "1.3.11", + "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.", From 8a9dab5014aad6f1687a604f876d2f6d97abee8c Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 10:51:44 +0000 Subject: [PATCH 3/9] Update custom download server documentation and implementation to require full URL with protocol --- src/terraform/NOTES.md | 4 ++-- src/terraform/devcontainer-feature.json | 2 +- src/terraform/install.sh | 12 +++++------- test/terraform/scenarios.json | 4 ++-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/terraform/NOTES.md b/src/terraform/NOTES.md index 92a651560..dd6d9fdb0 100644 --- a/src/terraform/NOTES.md +++ b/src/terraform/NOTES.md @@ -7,7 +7,7 @@ On August 10, 2023, HashiCorp announced a change of license for its products, in 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 hostname without protocol (e.g., `my-mirror.example.com` not `https://my-mirror.example.com`) +- Provide the complete URL including protocol (e.g., `https://my-mirror.example.com`) - The server should mirror the HashiCorp releases structure - For Sentinel with custom servers, specifying an exact version is recommended instead of "latest" @@ -15,7 +15,7 @@ Example: ```json "features": { "ghcr.io/devcontainers/features/terraform:1": { - "customDownloadServer": "my-mirror.example.com" + "customDownloadServer": "https://my-mirror.example.com" } } ``` diff --git a/src/terraform/devcontainer-feature.json b/src/terraform/devcontainer-feature.json index ce8780d78..db1bacc67 100644 --- a/src/terraform/devcontainer-feature.json +++ b/src/terraform/devcontainer-feature.json @@ -58,7 +58,7 @@ "customDownloadServer": { "type": "string", "default": "", - "description": "Custom server URL for downloading Terraform and Sentinel packages (default is releases.hashicorp.com)" + "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 aaafd231b..fb7abc6ee 100755 --- a/src/terraform/install.sh +++ b/src/terraform/install.sh @@ -27,9 +27,7 @@ SENTINEL_SHA256="${SENTINEL_SHA256:-"automatic"}" TFSEC_SHA256="${TFSEC_SHA256:-"automatic"}" TERRAFORM_DOCS_SHA256="${TERRAFORM_DOCS_SHA256:-"automatic"}" -# Set the default HashiCorp download server -HASHICORP_RELEASES_URL="releases.hashicorp.com" -# Use custom download server if provided +HASHICORP_RELEASES_URL="https://releases.hashicorp.com" if [ -n "${CUSTOM_DOWNLOAD_SERVER}" ]; then HASHICORP_RELEASES_URL="${CUSTOM_DOWNLOAD_SERVER}" fi @@ -365,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://${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/${terraform_filename}" + curl -sSL -o ${terraform_filename} "${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/${terraform_filename}" } mkdir -p /tmp/tf-downloads @@ -381,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://${HASHICORP_RELEASES_URL}/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS" - curl -sSL -o terraform_SHA256SUMS.sig "https://${HASHICORP_RELEASES_URL}/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 @@ -472,7 +470,7 @@ fi if [ "${INSTALL_SENTINEL}" = "true" ]; then SENTINEL_VERSION="latest" - sentinel_releases_url="https://${HASHICORP_RELEASES_URL}/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/scenarios.json b/test/terraform/scenarios.json index 5dc02ced1..ea6b35b09 100644 --- a/test/terraform/scenarios.json +++ b/test/terraform/scenarios.json @@ -76,7 +76,7 @@ "features": { "terraform": { "version": "1.6.5", - "customDownloadServer": "releases.hashicorp.com" + "customDownloadServer": "https://releases.hashicorp.com" } } }, @@ -86,7 +86,7 @@ "terraform": { "version": "1.6.5", "installSentinel": true, - "customDownloadServer": "releases.hashicorp.com" + "customDownloadServer": "https://releases.hashicorp.com" } } } From 54edd4825287ad8b303664acb085bfaaa3ead85e Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 10:52:57 +0000 Subject: [PATCH 4/9] Remove my changes from an auto-generated file --- src/terraform/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/terraform/README.md b/src/terraform/README.md index a64a0b0ca..941323e01 100644 --- a/src/terraform/README.md +++ b/src/terraform/README.md @@ -21,7 +21,6 @@ Installs the Terraform CLI and optionally TFLint and Terragrunt. Auto-detects la | installTFsec | Install tfsec, a tool to spot potential misconfigurations for your terraform code | boolean | false | | installTerraformDocs | Install terraform-docs, a utility to generate documentation from Terraform modules | boolean | false | | httpProxy | Connect to a keyserver using a proxy by configuring this option | string | - | -| customDownloadServer | Custom server URL for downloading Terraform and Sentinel packages (default is releases.hashicorp.com) | string | - | ## Customizations From f3e4823a526440996c22019ba8d721a04e526c1e Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 10:55:12 +0000 Subject: [PATCH 5/9] Remove my changes from an auto-generated file --- src/terraform/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/terraform/README.md b/src/terraform/README.md index 941323e01..f6f5c9636 100644 --- a/src/terraform/README.md +++ b/src/terraform/README.md @@ -1,3 +1,4 @@ + # Terraform, tflint, and TFGrunt (terraform) Installs the Terraform CLI and optionally TFLint and Terragrunt. Auto-detects latest version and installs needed dependencies. From 57dfb826eee6777d6458b5c6f86aed6d1c80a811 Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 11:01:51 +0000 Subject: [PATCH 6/9] Add security considerations for custom download servers in documentation --- src/terraform/NOTES.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/terraform/NOTES.md b/src/terraform/NOTES.md index dd6d9fdb0..9a568053e 100644 --- a/src/terraform/NOTES.md +++ b/src/terraform/NOTES.md @@ -9,7 +9,6 @@ The `customDownloadServer` option allows you to specify an alternative server fo 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 -- For Sentinel with custom servers, specifying an exact version is recommended instead of "latest" Example: ```json @@ -20,6 +19,20 @@ Example: } ``` +### 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. From 8873bed49e97961e27dd0683206a806dbec4ebfe Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 11:05:43 +0000 Subject: [PATCH 7/9] Update security considerations section in documentation with warning icon --- src/terraform/NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/terraform/NOTES.md b/src/terraform/NOTES.md index 9a568053e..28c85a705 100644 --- a/src/terraform/NOTES.md +++ b/src/terraform/NOTES.md @@ -19,7 +19,7 @@ Example: } ``` -### Security Considerations +### ⚠️ Security Considerations When using a custom download server, be aware of the following security implications: From 7f654cae297b642575d40f3d6737e4812727960f Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sun, 18 May 2025 11:15:26 +0000 Subject: [PATCH 8/9] Return leading empty lines back to NOTES.md --- src/terraform/NOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/terraform/NOTES.md b/src/terraform/NOTES.md index 28c85a705..74a90639e 100644 --- a/src/terraform/NOTES.md +++ b/src/terraform/NOTES.md @@ -1,3 +1,5 @@ + + ## Licensing 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 From 2e9c1d26d5e10253c4dcee7d7b90c776871643f1 Mon Sep 17 00:00:00 2001 From: iTiPo Date: Sat, 31 May 2025 18:13:03 +0000 Subject: [PATCH 9/9] Fix formatting in custom download server scripts by ensuring consistent newline handling and invoking reportResults function. --- test/terraform/custom_download_server.sh | 2 +- test/terraform/custom_download_server_with_sentinel.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/terraform/custom_download_server.sh b/test/terraform/custom_download_server.sh index 694c716d8..9f0fdd600 100755 --- a/test/terraform/custom_download_server.sh +++ b/test/terraform/custom_download_server.sh @@ -10,4 +10,4 @@ check "terraform installed" terraform --version check "terraform version matches" terraform --version | grep "1.6.5" # Report results -reportResults \ No newline at end of file +reportResults diff --git a/test/terraform/custom_download_server_with_sentinel.sh b/test/terraform/custom_download_server_with_sentinel.sh index c4c32e43a..9675b39b9 100755 --- a/test/terraform/custom_download_server_with_sentinel.sh +++ b/test/terraform/custom_download_server_with_sentinel.sh @@ -12,4 +12,5 @@ check "terraform version matches" terraform --version | grep "1.6.5" # Check if sentinel was installed correctly check "sentinel installed" sentinel --version -# Report results \ No newline at end of file +# Report results +reportResults