これは、なにをしたくて書いたもの?
SSL/TLSのトンネリングツールである、stunnelをちょっと試してみたいなぁと思いまして。
非SSL/TLSなクライアント、サーバー間の通信を、SSL/TLSに対応させる手段としては知っておいてもよいかな、と。
stunnel
最初に書きましたが、SSL/TLSのトンネリングツールです。
SSL/TLSに対応していないクラアントやサーバーの間にプロキシ的に配置することで、間の通信を暗号化することができます。
機能詳解は、こちら。
クロスプラットフォームで動作し、各プラットフォームに特化した機能もあります。
ドキュメントやExampleはこちら。
設定内容は、Exampleを見るとある程度想像できそうな感じですね。
その他の参考情報。
4.8. stunnel の使用 Red Hat Enterprise Linux 7 | Red Hat Customer Portal
@IT:Security Tips > SSL非対応メーラのSSL化
環境
今回の環境は、こちら。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
インストール
では、stunnelをインストールしてみましょう。
Ubuntu Linuxの場合は、aptでインストールすることができます。パッケージ名は「stunnel4」です。
$ sudo apt install stunnel4
インストールされるコマンドは「stunnel4」とそのエイリアス、そして「stunnel3」です。
$ ll /usr/bin/stunnel* lrwxrwxrwx 1 root root 8 Apr 19 2018 /usr/bin/stunnel -> stunnel4* -rwxr-xr-x 1 root root 2788 Apr 19 2018 /usr/bin/stunnel3* -rwxr-xr-x 1 root root 175888 Apr 19 2018 /usr/bin/stunnel4*
「stunnel4」のバージョンを見ると、4という名前の割には5.44がインストールされたようです。最新版ではありませんが、今回はこれで
良いでしょう。
$ 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/stunnel/READMEを見ると、ENABLEDを設定してね、サンプルがあるよ、と書かれています。
Stunnel 4 configuration files. Files found under the /etc/stunnel directory that end with .conf are used by the stunnel4 service as configuration files, and each will be used to start a daemon process setting up a tunnel with the given configuration. Note that this directory is initially empty, as the settings you may want for your tunnels are completely system dependent. In order to have the tunnels start up automatically on system boot you must *also* set ENABLED to 1 in /etc/default/stunnel4 A sample configuration file with defaults may be found at /usr/share/doc/stunnel4/examples/stunnel.conf-sample
サンプルの内容を見てみます。
$ zcat /usr/share/doc/stunnel4/examples/stunnel.conf-sample.gz ; Sample stunnel configuration file for Unix by Michal Trojnara 2002-2017 ; Some options used here may be inadequate for your particular configuration ; This sample file does *not* represent stunnel.conf defaults ; Please consult the manual for detailed description of available options ; ************************************************************************** ; * Global options * ; ************************************************************************** ; It is recommended to drop root privileges if stunnel is started by root ;setuid = stunnel4 ;setgid = stunnel4 ; PID file is created inside the chroot jail (if enabled) ;pid = /var/run/stunnel.pid ; Debugging stuff (may be useful for troubleshooting) ;foreground = yes ;debug = info ;output = /var/log/stunnel.log ; Enable FIPS 140-2 mode if needed for compliance ;fips = yes ; The pkcs11 engine allows for authentication with cryptographic ; keys isolated in a hardware or software token ; MODULE_PATH specifies the path to the pkcs11 module shared library, ; e.g. softhsm2.dll or opensc-pkcs11.so ; Each section using this feature also needs the "engineId = pkcs11" option ;engine = pkcs11 ;engineCtrl = MODULE_PATH:/usr/lib/softhsm/libsofthsm2.so ;engineCtrl = PIN:1234 ; ************************************************************************** ; * Service defaults may also be specified in individual service sections * ; ************************************************************************** ; Enable support for the insecure SSLv3 protocol ;options = -NO_SSLv3 ; These options provide additional security at some performance degradation ;options = SINGLE_ECDH_USE ;options = SINGLE_DH_USE ; ************************************************************************** ; * Include all configuration file fragments from the specified folder * ; ************************************************************************** ;include = /etc/stunnel/conf.d ; ************************************************************************** ; * Service definitions (remove all services for inetd mode) * ; ************************************************************************** ; ***************************************** Example TLS client mode services ; The following examples use /etc/ssl/certs, which is the common location ; of a hashed directory containing trusted CA certificates. This is not ; a hardcoded path of the stunnel package, as it is not related to the ; stunnel configuration in /etc/stunnel/. [gmail-pop3] client = yes accept = 127.0.0.1:110 connect = pop.gmail.com:995 verifyChain = yes CApath = @sysconfdir/ssl/certs checkHost = pop.gmail.com OCSPaia = yes [gmail-imap] client = yes accept = 127.0.0.1:143 connect = imap.gmail.com:993 verifyChain = yes CApath = @sysconfdir/ssl/certs checkHost = imap.gmail.com OCSPaia = yes [gmail-smtp] client = yes accept = 127.0.0.1:25 connect = smtp.gmail.com:465 verifyChain = yes CApath = @sysconfdir/ssl/certs checkHost = smtp.gmail.com OCSPaia = yes ; Encrypted HTTP proxy authenticated with a client certificate ; located in a cryptographic token ;[example-pkcs11] ;client = yes ;accept = 127.0.0.1:8080 ;connect = example.com:8443 ;engineId = pkcs11 ;cert = pkcs11:token=MyToken;object=MyCert ;key = pkcs11:token=MyToken;object=MyKey ; ***************************************** Example TLS server mode services ;[pop3s] ;accept = 995 ;connect = 110 ;cert = /etc/stunnel/stunnel.pem ;[imaps] ;accept = 993 ;connect = 143 ;cert = /etc/stunnel/stunnel.pem ;[ssmtp] ;accept = 465 ;connect = 25 ;cert = /etc/stunnel/stunnel.pem ; TLS front-end to a web server ;[https] ;accept = 443 ;connect = 80 ;cert = /etc/stunnel/stunnel.pem ; "TIMEOUTclose = 0" is a workaround for a design flaw in Microsoft SChannel ; Microsoft implementations do not use TLS close-notify alert and thus they ; are vulnerable to truncation attacks ;TIMEOUTclose = 0 ; Remote shell protected with PSK-authenticated TLS ; Create "/etc/stunnel/secrets.txt" containing IDENTITY:KEY pairs ;[shell] ;accept = 1337 ;exec = /bin/sh ;execArgs = sh -i ;ciphers = PSK ;PSKsecrets = /etc/stunnel/secrets.txt ; Non-standard MySQL-over-TLS encapsulation connecting the Unix socket ;[mysql] ;cert = /etc/stunnel/stunnel.pem ;accept = 3307 ;connect = /run/mysqld/mysqld.sock ; vim:ft=dosini
ドキュメントもExampleを見てもよいですし、こちらも参考になりそうですね。
stunnelの設定を行う。
最初にstunnel4サービスの状態を確認しています。
$ sudo systemctl status stunnel4 ● stunnel4.service - LSB: Start or stop stunnel 4.x (TLS tunnel for network daemons) Loaded: loaded (/etc/init.d/stunnel4; generated) Active: active (exited) since Tue 2020-04-07 14:59:47 UTC; 6min ago Docs: man:systemd-sysv-generator(8) Tasks: 0 (limit: 2317) CGroup: /system.slice/stunnel4.service Apr 07 14:59:47 ubuntu1804.localdomain systemd[1]: Starting LSB: Start or stop stunnel 4.x (TLS tunnel for network daemons)... Apr 07 14:59:47 ubuntu1804.localdomain stunnel4[1931]: TLS tunnels disabled, see /etc/default/stunnel4 Apr 07 14:59:47 ubuntu1804.localdomain systemd[1]: Started LSB: Start or stop stunnel 4.x (TLS tunnel for network daemons).
よくよく見ると、init.dですね。
Loaded: loaded (/etc/init.d/stunnel4; generated)
インストール直後は停止しています。
ここで、環境変数の設定を行います。
/etc/default/stunnel4
# /etc/default/stunnel # Julien LEMOINE <speedblue@debian.org> # September 2003 # Change to one to enable stunnel automatic startup ENABLED=0 FILES="/etc/stunnel/*.conf" OPTIONS="" # Change to one to enable ppp restart scripts PPP_RESTART=0 # Change to enable the setting of limits on the stunnel instances # For example, to set a large limit on file descriptors (to enable # more simultaneous client connections), set RLIMITS="-n 4096" # More than one resource limit may be modified at the same time, # e.g. RLIMITS="-n 4096 -d unlimited" RLIMITS=""
「ENABLED」を1に変更。
#ENABLED=0 ENABLED=1
起動。「restart」にしましたけど。
$ sudo systemctl restart stunnel4
これで、stunnelが利用できるようになります。
では、設定ファイルを書いていきましょう。Exampleを参考にします。
あと、こちらも参考にしましょう。
非SSL/TLSなクライアントを、SSL/TLSを使用するサーバーに対応させる
お題として、https://www.google.com/へのHTTPSアクセスをstunnelに肩代わりしてもらい、クライアントからはHTTPでアクセスするように
してみましょう。
stunnelは「/etc/stunnel/*.conf」というルールで設定ファイルを読み込むようになっているので、ミニマムとして以下の設定を記述。
※今回は、グローバルな設定はパスします
/etc/stunnel/stunnel.conf
[google-web] client = yes accept = 127.0.0.1:80 connect = www.google.com:443 verifyChain = yes CApath = /etc/ssl/certs checkHost = www.google.com OCSPaia = yes
それぞれ、以下の意味になります。
- client … yesの場合、クライアントに対してSSL/TLS通信を肩代わりする
- accept … リッスンするアドレス、ポート
- connect … 接続先のアドレス、ポート
- verifyChain … ルートCAから始まる証明書チェーンを検証する
- CApath … verifyChainまたはverifyPeerオプションが使用する証明書が格納されたディレクトリ
- checkHost … 証明書検証時のホスト名
- OCSPaia … AIA OCSPレスポンダーを使用する
今回は、実はclient、accept、connectの3つだけで動作するのですが。
acceptは、バインド先のIPアドレスを指定できます。やるかどうかはさておき、「0.0.0.0」で全ネットワークインターフェースにも
バインド可能です。
accept = 127.0.0.1:80 ;accept = 0.0.0.0:80
ところで、Exampleなどにある「@sysconfdir」というのは、今回の環境では以下のディレクトリを指しています。
/etc/ssl/certs
では、stunnelを再起動。
$ sudo systemctl restart stunnel4
起動状態を確認。
$ sudo systemctl status stunnel4 ● stunnel4.service - LSB: Start or stop stunnel 4.x (TLS tunnel for network daemons) Loaded: loaded (/etc/init.d/stunnel4; generated) Active: active (running) since Tue 2020-04-07 15:19:17 UTC; 2s ago Docs: man:systemd-sysv-generator(8) Process: 2624 ExecStop=/etc/init.d/stunnel4 stop (code=exited, status=0/SUCCESS) Process: 2646 ExecStart=/etc/init.d/stunnel4 start (code=exited, status=0/SUCCESS) Tasks: 2 (limit: 2317) CGroup: /system.slice/stunnel4.service └─2673 /usr/bin/stunnel4 /etc/stunnel/stunnel.conf Apr 07 15:19:17 ubuntu1804.localdomain systemd[1]: Starting LSB: Start or stop stunnel 4.x (TLS tunnel for network daemons)... Apr 07 15:19:17 ubuntu1804.localdomain systemd[1]: Started LSB: Start or stop stunnel 4.x (TLS tunnel for network daemons). Apr 07 15:19:17 ubuntu1804.localdomain stunnel4[2646]: Starting TLS tunnels: /etc/stunnel/stunnel.conf: started (no pid=pidfile specified!)
telnetで確認してみましょう。
$ curl telnet://localhost:80 GET / HTTP/1.1 Host: www.google.com HTTP/1.1 200 OK Date: Wed, 08 Apr 2020 14:51:51 GMT Expires: -1 Cache-Control: private, max-age=0 Content-Type: text/html; charset=ISO-8859-1 P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info." Server: gws X-XSS-Protection: 0 X-Frame-Options: SAMEORIGIN Set-Cookie: 1P_JAR=2020-04-08-14; expires=Fri, 08-May-2020 14:51:51 GMT; path=/; domain=.google.com; Secure Set-Cookie: NID=201=K1ffuoUljb0TF4f0eDIAqPm5Cdym1Do5K_AAlqUi69BSW6rf_QmRQIneW6vIMX03PYX3bEnDCBnN6_nciHcgHfNJBSBAmynzVhNzy2nzCJ2HpNOHMliECZmDmNueQiB_mGFEi7pg6C02nQen3vJMmny4vLxRvNAsvCa9R4CBZpI; expires=Thu, 08-Oct-2020 14:51:51 GMT; path=/; domain=.google.com; HttpOnly Alt-Svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,h3-T050=":443"; ma=2592000 Accept-Ranges: none Vary: Accept-Encoding Transfer-Encoding: chunked 64e4 <!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。" name="description"><meta content="noodp" name="robots"><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/logos/doodles/2020/thank-you-emergency-services-workers-6753651837108755-law.gif" itemprop="image"><meta content="救急隊員のみなさん、ありがとう。" property="twitter:title"><meta content="救急隊員のみなさん、ありがとう。#GoogleDoodle" property="twitter:description"><meta content="救急隊員のみなさん、ありがとう。#GoogleDoodle" property="og:description"><meta content="summary_large_image" property="twitter:card"><meta content="@GoogleDoodles" property="twitter:site"><meta content="https://www.google.com/logos/doodles/2020/thank-you-emergency-services-workers-6753651837108755-2xa.gif" property="twitter:image"><meta content="https://www.google.com/logos/doodles/2020/thank-you-emergency-services-workers-6753651837108755-2xa.gif" property="og:image"><meta content="1288" property="og:image:width"><meta content="460" property="og:image:height"><meta content="https://www.google.com/logos/doodles/2020/thank-you-emergency-services-workers-6753651837108755-2xa.gif" property="og:url"><meta content="video.other" property="og:type"><title>Google</title><script nonce="FqdOdIcTeadLpYiSohseeQ==">(function() 〜省略〜 function _F_installCss(c){} (function(){google.spjs=false;google.snet=true;google.em=[];google.emw=false;google.pdt=0;google.uwp=false;})();(function(){var pmc='{\x22d\x22:{},\x22sb_he\x22:{\x22agen\x22:true,\x22cgen\x22:true,\x22client\x22:\x22heirloom-hp\x22,\x22dh\x22:true,\x22dhqt\x22:true,\x22ds\x22:\x22\x22,\x22ffql\x22:\x22ja\x22,\x22fl\x22:true,\x22host\x22:\x22google.com\x22,\x22isbh\x22:28,\x22jsonp\x22:true,\x22msgs\x22:{\x22cibl\x22:\x22検索をクリア\x22,\x22dym\x22:\x22もしかして:\x22,\x22lcky\x22:\x22I\\u0026#39;m Feeling Lucky\x22,\x22lml\x22:\x22詳細\x22,\x22oskt\x22:\x22入力ツール\x22,\x22psrc\x22:\x22この検索キーワードは\\u003Ca href\x3d\\\x22/history\\\x22\\u003Eウェブ履歴\\u003C/a\\u003Eから削除されました\x22,\x22psrl\x22:\x22削除\x22,\x22sbit\x22:\x22画像で検索\x22,\x22srch\x22:\x22Google 検索\x22},\x22ovr\x22:{},\x22pq\x22:\x22\x22,\x22refpd\x22:true,\x22refspre\x22:true,\x22rfs\x22:[],\x22sbpl\x22:16,\x22sbpr\x22:16,\x22scd\x22:10,\x22stok\x22:\x224H1gy_x0YYHGa1RJ1NO8X9IIrZs\x22,\x22uhde\x22:false}}';google.pmc=JSON.parse(pmc);})();</script> </body></html> 0
HTTPでアクセスしましたが、結果が返ってきました。
$ curl telnet://localhost:80 GET / HTTP/1.1 Host: www.google.com
tcpdumpで見ると、ちゃんと443で通信しに行っていることが確認できます。
$ sudo tcpdump -i any -n tcp port 443 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes 14:54:19.139300 IP 192.168.121.216.38072 > 216.58.221.228.443: Flags [S], seq 1433332297, win 64240, options [mss 1460,sackOK,TS val 4078539507 ecr 0,nop,wscale 7], length 0 14:54:19.198305 IP 216.58.221.228.443 > 192.168.121.216.38072: Flags [S.], seq 929050666, ack 1433332298, win 60192, options [mss 1380,sackOK,TS val 1149326253 ecr 4078539507,nop,wscale 8], length 0 14:54:19.198371 IP 192.168.121.216.38072 > 216.58.221.228.443: Flags [.], ack 1, win 502, options [nop,nop,TS val 4078539566 ecr 1149326253], length 0 14:54:19.198853 IP 192.168.121.216.38072 > 216.58.221.228.443: Flags [P.], seq 1:347, ack 1, win 502, options [nop,nop,TS val 4078539567 ecr 1149326253], length 346 14:54:19.256534 IP 216.58.221.228.443 > 192.168.121.216.38072: Flags [.], ack 347, win 240, options [nop,nop,TS val 1149326312 ecr 4078539567], length 0 14:54:19.283249 IP 216.58.221.228.443 > 192.168.121.216.38072: Flags [P.], seq 1:2633, ack 347, win 240, options [nop,nop,TS val 1149326338 ecr 4078539567], length 2632 14:54:19.286097 IP 192.168.121.216.38072 > 216.58.221.228.443: Flags [.], ack 2633, win 495, options [nop,nop,TS val 4078539651 ecr 1149326338], length 0
ssでも見ておきましょう。
$ sudo ss -tnp | grep 443 ESTAB 0 0 192.168.121.216:38112 216.58.221.228:443 users:(("stunnel4",pid=3116,fd=10))
大丈夫そうですね。
非SSL/TLSなサーバーを、SSL/TLSに対応させる
次に、非SSL/TLSなサーバーを、SSL/TLS通信越しに使えるようにしてみましょう。
Pythonで、簡易なHTTPサーバーを立てます。
$ echo 'Hello World!!' > hello.txt $ python3 -m http.server Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
確認。
$ curl localhost:8000/hello.txt Hello World!!
このHTTPサーバーを、stunnelを使ってSSL/TLSに対応させてみます。
証明書が必要になるので、今回は自己署名証明書を作成しましょう。
秘密鍵の作成。
$ openssl genrsa -aes256 -out sample.key 2048
パスワードの解除。
$ openssl rsa -in sample.key -out sample.key
CSRの作成。
$ openssl req -new -key sample.key -out sample.csr
署名。
$ openssl x509 -req -days 365 -in sample.csr -signkey sample.key -out sample.crt
では、このキーを使うように、/etc/stunnel/stunnel.confを修正します。
[python-http] accept = 8443 connect = 8000 cert = /path/to/sample.crt key = /path/to/sample.key
accept、connectの意味は、クライアントとして動作する時と同じですね。今回はポートのみ指定で、バックエンドのPython HTTPサーバーの
前段に8443ポートで構えます。
cert、keyは自己署名証明書、秘密鍵をそれぞれ指定します。
stunnelを再起動。
$ sudo systemctl restart stunnel4
自己署名証明書なので、curlの「--cacert」オプションに指定して実行。
$ curl --cacert sample.crt https://localhost:8443/hello.txt Hello World!!
OKですね。