nginx
Lua

lua-nginx-moduleでヘッダ書き換え

やりたいこと

ブラウザ <-- http --> nginx(proxy) <-- https --> web

この場合、webサイトからcookieが送られて来たときに secure 属性が付いていると、ブラウザがcookieを保存してくれない。(本来httpsでしか送られてこないものがhttpで送られて来たのでブラウザ側で落としている?)
結果、ログインが必要なサイトが使えない。
ヘッダのSet-cookieが↓みたいな感じになっているので、ヘッダ書き換えて secure 属性落としたい。

Set-Cookie: xxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; path=/; secure; httponly

apacheのmod_headersなら結構楽にできるらしいけど、nginxでできないものかと調べてた時にlua-nginx-moduleを発見したのでこれを使ってみる。
公式ドキュメント 読むと、今回やりたいことは header_filter_by_lua_block で実現できそう。

nginxインストール

luaモジュールを使うためにはnginxをソースからビルドしないといけないみたいです。めんどくさいですね。
今回はluaモジュールが使えるdocker imageを使うことにします。

$ docker pull firesh/nginx-lua

ソースからビルドする方法は公式のgithubに手順が書いてあるのでそちらを参考に
https://github.com/openresty/lua-nginx-module#installation

dockerでnginxを動かす

$ mkdir -p nginx/conf.d
$ vi nginx/nginx.conf
nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    proxy_buffer_size   128k;
    proxy_buffers   4 256k;
    proxy_busy_buffers_size   256k;

    log_format  main  ' -  [] "" '
                      '0  "" '
                      '"" ""';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
$ vi nginx/conf.d/default.conf
default.conf
server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        proxy_pass https://hogehoge.com; # proxyしたいwebサイトのURL

        header_filter_by_lua_block {
            local cookie = ngx.header["Set-Cookie"];
            if cookie and type (cookie) == "string" then
                cookie = string.gsub(cookie, "secure; ", "");
                ngx.header["Set-Cookie"] = cookie;
            end
        }
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
$ vi Dockerfile
FROM firesh/nginx-lua
ADD nginx /etc/nginx
EXPOSE 80
$ docker build -t nginx-lua .
$ docker run -p 80:80 nginx-lua

これで localhost にアクセスすると hogehoge.com にプロキシしてくれるようになります。
パケットをみて secure 属性が落ちているか確認します。

$ sudo tcpdump -i any port 80 host localhost -A 
...
12:17:41.505396 IP 127.0.0.1.80 > 127.0.0.1.58811: Flags [P.], seq 1546:13748, ack 1310, win 10879, options [nop,nop,TS val 2075176958 ecr 2075176608], length 12202: HTTP: HTTP/1.1 200 OK
....E./...@.@............P.....v..=...*.-......
{...{...HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Sun, 04 Feb 2018 03:19:24 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 11341
Connection: keep-alive
X-Powered-By: PHP/5.4.45
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: xxxxxxxxx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx; path=/; httponly ←書き換えに成功してsecure属性が落ちてる
Content-Security-Policy: default-src 'none';script-src 'self' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: blob:;font-src 'self';connect-src 'self';media-src 'self'
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: Sameorigin
X-Robots-Tag: none
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
...

実際にログインが必要なサイトも使えるようになることが確認できました。

まとめ

  • lua-nginx-moduleはすごく使える
  • でもソースからnginxビルドするのすごく面倒、luaモジュール入ってるdocker imageも常に最新版に追従している訳ではない
    • 趣味ならいいけど仕事で使う場合nginxのバージョンアップする時とか動作確認・テストめんどくさそう
  • 誰かlua-nginx-module入ってるnginxのdocker imageのメンテナンス頼む(他力本願