catalinaの備忘録

ソフトウェアやハードウェアの備忘録。後で逆引きできるように。

NginxでHTTPS(SSL)対応する

暗号/復号関係は苦手です。かたりぃなです。

苦手な理由は、これ系は期待動作していない場合のデバッグが非常にやりにくいからなんですよね。

アルゴリズムそのものは実績がある前提だとすると、うまく動かないときはモジュール外から与えるパラメータが間違えているわけです。

鍵、IV、証明書、暗号アルゴリズム、暗号利用モード、暗号開始アドレスetc...こういうパラメータを確認して一つづつ見直しをするしかないわけです。

で、パラメータを変更して動作を追っても「あってる or 間違えている」しかわからないので、本当につらい。

数学が得意な人はもっと効率的に作業できたりするんでしょうか?

さて、今回はHTTPSとその周辺技術を触ってみます。 個人的にサーバ立ててサービス化するときも役立つと思いますので。

HTTPSとは

一言でいうとHTTPをセキュアにしたものです。

まずプロトコルの観点から整理します。

プロトコルスタック

だいたいこんな感じです。 TCPレイヤとHTTPレイヤの間にTLSレイヤを設けて、ここで暗号/復号などが行われます。

レイヤ プロトコル
アプリケーション HTTP
アプリケーション TLS/SSL
トランスポート TCP
ネットワーク IP

Python-FlaskでHTTPS対応してみる(断念)

ちょっと面倒なので断念です。

HTTPS化するだけのはずが、本題以外のことを考えないといけなくて、手間かかりすぎでした。

どういうところが手間だったかというと

  • アプリケーションとインフラとの結合が密になってしまう
    • 当然、コードが入り乱れてきてしまう
    • コード混乱の結果、リポジトリの管理どうするかとか、本題と関係ないところで悩む

アプリケーションはビジネスロジックとかに注力すべきであって、インフラ周りと密に結合した実装にするのはよくないですよね。

アプリケーションのモジュール構成をしっかり考えるという対策もありますが、今回は一般的なWebサーバを活用する方向で考えたいと思います。

というわけで、apacheとnginxを試していきます。

apacheでやってみる

apacheの設定こんな感じにすれば、とりあえずHTTPS対応できます。

証明書と鍵は後で説明します。

apacheの設定ファイル(httpd.conf)

# vhost
NameVirtualHost *:80
NameVirtualHost *:443
Include pass/apache/conf.d/*.conf

virtualhost(pass/apache/conf.d/httpd_vhosts_site.conf)

<VirtualHost *:80>
    ServerName local.my.api.mtg_card_detect
    # ~~ 略 ~~
<VirtualHost>

<VirtualHost *:443>
    ServerName local.my.api.mtg_card_detect:443
    SSLEngine On
    SSLCertificateFile pass/apache/server.crt
    SSLCertificateKeyFile pass/apache/server.key
<VirtualHost>

で、この後段にお好きなアプリケーションサーバを置いておけばよさそうです。

PHPなんかだとこの方法でちゃちゃっとやっつけてもいいかもしれませんね。

アプリケーションとwebサーバを分離したい

ここから、今回のエントリの本題です。一般的にSSLオフローダ、リバースプロキシと呼ばれる方式です。

クライアントからのアクセスを一旦Webサーバで受けて、WebサーバはSSLを解きます。

SSLを解いたら、Webサーバからアプリケーションサーバへ(HTTPSではなく)HTTPでリクエストを出します。

これで次のことが実現できます

いい感じの役割分担になってきました。

nginxリバースプロキシでSSLオフロードをする検討

以前やったnginxのリバースプロキシにSSLを解かせます。

一点だけ懸念がありますが、今回は気にしないことにします。まだ使わない機能なので。

何が懸念かというと、アプリケーションに必ずHTTPでリクエストが来るということは、リクエスURIが書き換わるということを意味します。

リクエスURIが書き換わると、アプリケーションが実装している盗聴対策, 認証, 認可などのセキュリティでエラーとして弾かれる可能性があります。

具体的にはOAuthとか。うろ覚えですがOAuthはリクエスURIを含めて何か作ってた気がします。またの機会に調査します。

nginxでSSLを解く

まず証明書と鍵が必要です。実験用なので自分で鍵を作って、自分で署名しましょう(通称:オレオレ証明書)。

$cd /usr/local/nginx/conf.d
$openssl genrsa 2048 > server.key
$openssl req -new -key server.key > server.csr
# ※以下のような質問が出るが、オレオレ証明書なので全てEnterでスキップでOK。
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
 
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
 
# 署名する
# 実験中に期限くると困るので10年(365 x 10=3650)くらいの有効期限で
$ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt

次にnginxの設定ファイルを書きましょう。 以前やったリバースプロキシの設定を書き換えています。

user  nginx;
worker_processes  1;

pid    /var/run/nginx.pid;

events {
  worker_connections  1024;
}

http{
  server {
    listen       443 ssl ;
    server_name  local.my.proxy.server;

    ### SSL有効化と証明書の保存場所指定
    ssl           on;
    ssl_certificate     /etc/nginx/cert/server.crt;
    ssl_certificate_key /etc/nginx/cert/server.key;

    ### プロキシ先の指定とApacheに渡すリクエストヘッダーの指定
    location / {
        proxy_pass http://192.168.xx.xx:port/;
        proxy_redirect                         off;
        proxy_set_header Host                  local.my.api.mtg_card_detect;
        proxy_set_header X-Real-IP             $remote_addr;
        proxy_set_header X-Forwarded-Host      $host;
        proxy_set_header X-Forwarded-For       $proxy_add_x_forwarded_for;
    }
  }
}

これでOKです。 nginxにHTTPSでリクエストを出すとmtg_card_detectというアプリケーションサーバにHTTPリクエストが出るようになりました。

感想と今後の展望

SSL対応もできたので、今後カードゲームARアプリのゲームサーバ(カード検出、分類)に対するリクエストもHTTPSで実現できる目途は立ちました。

本物の証明書はCAに発行してもらわないといけないので、実際にどうするのかは必要になってから調べることにします。

サーバ構成も少しづついじれるようになってきたので、今後のアプリづくりで有効活用したいですね。

それでは今回はこれくらいで。