CLOVER🍀

That was when it all began.

stunnelを使って、バックエンドにSSL/TLS通信しつつ、フォワードプロキシ越しにアクセスする

これは、なにをしたくて書いたもの?

stunnelでバックエンドのサーバーにSSL/TLS通信して転送する際に、フォワードプロキシサーバーを経由することができないかなぁと調べたら、
できそうだったので試してみようかなと。

環境

今回の環境は、こちらです。Ubuntu Linux 18.04 LTS。

$ uname -srvmpio
Linux 4.15.0-96-generic #97-Ubuntu SMP Wed Apr 1 03:25:46 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.4 LTS
Release:    18.04
Codename:   bionic

お題としては、https://www.google.com/へのアクセスを以下のような経路で行ってみましょう。

  • curl → stunnel(HTTP) → Apache(HTTP) → www.google.com(HTTPS)

間のApacheは、HTTP CONNECTでHTTPS通信をトンネリングさせます。SSL/TLS通信は、stunnel以降となり、curlはHTTPで通信を行います。

フォワードプロキシ(Apache)のインストール

まずは、Apacheをインストール。

$ sudo apt install apache2

バージョン。

$ apache2 -v
Server version: Apache/2.4.29 (Ubuntu)
Server built:   2020-03-13T12:26:16

mod_proxy_connectを有効にします。

$ sudo a2enmod proxy proxy_connect

フォワードプロキシとしての設定。

Listen 8080
<VirtualHost *:8080>
  ProxyRequests On
  ProxyVia On

  <Proxy *>
    Require host localhost
  </Proxy>

  ErrorLog ${APACHE_LOG_DIR}/proxy_error.log
  CustomLog ${APACHE_LOG_DIR}/proxy_access.log combined
</VirtualHost>

Apacheを再起動したら、準備完了です。

$ sudo systemctl restart apache2

確認。

$ https_proxy=http://localhost:8080 curl https://www.google.com

アクセスログを確認すると、HTTP CONNECT経由でアクセスしていることがわかります。

localhost - - [09/Apr/2020:13:45:00 +0000] "CONNECT www.google.com:443 HTTP/1.1" 200 20118 "-" "curl/7.58.0"

stunnelをインストール、設定する

続いて、stunnelをインストールします。

$ sudo apt install stunnel4

バージョン。

$ stunnel4 -version
stunnel 5.44 on x86_64-pc-linux-gnu platform
Compiled with OpenSSL 1.1.0g  2 Nov 2017
Running  with OpenSSL 1.1.1  11 Sep 2018
Update OpenSSL shared libraries or rebuild stunnel
Threading:PTHREAD Sockets:POLL,IPv6,SYSTEMD TLS:ENGINE,FIPS,OCSP,PSK,SNI Auth:LIBWRAP
 
Global options:
pid                    = /var/run/stunnel4.pid
RNDbytes               = 64
RNDfile                = /dev/urandom
RNDoverwrite           = yes
 
Service-level options:
ciphers                = FIPS (with "fips = yes")
ciphers                = HIGH:!DH:!aNULL:!SSLv2 (with "fips = no")
curve                  = prime256v1
debug                  = daemon.notice
logId                  = sequential
options                = NO_SSLv2
options                = NO_SSLv3
sessionCacheSize       = 1000
sessionCacheTimeout    = 300 seconds
stack                  = 65536 bytes
TIMEOUTbusy            = 300 seconds
TIMEOUTclose           = 60 seconds
TIMEOUTconnect         = 10 seconds
TIMEOUTidle            = 43200 seconds
verify                 = none

設定ファイル「/etc/default/stunnel4」のENABLEDを「1」に変更して、stunnelを有効化します。

ENABLED=1

設定ファイルを作成。
/etc/stunnel/stunnel.conf

[google-web]
client = yes
accept = 127.0.0.1:8000
connect = localhost:8080
protocol = connect
protocolHost = www.google.com:443
verifyChain = yes
CApath = /etc/ssl/certs
checkHost = www.google.com
OCSPaia = yes

stunnelでリッスンするポートは、8000とします。

ポイントは、以下です。

  • クライアントモードにしていること
  • connectで指定するのは、プロキシサーバーのアドレス、ポートとすること
  • protocolで「connect」と指定すること
  • protocolHostに、本来の転送先のバックエンドサーバーを書くこと

stunnel TLS Proxy

設定ができたので、stunnelを起動します

$ sudo systemctl start stunnel4

確認

では、確認してみましょう。

ローカルのポート8000に、HTTPでアクセスします。Hostヘッダーだけは合わせておきました。

$ curl -v localhost:8000 -H 'Host: www.google.com'

結果、プロキシサーバーにHTTP CONNECTでアクセスしていることがわかります。

localhost - - [09/Apr/2020:13:53:46 +0000] "CONNECT www.google.com:443 HTTP/1.1" 200 20332 "-" "-"

もうひとつ

結果がちょっとわかりづらかったかもなので、もうひとつ試してみましょう。

たとえば、www.yahoo.co.jpにHTTPでアクセスするとリダイレクトを要求されます。

$ curl -i http://www.yahoo.co.jp
HTTP/1.1 301 Redirect
Date: Thu, 09 Apr 2020 14:22:43 GMT
Connection: keep-alive
Via: http/1.1 edge2623.img.djm.yahoo.co.jp (ApacheTrafficServer [c s f ])
Server: ATS
Cache-Control: no-store
Location: https://www.yahoo.co.jp:443/
Content-Type: text/html
Content-Language: en
Content-Length: 1

ここで、stunnelの設定をwww.yahoo.co.jp向けに設定します。
/etc/stunnel/stunnel.conf

[yahoo-web]
client = yes
accept = 127.0.0.1:8000
connect = localhost:8080
protocol = connect
protocolHost = www.yahoo.co.jp:443
verifyChain = yes
CApath = /etc/ssl/certs
checkHost = www.yahoo.co.jp
OCSPaia = yes

stunnelを再起動。

$ sudo systemctl restart stunnel4

確認。

$ curl localhost:8000 -H 'Host: www.yahoo.co.jp' -v -I
* Rebuilt URL to: localhost:8000/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> HEAD / HTTP/1.1
> Host: www.yahoo.co.jp
> User-Agent: curl/7.58.0
> Accept: */*
> 
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Cache-Control: private, no-cache, no-store, must-revalidate
Cache-Control: private, no-cache, no-store, must-revalidate
< Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=UTF-8
< Date: Thu, 09 Apr 2020 14:25:01 GMT
Date: Thu, 09 Apr 2020 14:25:01 GMT
< Expires: -1
Expires: -1
< Pragma: no-cache
Pragma: no-cache
< Set-Cookie: B=5k0q8u5f8uc1t&b=3&s=93; expires=Sun, 10-Apr-2022 14:25:01 GMT; path=/; domain=.yahoo.co.jp
Set-Cookie: B=5k0q8u5f8uc1t&b=3&s=93; expires=Sun, 10-Apr-2022 14:25:01 GMT; path=/; domain=.yahoo.co.jp
< Vary: Accept-Encoding
Vary: Accept-Encoding
< X-Content-Type-Options: nosniff
X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
X-Frame-Options: SAMEORIGIN
< X-Vcap-Request-Id: eef40b90-5531-4aff-55f1-a9e3203a3eef
X-Vcap-Request-Id: eef40b90-5531-4aff-55f1-a9e3203a3eef
< X-Xss-Protection: 1; mode=block
X-Xss-Protection: 1; mode=block
< Age: 0
Age: 0
< Connection: keep-alive
Connection: keep-alive
< Via: http/1.1 edge1659.img.bbt.yahoo.co.jp (ApacheTrafficServer [c sSf ])
Via: http/1.1 edge1659.img.bbt.yahoo.co.jp (ApacheTrafficServer [c sSf ])
< Server: ATS
Server: ATS
< Set-Cookie: XB=5k0q8u5f8uc1t&b=3&s=93; expires=Sun, 10-Apr-2022 14:25:01 GMT; path=/; domain=.yahoo.co.jp; secure; samesite=none
Set-Cookie: XB=5k0q8u5f8uc1t&b=3&s=93; expires=Sun, 10-Apr-2022 14:25:01 GMT; path=/; domain=.yahoo.co.jp; secure; samesite=none

< 
* Connection #0 to host localhost left intact

今度は、リダイレクトされません。

アクセスログ側も確認してみます。

localhost - - [09/Apr/2020:14:25:00 +0000] "CONNECT www.yahoo.co.jp:443 HTTP/1.1" 200 7047 "-" "-"

OKそうですね。

これで、HTTP CONNECT越しに、クライアントをSSL/TLS化できました、と。