DevOps

LocalStack now requires an auth token: keeping it out of Git with Docker Compose

Marçal Albert Castellví
Principal Software Engineer·
Source:dev.to
·
5 min read
·
Human-written

AI tooling disclosure

The author reports no meaningful generative-AI assistance.

LocalStack now requires an auth token: keeping it out of Git with Docker Compose

How I run LocalStack without committing LOCALSTACK_AUTH_TOKEN

Updated October 2026: This article now includes envilder exec, Azure Key Vault, and LocalStack for Azure. The original .env workflow is still here, just no longer the default approach I recommend.

Since LocalStack for AWS 2026.03.0, starting the AWS emulator requires an auth token. With Docker Compose, that means supplying LOCALSTACK_AUTH_TOKEN.

Fair enough. What I didn't want was another secret pasted into a Compose file, copied between scripts, or remembered as an undocumented export command.

I wanted the repository to explain what the project needs, without containing the actual credential.

I ran into this while building Envilder. The solution turned out to be slightly recursive. We'll get to that.

The pattern

The part I want in Git is the answer to this question:

Where does this project get LOCALSTACK_AUTH_TOKEN?

Envilder reads that answer from a JSON mapping and retrieves the value from AWS SSM Parameter Store or Azure Key Vault. It can then either start a command with the secret in its environment (exec mode) or generate a local .env file (pull mode).

Same tool, same mapping, two ways to deliver the value.

Envilder resolves secrets from AWS SSM or Azure Key Vault and supplies them to Docker Compose through exec or pull mode

For starting LocalStack, I now prefer exec mode. No need to create a file just so another process can read it.

Choose where the token lives

Pick one of these configurations for your envilder.json. You don't need both clouds.

With AWS SSM Parameter Store:

{
	"$config": {
		"provider": "aws",
		"profile": "default"
	},
	"LOCALSTACK_AUTH_TOKEN": "/envilder/localstack/auth-token"
}

Enter fullscreen mode Exit fullscreen mode

Store your token at that parameter path as a SecureString, and give your AWS identity permission to read it.

With Azure Key Vault:

{
	"$config": {
		"provider": "azure",
		"vaultUrl": "https://my-development-vault.vault.azure.net"
	},
	"LOCALSTACK_AUTH_TOKEN": "localstack-auth-token"
}

Enter fullscreen mode Exit fullscreen mode

Store the token as a secret named localstack-auth-token in that vault. For local development, Envilder can use your az login session, provided your identity has permission to read the secret.

In both cases, the mapping contains a reference, not the credential. That's what goes into Git. You'll also need Docker Compose and Node.js 22.12+; the setup guide covers authentication.

One important detail: Developer Auth Tokens are personal. Each developer must resolve their own token, for example through separate accounts or vaults, or a per-user mapping. CI needs a separate CI Auth Token. A shared setup must not become a shared personal credential.

Let Compose do the rest

Here's a minimal compose.yaml for LocalStack for AWS:

services:localstack:
    image: localstack/localstack:stable
    ports:
      - "127.0.0.1:4566:4566"
    environment:
      LOCALSTACK_AUTH_TOKEN: "${LOCALSTACK_AUTH_TOKEN:?Start Compose through envilder exec}"

Enter fullscreen mode Exit fullscreen mode

Then run:

npx envilder exec -- docker compose up -d

Enter fullscreen mode Exit fullscreen mode

That command works with either mapping above.

Envilder resolves the token and starts Docker Compose with it in the process environment. Compose interpolates the variable and passes it to LocalStack.

No manual export. No .env generated by Envilder. And if the secret is missing, empty, or unreadable, exec mode refuses to start Compose rather than hoping for the best.

This is a minimal startup example. Add service-specific ports or Docker socket access only when your workload needs them, and pin a tested image version for reproducible CI runs.

And LocalStack for Azure?

For the same basic setup, replace the image with:

image: localstack/localstack-azure:latest

Enter fullscreen mode Exit fullscreen mode

LocalStack for Azure also uses LOCALSTACK_AUTH_TOKEN and port 4566 by default. The same token can activate either emulator when your account has the corresponding access. At the time of this update, Azure is in private preview and requires access to be enabled.

Where you store the token and which emulator you run are independent choices. Azure Key Vault can supply the token for LocalStack for AWS. AWS SSM can supply it for LocalStack for Azure.

Just use a real cloud secret store for this bootstrap credential. Asking an emulated Key Vault for the token needed to start that same emulator is a chicken-and-egg problem.

Still need a .env file?

The original approach remains available:

npx envilder --map=envilder.json --envfile=.env
docker compose up -d

Enter fullscreen mode Exit fullscreen mode

Add .env to .gitignore. Use this when a tool genuinely needs a file; otherwise, exec mode saves a step and avoids another plaintext copy.

When switching, remove any old secret-bearing .env you no longer need. Exec mode doesn't delete it, and Compose can still load it independently.

What this does not protect

No generated .env does not mean the token never touches disk.

Docker retains container environment variables in its configuration metadata. Someone with sufficient Docker access can read them through docker inspect. Likewise, docker compose config can print resolved values, so don't paste its output into a public issue without checking it.

The command you start, and its child processes, can also read the injected secrets. Exec mode is not a sandbox, and it resolves values once at startup rather than continuously refreshing them.

The improvement is specific: one fewer plaintext secret file in the working directory. Useful, but not magic.

The slightly meta part

I originally ran into this while working on Envilder's integration tests.

Envilder uses LocalStack. LocalStack needs a token. So I used Envilder to resolve the token needed to start the LocalStack environment used to test Envilder.

At that point, the meme was unavoidable.

Envilder uses Envilder to resolve the LocalStack token needed to test Envilder

Originally, that meant generating a .env file. Exec mode now offers another way to deliver the same secret without changing the mapping.

The tool became its own first customer, which is always a useful kind of feedback.

Why not lstk, direnv, 1Password, or chamber?

For running LocalStack by itself, I'd start with lstk. It handles login and normally stores the token in the system keyring. You don't need to add a cloud secret store just to try LocalStack.

There are good options for larger workflows too. direnv can run your secret-retrieval commands when you enter a directory. 1Password op run injects secrets from 1Password. chamber already handles AWS SSM and command execution.

Envilder isn't claiming to have invented environment injection.

What I'm building around is the explicit variable name -> secret path mapping: one JSON contract format shared by the CLI, GitHub Action, and .NET, Python, and Node.js SDKs, using AWS SSM or Azure Key Vault.

If a small script already solves your problem, keep it. The contract becomes useful when you would otherwise maintain the same mapping in several different places.

Takeaway

The original goal was to keep the token out of Git. Exec mode goes a little further: I no longer need to generate a local .env just to hand that token to Docker Compose.

The secret stays managed in my cloud provider. The repository describes where to find it. LocalStack receives the variable it already expects.

That's why I'm building Envilder: not to create another place to store secrets, but to make resolving them explicit and repeatable.

How are you handling this in your own projects? I'd be interested in hearing where your setup differs, especially where this approach wouldn't fit.

Comments(0)

Join the discussion by logging into your account.

No comments yet. Be the first to comment!

Marçal Albert Castellví
Marçal Albert Castellví

Principal Software Engineer

I've written code you people wouldn't believe. Debugged bugs that vanished the moment I enabled logging. Chased race conditions through the cloud. All those hours... lost in time, like tears in the rain. A Software Engineer, cloud enthusiast, and creator of Envilder. Still learning.

Subscribe to Marçal Albert Castellví's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.