3
1

【Linux】認証プロキシ+認証局のCA証明書の設定

Last updated at Posted at 2024-06-04

はじめに

とあるプロキシでは、HTTPS通信の中身を見たいという理由で、Basic認証proxyに加えて、proxyの認証局のCA証明書(SSLサーバ証明書)を加えないと,HTTP/HTTPS通信できないものが存在する。
HTTPS通信が行われるアプリ、ライブラリを使用する際は追加設定を行う必要があり、なんともブラウザファーストな厄介な代物である。
この仕組みでは、proxyがサイトのURLごとにCA証明書を作成し、pcとproxy間、proxyとサーバ間でSSL/TLS通信を確立する。

用語

  • プロキシユーザー名: プロキシサーバでBasic認証が必要な時のユーザー名
  • プロキシパスワード: プロキシサーバでBasic認証が必要な時のパスワード
  • CAfile: 使用するCA証明書ファイル
  • CApath: CA証明書が格納されたディレクトリ。CA証明書(もしくは証明書へのシンボリックリンク)は{hash}.0という名前になっている必要がある。 {hash}は証明書のsubjectをハッシュ化した値。openssl x509 -in <証明書ファイル> -hash -nooutで確認できる。
  • デフォルト値: アプリやライブラリで指定するCAfileやCApathの初期値。コンパイル時の設定やディストリビューションにより異なっている。

ハッシュの作成方法は以下のように行う。

$ openssl x509 -in IIJ1.pem -hash -noout
ec922ae0
$ sudo cp IIJ1.pem /etc/ssl/certs
$ cd /etc/ssl/certs
$ sudo ln -s IIJ1.pem $(openssl x509 -in IIJ1.pem -hash -noout).0

CA証明書のエンコードの種類

ASN.1というデータ構造で格納されており

  • DER形式: バイナリ形式でエンコード
  • PEM形式: BASE64方式でエンコード

詳しくはこちらhttps://qiita.com/TakahikoKawasaki/items/4c35ac38c52978805c69

curlとかLinuxで使用されているコマンドはほとんどがPEM形式のCA証明書で認識されている。DER形式のものはPEM形式に変更する必要がある。

DER形式からPEM形式に変更

openssl x509 -inform der -in IIJ1.der -outform pem -out IIJ1.pem

ディストリビューションのCA証明書の追加

ca-certificatesという大変ありがたい仕組みが用意されている。

Ubuntu22.04の場合

元がIIJ1.derというDER形式のファイルの場合

$ sudo apt install ca-certificates
$ ls
IIJ1.der
$ openssl x509 -inform der -in IIJ1.der -outform pem -out IIJ1.crt
$ sudo cp IIJ1.crt /usr/local/share/ca-certificates
$ sudo update-ca-certificates

※拡張子を.crtにすること

CAfile: /etc/ssl/certs/ca-certificates.crtとCApath: /etc/ssl/certsの中身が更新される。

CentOS Stream9の場合

元がIIJ1.derというDER形式のファイルの場合
rootディレクトリにファイルおいて実行

dnf install ca-certificates
openssl x509 -inform der -in IIJ1.der -outform pem -out IIJ1.pem
cp IIJ1.pem /usr/share/pki/ca-trust-source/anchors/
update-ca-trust

CAfile: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem が更新される。
(curlはCAfileとして/etc/pki/tls/certs/ca-bundle.crtを指定しているが、実態はそのシンボリックリンクになっている。)

ディストリビューション側で管理しているプログラムライブラリではシンボリックリンクを張ったりしてこのCA証明書を利用する設計になっているはずである。

※このようにありがたい仕組みあるので、間違ってもCA証明書の検証を無視する設定にしないこと。

方針

設定の優先度は
コマンドのオプション>プログラム毎の設定ファイル>環境変数>デフォルト値
となっていることが多い。

プロキシ認証関係

プロキシサーバのBasic認証はセキュリティ上の問題からコマンドのオプションはできるだけ使用せずにおこなう。プログラム毎の設定ファイル又は環境変数により設定する。

CA証明書関係

基本デフォルト値で行う。ディストリビューションのCA証明書の追加でカバーが可能ならそれで行う。

curlによる設定

CA証明書はPEM形式でないと読み込めない。

コマンドオプションによる設定

curl \
--proxy <protocol://host:port> \
--noproxy <no-proxy-list> \
--proxy-user <user:password> \
--cacert <file> \
--capath <dir> \

設定ファイル

~/.curlrc
proxy = "<protocol://host:port>"
noproxy = "<no-proxy-list>"
proxy-user = "<user:password>"
cacert = "<file>"
capath = "<dir>"

環境変数

  • http_proxy=protocol://[user:passwd@]host:port
  • HTTPS_PROXY=protocol://[user:passwd@]host:port
  • https_proxy=protocol://[user:passwd@]host:port
  • ALL_PROXY
  • NO_PROXY
  • no_proxy
  • CURL_CA_BUNDLE: CA証明書のパス

※http_prxoyは小文字のみ、それ以外は両方OK。両方ある場合は小文字優先。

CA証明書のデフォルト値

curl --verboseで調べることが可能。

Ubuntu22.04でのCA証明書のデフォルト値

ca-certificatesパッケージのデータを利用している。

  • CAfile: /etc/ssl/certs/ca-certificates.crt
  • CApath: /etc/ssl/certs

基本はca-certificatesの仕組みで組み込めばよい。

CentOS Stream 9でのCA証明書のデフォルト値

ca-certificatesパッケージのデータを利用している。

  • CAfile: /etc/pki/tls/certs/ca-bundle.crt
  • CApath: None

基本はca-certificatesの仕組みで組み込めばよい。

dnfの設定

http/https通信はcurlを利用。

設定ファイル

dnfは内部でcurlを用いているが、~/.curlrc読み込まない。

/etc/dnf/dnf.conf
[main]
proxy=<protocol://host:port>
proxy_username=<user>
proxy_password=<password>
sslcacert=<pemfile>

環境変数

curlの使っているのでcurlと同じ

dnfのデフォルト値

curlのデフォルト値となるが

  • CAfile: /etc/pki/tls/certs/ca-bundle.crt
  • CApath: None

基本はca-certificatesの仕組みで組みこんでsslcacertは使わない。

aptの設定

コマンドオプションによる設定

sudo apt \
-o Acquire::http::Proxy=<http_proxy> \
-o Acquire::https::Proxy=<https_proxy>

設定ファイル

/etc/apt/apt.confまたは/etc/apt/apt.conf.d以下で作成したXXXX.confファイルに記載

/etc/apt/apt.conf or /etc/apt/apt.conf.d/proxy.conf
Acquire {
    http {
        Proxy "http://[[user][:pass]@]host[:port]/";
    };
    https {
        proxy "http://[[user][:pass]@]host[:port]/";
    };
};

環境変数による設定

  • http_proxy=protocol://[user:passwd@]host:port
  • https_proxy=protocol://[user:passwd@]host:port

※sudo実行する場合はデォルトではこの環境変数は削除されて実行してしまうので、sudoの設定ファイルを変更してください。

/etc/sudoers.d/proxy
Defaults env_keep = "http_proxy https_proxy"

デフォルトのCA証明書について

CApath:/etc/ssl/certs
CAfile:/etc/ssl/certs/ca-certificates.crt

基本はca-certificatesの仕組みで組み込めばよい。

Python pipの設定

コマンドオプションによる設定

python -m pip --proxy <protocol://[user:passwd@]host:port> \
--cert <file.pem>

設定ファイル

コマンドでpip.confに書き込む

python -m pip config set global.proxy <protocol://[user:passwd@]host:port>
python -m pip config set global.cert <file.pem>

直接書き込む

~/.config/pip/pip.conf
[global]
proxy = <protocol://[user:passwd@]host:port>
cert = <file.pem>

ちなみにLinuxでの場所は
$HOME/.config/pip/pip.conf($XDG_CONFIG_HOME=$HOME/.config)
Windowsでの場所は%APPDATA%\pip\pip.ini

環境変数による設定

  • http_proxy=protocol://[user:passwd@]host:port
  • https_proxy=protocol://[user:passwd@]host:port
  • no_proxy
  • PIP_CERT="CAfile"
  • REQUESTS_CA_BUNDLE="CAfile"
  • CURL_CA_BUNDLE="CAfile"

デフォルトのCA証明書

デフォルトのCA証明書はpipの中にあるcertifiモジュールの中にある。下記の図のようにsite-packagesの直下ではなくpipディレクトリの_vendorディレクトリに組み込んでいる。

image.png

環境変数REQUESTS_CA_BUNDLEにca-certificatesで作成されたCAfileパスを設定するのが一番簡単である。

Python urllib.requestの設定

環境変数による設定

  • http_proxy=protocol://[user:passwd@]host:port
  • https_proxy=protocol://[user:passwd@]host:port

デフォルトのCA証明書

https通信ではsslライブラリ(Openssl)を利用している

import ssl
ssl.get_default_verify_paths()
# Ubuntu22.04 
# DefaultVerifyPaths(cafile=None, capath='/usr/lib/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/lib/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/lib/ssl/certs')
# CentOS Stream9
# DefaultVerifyPaths(cafile='/etc/pki/tls/cert.pem', capath='/etc/pki/tls/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/etc/pki/tls/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/etc/pki/tls/certs')

Ubuntu22.04の場合

/usr/lib/ssl/certs -> /etc/ssl/certsのシンボリックリンク
/usr/lib/ssl/cert.pem -> 存在しない

CentOS Steam9の場合

/etc/pki/tls/cert.pem -> /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pemのシンボリックリンク
/etc/pki/tls/certs/ -> 存在する。(ca-bundle.crt,ca-bundle.trust.crt)

いずれもディストリビューションが設定したopensslを利用しているのでca-certificatesの仕組みで組み込めばよい。

※Anacondaの場合はAnacondaのopensslの設定を利用しているので異なる。

Python requestsの設定

スクリプトで直接記入

import requests

proxies = {
  'http': 'protocol://[user:passwd@]host:port',
  'https': 'protocol://[user:passwd@]host:port',
}
verify = '/path/to/certfile'

requests.get('https://github.com', proxies=proxies, verify=verify)

環境変数

  • http_proxy=protocol://[user:passwd@]host:port
  • HTTP_PROXY=protocol://[user:passwd@]host:port
  • https_proxy=protocol://[user:passwd@]host:portt
  • HTTPS_PROXY=protocol://[user:passwd@]host:portt
  • no_proxy
  • NO_RROXY
  • REQUESTS_CA_BUNDLE="CAfile"
  • CURL_CA_BUNDLE="CAfile"

デフォルトのCA証明書

CAバンドルはcertifiライブラリを使用

import certifi
certifi.where()
# .venv/lib/python3.11/site-packages/certifi/cacert.pem

このcacert.pemにPEM形式のファイルを追記等を行うか、環境変数REQUESTS_CA_BUNDLEにca-certificatesで作成されたCAfileパスを設定するのが一番簡単である。

wgetの設定

コマンドオプションによる設定

wget --proxy-user=<user> \
--proxy-password=<password> \
--ca-certificate=<file> \
--ca-directory=<directory>

※ --http-proxyのようなオプションはないので、環境変数とかでカバーする。

設定ファイル

~/.wgetrc
http_proxy = <http_proxy>
https_proxy = <https_proxy>
no_proxy = <no_proxy>
proxy_user = <user>
proxy_password = <password>
ca_certificate = <file>
ca_directory = <directory>

環境変数

  • http_proxy=protocol://[user:passwd@]host:port
  • https_proxy=protocol://[user:passwd@]host:port
  • no_proxy

デフォルトのCA証明書

ディストリビューションのOpenSSLからで、
CAfile: "OpenSSL directory"配下のcert.pem
CApath: "OpenSSL directory"配下のcertsディレクトリ
となる。
"OpenSSL directory"はopenssl version -dで確認可能。

$ openssl version -d
# Ubuntu 22.04
# OPENSSLDIR: "/usr/lib/ssl"
# CentOS Stream 9
# OPENSSLDIR: "/etc/pki/tls"

Ubuntu22.04の場合

/usr/lib/ssl/certs -> /etc/ssl/certsのシンボリックリンク
/usr/lib/ssl/cert.pem -> 存在しない

CentOS Steam9の場合

/etc/pki/tls/cert.pem -> /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pemのシンボリックリンク
/etc/pki/tls/certs/ -> 存在する(ca-bundle.crt,ca-bundle.trust.crt)

基本的にca-certificatesの仕組みで組み込めばよい。

gitの設定

設定ファイル

git configコマンドで~/.gitconfigに書き込む

git config --global user.name "<user>"
git config --global user.email "<e-mail>"
git config --global http.proxy "<[protocol://][user[:password]@]proxyhost[:port]>"
git config --global http.sslCAInfo "<cafile>"
git config --global http.sslCAPath "<capath>"

※https.proxyという設定はない!

確認

git config --global --list

~/.gitconfig(ini形式に近いが同じではない。)

ちなみにWindowsではC:\Users\(ユーザー)\.gitconfig

~/.gitconfig
[user]
        name = <user>
        email = <e-mail>
[http]
        proxy = <[protocol://][user[:password]@]proxyhost[:port]>
        sslCAInfo = <cafile>
        sslCAPath = <capath>

環境変数

curlの環境変数に加えて

  • http_proxy=protocol://[user:passwd@]host:port
  • HTTPS_PROXY=protocol://[user:passwd@]host:port
  • https_proxy=protocol://[user:passwd@]host:port
  • ALL_PROXY
  • NO_PROXY
  • no_proxy
  • CURL_CA_BUNDLE: CA証明書のパス
  • GIT_SSL_CAINFO
  • GIT_SSL_CAPATH

デフォルトのCA証明書

curlと同じなので基本はca-certificatesの仕組みで組み込めばよい。

Condaの設定

設定ファイル

YAML形式で書かれる
Linux: ~/.condarc
Windows: C:\Users\(ユーザー)\Anaconda3\.condarc

conda configコマンドによる入力

conda config --set proxy_servers.http <protocol://[user:passwd@]host:port>
conda config --set proxy_servers.https <protocol://[user:passwd@]host:port>
conda config --set ssl_verify <file.pem>

設定を見る

conda config --show

直接入力

~/.condarc
proxy_servers:
  http: <protocol://[user:passwd@]host:port>
  https: <protocol://[user:passwd@]host:port>
ssl_verify: <file.pem>

環境変数

  • HTTP_PROXY=protocol://[user:passwd@]host:port
  • HTTPS_PROXY=protocol://[user:passwd@]host:port
  • REQUESTS_CA_BUNDLE
  • CURL_CA_BUNDLE

デフォルトのCA証明書

condaの中にあるopensslを利用していると思われる。

$ ~/miniconda3/bin/openssl version -d
# OPENSSLDIR: "~/miniconda3/ssl"

これを見ると~/miniconda3/ssl/cert.pem -> ~/miniconda3/ssl/cacert.pemがCA証明書となる。
環境変数REQUESTS_CA_BUNDLEにca-certificatesで作成されたCAfileパスを設定するのが一番簡単である。

まとめ

どのプログラムでも可能な一番簡単な設定は

  • ca-certificatesでCA証明書を取り込む
  • 環境変数ですべて設定する

設定例

~/.bash_profile or ~/.profile
export proxy_host=proxy.server
export proxy_port=8080
# どちらかを利用、ただしCIDR表記は認識しないプログラムが多いと思われる。ドメインはワイルドカードなしで記入する。
#no_use_proxy=192.168.0.0/16
no_use_proxy="$(echo 192.168.1.{1..255})"
no_use_proxy="${no_use_proxy// /,}"
no_use_proxy="$no_use_proxy",.example.com
export no_use_proxy

# Usage: set_proxy
function set_proxy() {
	read -p "Please enter your name: " __user
	read -sp "Please enter your password: " __pass ; echo
	
	# パーセントエンコーディング
	user=$(echo "$__user" | jq -Rr @uri)
	pass=$(echo "$__pass" | jq -Rr @uri)

	proxy="http://${user}:${pass}@${proxy_host}:${proxy_port}"
	http_proxy="$proxy"
	HTTP_PROXY="$proxy"
	https_proxy="$proxy"
	HTTPS_PROXY="$proxy"
	no_proxy=127.0.0.1,localhost,"$no_use_proxy"
	NO_PROXY="$no_proxy"
	
	osName=$(grep ^ID= /etc/os-release | sed s/ID=// | sed s/\"//g)
	if [[ "$osName" == "ubuntu" ]]; then
		CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
	fi
	if [[ "$osName" == "centos" ]]; then
		CA_BUNDLE=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
	fi
	REQUESTS_CA_BUNDLE="$CA_BUNDLE"
	CURL_CA_BUNDLE="$CA_BUNDLE"
	
	export http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
	export REQUESTS_CA_BUNDLE CURL_CA_BUNDLE
}

# Usage: unset_proxy
function unset_proxy() {
	unset http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
	unset REQUESTS_CA_BUNDLE CURL_CA_BUNDLE
}

※jqを使用しています。

セキュリティの観点からユーザー名とパスワードを入力するようにした。
使用するときにset_proxyと入力してユーザー名とパスワードを入力する。
削除する際はunset_proxyと入力する。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1