Skip to content

fridim/claude-container

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code in a Container

This project allows you to run Claude Code, configured to use models via Vertex, inside a Podman container with SELinux isolation. This means that only the files on your current project are available to Claude; it has no ability to either see other files or modify your system.

In addition, Claude is configured to use its own sandbox, which blocks the Bash tool from writing to files outside of your project, in exchange for not prompting you to approve each command. (Note that in my experience you must also be in "accept edits" mode to skip the prompts. Press Shift-Tab to cycle between modes.) It also has a network proxy that allows it to control any network access by the Bash tool.

Why Run Claude Code in a Container?

Many commentators have observed that running Claude Code with --dangerously-skip-permissions is a qualitatively different experience to running without. When you don't have to constantly approve each command to make progress, you can set Claude to work on a problem and go do something else. (Often the task could be something like fixing a broken unit test, which requires many experiments but not necessarily large-scale code changes.)

Unfortunately, as the name suggests, this is dangerous. There are many ways to give the LLM access to untrusted input (e.g. random review comments on a public repository), and it will be only too happy to follow any instructions therein. Meanwhile, it has the ability to write arbitary code and run it, with full access to the environment in which it is running. And, in fact, this is largely true even when you don't skip permissions: if you have given Claude permission to run your tests, and it is also in a mode where it can write code, then it can run arbitrary code in your environment, possibly at the instruction of an untrusted attacker.

Claude Code now has its own sandbox mode, but unfortunately it is not very helpful for this problem. It is focused on preventing network egress to avoid exfiltration of data, and as such it only prevents modifying files outside of the project (to avoid circumventing the network proxy), not reading them. Thus it can prevent the LLM running rm -rf ~, but not reading your SSH private key and posting it on some site that you have previously given permission for (e.g. GitHub). Furthermore, if any command fails as a result of the sandboxing, the LLM can and will simply retry it outside of the sandbox.

Running inside a container means that Claude Code can only see and modify data that is explicitly mounted into the container environment. Using Podman means the container can be run without root permissions, reducing the danger of privilege escalation, and using SELinux means that the isolation is enforced by mandatory access control. Within the container, you can allow Claude to install new packages without affecting your system.

If your personal risk calculus allows it, you may choose to run with --dangerously-skip-permissions inside the container. However, the sandbox mode is also enabled and this has the effect of reducing the permission requests that you generally would not want to see (allowing Claude to grind away in the background with sandboxed commands in accept-edits mode) without eliminating all permissions checks.

Installation

First, you must log in to GCloud to provide access to Vertex by doing:

gcloud auth application-default login
gcloud auth application-default set-quota-project ...

The easiest way to run Claude is to add an alias in your ~/.bashrc file:

alias claude="path/to/claude-container/claude"
alias yolo="path/to/claude-container/claude --dangerously-skip-permissions"

Then just run claude in your project directory (from a new shell). The first time will take a while as it builds the container image locally.

Updating

Auto-updating is disabled. To update, rebuild the container image by running build-claude.sh --rebuild. This restarts the image build with the latest version of Fedora and its packages as well as Claude Code.

GitHub integration

To allow Claude to use the gh CLI command, create a fine-grained personal access token and store it in the Podman Secret claude-github-token by copying it to the clipboard and doing:

podman secret create --replace claude-github-token <(wl-paste)

Example permissions:

To pass through all of your GitHub permissions (not recommended!), you can do:

gh auth token | podman secret create --replace claude-github-token

Google Workspace integration

To allow Claude to query your Gmail, Calendar, Drive, and Tasks (read-only), install the Google Workspace CLI on your host and set up credentials:

npm install -g @googleworkspace/cli
gws auth setup
gws auth login

During gws auth login, select only read-only scopes for each service: gmail.readonly, calendar.readonly, drive.readonly, tasks.readonly.

The container mounts ~/.config/gws/ read-only and sets GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND=file so gws can decrypt credentials using the file-based encryption key.

To test inside the container:

gws gmail users getProfile --params '{"userId": "me"}'
gws calendar events list --params '{"calendarId": "primary", "singleEvents": true, "orderBy": "startTime"}'

Jira integration

To allow Claude to manage Jira issues, first set up jira-cli on your host:

go install github.com/ankitpokhrel/jira-cli/cmd/jira@latest
export JIRA_API_TOKEN=YOUR_TOKEN    # from https://id.atlassian.com/manage-profile/security/api-tokens
jira init

jira init is interactive — it queries your Jira instance for issue types, boards, and custom fields, then writes a full config to ~/.config/.jira/.config.yml. This step cannot be done inside the container (the TUI board picker requires interactive input).

Once initialized, create the Podman secrets:

podman secret create --replace jira-api-token <(echo -n 'YOUR_TOKEN')
podman secret create --replace jira-config ~/.config/.jira/.config.yml

The container mounts the config at ~/.config/.jira/.config.yml and injects JIRA_API_TOKEN as an environment variable.

To test inside the container:

jira issue list -q 'assignee = currentUser() AND status not in (Closed)' --project YOURPROJECT

Drawbacks

It is currently not possible to run a nested Podman container inside the container. Unfortunately getting this working would require disabling SELinux labelling on the outer container.

Other capabilities may be disabled or packages missing simply because I haven't encountered a need for them yet. Pull requests are welcome.

About

Container isolation for Claude Code

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Shell 56.5%
  • Dockerfile 43.5%