Managing tag-based Custom Assembly with Terraform
How to use the Chainguard Terraform provider to create overlays and bind them to specific tags of a Custom Assembly …
For the complete documentation index, see llms.txt.
Note: Guarded Entrypoint is in beta. To use it, contact Chainguard customer support to enable it for your organization.
This page has four example manifests for Guarded Entrypoint. Each one is a complete manifest for chainctl images repos build edit or chainctl images repos build apply. None of them contains a literal secret. Each secret is a reference that the wrapper resolves when the container starts.
Applying a manifest replaces the repo’s stored configuration. If your repo already has other customizations, such as packages, add the Guarded Entrypoint keys to your existing manifest instead of replacing it.
The examples use the following variables:
export REPO=my-custom-app
export ORGANIZATION=example.comTo try an example, save it as build.yaml. Preview the change, then apply it:
chainctl images repos build apply -f build.yaml --repo $REPO --parent $ORGANIZATION --dry-run
chainctl images repos build apply -f build.yaml --repo $REPO --parent $ORGANIZATION --yesThe first command prints the diff and exits with a non-zero status when it finds a change. The second command applies the manifest and starts a rebuild.
A Java application reads its database password and an API address from its environment. Today the team adds envconsul to a derived image to supply them. With Guarded Entrypoint, the references are part of the Custom Assembly repo.
guarded_entrypoint: true
environment:
VAULT_ADDR: https://vault.example.com:8200
VAULT_K8S_ROLE: orders-service
DB_PASSWORD: cg+vault://secret/data/orders#db_password
CONSUL_HTTP_ADDR: https://consul.example.com:8501
ORDERS_API_URL: cg+consul://apps/orders/api-urlWhen the container starts, the wrapper does the following:
orders-service role. It reads the db_password field of the orders secret, in the secret KV version 2 mount, into DB_PASSWORD.apps/orders/api-url key from Consul into ORDERS_API_URL.The image stores the references and the addresses. It doesn’t store the secrets. To read from Consul with a token, set CONSUL_HTTP_TOKEN or CONSUL_HTTP_TOKEN_FILE on the deployment, not in the manifest. A token in the manifest would be visible to anyone who can pull the image. VAULT_TOKEN, if you set it, takes precedence over the Kubernetes login, and CONSUL_HTTP_TOKEN_FILE wins over CONSUL_HTTP_TOKEN. A token can’t be a cg+ reference.
The default fail_mode is closed. If Vault or Consul can’t serve a reference, the container stops with exit code 121 and the application doesn’t start.
An application fails when its database isn’t ready at start. The following manifest holds the container until the database accepts connections, and then checks that a mounted file exists:
guarded_entrypoint: true
preflight:
- tcp: db.internal:5432
timeout: 60s
interval: 1s
on_failure: fail
- path: /run/secrets/tls-ready
timeout: 10s
on_failure: continueThe wrapper runs the checks in order, after it resolves secrets and before it starts the application:
db.internal:5432 for up to 60 seconds, and pauses one second between attempts. Each attempt has its own timeout. If the connection never succeeds, the container stops with exit code 122./run/secrets/tls-ready to exist. With on_failure: continue, the wrapper logs a warning and starts the application if the file never appears.A target can read from the environment. The following entry waits for the address in the CACHE_ADDR variable, which you set on the deployment:
guarded_entrypoint: true
preflight:
- tcp: ${CACHE_ADDR}
timeout: 30sIf CACHE_ADDR isn’t set, the check fails.
A Python image has no shell and ships with both an ENTRYPOINT and a CMD. The application needs a different command, and both defaults must go. Without Guarded Entrypoint, you build a derived image to do this.
guarded_entrypoint: true
environment:
PORT: "8080"
command_override:
mode: override
command:
- python
- /app/main.py
- --port
- ${PORT}In override mode, the wrapper starts command alone. The image’s ENTRYPOINT and CMD, and any arguments you pass at run time, are dropped. The wrapper expands ${PORT} from the container’s environment, so a deployment can change the port by setting PORT. The image needs no shell, because the wrapper starts python directly.
To keep the image’s own command and add arguments in front of it, use mode: prepend instead. See Command override.
Don’t pass a secret on the command line. The expanded value is visible in the process’s command line. Have the application read a secret from its environment, and use a secret reference to supply it.
An application reads a feature-flag address from Consul. The application has a built-in default, so it can start when Consul is down. The following manifest sets the repo to fail open:
guarded_entrypoint: true
fail_mode: open
environment:
CONSUL_HTTP_ADDR: https://consul.example.com:8501
FEATURE_FLAGS_URL: cg+consul://apps/web/feature-flags-urlIf Consul can’t serve the key, the application starts anyway. FEATURE_FLAGS_URL keeps the literal value cg+consul://apps/web/feature-flags-url, and the wrapper logs a warning for it. The application must handle that value, for example by falling back to its default when the value starts with cg+.
Use open only for variables that aren’t credentials. An unresolved variable holds a value that anyone with access to the image configuration can read. For a password or a token, keep the default of closed. See Fail mode.
Last updated: 2026-10-07 21:37