Forum

Notifications
Clear all

What's the most paranoid, but still usable, secret setup you've seen?

2 Posts
2 Users
0 Reactions
4 Views
(@home_lab_builder_sam)
Eminent Member
Joined: 2 months ago
Posts: 29
Topic starter   [#1804]

Hey everyone. I've been down a real rabbit hole this month, trying to reconcile two things: my deep-seated paranoia about leaking API keys and model weights from my OpenClaw rig, and my desire for a setup that doesn't require a secret decoder ring and three handshakes just to restart an agent. I think I've landed on a pattern that's *almost* paranoia-compatible, but I wanted to throw it to the group to see where the weak points are.

My base assumption is that the `docker-compose.yml` file itself is going to live in a git repo. So anything committed there is out. That rules out hardcoding, and honestly, I don't even like putting placeholder variable names in there because it creates a map of what to look for. My current approach leans heavily on Docker's build-time secrets and runtime config objects, combined with a strict "no secrets in the orchestration file" rule.

Here's the core idea: Secrets are injected only at **container creation**, never stored in the image or the compose file. For a local LLM agent that needs an `OPENAI_API_KEY` and a `GROQ_API_KEY`, I do this in two layers.

1. **Build-Time for "fixed" secrets:** If an agent needs a key baked into a config file (think a `config.yaml` for the agent framework itself), I use Docker build secrets. The `docker-compose.yml` doesn't contain the secret, it just points to a file that lives *outside* the repo, on the host.

```yaml
# docker-compose.yml snippet
services:
my_agent:
build:
context: ./agent
secrets:
- openai_key
- groq_key
# ... other config

secrets:
openai_key:
file: /mnt/secure_drive/docker_secrets/openai_key.txt
groq_key:
file: /mnt/secure_drive/docker_secrets/groq_key.txt
```

Then, in the Dockerfile, I `COPY --from` the secret to a location, and have my entrypoint script potentially move it or source it. The secret never ends up in the final image layers if you use `--mount=type=secret` correctly.

2. **Runtime for dynamic secrets:** This is where I got more experimental. For environment variables that the agent picks up at runtime, I've stopped using the `environment:` block in compose entirely. Instead, I create a Docker config object from a local file that contains *only* the key-value pairs. This file is also outside the repo.

```bash
# Create a config from a file (done once, or scripted)
docker config create agent_secrets_env /mnt/secure_drive/docker_secrets/agent_env.txt
```

Then, in the compose file:

```yaml
services:
my_agent:
# ... build or image
configs:
- source: agent_secrets_env
target: /run/secrets/agent_runtime_env
entrypoint: ["/bin/sh", "-c", "set -a && . /run/secrets/agent_runtime_env && set +a && exec /path/to/agent"]
```

This sources the key-value file into the container's shell environment right before the agent starts. The config object is stored encrypted by Docker (swarm mode), and on disk it's not in plaintext in the compose project directory.

The "paranoid" part is that the `docker-compose.yml` file is now completely devoid of any secret *names or values*. It only references external secret and config objects. The trade-off is usability: restarting the stack requires those external files to exist on that specific host. It's not portable without extra steps.

Is this overkill? For a homelab, probably. But I've been playing with more agent frameworks that call out to external APIs, and the idea of a prompt injection exfiltrating my `GROQ_API_KEY` because it was sitting in an env var scares me a bit less if that env var is mounted as a file that's not world-readable. The real question I have for you all: is the config-object-as-env-file pattern actually safer than Docker secrets or a plain `.env` file excluded from git? I'm still not sure if I'm just adding complexity theater.

What's your most paranoid-but-usable secret setup? Have you gone full Vault with dynamic secrets for per-invocation keys, or is there a simpler host-volume-with-`ro`-mount pattern that's good enough?

- Sam


Still learning, still breaking things.


   
Quote
(@homelab_network_al)
Eminent Member
Joined: 2 months ago
Posts: 17
 

That's a solid starting point, and I'm with you on keeping secrets out of the compose file. The build-time secret for a baked config is clever, but it locks that secret to that specific image build. What happens when you need to rotate the key? You're rebuilding the image, which can be a hassle.

For runtime, I've moved almost entirely to using Docker secrets mounted as files, even for API keys. The container just reads from `/run/secrets/whatever`. It keeps everything out of env logs and process lists. You can manage those secret files with a dedicated vault container on a separate, isolated management network. That way, your app network never even sees the traffic fetching the secrets.

Have you considered the network path, though? If the agent itself gets popped, those runtime secrets are still in memory. That's where I start drawing my VLAN lines.


--Al


   
ReplyQuote