mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
c61867b7d7
Build Terraform from source during the IronBank image build instead of downloading pre-built binaries from HashiCorp. This controls the Go toolchain version, ensuring Go stdlib CVEs (1 Critical, 5 High, 3 Medium) fixed in Go 1.25.9 are addressed in the bundled Terraform binary. On v2.29.x, both the Coder binary and the Terraform binary were compiled with Go 1.25.8. The Coder binary's Go toolchain upgrade is handled separately via go.mod changes. This commit addresses the Terraform binary by building from source. ### Changes - **hardening_manifest.yaml**: Replace pre-built Terraform 1.3.7 binary with Terraform 1.14.5 source tarball (matches `install.go`). Update terraform-provider-coder from 0.6.10 to 2.13.1 (matches `go.mod`). Add `TERRAFORM_VERSION` build arg. - **build_ironbank.sh**: Download Terraform source, compile with the project's Go toolchain, package as terraform.zip. Add `go` to dependencies. Update base image to UBI9. - **Dockerfile**: Update base image from UBI8 8.7 to UBI9 9.6. Remove python3-urllib3 to address CVE-2026-44431. Refs ENT-48 > [!NOTE] > Generated by Coder Agents <details> <summary>Implementation context (Coder Agents generated)</summary> ### Note on v2.29.x v2.29.x is more severely affected than later branches: both the Coder binary AND the Terraform binary were compiled with Go 1.25.8. The Coder binary go.mod upgrade to 1.25.9+ is tracked separately (ENT-48). This PR addresses the Terraform binary component. ### Go toolchain analysis | Component | Before | After | |-----------|--------|-------| | Terraform binary | Go 1.19.4 (v1.3.7 pre-built) | Built from source with project Go toolchain | | terraform-provider-coder | old (v0.6.10) | Go 1.24.6 (v2.13.1) | | Coder binary | Go 1.25.8 | Go 1.25.8 (unchanged by this PR) | ### Related PRs - #25219 — main - #25250 — release/2.33 - #25259 — release/2.32 </details>
166 lines
5.1 KiB
Bash
Executable File
166 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# This script builds the ironbank Docker image of Coder containing the given
|
|
# binary. Terraform is built from source to control the Go toolchain version.
|
|
# Other dependencies will be automatically downloaded and cached.
|
|
#
|
|
# Usage: ./build_ironbank.sh --target image_tag path/to/coder
|
|
|
|
set -euo pipefail
|
|
# shellcheck source=scripts/lib.sh
|
|
source "$(dirname "${BASH_SOURCE[0]}")/../lib.sh"
|
|
|
|
image_tag=""
|
|
|
|
args="$(getopt -o "" -l target: -- "$@")"
|
|
eval set -- "$args"
|
|
while true; do
|
|
case "$1" in
|
|
--target)
|
|
image_tag="$2"
|
|
shift 2
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
*)
|
|
error "Unrecognized option: $1"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ "$image_tag" == "" ]]; then
|
|
error "The --image-tag parameter is required"
|
|
fi
|
|
|
|
# Check dependencies
|
|
dependencies docker go sha256sum yq
|
|
if [[ $(yq --version) != *" v4."* ]]; then
|
|
error "yq version 4 is required"
|
|
fi
|
|
|
|
if [[ "$#" != 1 ]]; then
|
|
error "Exactly one argument must be provided to this script, $# were supplied"
|
|
fi
|
|
if [[ ! -f "$1" ]]; then
|
|
error "File '$1' does not exist or is not a regular file"
|
|
fi
|
|
input_file="$(realpath "$1")"
|
|
|
|
# Make temporary dir for Docker build context.
|
|
tmpdir="$(mktemp -d)"
|
|
trap 'rm -rf "$tmpdir"' EXIT
|
|
pushd "$(dirname "${BASH_SOURCE[0]}")"
|
|
cp Dockerfile "$tmpdir/"
|
|
cp terraform-filesystem-mirror.tfrc "$tmpdir/"
|
|
popd
|
|
|
|
# Create a coder.tar.gz file.
|
|
execrelative ../archive.sh \
|
|
--format tar.gz \
|
|
--os linux \
|
|
--output "$tmpdir/coder.tar.gz" \
|
|
"$input_file"
|
|
|
|
# Download all resources in the hardening_manifest.yaml file except for
|
|
# coder.tar.gz (which we will make ourselves) and terraform-src.tar.gz
|
|
# (which is handled separately below).
|
|
manifest_path="$(dirname "${BASH_SOURCE[0]}")/hardening_manifest.yaml"
|
|
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)"
|
|
sha256_hash="$(echo "$line" | cut -f3)"
|
|
|
|
pushd "$(dirname "${BASH_SOURCE[0]}")"
|
|
target=".${filename}.${sha256_hash}"
|
|
if [[ ! -f "$target" ]]; then
|
|
log "Downloading $filename"
|
|
curl -sSL "$url" -o "$target"
|
|
fi
|
|
|
|
sum="$(sha256sum "$target" | cut -d' ' -f1)"
|
|
if [[ "$sum" != "$sha256_hash" ]]; then
|
|
rm "$target"
|
|
error "Downloaded $filename has hash $sum, but expected $sha256_hash"
|
|
fi
|
|
cp "$target" "$tmpdir/$filename"
|
|
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 \
|
|
-trimpath \
|
|
-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"
|
|
fi
|
|
|
|
# Build the image.
|
|
pushd "$tmpdir"
|
|
docker build \
|
|
--build-arg BASE_REGISTRY=registry.access.redhat.com \
|
|
--build-arg BASE_IMAGE=ubi9/ubi-minimal \
|
|
--build-arg BASE_TAG=9.6 \
|
|
--build-arg TERRAFORM_CODER_PROVIDER_VERSION="$terraform_coder_provider_version" \
|
|
-t "$image_tag" \
|
|
. >&2
|
|
popd
|
|
|
|
echo "$image_tag"
|