私の目標は、pyenvとvirtualenvを介してロードされたPython Webサーバーモジュールを便利に実行することです。ポート番号によっては、sudo(1025未満のポート番号)を使用する必要があります。これまで〜/.zshrcに追加した内容は次のとおりです。
uploadserver() {
if [ $1 = 'end' ]; then
pyenv deactivate uploadserver
elif [ $1 -lt 1025 ]; then
pyenv activate uploadserver
sudo python -m uploadserver $1
elif [ $1 -gt 1024 ]; then
pyenv activate uploadserver
python -m uploadserver $1
else
print "uploadserver <port> <start/end>"
fi
}
sudoがなければ、私は好きなように動作します。しかし、sudoの場合、「sudo:python:コマンドが見つかりません」というメッセージで失敗します。どのように動作させることができますか?コマンドを手動で実行しても失敗するため、一般的なスクリプトの問題ではないようです。
parrot@parrot ~$ uploadserver 80
sudo: python: command not found
(uploadserver) parrot@parrot ~$ uploadserver end
parrot@parrot ~$
仮想環境でPythonへのフルパスを追加してもsudo呼び出しは失敗します。
(uploadserver) parrot@parrot ~$ sudo /home/parrot/.pyenv/shims/python
pyenv:python:コマンドが見つかりません
アップデート1 私は正しい解決策を見つけたと思います。スクリプトのsudo呼び出しを以下の呼び出しに置き換えると機能します。これが正しい解決策であるかどうかわかりません。
$ sudo -E env PATH=${PATH} python -m uploadserver $1
アップデート2 Gillesのアドバイス「だから邪悪なことをやめてください」を読んだ後、Python実行可能ファイルにCAP_NET_BIND_SERVICEオプションを設定することにしました。これは他のユーザーにとっても適切な解決策ではないかもしれませんが、私のユースケースではこれを処理しても大丈夫だと思います。動作するには、次のコマンドを実行する必要がありました。
parrot@parrot ~$ sudo setcap 'cap_net_bind_service=+ep' /home/parrot/.pyenv/versions/3.12.2/bin/python3.12
Pythonのpyenvは単なるラッパーなので、このファイルの機能設定はうまくいきません。
(uploadserver) parrot@parrot ~$ which python
/home/parrot/.pyenv/shims/python
(uploadserver) parrot@parrot ~$ getcap /home/parrot/.pyenv/shims/python
/home/parrot/.pyenv/shims/python cap_net_bind_service=ep
(uploadserver) parrot@parrot ~$ python -m uploadserver 80
...
PermissionError: [Errno 13] Permission denied
答え1
Sudoはほとんどの環境変数を削除します(またはその一部を「安全な」デフォルト値にリセットしますPATH
)。これは、特定の環境変数があるとコマンドが予期しない方法で動作し、呼び出し側が意図したよりも多くの操作を実行できるため、sudoルールが特定のコマンドへのアクセスを許可するときに必要です。たとえば、LD_PRELOAD
呼び出し元が昇格した権限で任意のコードを実行できるようにします。PYTHONPATH
コマンドがPythonプログラムの場合でも同様です。
sudoルールがターゲットユーザーとして任意のコマンドを実行できるようにする場合、このセキュリティ機能は必要ありません。ただし、sudoはこの機能をデフォルトで軽減しません。なぜなら、実行するのがより難しく、管理者が間違えやすいからです。
--preserve-env
sudoルールが許可している場合は、()を使用してほぼすべての環境変数を維持するように指示するか、-E
特定の変数を設定できます(sudo FOO=bar mycommand
機能的に同じsudo env FOO=bar mycommand
)。その後、実行できますsudo PATH="$PATH" python …
。
しかし、これはプログラムをrootとして起動するので、悪い考えです。特権ポートを開いた後、Pythonスクリプトを使用して権限を正しく削除します。また、コマンドラインや構成ファイルを解析するときなど、権限を放棄する前に予期しない操作を実行しないことにも依存します。
sudoの代わりに(1)ポートを開き、(2)(3)サーバープログラムを実行する前に権限を削除するように設計されたツールを使用してください。これができるtcpd
、システム化された同等物、承認バインディングまたは他の多くの可能性の一つ1 2。