{"id":724,"date":"2019-10-09T18:38:00","date_gmt":"2019-10-09T23:38:00","guid":{"rendered":"http:\/\/zewwy.ca\/?p=724"},"modified":"2023-09-19T22:12:44","modified_gmt":"2023-09-20T03:12:44","slug":"run-bitwardenrs-with-internal-pki","status":"publish","type":"post","link":"https:\/\/zewwy.ca\/index.php\/2019\/10\/09\/run-bitwardenrs-with-internal-pki\/","title":{"rendered":"Run BitWardenRS with Internal PKI"},"content":{"rendered":"<p>I recently covered installing BitWarden_RS, that used let&#8217;s encrypt which is great for public service type.<\/p>\n<p>Private industry that like to run on prem sometimes doesn&#8217;t want to have the front end exposed to the interwebs, and without any direct NAT and sec rules to allow external entities to hit the bitwarden server at all, HTTP validation (which these scripts use) will fail, even if you configured them to use DNS validation, getting the certs on the server still requires access of some kind if automation is wanted.<\/p>\n<p>With an internal PKI the life of certs can be greatly extended and also kept entirely in-house, if one so pleases.<\/p>\n<p>So this Guide continues on after the last just before letsencrypt is installed but after the NginX setup as been configured to allow the challenges, I might simply pull that part of the includes part of the NginX config as it won&#8217;t be needed but lets move on.<\/p>\n<p>Now the letsencrypt uses etc\/letsencrypt path to store certs n keys. Since I will be using this all just for nginx, i&#8217;lll use \/etc\/nginx\/certs:<\/p>\n<pre>mkdir \/etc\/nginx\/certs<\/pre>\n<pre>cd \/etc\/nginx\/certs<\/pre>\n<pre>openssl req -new -newkey rsa:2048 -nodes -keyout bwserver.key -out bwserver.csr<\/pre>\n<p><a href=\"https:\/\/i.imgur.com\/aaZqxUt.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/aaZqxUt.png\" alt=\"\" width=\"1096\" height=\"463\" \/><\/a><\/p>\n<p>use cat to open the CSR n copy n paste the contents:<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/vAqkBY7.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/vAqkBY7.png\" alt=\"\" width=\"443\" height=\"285\" \/><\/a><\/p>\n<p>Navigate to your internal CA server, request cert -&gt; advanced template to use: Web Server, Paste your CSR<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/WtlOCit.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/WtlOCit.png\" alt=\"\" width=\"717\" height=\"579\" \/><\/a><\/p>\n<p>THen save the file (for now I saved both Base 64 and DER and used WinSCP to copy them to the server<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/jK847Bt.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/jK847Bt.png\" alt=\"\" width=\"1063\" height=\"461\" \/><\/a><\/p>\n<p>now I noticed that the config uses PEM files so I found out<a href=\"https:\/\/knowledge.digicert.com\/solution\/SO26210.html\"> how to convert the certs<\/a> into what I need:<\/p>\n<pre>openssl x509 -inform der -in \/home\/zewwy\/bwserverCert.der -out \/etc\/nginx\/certs\/bwserver.pem<\/pre>\n<pre>$EDIT sites-available\/bitwarden<\/pre>\n<p>Adjust the HTTPS section under the HTTP section accordingly:<\/p>\n<pre><code>#\r\n# HTTPS\r\n#\r\n# This assumes you're using Let's Encrypt for your SSL certs (and why wouldn't\r\n# you!?)... https:\/\/letsencrypt.org\r\nserver {\r\n    # add [IP-Address:]443 ssl in the next line if you want to limit this to a single interface\r\n    listen 0.0.0.0:443 ssl;\r\n    ssl on;\r\n    ssl_certificate \/etc\/letsencrypt\/live\/[your domain]\/fullchain.pem;\r\n    ssl_certificate_key \/etc\/letsencrypt\/live\/[your domain]\/privkey.pem;\r\n    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\r\n    # to create this, see https:\/\/raymii.org\/s\/tutorials\/Strong_SSL_Security_On_nginx.html\r\n    ssl_dhparam \/etc\/ssl\/certs\/dhparam.pem;\r\n    keepalive_timeout 20s;<\/code> <code>    server_name [your domain];\r\n    root \/home\/data\/[your domain];\r\n    index index.php;<\/code> <code>    # change the file name of these logs to include your server name\r\n    # if hosting many services...\r\n    access_log \/var\/log\/nginx\/[your domain]_access.log;\r\n    error_log \/var\/log\/nginx\/[your domain]_error.log;<\/code> <code>    location \/notifications\/hub\/negotiate {\r\n        proxy_pass http:\/\/127.0.0.1:8080;\r\n        proxy_set_header Upgrade $http_upgrade;\r\n        proxy_set_header Connection \"upgrade\";\r\n        proxy_set_header Host $http_host;\r\n        proxy_set_header X-Real-IP $remote_addr;\r\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\r\n        proxy_set_header X-Forwarded-Host $server_name;\r\n        proxy_set_header X-Forwarded-Proto https;\r\n        proxy_connect_timeout 2400;\r\n        proxy_read_timeout 2400;\r\n        proxy_send_timeout 2400;\r\n    }<\/code> <code>    location \/ {\r\n        proxy_pass http:\/\/127.0.0.1:8080;\r\n        proxy_set_header Upgrade $http_upgrade;\r\n        proxy_set_header Connection \"upgrade\";\r\n        proxy_set_header Host $http_host;\r\n        proxy_set_header X-Real-IP $remote_addr;\r\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\r\n        proxy_set_header X-Forwarded-Host $server_name;\r\n        proxy_set_header X-Forwarded-Proto https;\r\n        proxy_connect_timeout 2400;\r\n        proxy_read_timeout 2400;\r\n        proxy_send_timeout 2400;\r\n    }<\/code> <code>    location \/notifications\/hub {\r\n        proxy_pass http:\/\/127.0.01:3012;\r\n        proxy_set_header Upgrade $http_upgrade;\r\n        proxy_set_header Connection \"upgrade\";\r\n    }\r\n    #\r\n    # These \"harden\" your security\r\n    add_header 'Access-Control-Allow-Origin' \"*\";\r\n}<\/code><\/pre>\n<p>in this case I adjusted my certs to my now internal signed ones:<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/VIaBZ6G.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/VIaBZ6G.png\" alt=\"\" width=\"939\" height=\"1163\" \/><\/a><\/p>\n<p>After this follow the remaing part of the bitwarden install guide&#8230; when I did I was able to get it up but I got a cert error, at first it was cause in my enviroment, I didn&#8217;t have my offline-root cert installed on the client, so after I got that, and verified my intermidate sub CA was good, I verified it by navigating to my CA certsrv site and it was all green&#8230; yet I was getting an error even though my chain was green across the board&#8230;.<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/xjDp6Pe.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/xjDp6Pe.png\" alt=\"\" width=\"838\" height=\"330\" \/><\/a><\/p>\n<p>Oh yeah&#8230;. shit Chrome requires a SAN even if no alternative names is ever planned to be used, &#8230;. THanks Google!<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/BHuMcM0.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/BHuMcM0.png\" alt=\"\" width=\"431\" height=\"380\" \/><\/a><\/p>\n<p>ok&#8230; lets backup a bit&#8230; stop the docker instance::<\/p>\n<pre>docker-compose stop<\/pre>\n<p>Now I should just need to reconfigure that nginx bitwarden file after creating new certificates with a SAN in it&#8230; but how to do that with OpenSSL&#8230;. lil more googling I found <a href=\"https:\/\/langui.sh\/2009\/02\/27\/creating-a-subjectaltname-sanucc-csr\/\">this great guide<\/a> by Paul Kehrer almost 10 years ago&#8230; first thing I read is &#8230;<\/p>\n<p>&#8220;SAN CSRs cannot be generated using the interactive prompt in OpenSSL&#8221; &#8230; Why?! it&#8217;s now literally standard&#8230; and the prompts don&#8217;t even ask for it.. what is this an IMSVA?! :@<\/p>\n<p>anyway&#8230; lets following along<\/p>\n<pre>cd \/etc\/nginx\/certs\r\nnano req.conf<\/pre>\n<pre>[ req ]\r\ndefault_bits        = 2048\r\ndefault_keyfile     = bwserverSAN.key\r\ndistinguished_name  = req_distinguished_name\r\nreq_extensions     = req_ext # The extentions to add to the self signed cert\r\n\r\n[ req_distinguished_name ]\r\ncountryName           =\r\n \r\n\r\nCA\r\ncountryName_default   = CA\r\nstateOrProvinceName   = MB\r\nstateOrProvinceName_default = MB\r\nlocalityName          = WPG\r\nlocalityName_default  = WPG\r\norganizationName          = ZWY\r\norganizationName_default  = ZWY\r\ncommonName            = bitwarden.zewwy.ca\r\ncommonName_max        = 64\r\n\r\n[ req_ext ]\r\nsubjectAltName          = @alt_names\r\n\r\n[alt_names]\r\nDNS.1   = bitwarden.zewwy.ca\r\nDNS.2   = www.bitwarden.zewwy.ca\r\nDNS.3   = bw.zewwy.ca\r\n\r\n<\/pre>\n<pre class=\"highlight\"><code>openssl req <span class=\"nt\">-new<\/span> <span class=\"nt\">-nodes<\/span> <span class=\"nt\">-out<\/span> myreq.csr <span class=\"nt\">-config<\/span> req.conf<\/code><\/pre>\n<p><a href=\"https:\/\/i.imgur.com\/rCaBgDZ.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/rCaBgDZ.png\" alt=\"\" width=\"862\" height=\"304\" \/><\/a><\/p>\n<p>k&#8230; checking our files, we just need to resign our new CSR&#8230;copy it back to the server with WinSCP, convert it with the openssl command, check our files are as needed:<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/M8tEvq3.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/M8tEvq3.png\" alt=\"\" width=\"1031\" height=\"101\" \/><\/a><\/p>\n<p>lets change our nginx files:<\/p>\n<pre>nano \/etc\/nginx\/sites-available\/bitwarden<\/pre>\n<p>test it, confirm it, apply it, and bring up our docker instance again:<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/QzGCAuN.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/QzGCAuN.png\" alt=\"\" width=\"843\" height=\"145\" \/><\/a><\/p>\n<p>and test it from the client side&#8230;<\/p>\n<p><a href=\"https:\/\/i.imgur.com\/t3o3Cdh.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/i.imgur.com\/t3o3Cdh.png\" alt=\"\" width=\"751\" height=\"387\" \/><\/a><\/p>\n<p>I hope this helps someone, mainly future me.<\/p>\n<p>Cheers.<\/p>\n<p>*UPDATE 2023* Very helpful thank you.<br \/>\nNote 1) When generating a new certificate, the old private key is used unless you generate a new private key.<\/p>\n<p>Note 2) you only need to restart nginx service, you don&#8217;t need to drop the container, and repull it, unless you want the latest updates to the container software.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently covered installing BitWarden_RS, that used let&#8217;s encrypt which is great for public service type. Private industry that like to run on prem sometimes doesn&#8217;t want to have the front end exposed to the interwebs, and without any direct NAT and sec rules to allow external entities to hit the bitwarden server at all, &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/zewwy.ca\/index.php\/2019\/10\/09\/run-bitwardenrs-with-internal-pki\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Run BitWardenRS with Internal PKI&#8221;<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"sfsi_plus_gutenberg_text_before_share":"","sfsi_plus_gutenberg_show_text_before_share":"","sfsi_plus_gutenberg_icon_type":"","sfsi_plus_gutenberg_icon_alignemt":"","sfsi_plus_gutenburg_max_per_row":"","footnotes":""},"categories":[8],"tags":[243,244],"class_list":["post-724","post","type-post","status-publish","format-standard","hentry","category-server-administration","tag-bitwarden","tag-internal-pki"],"_links":{"self":[{"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/posts\/724","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/comments?post=724"}],"version-history":[{"count":3,"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/posts\/724\/revisions"}],"predecessor-version":[{"id":1502,"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/posts\/724\/revisions\/1502"}],"wp:attachment":[{"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/media?parent=724"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/categories?post=724"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zewwy.ca\/index.php\/wp-json\/wp\/v2\/tags?post=724"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}