Kaynağa Gözat

PROD-1704: Client certificate improvements

* Separate server blocks for VEN vs. Admin traffic
* Enforce chain of trust for VEN via cert chain in clientssl.crt
* Require VEN clients to provide a client certificate
* Document certificate file structure
Blake Schneider 6 yıl önce
ebeveyn
işleme
39597bc05f
3 değiştirilmiş dosya ile 51 ekleme ve 19 silme
  1. 9 3
      README.md
  2. 3 0
      docker-compose.yml
  3. 39 16
      nginx.conf

+ 9 - 3
README.md

@@ -31,8 +31,12 @@ chmod +x /usr/local/bin/docker-compose
 Now clone this repo to `/root/epri-vtn_custom`. Install the following files:
 
 * `/root/epri-vtn_custom/.env` Environment variables for docker-compose, use `example.env` as a starting place and be sure to change `RAILS_SECRET_TOKEN`.
-* `/root/epri-vtn_custom/ssl.crt` VTN certificate file in PEM format. This will be the concatenated result of 3 certificates: 1) VTN cert `TEST_RSA_VTN_2003XXXXXXXXX_cert.pem`, 2) Root Cert Authority `TEST_OpenADR_RSA_RCA0002_Cert.pem`, 3) Service Provider `TEST_OpenADR_RSA_SPCA0002_Cert.pem`. Certificates must be present in that order.
-* `/root/epri-vtn_custom/ssl.key` VTN key file in PEM format. This will come from a file that looks like `TEST_RSA_VTN_2003XXXXXXXXX_privkey.pem`.
+* `/root/epri-vtn_custom/ssl.crt` VTN certificate file in PEM format. This will be the concatenated result of 3 certificates from the VTN cert bundle (e.g. TEST_RSA_VTN_2003XXXXXXXXX_certs.zip): 1) VTN cert `TEST_RSA_VTN_2003XXXXXXXXX_cert.pem`, 2) Root Cert Authority `TEST_OpenADR_RSA_RCA0002_Cert.pem`, 3) Service Provider `TEST_OpenADR_RSA_SPCA0002_Cert.pem`. Certificates must be present in that order.
+* `/root/epri-vtn_custom/ssl.key` VTN key file in PEM format. This will come from a file that looks like `TEST_RSA_VTN_2003XXXXXXXXX_privkey.pem` in the VTN cert bundle.
+* `/root/epri-vtn_custom/clientssl.crt` VEN CA certificate file in PEM format. This will be the concatenated result of 2 certificates from the VEN cert bundle (e.g. TEST_RSA_VEN_2003XXXXXXXXX_certs.zip): 1) Intermediate "MCA" cert `TEST_OpenADR_RSA_MCA0002_Cert.pem`, 2) Root "RCA" cert `TEST_OpenADR_RSA_RCA0002_Cert.pem`. Certificates must be present in that order. nginx uses this to validate client certificates.
+* `/root/epri-vtn_custom/adminssl.crt` Admin WEB UI certificate. This is a plain HTTPS TLS certificate, it can be LetsEncrypt, a paid-for cert from a CA, or even a
+self-signed certificate if the risk profile is acceptable. Main certificate first, any chained "ca bundle" certs after that.
+* `/root/epri-vtn_custom/adminssl.key` Private key for the first certificate in `adminssl.crt`.
 
 ### Provision database
 This step needs to be ran on a fresh database. Once it has been ran there will be no need to re-provision the database again even if EPRI is updated.
@@ -43,7 +47,9 @@ Edit `docker-compose.yml` and uncomment the `# command: initdb` line. Now run
 docker-compose up --build
 ```
 
-And you should see a message `initdb finished successfully`. When you see that you can Ctrl-C to kill the session and comment out the `command: initdb` line.
+This process may take a long time, 15 minutes or so, especially on the `RUN rake assets:precompile` step. This is normal.
+
+You should see a message `initdb finished successfully`. When you see that you can Ctrl-C to kill the session and comment out the `command: initdb` line.
 
 ### Run EPRI
 Ensure `command: initdb` is commented out. Run

+ 3 - 0
docker-compose.yml

@@ -11,6 +11,9 @@ services:
       - "./nginx.conf:/etc/nginx/conf.d/default.conf"
       - "./ssl.crt:/etc/ssl/ssl.crt"
       - "./ssl.key:/etc/ssl/ssl.key"
+      - "./clientssl.crt:/etc/ssl/clientssl.crt"
+      - "./adminssl.crt:/etc/ssl/adminssl.crt"
+      - "./adminssl.key:/etc/ssl/adminssl.key"
     depends_on:
       - rails
     restart: unless-stopped

+ 39 - 16
nginx.conf

@@ -5,24 +5,17 @@ map $ssl_client_s_dn $ssl_client_s_dn_cn {
 
 server {
     listen 443 ssl;
-    server_name localhost;
+    # TODO: nginx doesn't natively support env variable expansion here, but
+    # you can eventually create a custom Dockerfile/entrypoint to populate
+    # this value from an env variable rather than hard-coding.
+    server_name vtn1.bsch.ca;
     root /dev/null;
     
-    # TODO: once the JACE sends an official Kyrio cert, this can be set to 
-    # 'on' so the trust-chain is verified against the CA certs in ssl.crt.
-    # Also may require tuning of ssl_verify_depth directive.
-
-    # In its current state EPRI will validate that the client cert's CN
-    # is correct, but in theory someone could spoof it with a self-signed
-    # certificate containing the "correct" CN.
-
-    # Also note that webui admin routes will likely be hit without a client
-    # cert, so you will probably want to either:
-    # a) have a seperate server/vhost for VEN traffic vs. admin traffic
-    # b) leave ssl_verify_client at optional or optional_no_ca, and match
-    #    on $ssl_client_verify in a location block.
-
-    ssl_verify_client optional_no_ca;
+    # next 3 lines force clients to provide a client cert, and ensure that the
+    # cert is trusted by the chain in clientssl.crt.
+    ssl_verify_client on;
+    ssl_client_certificate /etc/ssl/clientssl.crt;
+    ssl_verify_depth 2;
 
     # Don't advertise
     server_tokens off;
@@ -51,3 +44,33 @@ server {
     ssl_certificate /etc/ssl/ssl.crt;
     ssl_certificate_key /etc/ssl/ssl.key;
 }
+
+server {
+    listen 443 ssl;
+    server_name admin.vtn1.bsch.ca;
+    root /dev/null;
+
+    # Don't advertise
+    server_tokens off;
+
+    # Don't merge slashes
+    merge_slashes off;
+
+    location / {
+        proxy_set_header  X-Real-IP        $remote_addr;
+        proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
+        proxy_set_header  Host             $http_host;
+        proxy_set_header  X-Forwarded-Proto $scheme;
+        proxy_set_header  X-Forwarded-Ssl on;
+        proxy_set_header  X-Forwarded-Port $server_port;
+        proxy_set_header  X-Forwarded-Host $host;
+
+        proxy_set_header  HTTPS true;
+
+        proxy_redirect    off;
+        proxy_pass http://vtn-rails:8080;
+    }
+
+    ssl_certificate /etc/ssl/adminssl.crt;
+    ssl_certificate_key /etc/ssl/adminssl.key;
+}