Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dynamic certificate internals with ngx_mruby #n...

Dynamic certificate internals with ngx_mruby #nagoyark03

Talk for Nagoya Ruby Kaigi 03 (http://regional.rubykaigi.org/nagoya03/) by OKUMURA Takahiro.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[Links in the slides]
mruby: https://github.com/mruby/mruby

200万 Webサイトを支える ロリポップ!と mruby:
https://speakerdeck.com/harasou/200mo-websaitowozhi-eru-roripotupu-to-mruby

haconiwa: https://github.com/haconiwa/haconiwa

ngx_mruby の Nginx::Var クラスの実装を理解する〜変数取得編
http://blog.hifumi.info/2016/11/07/ngx_mruby-nginx-var-using-method-missing/

How to build ngx_mruby:
https://github.com/matsumotory/ngx_mruby/wiki/Install
https://github.com/hsbt/ngx_mruby-package-builder
https://hub.docker.com/r/hfmgarden/ngx_mruby
https://github.com/giraffi/docker-nginx-mruby-base

100行あったmod_rewirteを ngx_mrubyで書き換えた話:
https://speakerdeck.com/buty4649/100xing-atutamod-rewirtewo-ngx-mrubydeshu-kihuan-etahua

goope: https://goope.jp

Too many domains and certificates:
https://gist.github.com/hfm/4a045a429f9303c90eac7c348d1a424a

SSL_CTX_set_cert_cb(): https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_cert_cb.html

Announce that ngx_mruby supports dynamic certificates:
https://twitter.com/matsumotory/status/685341115814289408

ngx_mruby に mruby_ssl_handshake_handler を実装した:
http://blog.hifumi.info/2016/10/03/ngx_mruby-mruby_ssl_handshake_handler/

mruby のテスト用に MySQL 環境を自動で構築する mruby-test-mysqld を書いた
:
http://blog.hifumi.info/2016/09/06/mruby-test-mysqld/

How to test code with mruby:
http://www.slideshare.net/hsbt/20150525-testing-casualtalks

Okumura Takahiro

February 13, 2017
Tweet

More Decks by Okumura Takahiro

Other Decks in Programming

Transcript

  1. Senior web operation engineer at GMO Pepabo, Inc. A maintainer

    of ngx_mruby. http://blog.hifumi.info hfm hfm OKUMURA
 Takahiro (okkun)
  2. Today’s Agenda Introduce mruby/ngx_mruby How to build ngx_mruby How hosting

    too many domains & certificates Dynamic certificate with ngx_mruby
  3. ngx_mruby •A fast and memory-efficient web server extension mechanism using

    mruby for nginx •Created by @matsumotory •An alternative to mod_mruby
  4. ngx_mruby sample code location /hello_world { mruby_content_handler_code ‘ Nginx.rputs "Hello

    ngx_mruby world!" '; } $ curl http://127.0.0.1/hello_world Hello ngx_mruby world!
  5. ngx_mruby sample code v = Nginx::Var.new Nginx.rputs "Date: #{v.date_local}" #=>

    Date: Friday, 14-Oct-2016 02:20:00 JST # Using ngx_http_geoip_module Nginx.rputs "Country: #{v.geoip_country_name}" #=> Country: Japan
  6. ngx_mruby sample code v = Nginx::Var.new Nginx.rputs "Date: #{v.date_local}" #=>

    Date: Friday, 14-Oct-2016 02:20:00 JST # Using ngx_http_geoip_module Nginx.rputs "Country: #{v.geoip_country_name}" #=> Country: Japan Do you want to know Nginx::Var internal? => ngx_mruby ͷ Nginx::Var Ϋϥεͷ࣮૷Λཧղ͢Δʙม਺औಘฤ http://blog.hifumi.info/2016/11/07/ngx_mruby-nginx-var-using-method-missing/
  7. hsbt/ngx_mruby-package-builder •Providing RPM and DEB packages •CentOS 6, 7 •Ubuntu

    14.04, 16.04 •https://github.com/hsbt/ngx_mruby-package-builder
  8. Two problems •IP address per domain ➡ TLS SNI extension

    •Web server load too many certificates
  9. TLS SNI extension TLS SNI sample-a.com Certificate IP Address Certificate

    IP Address Certificate IP Address sample-b.com sample-c.com IP Address Certificate Certificate Certificate sample-a.com sample-b.com sample-c.com
  10. Two problems •IP address per domain ✓ TLS SNI extension

    •Web server load too many certificates
  11. Two problems •IP address per domain ✓ TLS SNI extension

    •Web server load too many certificates
  12. Too many domains and certificates https://a.jp application N https://b.jp https://z.jp

    … Certificate Certificate Certificate Certificate Certificate Certificate oh… Certificate Certificate Certificate
  13. Too many domains and certificates https://a.jp application N https://b.jp https://z.jp

    https://aa.jp … … Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate Oops… Certificate Certificate Certificate
  14. Too many domains and certificates https://a.jp application N https://b.jp https://z.jp

    https://aa.jp … … Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate x 10,000 # ps axfo rss,cmd RSS CMD 2872 bash 256168 nginx (master) 258384 \_ nginx (worker) Certificate Certificate Certificate
  15. Too many domains and certificates https://a.jp application N https://b.jp https://z.jp

    https://aa.jp … … Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate Certificate x 10,000 # ps axfo rss,cmd RSS CMD 2824 bash 512808 nginx (master) 511396 \_ nginx (worker) SIGHUP !? Certificate Certificate Certificate Certificate reproduce: https://gist.github.com/hfm/4a045a429f9303c90eac7c348d1a424a
  16. Two problems •IP address per domain ✓ TLS SNI extension

    •Web server load too many certificates
  17. Two problems •IP address per domain ✓ TLS SNI extension

    •Web server load too many certificates ➡ Dynamic certificates
  18. SSL_CTX_set_cert_cb() •available in OpenSSL 1.0.2 and later •handle certificate callback

    function •It’s called before certificate will be used by client/server •https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_cert_cb.html
  19. mruby_ssl_handshake_handler_code # simple pattern (inline) mruby_ssl_handshake_handler_code ' ssl = Nginx::SSL.new

    ssl.certificate = "/path/to/#{ssl.servername}.crt" ssl.certificate_key = "/path/to/#{ssl.servername}.key" ’;
  20. mruby_ssl_handshake_handler # simple pattern (file) mruby_ssl_handshake_handler /path/to/handler.rb cache; # /path/to/handler.rb

    ssl = Nginx::SSL.new ssl.certificate = "/path/to/#{ssl.servername}.crt" ssl.certificate_key = "/path/to/#{ssl.servername}.key"
  21. mruby_ssl_handshake_handler # simple pattern (file) mruby_ssl_handshake_handler /path/to/handler.rb cache; # /path/to/handler.rb

    ssl = Nginx::SSL.new ssl.certificate = "/path/to/#{ssl.servername}.crt" ssl.certificate_key = "/path/to/#{ssl.servername}.key" => ngx_mruby ʹ mruby_ssl_handshake_handler Λ࣮૷ͨ͠ http://blog.hifumi.info/2016/10/03/ngx_mruby-mruby_ssl_handshake_handler/
  22. Two problems •IP address per domain ✓ TLS SNI extention

    •Web server load too many certificates ✓ Dynamic certificates with ngx_mruby
  23. Dynamic certificates architecture client application cache db 1. sent server_name

    2. fetch crt/key pair from cache or db 3. proxy 2-a. set cache if missing direct pattern
  24. Dynamic certificates architecture client application cache db 1. sent server_name

    2. fetch crt/key pair 3. proxy internal api api pattern
  25. mruby_init_worker.rb conf = Ini.load_file('config.ini') redis = Redis.new(conf['redis']['server'], 6379) Userdata.new(“redis_#{Process.pid}").redis_conn =

    redis mysql = MySQL::Database.new(conf[‘mysql’][‘host’], conf[‘mysql’][‘user’], conf[‘mysql’][‘pass’], conf[‘mysql’]['db']) Userdata.new(“mysql_#{Process.pid}").mysql_conn = mysql mruby_init_worker /path/to/mruby_init_worker.rb cache; mruby_exit_worker /path/to/mruby_exit_worker.rb cache;
  26. mruby_exit_worker.rb # Close all connections redis = Userdata.new("redis_#{Process.pid}").redis_conn redis.close unless

    redis.nil? mysql = Userdata.new("mysql_#{Process.pid}").mysql_conn mysql.close unless mysql.nil? mruby_init_worker /path/to/mruby_init_worker.rb cache; mruby_exit_worker /path/to/mruby_exit_worker.rb cache;
  27. Reconnecting with nginx workers nginx master worker worker redis mysql

    Reconnection def mysql_reconnect ... mysql = MySQL::Database.new(host, user, pass, db) Userdata.new("mysql_#{Process.pid}").mysql_conn = mysql end
  28. hfm/mruby-test-mysqld •mruby porting from Test::mysqld of perl •mysqld runner for

    tests with mruby http://blog.hifumi.info/2016/09/06/mruby-test-mysqld/
  29. Testing sample (1/2) if Object.const_defined?(:MTest) class DynCrtTest < MTest::Unit::TestCase def

    setup @mysqld = TestMysqld.new(database: 'foo') @mysql = MySQL::Database.new '127.0.0.1', 'root', '', 'foo', 3306 end def teardown @mysql.close @mysqld.stop end ...