Claude for the security-conscious: run claude-code, the claude cli tool, in a rootless podman container.
First, download and install podman. Then install the script with curl. Set
REPO to match your fork (e.g. ?????/claude-podman):
REPO=evancarroll/claude-podman
curl --proto '=https' --tlsv1.2 -sSf \
"https://raw.githubusercontent.com/$REPO/refs/heads/main/bin/claude" |
sed "s|^REPO_NAME=.*|REPO_NAME=$REPO|" |
sudo tee /usr/local/bin/claude-podman > /dev/null
sudo chmod a+x /usr/local/bin/claude-podmanNow you can just run claude-podman.
This provides the following benefits:
- Claude only gets file access to
- Files in the present working directory
$HOME/.claude.json$HOME/.claude
- Claude can only execute the files that exist in the image.
This image runs in rootless podman, and even inside rootless podman it runs as a non-root user inside the container. Claude code is maximally locked down and can't even update itself!
Need to add packages to the container, or run an init script? no problem
--apk-packages foo,bar,baz # adds packages foo, bar, baz, with apk
--init-script ./foobar.sh # copies foobar.sh into the container and executes it as root
For example, let's say you're using kubernetes and you do want claude to be able to troubleshoot it.
claude-podman \
--apk-packages kubectl \
--podman-arg "-v $HOME/.kube/config:/home/claude/.kube/config"By default the container uses podman's rootless network and can't reach other
containers by name. Use --network NAME to join a dedicated, user-defined
podman network (it's created automatically if it doesn't exist). Any other
container on the same network is then reachable from inside by its container
name, thanks to podman's built-in DNS.
# Start the service Claude should reach, on a shared network
podman run -d --name myservice --network claude-net some/image
# Run Claude on the same network (creates claude-net if needed)
claude-podman --network claude-netInside the container, Claude can now reach the service at http://myservice:<port>.