#6873·terragrunt

Terragrunt 1.1.x fails AWS configuration when AWS_CA_BUNDLE is set because Venv injects a plain *http.Client

Author: absltkaosCreated Sep 10, 2026Updated Sep 16, 2026
Labelsbug

Describe the bug

Terragrunt 1.1.x fails while evaluating AWS HCL helpers such as get_aws_caller_identity_arn() whenever AWS_CA_BUNDLE is set.

The failure happens during AWS SDK configuration, before any AWS request is sent:

error loading AWS config: unable to add custom RootCAs HTTPClient, has no WithTransportOptions, *http.Client

Terragrunt 1.0.1 works with the same configuration.

This is a Terragrunt 1.1 regression. In 1.1.x, internal/awshelper always injects Terragrunt’s generic Venv HTTP client (*http.Client from vhttp.NewOSClient()) into config.LoadDefaultConfig. AWS SDK v2 can only apply AWS_CA_BUNDLE to an *awshttp.BuildableClient. A plain *http.Client does not implement WithTransportOptions, so configuration fails.

AWS_CA_BUNDLE is the documented AWS SDK mechanism for custom CA roots, including HTTPS inspection proxies.

Steps To Reproduce

  1. Use Terragrunt 1.1.4 (or any 1.1.x release with the Venv HTTP client wired into awshelper).

  2. Create a valid PEM CA bundle. A system bundle is enough; the contents do not matter as long as the file exists and is readable:

bash
export AWS_CA_BUNDLE="$(python3 -c 'import certifi; print(certifi.where())')"
# or: export AWS_CA_BUNDLE=/etc/ssl/cert.pem
  1. Create this fixture:
hcl
# terragrunt.hcl
locals {
  caller_arn = get_aws_caller_identity_arn()
}

terraform {
  source = "."
}

Valid AWS credentials are not required. The crash happens while loading AWS config, before STS is called.

  1. Evaluate the configuration:
bash
terragrunt render

Any command that evaluates the helper also reproduces it (terragrunt run -- providers lock, terragrunt plan, etc.).

Expected behavior

Terragrunt should load AWS_CA_BUNDLE and continue. If credentials are missing or invalid, the error should come from STS, not from HTTP-client construction.

Must haves

  • Steps for reproduction provided.

Nice to haves

  • Terminal output
ERROR  ./terragrunt.hcl:3,16-42: Error in function call; Call to function "get_aws_caller_identity_arn" failed: error loading AWS config: unable to add custom RootCAs HTTPClient, has no WithTransportOptions, *http.Client.

Versions

  • Terragrunt version: 1.1.4 (fails); 1.0.1 (works)
  • OpenTofu/Terraform version: Terraform 1.9.8 (not required for this failure)
  • Environment details: macOS Darwin 25.6.0, arm64

Additional context

Root cause

In Terragrunt 1.1.4, internal/vhttp.NewOSClient() returns a plain *http.Client:

go
func NewOSClient() Client {
    return &http.Client{Transport: newOSTransport()}
}

AWSConfigBuilder.Build() always injects that client:

go
configOptions = append(
    configOptions,
    config.WithAppID("terragrunt/"+version.GetVersion()),
    config.WithHTTPClient(v.HTTP),
)

cfg, err := config.LoadDefaultConfig(ctx, configOptions...)

AssumeIamRole does the same.

AWS SDK v2 then sees AWS_CA_BUNDLE and tries to attach the PEM roots with WithTransportOptions. That API exists on *awshttp.BuildableClient, not on *http.Client.

This also affects other Terragrunt-owned AWS operations that use the same builder (remote-state S3/DynamoDB, iam_role / assume-role, HCL identity helpers).

We originally hit this behind an HTTPS MITM proxy that sets AWS_CA_BUNDLE and HTTPS_PROXY. The proxy is not required to reproduce the config error; setting AWS_CA_BUNDLE is enough.

Recommended minimal fix

Do not inject the generic Venv HTTP client when AWS_CA_BUNDLE is set, in both AWSConfigBuilder.Build and AssumeIamRole:

go
configOptions := []func(*config.LoadOptions) error{
    config.WithAppID("terragrunt/" + version.GetVersion()),
}

if v.Env["AWS_CA_BUNDLE"] == "" {
    configOptions = append(configOptions, config.WithHTTPClient(v.HTTP))
}

If no client is supplied, AWS SDK v2 creates an awshttp.BuildableClient, applies AWS_CA_BUNDLE, and still honors HTTPS_PROXY.

Longer-term option

Keep generic HTTP (vhttp.Client) separate from the AWS SDK HTTP client, and default the AWS path to awshttp.NewBuildableClient(). That preserves test injection and satisfies the SDK’s custom-CA contract.

Suggested regression test

Set AWS_CA_BUNDLE to a valid test PEM on the production/default AWS HTTP path and assert that building AWS config does not return the WithTransportOptions error.