【保存版】開発者のための企業プロキシ突破チートシート（SSL復号型HTTPプロキシ対応） 

# 背景

企業のイントラ内の開発現場でプロキシの問題で外と通信する開発ツールがすぐに使用できないことがある。
その度にプロキシの設定を調べて対応していくのは、非常に大変な作業になる。
筆者は社内IT部門ではなく、製品の開発者として開発者泣かせのプロキシと戦ってきた。
今回はその経験から、プロキシを超えるためのノウハウと、実際の設定内容を各種ツール別にまとめておく。

## 概論

### プロキシの存在価値

企業内にプロキシがある５つの理由。

- クライアントが外に対して秘匿させるという、ユーザーを守る観点からのセキュリティ
- クライアントの通信を監視するというユーザーを疑う観点からのセキュリティ
- 特定のホストやポートをブロックするようなセキュリティポリシーの実施
- ラウンドロビン方式などによる、外部通信のロードバランシング	
- 通信量削減のためのページキャッシュとして	



### プロキシの種類

#### (難易度:★☆☆☆) 透過型HTTPプロキシ

プロキシは存在するが、ツールに指定する必要がないケース。
HTTP通信を経路の途中で勝手に曲げる。
ほとんどのツールはHTTP/HTTPSを使うので、問題なく動作するし、ユーザーは意識せず、ほとんどの人が気づかない。
ただし社内からHTTP以外の通信（IoTプロトコルのMQTTとか）を行う場合注意が必要。

#### (難易度:★★☆☆) 非透過型HTTPプロキシ

オーソドックスなHTTPプロキシ。各種ツールに設定が必要
認証を要求する場合が多く、Basic認証や　NTLM認証などがある。
いつも必要なわけではなく、IPレベルでセッションが一定時間記憶されるケースがほとんどだと思われる。
必要な設定先はツールによって異なり、OS、ランタイム（JVM等）、ツール自身の３通り考えられる。

#### (難易度:★★★☆) Socksプロキシ

Connection確立時のハンドシェイクに、HTTPではなく、Socksプロトコルを使用する。
TorやVPNではよく使われる方式。
透過型Socksプロキシなんてのもあるらしく、それなら各種ツールが設定無しで使えるだろう。
Socksプロキシについては、この記事では想定しないが、オプションで使用可能なツールはそれなりにあるようだ。

#### (難易度:★★★★) SSL復号型HTTPプロキシ

通常のHTTPプロキシの機能に加えて、SSL監視能力を付けたもの。
実際このような企業向けの製品は多数存在する。

SSL通信は当然、通信途中でペイロードの中身を見ることができない。
しかし、このタイプのプロキシはサーバー証明書を自分のものに書き換えて、クライアントに強制することで、プロキシはSSL通信の中を覗くことができる。		
さらにクライアント証明書まで書き換えられると、IoTプロトコルで使うようなSSLの証明書認証で端末の識別が不可能になったりもする。

安全のためとは言え、非常に厄介な存在であり、このSSL復号型HTTPプロキシについて、特に重点的に対策を解説する。





### SSL復号型HTTPプロキシの基本原則

各種ツールに対しての設定では以下のチェックポイントを確認。

- HTTPS通信を行う場合、基本的にプロキシはオレオレ証明書を強制するので、専用のCA証明書の設定がクライアントで必要である。

- 予めシステムにインストールされているCA証明書を参照できる場合がある。

- 証明書を設定できないツールの場合SSLの検証を無効化できる設定があればそれを有効にする（比較的簡単）。

- SSL無効化設定が利用できないツールの場合、通信先を強制的にHTTPサーバーにすることで対応できる場合がある。

- 以上で対応できない場合そのツールはソースコードを修正しない限りプロキシを超えることは不可能である。


### 実装レベルの原則

サーバー側での証明書認証などに接続するようなアプリケーションを実装する必要がある場合、開発サイドで注意すべきこと。

- SSLの場合ではサーバー証明書が改竄されるので、クライアント側に企業CA証明書の登録か検証無視が必要。

- SSLの場合ではクライアント証明書が改竄されるので、サーバー側に企業CA証明書の登録か検証無視が必要であり、クライアント証明書を用いた機器の識別はできない。

- もちろんここまで、見切れてもファイアウォール等のセキュリティポリシーなどで、特定のホストやポートがブロックされる可能性もあるので、IT管理者に要確認。

# チートシート

ここからは、SSL復号型HTTPプロキシを乗り越えてきた、ツール別の対策ノウハウを網羅する。

## クラウドCLI

### AWS CLI(Linux, Mac)
```shell
$ export HTTP_PROXY=http://<username>:<password>@<hostname>:<port>
```

```shell
$ export HTTPS_PROXY=http://<username>:<password>@<hostname>:<port>
```

### AWS CLI(Win)
```shell
> set HTTP_PROXY=http://<username>:<password>@<hostname>:<port>
```

```shell
> set HTTPS_PROXY=http://<username>:<password>@<hostname>:<port>
```

## パッケージ管理

### npm(Win/Linux)
```shell
$ npm -g config set proxy http://<username>:<password>@<hostname>:<port>
$ npm -g config set http-proxy http://<username>:<password>@<hostname>:<port>
$ npm -g config set https-proxy http://<username>:<password>@<hostname>:<port>
$ npm config set strict-ssl false
```

### yarn(Win/Linux)
```shell
$ yarn config set proxy http://<username>:<password>@<hostname>:<port>
$ yarn config set http-proxy http://<username>:<password>@<hostname>:<port>
$ yarn config set https-proxy http://<username>:<password>@<hostname>:<port>
$ yarn config set strict-ssl false
```

### yum(CentOS)
```shell
$ echo 'proxy=http://<username>:<password>@<hostname>:<port>' >> /etc/yum.conf
$ yum -y install --nogpgcheck zlib-devel
```

### Anaconda(Win/Linux)
```shell
$ conda config --set proxy_servers.http http://<hostname>:<port>
$ conda config --set proxy_servers.https http://<hostname>:<port>
$ conda config --set ssl_verify false
```

### pip(Win/Linux)
```shell
$ pip install --proxy=http://<username>:<password>@<hostname>:<port> --trusted-host --index-url=http://pypi.python.org/simple/ <library_name>
$ pip install --index-url=http://pypi.python.org/simple/ --trusted-host=pypi.python.org --proxy=<hostname>:<port> <library_name>
```

### apt-get(Ubuntu/Debian)
```shell
echo 'Acquire::http::proxy "http://<username>:<password>@<hostname>:<port>/";' >> /etc/apt/apt.conf.d/apt-get.conf
echo 'Acquire::http::proxy "http://<hostname>:<port>/";' >> /etc/apt/apt.conf.d/apt-get.conf
```

### Maven(Win/Linux)

```shell
#証明書無視
 $ mvn clean install -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true
```

OR

```shell
#証明書適用
> keytool -importcert -trustcacerts -alias OriginalCA -file ca_cert.cer -keypass changeit -keystore originalca.trustStore -storepass changeit
> mvn clean install -Djavax.net.ssl.trustStore="./originalca.trustStore" -Djavax.net.ssl.trustStorePassword=changeit
```

OR

* ~/.m2/settings.xml

```xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                          https://maven.apache.org/xsd/settings-1.0.0.xsd">

	<proxies>
		<proxy>
			<id>1</id>
			<active>true</active>
			<protocol>http</protocol>
			<username>username</username>
			<password>password</password>
			<host>hostname</host>
			<port>port</port>
	  </proxy>
		<proxy>
			<id>2</id>
			<active>true</active>
			<protocol>https</protocol>
			<username>username</username>
			<password>password</password>
			<host>hostname</host>
			<port>port</port>
	  </proxy>
</proxies>
<mirrors>
  <mirror>
      <id>central-no-ssl</id>
      <name>Central without ssl</name>
      <url>http://repo.maven.apache.org/maven2</url>
      <mirrorOf>central</mirrorOf>
  </mirror>
</mirrors>
</settings>
```

### Gradle(Win/Linux)
* USER_HOME/.gradle/gradle.properties

```gradle
systemProp.proxySet="true"
systemProp.http.keepAlive="true"
systemProp.http.proxyHost=hostname
systemProp.http.proxyPort=port
systemProp.http.proxyUser=username
systemProp.http.proxyPassword=password
systemProp.http.nonProxyHosts=local.net|some.host.com

systemProp.https.keepAlive="true"
systemProp.https.proxyHost=hostname
systemProp.https.proxyPort=port
systemProp.https.proxyUser=username
systemProp.https.proxyPassword=password
systemProp.https.nonProxyHosts=local.net|some.host.com
```

注：最近GradleのレポジトリはHTTP非サポートになり使えないらしい。

## 仮想化

### Docker Machine(Windows)
```shell
> set HTTP_PROXY="http://<username>:<password>@<hostname>:<port>"
> set HTTPS_PROXY=%HTTP_PROXY%
> set NO_PROXY="localhost,127.0.0.1,.sock,<virtualbox ipaddress>"		
```

### Docker (Linux in Windows)

* /var/lib/boot2docker/profile

```shell
$ export "http_proxy=http://<user name>:<password>@<hostname>:<port>"
$ export "https_proxy=http://<user name>:<password>@<hostname>:<port>"
$ export "no_proxy=localhost,127.0.0.1,.sock,<virtualbox ipaddress>"	
```

```shell
$ sudo cp /path/to/ca_cert.cer /home/docker
$ mv ca_cert.cer /var/lib/boot2docker/profile<hostname>.crt
```

### Docker Machine(Windows)
```shell
$ docker-machine create -d virtualbox \
    --engine-env HTTP_PROXY=http://<username>:<password>@<hostname>:<port> \
    --engine-env HTTPS_PROXY=http://<username>:<password>@<hostname>:<port> \
    default
```

Windows10の場合最新(2019/1/20現在)のboot2dockerイメージにバグがあるため、古いイメージを指定する必要がある。

```shell
> docker-machine create --virtualbox-boot2docker-url "https://github.com/boot2docker/boot2docker/releases/download/v18.06.1-ce/boot2docker.iso" -d virtualbox dockerVM
```

### Vagrant(Windows)
```shell
> set http_proxy=http://<username>:<password>@<hostname>:<port>
> set https_proxy=http://<username>:<password>@<hostname>:<port>
> vagrant plugin install vagrant-proxyconf
```

* Vagrantfile

```rb
Vagrant.configure(2) do |config|
    if Vagrant.has_plugin?("vagrant-proxyconf")
        config.proxy.http     = "http://<username>:<password>@<hostname>:<port>"
        config.proxy.https    = "http://<username>:<password>@<hostname>:<port>"
        config.proxy.no_proxy = "localhost,127.0.0.1"
    end
    config.vm.box = "bento/ubuntu-16.04"
    config.vm.box_download_insecure = true
end
```

> Windows10の場合、以下のEXEを管理者権限で起動させてから実行"vagrant up"を実行

> https://www.virtualbox.org/raw-attachment/ticket/14040/VBox-Win10-fix-14040.exe


## バージョン管理

### Git(Win/Linux)
```shell
$ git config --global http.proxy http://<username>:<password>@<hostname>:<port>
$ git config --global https.proxy http://<username>:<password>@<hostname>:<port>
$ git config --global http.sslVerify false
```

### Subversion(Win/Linux)
* ~/.subversion/servers

```toml
[global]
http-proxy-host = <hostname>
http-proxy-port = <port>
```

## その他

### Java(Win/Linux)
```shell
#Java系ツールでJVMに証明書設定することでSSL対応できることもある。
#コマンドプロンプト(Administrator)
#パスは自分用に要修正
> keytool -importcert -trustcacerts -alias OriginalCA -file ca_cert.cer -keypass changeit -keystore  "C:\Program Files\Java\jdk1.8.0_162\jre\lib\security\cacerts" -storepass changeit
```

### Atom(Win/Mac/Ubuntu)
```shell
> apm config set https-proxy http://<username>:<password>@<hostname>:<port>

> apm config set http-proxy http://<username>:<password>@<hostname>:<port>

> apm config set strict-ssl false

> set NODE_TLS_REJECT_UNAUTHORIZED=0
```

OR

* ~\.atom\.apmrc

```toml
http-proxy = http://<username>:<password>@<hostname>:<port>
https-proxy = http://<username>:<password>@<hostname>:<port>
strict-ssl = false
```

### wget(Linux)

```shell
echo 'http_proxy=http://<username>:<password>@<hostname>:<port>/' >> ~/.wgetrc
echo 'https_proxy=http://<username>:<password>@<hostname>:<port>/' >> ~/.wgetrc
```

### Linux一般

```shell
echo 'export http_proxy="http://<username>:<password>@<hostname>:<port>/"' >> ~/.bashrc
echo 'export no_proxy="<hostname>;"' >> ~/.bashrc
```

### Docker Tools for Windows (最高難易度なためここで説明)

Docker-Compose, Docker-Machine, DockerのCLIにパスを事前に通して使えるようにしておく。
またプロキシは普段ブラウザでアクセスしているものを利用。
セッションが確立されているはずなので再度のユーザー認証は不要。
GitBashからDocker-Machine用のプロキシ対応（Docker環境LinuxVMイメージをダウンロードするため）

```
$ export "http_proxy=http://<proxyhost>:<proxyport>"
$ export "https_proxy=http://<proxyhost>:<proxyport>"
$ export "no_proxy=localhost,127.0.0.1,.sock,<<dockerVMのIPを追加(192.168.99.100とか（次のステップで確定する）)>>"
```


Win 10 の場合、最新VirtualBoxのイメージにバグありなんで、旧版使用

```
$ docker-machine create --virtualbox-boot2docker-url "https://github.com/boot2docker/boot2docker/releases/download/v18.06.1-ce/boot2docker.iso" -d virtualbox default
```

Win10以外は以下でOK

```
$ docker-machine create -d virtualbox default
$ eval $(docker-machine env default)
$ docker-machine ssh default
```

ここでゲストOSのLinux内にSSH接続される。
"vi"を使って"/var/lib/boot2docker/profile"に以下追記

```
export "http_proxy=http://<proxyhost>:<proxyport>"
export "https_proxy=http://<proxyhost>:<proxyport>"
export "no_proxy=localhost,127.0.0.1,.sock,<dockerVMのIPを追加(192.168.99.100とか)>"  
```

ここでホストのWindows環境からフォルダ共有経由で企業の証明書を入れる。以下のような感じで、

```
$ sudo cp /path/to/ca_cert.cer /home/docker
$ mv ca_cert.cer /var/lib/boot2docker/profile<hostname>.crt
$ exit
```

またホストに戻る。

```
$ docker-machine restart
```

これでDockerHubからイメージをダウンロードできるようになる。

```
$ docker pull python
```

# おわりに

読んで頂きありがとうございました。
最後に開発中の個人アプリの紹介をさせて下さい。

Mockers
https://mockers.io

「Mockers」は、「危険すぎる」と話題の大規模教師なし機械学習技術「GPT-2」を搭載した多言語対応オンライン自動テキスト生成ツールです。 「Mockers」を使用すると、この素晴らしい技術をWeb上で簡単に使用できるだけでなく、Webサイトの記事やTwitterのツイートを学習して、そのスタイルやコンテキストを模倣して、関連性の高い文章を自動生成し、WordpressやTwitterに自動的に投稿することができます。