{"id":3665,"date":"2019-02-16T11:35:49","date_gmt":"2019-02-16T17:35:49","guid":{"rendered":"https:\/\/dev.iachieved.it\/iachievedit\/?p=3665"},"modified":"2019-02-23T06:14:05","modified_gmt":"2019-02-23T12:14:05","slug":"tls-1-3-with-nginx-and-ubuntu-18-10","status":"publish","type":"post","link":"https:\/\/dev.iachieved.it\/iachievedit\/tls-1-3-with-nginx-and-ubuntu-18-10\/","title":{"rendered":"TLS 1.3 with NGINX and Ubuntu 18.10"},"content":{"rendered":"<p><a href=\"https:\/\/wiki.openssl.org\/index.php\/TLS1.3\"><b>TLS 1.3<\/b><\/a> is on its way to a webserver near you, but it may be a while before major sites begin supporting it.  It takes a bit of time for a new version of anything to take hold, and even longer if it&#8217;s the first new version of a protocol in <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transport_Layer_Security#TLS_1.2\">nearly 10 years<\/a>.<\/p>\n<p>Fortunately you don&#8217;t have to wait to start experimenting with TLS 1.3; all you need is <a href=\"https:\/\/www.openssl.org\/blog\/blog\/2018\/09\/11\/release111\/\">OpenSSL 1.1.1<\/a> and open source NGINX 1.15 (currently the <a href=\"http:\/\/nginx.org\/en\/CHANGES\">mainline version<\/a>), and you&#8217;re good to go.<\/p>\n<h3>OpenSSL<\/h3>\n<p><a href=\"https:\/\/www.openssl.org\/blog\/blog\/2018\/09\/11\/release111\/\">OpenSSL 1.1.1<\/a> is the first version to support TLS 1.3 and its ciphers:<\/p>\n<ul>\n<li>TLS_AES_256_GCM_SHA384<\/li>\n<li>TLS_CHACHA20_POLY1305_SHA256<\/li>\n<li>TLS_AES_128_GCM_SHA256<\/li>\n<li>TLS_AES_128_CCM_8_SHA256<\/li>\n<li>TLS_AES_128_CCM_SHA256<\/li>\n<\/ul>\n<p>Since 1.1.1 is available out-of-the-box in <a href=\"http:\/\/releases.ubuntu.com\/18.10\/\">Ubuntu 18.10 Cosmic Cuttlefish<\/a> (as well as <a href=\"https:\/\/www.freebsd.org\/releases\/12.0R\/announce.html\">FreeBSD 12.0<\/a> and <a href=\"https:\/\/alpinelinux.org\/posts\/Alpine-3.9.0-released.html\">Alpine 3.9<\/a>), we&#8217;ll be using it for this tutorial.  Note that 18.10 is <em>not<\/em> an LTS release, and the decision was made to port to OpenSSL 1.1.1 to 18.04 (Bionic Beaver), but <a href=\"https:\/\/bugs.launchpad.net\/ubuntu\/+source\/openssl\/+bug\/1797386\">it did not make it<\/a> in 18.04.2.  We like to make things easy on ourselves, and launched a publicly available ubuntu-cosmic-18.10-amd64-server-20181018 AMI in AWS.<\/p>\n<h3>NGINX<\/h3>\n<p><a href=\"https:\/\/www.nginx.com\">NGINX<\/a> hardly needs an introduction, so we&#8217;ll skip straight to its support for TLS 1.3, which came all the way back in version 1.13.0 (August 2017), well before the protocol was finalized.  Combined with OpenSSL 1.1.1, the current open source version (1.15), NGINX is fully capable of supporting TLS 1.3, including <a href=\"https:\/\/blog.cloudflare.com\/introducing-0-rtt\/\">0-RTT<\/a>.<\/p>\n<h3>Current Browser Support for TLS 1.3<\/h3>\n<p>TLS 1.3 will be a moving target for months to come, but as of this writing (February 23, 2018), here&#8217;s a view of browser support for it.  As you can see, it&#8217;s pretty limited at this point, with only the Chrome, Brave, and Firefox browsers capable of establishing a connection with a TLS 1.3-only webserver.<\/p>\n<table style='font-size:80%'>\n<tr>\n<th>OS<\/th>\n<th>Browser<\/th>\n<th>TLS 1.3 Support<\/th>\n<th>Negotiated Cipher<\/t><br \/>\n  <\/tr>\n<tr>\n<td>macOS 10.14.3<\/td>\n<td>Chrome 72.0.3626.109<\/td>\n<td>Yes<\/td>\n<td>TLS_AES_256_GCM_SHA384<\/td>\n<\/tr>\n<tr>\n<td>macOS 10.14.3<\/td>\n<td>Firefox 65.0.1<\/td>\n<td>Yes<\/td>\n<td>TLS_AES_256_GCM_SHA384<\/td>\n<\/tr>\n<tr>\n<td>macOS 10.14.3<\/td>\n<td>Brave 0.59.35<\/td>\n<td>Yes<\/td>\n<td>TLS_AES_256_GCM_SHA384<\/td>\n<\/tr>\n<tr>\n<td>macOS 10.14.3<\/td>\n<td>Safari 12.0.3 (14606.4.5)<\/td>\n<td>No<\/td>\n<td>NA<\/td>\n<\/tr>\n<tr>\n<td>macOS 10.14.4<\/d><\/p>\n<td>Safari 12.1<\/td>\n<td>Yes<\/td>\n<td>TLS_AES_256_GCM_SHA384<\/td>\n<\/tr>\n<tr>\n<td>iOS 12.2 (Beta)<\/td>\n<td>Safari<\/td>\n<td>Yes<\/td>\n<td>TLS_AES_256_GCM_SHA384<\/td>\n<\/tr>\n<tr>\n<td>Windows 10.0.17134<\/td>\n<td>IE 11.345.17134.0<\/td>\n<td>No<\/td>\n<td>NA<\/td>\n<\/tr>\n<tr>\n<td>Windows 10.0.17134<\/td>\n<td>Edge 17.17134<\/td>\n<td>No<\/td>\n<td>NA<\/td>\n<\/tr>\n<tr>\n<td>Ubuntu 18.10<\/td>\n<td>curl\/7.61.0<\/td>\n<td>Yes<\/td>\n<td>TLS_AES_256_GCM_SHA384<\/td>\n<\/tr>\n<tr>\n<td>Ubuntu 18.04.2<\/td>\n<td>curl\/7.58.0<\/td>\n<td>No<\/td>\n<td>NA<\/td>\n<\/tr>\n<\/table>\n<p>Note:  An astute reader might notice iOS 12.2 (currently in Beta) indeed <a href=\"https:\/\/mailarchive.ietf.org\/arch\/msg\/tls\/5QjzTilqjomSyzENtgfaAqQOhbA\">supports TLS 1.3<\/a> and our webserver confirms it!<\/p>\n<h2>Testing It Out<\/h2>\n<p>To test things out, we&#8217;ll turn to our favorite automation tool, <a href=\"https:\/\/www.ansible.com\">Ansible<\/a> and our <a href=\"https:\/\/github.com\/iachievedit\/tls13_nginx_cosmic\">tls13_nginx_cosmic<\/a> repository with playbooks.<\/p>\n<p>We happened to use an EC2 instance running Ubuntu 18.10, as well as <a href=\"https:\/\/letsencrypt.org\">Let&#8217;s Encrypt<\/a> and <a href=\"https:\/\/www.digitalocean.com\">Digital Ocean<\/a>&#8216;s <a href=\"https:\/\/developers.digitalocean.com\/documentation\/v2\/#domain-records\">Domain Records API<\/a>.  That&#8217;s a fair number of dependencies, but an enterprising DevOps professional should be able to take our example playbooks and scripts and modify them to suit their needs.<\/p>\n<p>Rather than return HTML content (<code>content-type: text\/html<\/code>), we return <code>text\/plain<\/code> with interesting information from NGINX itself.  This is facilitated by the <a href=\"https:\/\/www.lua.org\">LUA<\/a> programming language and <a href=\"https:\/\/github.com\/openresty\/lua-nginx-module\">LUA NGINX module<\/a>.  The magic is here in our <code>nginx.conf<\/code>:<\/p>\n<pre class=\"theme:terminal lang:default decode:true \" >\nlocation \/ {\n  default_type 'text\/plain';\n  content_by_lua_block {\n    ngx.say(\"Thanks for connecting to {{ HOSTNAME }}\");\n    ngx.say(\"\");\n    ngx.say(\"       Client User Agent:  \" .. ngx.var.http_user_agent);\n    ngx.say(\"Client supported ciphers:  \" .. ngx.var.ssl_ciphers);\n    ngx.say(\"         Selected cipher:  \" .. ngx.var.ssl_cipher);\n  }\n}\n<\/pre>\n<p>This results in output similar to:<\/p>\n<pre class=\"theme:terminal lang:default decode:true \" >\nThanks for connecting to tls13.iachieved.it\n\n       Client User Agent:  Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/72.0.3626.81 Safari\/537.36\nClient supported ciphers:  0x2a2a:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:0x000a\n         Selected cipher:  TLS_AES_256_GCM_SHA384\n<\/pre>\n<p>In all of our tests thus far, TLS_AES_256_GCM_SHA384 was chosen as the ciphersuite.<\/p>\n<h3>Qualys SSL Assessment<\/h3>\n<p>Now let&#8217;s look at what Qualys SSL Server Test has to say about our site.<\/p>\n<p><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2019\/02\/sslreportscore.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2019\/02\/sslreportscore.png\" alt=\"\" width=\"1028\" height=\"539\" class=\"aligncenter size-full wp-image-3679\" \/><\/a><\/p>\n<p>Not an A+, but notice in our <code>nginx.conf<\/code> we are not configuring <a href=\"https:\/\/en.wikipedia.org\/wiki\/HTTP_Strict_Transport_Security\">HSTS<\/a> or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Online_Certificate_Status_Protocol\">OCSP<\/a>.  Our standard Let&#8217;s Encrypt certificate is also <a href=\"https:\/\/community.letsencrypt.org\/t\/howto-a-with-all-100-s-on-ssl-labs-test-using-nginx-mainline-stable\/55033\">hampering our score here<\/a>.<\/p>\n<p>Here&#8217;s what Qualys has to say about our server configuration:<\/p>\n<p><a href=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2019\/02\/sslconfiguration.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dev.iachieved.it\/iachievedit\/wp-content\/uploads\/2019\/02\/sslconfiguration.png\" alt=\"\" width=\"950\" height=\"631\" class=\"aligncenter size-full wp-image-3681\" \/><\/a><\/p>\n<p>The highlight here is that TLS 1.3 is supported by our server, whereas TLS 1.2 is not.  This was done on purpose to not allow a connecting client to use anything but TLS 1.3.  You definitely would not do this in practice as of February 2019, as the Qualys <em>Handshake Simulation<\/em> shows.  Only Chrome 70 was able to connect to our server.<\/p>\n<h2>Closing Thoughts<\/h2>\n<p>As a DevOps practitioner, and someone who manages dozens of webservers professionally, I&#8217;m quite excited about the release and adoption of TLS 1.3.  It will, no doubt, take quite some time before a majority of browsers <i>and<\/i> sites support it.<\/p>\n<p>If you&#8217;re interested more about TLS 1.3 in general, there are a lot of great resources out there.  Here are just a few:<\/p>\n<p>Wikipedia has a good <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transport_Layer_Security#TLS_1.3\">rundown<\/a> of TLS 1.3 features and changes from TLS 1.2.<\/p>\n<p>The folks at NGINX recently hosted a webinar on R17, the latest NGINX Plus version.  TLS 1.3 and it&#8217;s benefits were covered in more detail.<\/p>\n<p>https:\/\/www.slideshare.net\/Nginx\/tls-13-and-other-new-features-in-nginx-plus-r17-and-nginx-open-source<\/p>\n<p>Here&#8217;s a great tutorial on <a href=\"https:\/\/blog.probely.com\/how-to-deploy-modern-tls-in-2018-1b9a9cafc454\">deploying modern TLS configurations (including 1.3) <\/a> from <a href=\"https:\/\/probely.com\/\">Probely<\/a>.<\/p>\n<p>And, last but not least, <a href=\"https:\/\/cloudflare.com\">Cloudflare<\/a> has a number of in-depth <a href=\"https:\/\/blog.cloudflare.com\/rfc-8446-aka-tls-1-3\/\">TLS 1.3<\/a> articles.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TLS 1.3 is on its way to a webserver near you, but it may be a while before major sites begin supporting it. It takes a bit of time for a new version of anything to take hold, and even longer if it&#8217;s the first new version of a protocol in nearly 10 years. Fortunately [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3547,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21,22,72,71],"tags":[83],"class_list":["post-3665","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-hacking","category-nginx","category-ubuntu","tag-tls-1-3"],"_links":{"self":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3665"}],"collection":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/comments?post=3665"}],"version-history":[{"count":17,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3665\/revisions"}],"predecessor-version":[{"id":3706,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/posts\/3665\/revisions\/3706"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media\/3547"}],"wp:attachment":[{"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/media?parent=3665"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/categories?post=3665"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev.iachieved.it\/iachievedit\/wp-json\/wp\/v2\/tags?post=3665"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}