# k8s-sidecar mounts configmaps and secrets as files

> k8s-sidecar is a container that runs next to your application in a pod, watches configmaps and secrets matching a label, and writes their contents to a shared volume so the files stay current at runtime. It suits teams that want mounted configuration without a restart on every change, and it does not rotate credentials for clients that read env vars.

**kiwigrid/k8s-sidecar** — This is a docker container intended to run inside a kubernetes cluster to collect config maps with a specified label and store the included files in a local folder.

- Repository: https://github.com/kiwigrid/k8s-sidecar
- Stars: 768 · Forks: 216
- Language: Python
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/kiwigrid-k8s-sidecar

## A watcher that writes files instead of restarting pods

k8s-sidecar is a container intended to run inside a Kubernetes cluster to collect configmaps with a specified label and store the included files in a local folder. The stated purpose is narrow and practical. It is the project's simple way to provide files from configmaps or secrets to a service and keep them updated during runtime. The main target is running as a sidecar container to supply an application with information from the cluster. That design decision is what separates it from the built-in mechanism. Kubernetes can mount a configmap as a volume, and the kubelet refreshes the mounted files, but a process that read its configuration once at startup does not notice. The sidecar sits next to the application, watches the API, and writes the same files, which means an application that rereads a file on change or on request can pick up new values without a pod restart. The main target audience is a team whose service expects a file on disk and whose operators do not want to redeploy for a configuration change.

## Label filtering decides what lands on disk

What gets collected is decided by labels, and the configuration is done through environment variables and command line flags. LABEL is the label used for filtering and it is required. LABEL_VALUE is the value to filter resources on, and the documentation notes that you leave it unset to filter by any value. FOLDER is the folder where the files should be placed and is also required. The pairing of a label key and an optional value is a deliberate design, since it lets one sidecar collect the resources of one application without pulling in everything else in the namespace, and the optional value lets a single sidecar collect across applications that share a label key. The default target directory is set through the FOLDER_ANNOTATION environment variable, which names a configmap annotation, and if that annotation is not present it falls back to k8s-sidecar-target-directory. A configmap can therefore redirect where its files land:

```yaml
metadata:
  annotations:
    k8s-sidecar-target-directory: "/path/to/target/directory"
```

The sidecar attempts to create directories defined by configmaps if they are not present, so a nested path in the annotation does not need to exist beforehand.

## Updates, deletions and unique filenames

The feature list says the sidecar extracts files from configmaps and secrets, filters based on label, updates and deletes on change of the configmap or secret, and enforces unique filenames. That last point deserves attention because it is the kind of detail that causes bugs. A configmap has a namespace of keys, and multiple configmaps in the same namespace can use the same key names, so writing them into one directory without a uniqueness rule means one resource silently overwrites another. Enforcing unique filenames makes the collision visible instead. The update and delete behaviour matters for a different reason. A sidecar that only ever wrote files on first sight would leave a stale file behind when a key was removed from a configmap, and the application would keep reading a value the operator believed they had deleted. Handling deletion means the directory reflects the current state of the cluster rather than the union of everything ever seen. Between them, these two behaviours are what make the mounted directory safe to treat as a live view of cluster state.

## Binary data and the .url convention

Secrets and configmaps are not only text, and the sidecar handles two binary cases. Support for binaryData is listed for both Secret and ConfigMap kinds, and the binary content is base64 decoded before the file is generated on disk. Second, values can be base64 encoded URLs that download binary data, for example executables, and the rule is that the key in the ConfigMap or Secret must end with .url. So a key ending in .url is treated as a pointer rather than as content, and the file is fetched from that location. The practical effect is that a large binary, a certificate, or an executable can be delivered through the same configmap mechanism and land on disk in its binary form, without a separate init container or an object store mount. The .url suffix is a convention rather than a separate resource type, so a key that happens to end in that way is interpreted as a download instruction. That is worth checking for if you have keys with that suffix in an existing configmap, since the behaviour is driven by the name.

## The HTTP request after a change

The sidecar can also send an HTTP request to a specified URL after a configmap change, and this is what turns a file writer into something an application can react to. Two configuration mechanisms exist for it. The REQ_URL environment variable names the URL to call, and the change notification is what tells an application to reload rather than continuing to serve a stale configuration from memory. Credentials for that request, and for the .url triggered downloads, can be supplied in files rather than in environment variables, which is the safer option in a cluster. Two command line flags exist for this, --req-username-file and --req-password-file, and each takes the path to a file containing the username or password. The documentation is precise about precedence. The flags override REQ_USERNAME and REQ_PASSWORD, and they in turn take precedence over the REQ_USERNAME_FILE and REQ_PASSWORD_FILE environment variables. The deployment snippet shows the shape:

```yaml
containers:
  - name: k8s-sidecar
    image: ghcr.io/kiwigrid/k8s-sidecar:latest
    args:
      - --req-username-file=/path/to/username
      - --req-password-file=/path/to/password
```

The point of the file based credentials is that a secret can be mounted into the pod and read at request time, so the sidecar never carries the credential in its environment, which is visible in a pod spec and in any log that dumps the environment.

## Multi-arch images, a non-root user and a Python base

The images are published to three registries, docker.io, quay.io and ghcr.io, under kiwigrid/k8s-sidecar, and the documentation states that all are identical multi-arch images built for amd64, arm64, arm/v7, ppc64le, riscv64 and s390x. The architecture history section explains a small piece of engineering history. With v2.x the project dropped ppc64le and s390x support, ppc64le was restored first, and s390x stayed unsupported because the Rust toolchain available on Alpine for s390x was too old to build the cryptography dependency. Since the image no longer needs any Rust or C++ dependency, s390x is supported again. The Dockerfile reflects the current state, built on a pinned python alpine base with libcrypto and libssl added, a builder stage that creates a virtual environment and installs the package, and a final stage that copies only the virtual environment. Two details in that file are deliberate. The build installs a C toolchain because a dependency such as PyYAML has no wheel for the target platform, and the runtime container runs as the numeric nobody user 65534 to satisfy MustRunAsNonRoot pod security policies, with a comment pointing at the Kubernetes documentation. The entrypoint is python -u -m sidecar, and the image declares its licence as MIT through an OCI label.

## What the sidecar does not do

The limits here are worth stating because the mental model of a sidecar is often that it replaces more than it does. The sidecar writes files and sends a request. It does not inject values into the environment of the other container in the pod, so an application that reads its configuration from environment variables will not see a changed secret until the pod is restarted, at which point the kubelet sets the env from the then-current secret. That is a different and well understood model, and for some applications it is the right one, but it is not what this sidecar provides. The sidecar also does not decrypt anything for the application, it writes what the API hands it and the application reads it with the same permissions, so the security of the file depends on the pod's filesystem permissions and on the service account's access to those secrets in the first place. Finally, the sidecar needs API access. It watches configmaps and secrets, so its service account needs permission to list and watch them, and depending on the cluster setup you may have to grant more than the project assumes, which is why the usage section points at an example deployment and notes that you have to grant yourself admin rights first depending on your cluster.

## Conclusion

Adopt k8s-sidecar when your application reads configuration from files and you need those files to follow configmap or secret changes without restarting the pod, and when you can add a second container and a shared volume to the deployment. Do not adopt it expecting secret material to reach an application that reads environment variables, since the sidecar writes files and a restarted pod still needs its env refreshed. Verify first that the LABEL and LABEL_VALUE you set match the resources you want collected, that the application can tolerate its configuration files changing under it, and that the sidecar's service account has permission to list and watch the configmaps and secrets you intend to mount.

## FAQ

### What does k8s-sidecar do inside a pod?

It watches configmaps and secrets matching the label you configure, extracts their files and writes them to the folder you specify, updating and deleting files as the resources change. It can also send an HTTP request to a URL after a configmap change.

### How do I choose which configmaps the k8s-sidecar collects?

You set the LABEL environment variable to the label key to filter on, and optionally LABEL_VALUE to a specific value, leaving it unset to match any value. The FOLDER environment variable sets where the files are written, and FOLDER_ANNOTATION names a configmap annotation that can override the target directory per resource.

### Does k8s-sidecar update environment variables in the application container?

No. The sidecar writes files to a shared volume, so an application that reads configuration from environment variables will not see a changed secret until the pod restarts. Applications that reread files are the ones that benefit.

### How does k8s-sidecar handle binary data in secrets?

Support for binaryData is listed for both Secret and ConfigMap kinds, and binary content is base64 decoded before the file is written. Values can also be base64 encoded URLs that download binary data, where the key in the resource must end with .url.

## Sources

- [Issues](https://github.com/kiwigrid/k8s-sidecar/issues)
- [kiwigrid/k8s-sidecar on GitHub](https://github.com/kiwigrid/k8s-sidecar)
- [License: MIT](https://github.com/kiwigrid/k8s-sidecar/blob/master/LICENSE)
- [README](https://github.com/kiwigrid/k8s-sidecar/blob/master/README.md)
- [Releases](https://github.com/kiwigrid/k8s-sidecar/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kiwigrid-k8s-sidecar
