diff --git a/scripts/ironbank/build_ironbank.sh b/scripts/ironbank/build_ironbank.sh index 902c9d1dbc..fd8ba85c7e 100755 --- a/scripts/ironbank/build_ironbank.sh +++ b/scripts/ironbank/build_ironbank.sh @@ -1,7 +1,9 @@ #!/usr/bin/env bash # This script builds the ironbank Docker image of Coder containing the given -# binary. Other dependencies will be automatically downloaded and cached. +# binary. Terraform is compiled from source to control the Go toolchain version +# and address Go stdlib CVEs. Other dependencies will be automatically +# downloaded and cached. # # Usage: ./build_ironbank.sh --target image_tag path/to/coder @@ -34,7 +36,7 @@ if [[ "$image_tag" == "" ]]; then fi # Check dependencies -dependencies docker sha256sum yq +dependencies docker sha256sum yq go if [[ $(yq --version) != *" v4."* ]]; then error "yq version 4 is required" fi @@ -63,9 +65,10 @@ execrelative ../archive.sh \ "$input_file" # Download all resources in the hardening_manifest.yaml file except for -# coder.tar.gz (which we will make ourselves). +# coder.tar.gz (which we will make ourselves) and terraform-src.tar.gz +# (which we will build from source below). manifest_path="$(dirname "${BASH_SOURCE[0]}")/hardening_manifest.yaml" -resources="$(yq e '.resources[] | select(.filename != "coder.tar.gz") | [.filename, .url, .validation.value] | @tsv' "$manifest_path")" +resources="$(yq e '.resources[] | select(.filename != "coder.tar.gz" and .filename != "terraform-src.tar.gz") | [.filename, .url, .validation.value] | @tsv' "$manifest_path")" while read -r line; do filename="$(echo "$line" | cut -f1)" url="$(echo "$line" | cut -f2)" @@ -87,6 +90,62 @@ while read -r line; do popd done <<<"$resources" +# Build Terraform from source to control the Go toolchain version. +# This ensures the bundled Terraform binary uses Go 1.25.9+ to address +# Go stdlib CVEs that affect pre-built HashiCorp binaries. +terraform_src="$(yq e '.resources[] | select(.filename == "terraform-src.tar.gz") | [.url, .validation.value] | @tsv' "$manifest_path")" +if [[ -n "$terraform_src" ]]; then + terraform_src_url="$(echo "$terraform_src" | cut -f1)" + terraform_src_sha256="$(echo "$terraform_src" | cut -f2)" + + pushd "$(dirname "${BASH_SOURCE[0]}")" + terraform_src_cache=".terraform-src.tar.gz.${terraform_src_sha256}" + if [[ ! -f "$terraform_src_cache" ]]; then + log "Downloading Terraform source" + curl -sSL "$terraform_src_url" -o "$terraform_src_cache" + fi + + sum="$(sha256sum "$terraform_src_cache" | cut -d' ' -f1)" + if [[ "$sum" != "$terraform_src_sha256" ]]; then + rm "$terraform_src_cache" + error "Downloaded Terraform source has hash $sum, but expected $terraform_src_sha256" + fi + popd + + # Extract and build Terraform from source. + terraform_build_dir="$(mktemp -d)" + trap 'rm -rf "$tmpdir" "$terraform_build_dir"' EXIT + pushd "$(dirname "${BASH_SOURCE[0]}")" + tar -xzf "$terraform_src_cache" -C "$terraform_build_dir" --strip-components=1 + popd + + # Read the Go version from the Coder project's go.mod to ensure we use + # the same toolchain version for all binaries in the image. + coder_go_version="$(head -5 "$(dirname "${BASH_SOURCE[0]}")/../../go.mod" | grep '^go ' | awk '{print $2}')" + log "Building Terraform from source with Go ${coder_go_version}" + + pushd "$terraform_build_dir" + GOTOOLCHAIN="go${coder_go_version}" CGO_ENABLED=0 \ + go build \ + -ldflags="-s -w -X 'github.com/hashicorp/terraform/version.dev=no'" \ + -o "$tmpdir/terraform" . + popd + + # Verify the compiled binary uses the expected Go toolchain. + built_go_version="$(go version "$tmpdir/terraform" | grep -oP 'go[0-9]+\.[0-9]+\.[0-9]+')" + log "Terraform built with ${built_go_version}" + + # Package as terraform.zip for the Dockerfile. + pushd "$tmpdir" + zip terraform.zip terraform + rm terraform + popd + + rm -rf "$terraform_build_dir" +else + error "terraform-src.tar.gz resource not found in hardening_manifest.yaml" +fi + terraform_coder_provider_version="$(yq e '.args.TERRAFORM_CODER_PROVIDER_VERSION' "$manifest_path")" if [[ "$terraform_coder_provider_version" == "" ]]; then error "TERRAFORM_CODER_PROVIDER_VERSION not found in hardening_manifest.yaml" diff --git a/scripts/ironbank/hardening_manifest.yaml b/scripts/ironbank/hardening_manifest.yaml index dfcbd75d66..192c1ca862 100644 --- a/scripts/ironbank/hardening_manifest.yaml +++ b/scripts/ironbank/hardening_manifest.yaml @@ -13,7 +13,7 @@ tags: # Build args passed to Dockerfile ARGs args: # Needs to be kept in sync with the resource below. - TERRAFORM_CODER_PROVIDER_VERSION: "0.6.10" + TERRAFORM_CODER_PROVIDER_VERSION: "2.16.0" # Docker image labels labels: @@ -38,22 +38,25 @@ resources: validation: type: sha256 value: 2c88555777f1d9cc77a8f049093f4002472dc43d52b026e6784ef477bdced4a2 - # Terraform binary, bundled inside of Coder to support air-gapped installs. - - url: https://releases.hashicorp.com/terraform/1.3.7/terraform_1.3.7_linux_amd64.zip - filename: "terraform.zip" + # Terraform source, built from source during the IronBank image build to + # control the Go toolchain version (addresses Go stdlib CVEs). + # Version must stay in sync with TerraformVersion in + # provisioner/terraform/install.go and scripts/Dockerfile.base. + - url: https://github.com/hashicorp/terraform/archive/refs/tags/v1.14.5.tar.gz + filename: "terraform-src.tar.gz" validation: type: sha256 - value: b8cf184dee15dfa89713fe56085313ab23db22e17284a9a27c0999c67ce3021e + value: ac3faee7b1d301a4d12fe6b7f33b1ba57a183e080a2442f6f1466a30f257ba45 # Coder Terraform provider, bundled inside of Coder to support air-gapped # installs. # # The version of this provider needs to be kept in sync with the # TERRAFORM_CODER_PROVIDER_VERSION build arg. - - url: https://github.com/coder/terraform-provider-coder/releases/download/v0.6.10/terraform-provider-coder_0.6.10_linux_amd64.zip + - url: https://github.com/coder/terraform-provider-coder/releases/download/v2.16.0/terraform-provider-coder_2.16.0_linux_amd64.zip filename: "terraform-provider-coder.zip" validation: type: sha256 - value: 4c2a16010621e146251f6fb5e27105dde9213d85ca8f3c8866c3f5a4159b81b0 + value: 8eeb2c74e804087c3959d37c5cf773ec00beba431d3a312518aea5934bc8c73b # List of project maintainers maintainers: