Building Guarded Entrypoint for Chainguard Containers
- View all articles
Jeremy Harrington
Senior Software Engineer
Chainguard
- View all articles
Rodrigo Munoz
Associate Software Engineer
Chainguard
Jeremy Harrington Senior Software Engineer + 1 other
Every container does a little work before your application actually starts. It pulls secrets into environment variables, tests connectivity, or builds a runtime truststore. Historically, the only way for platform teams to execute this startup logic was to add a custom Dockerfile layer on top of their vendor's base image. But the moment you build a derived image, you break the core value of using Chainguard. The deployed image is no longer the exact artifact we build, sign, and update daily. Scanners start flagging differences, SBOMs drift, new engineers can't trace where an extra binary came from, and you erode your zero-CVE SLA.
Today, we're announcing Guarded Entrypoint, a new capability within Chainguard Containers Custom Assembly that eliminates the need for derived builds just to run startup logic. Guarded Entrypoint lets you declare your startup configuration directly in your Custom Assembly repo. Chainguard then sets your image’s entrypoint to a small, built-in binary that prepares the environment and safely hands off to your application. Your image remains exactly what we built and signed, while your startup behavior is configured just as easily as adding a package.
What you get
Guarded Entrypoint handles standard startup requirements, such as setting environment variables to secret references (Google Secret Manager, Vault, Consul), building a Java truststore at startup, and managing command control, all directly from the Custom Assembly manifest. Crucially, it guarantees normal process behavior. It acts as a proper PID 1 init: the app runs as a child process, signals are forwarded so pod terminations reach it, orphaned processes are safely reaped, and your app's exit code becomes the container's exit code.
Secret references in your environment. Set an environment variable to a reference, such as
cg+gsm://projects/<project>/secrets/<name>/versions/latest, and the app can see the secret. Google Secret Manager, HashiCorp Vault, and Consul are supported.A Java truststore built at startup. Certificates mounted into the pod at runtime, such as a rotating cluster CA or a private CA, are added to the image's trusted certificates, and the JVM is pointed at the result. You set it in the Custom Assembly manifest with a
truststoreentry that specifies where the certificates are mounted, where to write the store, whether to keep the image's own certificates, and which variable holds the store's password. The store is rewritten on every start, so a rotated CA takes effect the next time the container starts. With a read-only root filesystem, mount an emptyDir where the store is written.Startup checks. Wait for a TCP endpoint or a file to appear before the app starts, with a timeout. You choose whether a timeout stops the container or lets it continue.
Command control. Set a default command, prepend to the container's arguments, or override them. Secrets that were just resolved can be used in the command.
Turn it on
In Custom Assembly, opt a repo in and put the references in its environment map:
guarded_entrypoint: true
environment:
DB_PASSWORD: cg+gsm://projects/<project>/secrets/db-password/versions/latest
API_KEY: cg+consul://apps/billing/api-key
CONSUL_HTTP_ADDR: https://<consul-host>:8501
Custom Assembly rebuilds the image with the init in front of your original entrypoint, so the app starts the same way it did before. A repo that hasn't opted in isn't changed. The init authenticates to each backend with credentials from the container's environment: Application Default Credentials for Google Secret Manager, a token or Kubernetes login for Vault, and a token for Consul. To turn it on for your organization, contact your Chainguard account team.
When something goes wrong
If a reference cannot be resolved, Guarded Entrypoint defaults to stopping the container before the app starts, providing a clear deploy-time exit code. You can optionally enable an open mode for non-critical secrets, which starts the app with the reference left in place and logs warnings. If you ever suspect the init is causing an issue, we built in an immediate escape hatch: set an environment variable to skip the init entirely and run your original command. This is honored before any configuration is read, meaning recovery is a simple redeploy rather than a full image rebuild.
What it doesn't do
Only environment variables are resolved, not container arguments. Kubernetes expands $(VAR) in args before the init runs, so an argument written that way reaches the app as the literal reference. Read secrets from the environment, or put the command in the init's configuration, where references are expanded after they're resolved.
The init keeps secrets out of its own logs. It can't hide an expanded command from something that reads the process's /proc/<pid>/cmdline, so prefer environment variables to command-line flags for secrets.
Secrets are read once, at startup. A short-lived credential, such as a Vault dynamic secret, isn't renewed, and it lapses when its lease does.
What it costs
With nothing to resolve, the Guarded Entrypoint init adds under 4 ms to the median container start time on both x86_64 and aarch64. The only additional latency introduced is the exact network round trip to your configured secret backend, as the init makes absolutely no other outbound network connections.
Get started
The Custom Assembly docs cover how to opt a repo in and the reference syntax for each backend. If you're not sure it fits your images, your account team can walk you through it, or you can get in touch with our team to learn more.
Share this article
Related articles
productChainguard endpoints now handle breaking changes
productIntroducing Chainguard MCP for secure agentic development
productIntroducing Chainguard Workspaces
productEverything we announced at Chainguard Assemble London 2026
productIntroducing Chainguard Checks
productChainguard Libraries expands to Go and .NET