VPN, Proxy, MITM環境で消耗している場合のbash/zsh設定

また、コロナ感染者が再び増えてきましたね。リモートワークはさらにデフォルトな働き方になりそうですね。

昨今ゼロトラストネットワークなどと言われていますが、VPN渋滞などという言葉もあるように、リモートワーク時にはVPNを利用し従来の社内システムを利用するなんて会社は多いかと思います。

参考:[ゼロトラストネットワークとは何者なのか](https://qiita.com/tsukasa1301/items/24dc9b6e51d6be1c21cf)

## 想定環境

![vpn-proxy-env.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132537/c4914c10-f899-3a83-fe7b-bc6babc3ef51.png)

- VPNを利用すると完全に社内ネットワークに繋がったことになり、そこから社外へのアクセスは社内のHTTPプロキシー経由になる(緑色経路）
- [プロキシ自動設定 (Proxy Auto-Configuration, PAC)ファイル](https://developer.mozilla.org/ja/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file)が提供されているのでWebブラウザーだけの利用はVPNを切っても困らない
- ソフトウェア開発者は apt, yum, pip, npm, gem などでパッケージ管理サイト等を利用するが、ブラウザーのPACファイルには対応しておらず（対応方法ありますか？） http_proxy系の環境変数を設定する必要がある（赤色経路）
- 社内に常設している開発PCなら常に環境変数を設定しておくことで困らないが、リモートワークで環境で社外からのVPN接続・出社して会社ネットワーク接続・VPN接続せず開発に集中（青色経路）となるとなかなか困る

## VPN, Proxy, MITM環境で消耗

ということで、ここらへんの環境に消耗してるいる開発者も多いと思います（少なくとも私は）。

環境変数の設定＆解除が必要で、家で集中して作業しようと思ったら会社のHTTPプロキシーを参照してたりして通信エラー

## bash/zsh設定の雛形

ここらへんを解決するためにbash/zshの設定をしてみました。

単純に

- 自社内のIPアドレスブロックを定義する正規表現の定義
    - 自宅と会社のアドレスブロックが同じだと困りますけどね192.168.0.0/24とか
    - ifconfig/ipコマンドから引いてるので細かい正規表現は不要ですね。例は XXX.YYY.0.0/16をチェック 
- Proxy関係を定義
- 今のIPアドレスが社内のものならProxyとMITMの証明書を環境変数に設定
    - MITM Proxyでなければ`MITM_CERT_FILE`のある行不要（後述）
- そうでなければProxyや証明書関連の環境変数を消去

なだけです。

```sh
# Intranet, Proxy, Private CA config
IP_REGEX="^XXX\.YYY\..*\..*$"                 # 自社内ネットワークのネットワークを正規表現で
PROXY=http://proxy.example.co.jp:8080         # 自社のプロキシー設定
NO_PROXY=127.0.0.1,localhost,.example.co.jp
MITM_CERT_FILE=~/.cert/my-ca-bundle.crt       # MITM proxyで証明書を中間で書き換えられる場合

# Check Intranet
if [ -f /sbin/ifconfig ]; then
  # macOS, FreeBSD, etc
  ipcmd="/sbin/ifconfig"
  ipcmd_opt="-a"
elif [ -f /sbin/ip ]; then
  # Linux, etc
  ipcmd="/sbin/ip"
  ipcmd_opt="address"
fi
ipv4addr=$($ipcmd $ipcmd_opt | grep 'inet ' | sed 's/.*inet[^6][^0-9]*\([0-9.]*\)[^0-9]*.*/\1/' | grep -v '^127\.' | gre

for i in $ipv4addr; do
  if [[ $i =~ $IP_REGEX ]]; then
    intranet=1
  fi
done

# Proxy & CA certificate
if [ $intranet ]; then
  echo Intranet mode - Proxy and Private CA
  export http_proxy=$PROXY
  export https_proxy=$PROXY
  export no_proxy=$NO_PROXY
  export HTTP_PROXY=$PROXY
  export HTTPS_PROXY=$PROXY
  export NO_PROXY=$NO_PROXY
  export SSL_CERT_FILE=$MITM_CERT_FILE
  export PIP_CERT=$MITM_CERT_FILE
  export NODE_EXTRA_CA_CERTS=$MITM_CERT_FILE
else
  echo Intertnet mode
  unset http_proxy
  unset https_proxy
  unset no_proxy
  unset HTTP_PROXY
  unset HTTPS_PROXY
  unset NO_PROXY
  unset SSL_CERT_FILE
  unset PIP_CERT
  unset NODE_EXTRA_CA_CERTS
fi
```

```
# 上記を ~/.proxyrc等に保存して、
# .bash_profile/.zshrc等に次を追加

source ~/.proxyrc
```

### MITM(Man in the middle)プロキシー対応

私の会社はMITM(Man in the middle)タイプのプロキシーでEnd-to-EndでSSL/TLSされず、一旦SSL/TLSはデコードされ通信内容を検閲されてからプロキシーが再度HTTPSクライアントとしてターゲットとなるサイトにアクセスし、ユーザー側は自社証明書に差し替えられた形でアクセスする仕組みです。

私の会社でどんな製品を利用しているかは知りませんがちょっと検索すると、
[GUARDIANWALL Webセキュリティ](https://cweb.canon.jp/it-sec/solution/guardianwall_web/)
この手もモノがそうだと思われます。

ここらへんの仕組みが導入されていない単純なHTTPプロキシーの場合は、`MITM_CERT_FILE`のある行は不要ですね。
汎用的な、`SSL_CERT_FILE`とpip, npmが参照する`PIP_CERT`,`NODE_EXTRA_CA_CERTS`を定義していますが、他の処理系で参照する環境変数ってあったら教えて下さい（とりあえずpip, npm中心なので困ってないですが）。

## その他

```sh
echo Intranet mode - Proxy and Private CA
echo Intertnet mode
```
などとテスト的に表示しちゃってますが、

```sh
export NETWORK_MODE=intranet
export NETWORK_MODE=internet
```

などとしてPowerline系などみたいにプロンプトに状況をだすと嬉しいかも。