Do you trust whatever comes out of pip install
?
Do you trust nightly builds?
A single hijacked package in your dependencies can leak all your secrets (private keys, tokens, github access, emails, ...).
No? Good! Maybe this is a solution for you, then.
This project aims to provide firejail profiles for python development environments. This means that you will have an isolated shell with only selected parts, some read-only, some not at all visible, of your host filesystem.
This is by no means perfect but at least it is better than being at the mercy of pypi.
- firejail
- python-virtualenv
- bash or zsh
- Linux based OS (WSL2 might work)
This will give you the ability to create python sandboxes from a template and nothing more. No integration into your shell. This is how to do it:
$ sudo apt install firejail python-virtualenv
$ git clone git@github.com:githubnemo/python-sandbox.git
<add $PWD/python-sandbox to your PATH in .bashrc / .zshrc / ...>
This setup assumes that your python envs will live in ~/envs/<sandbox-name>
.
There are examples for ZSH and bash on how to integrate these sandboxes better into your environment. These features are showcased in the Neat Things section. I'm not confident enough in these features yet to build a script that you can simply source, sorry.
The default template will never cover all your custom setup. To allow for additional tools outside of the basic template, you can add your own access configuration with a local override that works for every template.
You can place arbitrary rules in ~/.config/firejail/python-env-template.local
and they are included in the environment profile.
For example, if you have a specific tool, say fzf
, in a directory outside of
the sandbox and your .bashrc
depends on that path, you could add it there.
Example python-env-template.local
file:
whitelist ${HOME}/Code/fzf
read-only ${HOME}/Code/fzf
With the above content your sandbox is now able to access ~/Code/fzf
.
See man firejail-profile
for all possible directives.
New python project? New sandbox.
$ mkdir ~/code/mynewproject
$ create-python-sandbox mynewproject ~/code/mynewproject
# After profile creation we can jump into the sandbox
$ firejail --profile=python-env-mynewproject --tab bash
# We can now create a virtualenv there (or use poetry, conda, ...)
$ python -m venv ~/envs/mynewproject
$ . ~/envs/mynewproject/bin/activate
$ pip install [...]
It is best to make access to the sandbox as easy as possible. At best, never leave it (launch a tmux session inside the sandbox, work in there). Second best: create an alias to quickly jump into the sandbox. See section "Common entrypoint":
$ sbox mynewproject
I have a function definition for invoking sandboxed shells
sbox() {
# replace "bash" with any shell you like
firejail --profile=python-env-$1 --tab bash
}
so I can quickly jump into the sandbox using sbox myenv
.
To gauge if I'm in a sandbox or not the sandbox environment
provides an environment variable (JAILED_ENV=<env name>
) so it is
easy to react on that in the shell prompt.
Example from my .bashrc
:
jail=""
if [ -n "$JAILED_ENV" ]; then
jail="(J:${JAILED_ENV})"
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}${jail}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}${jail}\u@\h:\w\$ '
fi
To enter the sandbox as soon as you're working on a project, you can configure
your shell to watch for .python-sandbox
files with the sandbox's name in it.
There's an example for ZSH in examples/zsh.md
,
the gist is:
# Little helper to go upward the directory tree in search for a file.
# Makes sure to use the least amount of external tools for performance.
_upfind() {
if [[ "$2" -eq 0 ]]; then
return 1
fi
[[ -e "$1" ]] && echo "$1" || _upfind "../$1" "$(($2 - 1))"
}
enable_sbox_if_needed() {
if [ -n "$JAILED_ENV" ]; then
return
fi
# Look into current and upward directories for sandbox file to
# enable sandbox upon finding it.
sandbox_file=$(_upfind ".python-sandbox" 5)
if [[ "$?" -eq 0 ]]; then
export PWD_BEFORE_JAIL="$PWD"
sbox "$(head -n1 "$sandbox_file")"
fi
}
add-zsh-hook chpwd enable_sbox_if_needed
enable_sbox_if_needed
Depending on your firejail version, the sandbox bashrc is sourced from
/etc/skel/.bashrc
. Newer versions of firejail support the keep-shell-rc
configuration option. Enable it in the template to avoid this problem.
Note the --tab
option of firejail. Firejail disables tab completion for
bash since there were vulnerabilities in the implementation before and you
have to supply --tab
to enable that feature explicitly.
- [ ] limit access to SSH agent from inside the sandbox
- [ ] limit access to specific read-only tokens (e.g. hf hub)
- [ ] make paths to tools like fzf, pyenv, conda, etc. configurable