diff --git a/terraform/environments/azure/build.tf b/terraform/environments/azure/build.tf index ad237360..4e9ef9b7 100644 --- a/terraform/environments/azure/build.tf +++ b/terraform/environments/azure/build.tf @@ -21,7 +21,9 @@ module "build" { # platform not set — auto-detected from builder host (Container Apps and AKS support arm64 and amd64) # Registry login with the caller's Entra identity (deploy SP in CI, az login - # locally); the principal needs AcrPush on the registry. + # locally); the principal needs AcrPush on the registry. Identity-based, so + # it carries no static credential, matching the module's + # registry_login_command contract (see its variable description). registry_login_command = "az acr login --name ${azurerm_container_registry.main.name}" # Build options diff --git a/terraform/modules/build/main.tf b/terraform/modules/build/main.tf index 4e93dd6a..c65a9c5b 100644 --- a/terraform/modules/build/main.tf +++ b/terraform/modules/build/main.tf @@ -68,7 +68,20 @@ resource "terraform_data" "docker_build" { provisioner "local-exec" { working_dir = var.source_path - command = <<-EOT + # extra_build_args is passed through the environment, not interpolated into + # the script text below, so shell metacharacters in its value (;, `, $()) + # are never parsed as script syntax. registry_login_command still has to be + # interpolated as literal shell source (it is documented to be a full + # command, e.g. a pipe into `docker login`), so it stays a trusted, + # identity-based-only input (see its variable description) rather than a + # secret: neither variable is marked sensitive, because that would + # suppress this resource's entire local-exec output (the build/push log + # deploy-*.yml workflows tee and grep to detect failures), not just the + # two variables' own values. + environment = { + EXTRA_BUILD_ARGS = var.extra_build_args + } + command = <<-EOT set -e echo "Logging in to registry..." ${var.registry_login_command} @@ -105,11 +118,11 @@ resource "terraform_data" "docker_build" { $PLATFORM_ARG \ --provenance=false \ --sbom=false \ - --tag ${local.image_uri} \ - --build-arg GIT_COMMIT=${local.git_commit} \ - --build-arg BUILD_DATE=${local.timestamp} \ + --tag "${local.image_uri}" \ + --build-arg "GIT_COMMIT=${local.git_commit}" \ + --build-arg "BUILD_DATE=${local.timestamp}" \ --push \ - ${var.extra_build_args} \ + $EXTRA_BUILD_ARGS \ . echo "Docker image built and pushed successfully" diff --git a/terraform/modules/build/variables.tf b/terraform/modules/build/variables.tf index 8133841f..a9bafd7a 100644 --- a/terraform/modules/build/variables.tf +++ b/terraform/modules/build/variables.tf @@ -35,13 +35,13 @@ variable "skip_docker_build" { } variable "extra_build_args" { - description = "Extra arguments to pass to docker build" + description = "Extra arguments to pass to docker build. Passed through the local-exec provisioner's environment (not interpolated into the script), then whitespace-split unquoted (no shell quoting is honored): a value like \"--build-arg LABEL=hello world\" splits into two docker buildx arguments, not one. No caller sets this today; if a value ever needs an embedded space, extend the module to accept a list(string) instead." type = string default = "" } variable "registry_login_command" { - description = "Command to authenticate with registry (e.g., aws ecr get-login-password | docker login...)" + description = "Command to authenticate with registry (e.g., az acr login --name ..., aws ecr get-login-password | docker login ..., gcloud auth configure-docker ...). Runs verbatim as shell input. Must be an identity-based login (the CLI resolves/mints the credential itself); never embed a static, long-lived credential literal (a password, API key, or JSON key) in this value; it is not redacted in terraform plan/apply output, and marking it sensitive would suppress this resource's entire local-exec log (build/push progress, docker error output), which deploy-*.yml workflows tee and grep to detect build failures." type = string }