John Wang
John Wang

Reputation: 4692

pip does not honor PIP_INDEX_URL with sudo

According to the doc I can direct pip to use my private pypi repository instead of the official one:

For pip this can be done by setting the environment variable PIP_INDEX_URL in your .bashrc/.profile/.zshrc:
export PIP_INDEX_URL=http://localhost:8080/simple/

So I added my private repository(e.g., http://pypi.mycompany.com/simple ) into /etc/profile on my Debian server. However pip still raises error:

john@server:~$ sudo pip install ipython
Downloading ...
    Cannot fetch index base URL https://pypi.python.org/simple/
    ...

Looks like pip ignores the environment variable PIP_INDEX_URL I've set. Why?

Update:

Following @Ivo's direction, I found my Python didn't see the variable at all:

john@server:~$ sudo python -c "import os; print(os.getenv('PIP_INDEX_URL'))"
None

Upvotes: 10

Views: 20674

Answers (2)

spazm
spazm

Reputation: 4809

Sudo sanitizes the secure environment by reseting most environment variables. By default it resets all variables outside of those in its preserve list. Sudo has three classes of environment variables: check, reset, preserve. By default it resets all variables outside of those listed in the preserve list.

Available options:

  1. As noted, you can globally pass all environment variables with -E also spelled --preserve-env.

    This represents a security issue. Passing environment variables may taint or otherwise affect execution within a (secure) environment. Consider the issues of $LD_PRELOAD or $IFS.

  2. -E and --preserve-env support an argument list of variables to preserve, in addition to the default variables:

    sudo --preserve-env=PIP_INDEX_URL pip install python
    
  3. You can explicitly pass env variables to the ssh command via the shell:

    sudo -e PIP_INDEX_URL=${PIP_INDEX_URL} pip install ipython
    

    ${PIP_INDEX_URL} is expanded by the shell before passing to sudo.

    This is a handy shell trick and works with ssh and anything else that passing args and environment directly to a subprocess.

  4. Modify your sudo configuration in sudoers to extend the list of allowed environment variables to pass to the child. See the env_keep option.

    DEFAULT env_keep+=PIP_INDEX_URL
    

    I would argue that this option is the cleanest, especially on a system with multiple users that are expected to use the same pip options.

    The last line of your sudoers file may contain an #includedir directive. If so, put your modifications in a file in that directory. e.g. /etc/sudoers.d/pip_environment and add keep options for PIP_INDEX_URL, PIP_TRUSTED_HOST, PIP_EXTRA_INDEX_URL and any other options needed in your configurations.

references:

  • sudoers configuration: man 5 sudoers

  • sudo options: man 8 sudo

  • Secure Programming for Linux and Unix HOWTO

  • pip environment variables are named in a format of PIP_ followed by an upper case spelling of the full command line flag. see: the pip config file documentation

  • You can view the check, reset, and reserve lists in the output of running sudo -V as root:

    % sudo sudo -V
    
    # ...
    Environment variables to check for sanity:
            TZ
            TERM
    # ...
    Environment variables to remove:
            *=()*
    # ...
    Environment variables to preserve:
            MAIL
            HOME
    

Upvotes: 4

John Wang
John Wang

Reputation: 4692

Found it. It's simple: sudo by default will not use the environment variables for security reasons. To tell sudo preserve env variables, -E option can be used, e.g.

sudo -E pip install ipython

Upvotes: 11

Related Questions