こんにちは。生産性向上チームの宮田(@miyajan)です。
サイボウズには、生産性向上チームという、組織横断で使える開発基盤を整備するためのチームが存在します。「チーム」となっていますが、今のところ私一人です。
今回は、弊社製品のkintoneとオープンソースのnginxによるリバースプロクシを組み合わせて、社内のエンジニアが手軽にHTTPSを使えるようにした話を書きます。
モチベーション
開発者が手元の開発環境でHTTPSを使いたい場面というのは、意外とたくさんあります。以下は、実際に社内であったケースです。
- HTTPSでのみ発生する問題を手元で再現させたい
- 社内システムをHTTPSで運用する必要がある
- 例1) SAML認証でSSOするためにHTTPSが必須
- 例2) Service Workerを利用するためにHTTPSが必須
- 例3) 社内でDocker Registryを運用しているが、HTTPだと利用者全員に
--insecure-registry
というオプションを設定してもらう必要がある - 例4) iOSアプリ開発でHTTPSによる接続を要求される
自分で証明書を作成する、いわゆるオレオレ証明書で運用する手もあるのですが、信頼されないオレオレ証明書では警告や例外設定といった問題が発生しがちです。また、開発者が個別にそういった作業を行うのは手間なので、もっと手軽にHTTPSを使えるようにしたいと考えました。
そこで、ドメインとワイルドカード証明書を会社で購入し、社内の開発者が手軽にHTTPSを使えるシステムを構築することにしました。
構成
ここからは、開発用のドメインをdev.cybozu.xyz
とし、*.dev.cybozu.xyz
のワイルドカード証明書を持っているとします。
構成としては、上の図のように証明書を配置したリバースプロクシを用意し、クライアントから*.dev.cybozu.xyz
へのリクエストはリバースプロクシを経由してサーバーに送られるようにします。クライアント⇔リバースプロクシ間の通信はHTTPSとなりますが、リバースプロクシ⇔サーバー間の通信はHTTPのままで問題ありません。なので、なんらかのサーバーを立てる開発者側はHTTPSまわりの設定はなにもしなくてよくなります。必要なのは、リバースプロクシにドメイン名とIPアドレス+ポート番号の対応を設定するだけです。
リバースプロクシの設定が大変だと意味がないので、開発者は上の図のようにkintoneに登録するだけにします。cronで実行されるスクリプトが定期的にkintoneからデータを取得し、DNSとリバースプロクシの設定変更を行います。DNSには登録されたドメインがリバースプロクシを指すように設定し、リバースプロクシには登録されたドメインが指定のアドレスに転送されるように設定します。
kintone
今回のシステムでkintoneの役割は以下になります。
- データの蓄積
- データ登録用フォームをGUIで提供
- 他システムがデータを取得するためのAPIを提供
これらの部分を自作するとなると、かなりの工数が必要となってしまいます。このような連携込みの基幹システムがお手軽簡単に構築できてしまうところが、kintoneの素晴らしい点です(ステマ)。
kintoneだと、以下のようなフォームを持つ業務アプリが、慣れれば3分ほどで作成できます。
DNS
DNSは、PowerDNSを使っています。PowerDNSにはREST APIがあるので、連携しやすいと考えたのが理由です。とはいえ、直接ファイルシステムを書き換えるとかでも正直問題ないので、どのDNSソフトを使っても問題ないでしょう。
DNSがあるマシンではcronで毎分スクリプトが実行され、kintoneからHTTPS化したいドメインを取得してきて、PowerDNSが参照するMySQLにリバースプロクシを指すように設定します。
あとは、社内のDNSサーバーから、dev.cybozu.xyz
の名前解決を転送するように設定してもらえばOKです。
リバースプロクシ
リバースプロクシは、nginx+lua-nginx-moduleとredisの組み合わせで実現しています。nginxの設定ファイルは以下のようになります。
worker_processes auto; # redisの接続先を環境変数から取得 env REDIS_ADDR; env REDIS_PORT; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name *.dev.cybozu.xyz; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name *.dev.cybozu.xyz; ssl_certificate /etc/nginx/crt/nginx.crt; ssl_certificate_key /etc/nginx/crt/nginx.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA; ssl_prefer_server_ciphers on; add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains'; proxy_hide_header Strict-Transport-Security; client_max_body_size 0; location / { set $upstream ""; # luaでredisからプロクシ先を取得する rewrite_by_lua ' local redis = require "redis" local client = redis.connect(os.getenv("REDIS_ADDR"), tonumber(os.getenv("REDIS_PORT"))) route = client:get(ngx.var.http_host) if route ~= nil then ngx.var.upstream = route else ngx.log(ngx.ERR, "Host not found: ", ngx.var.http_host) ngx.exit(ngx.HTTP_NOT_FOUND) end '; proxy_set_header Host $host; proxy_set_header HTTPS on; proxy_set_header Forwarded "proto=https; for=$remote_addr; host=$host"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Connection ""; proxy_redirect http:// https://; proxy_pass http://$upstream; proxy_http_version 1.1; proxy_buffering off; proxy_request_buffering off; } } }
rewrite_by_lua
の部分でプロクシ先をredisから取得して動的に設定しています。
nginxがあるマシンでもcronで毎分スクリプトが実行され、kintoneからドメインと対応するプロクシ先を取得してきて、nginxが参照するredisに登録します。
まとめ
社内の開発者が手軽にHTTPSを使えるように、kintoneとnginxで構築したシステムについて説明させていただきました。
このシステムを今年初めに社内公開したところ、現時点で10人以上の開発者に活用していただいています。想定していたよりも社内でHTTPSを利用する機会は多かったようです。
ちなみに、独自CAを運用する方法もありますが、ワイルドカード証明書には証明書発行や利用者のブラウザに証明書を登録する手間が不要であるメリットがあります。
このように、生産性向上チームでは、社内の開発者が本質的な開発に集中できるようにするための活動を行っています。あまり一般的な職種ではないかもしれませんが、組織を横断して生産性を向上させることにより、よりお客様への価値提供を促進していくことがミッションです。
今回この記事を書いたことによって世の中の生産性向上へもつながれば幸いです。