getting Firefox/Chrome to trust your internal websites (internal Certificate Authority)

I’m always developing internal websites in our company, for example recently I deployed a Flask-based market data connection tracker on one of our Amazon EC2 hosts

The problem is whenever I access the site via browser, its HTTPS connection is always untrusted since the browser doesnt trust my company’s Certificate Authority as a valid CA (unlike Varisign, Google, Comodo, etc)

This tutorial shows how to

  1. create an internal corporate CA
  2. deploy CA certificate to employee’s desktops and browsers
  3. generate new certificate and keys for internal websites
  4. configure a website (Apache) to use these internal certs and keys

In this example, my company’s name and Domain is Spaceballs, and my internal website is called “lonestar.spaceballs”

The gist of the whole setup is like this,

Part 1 — Create a Certificate Authority

on a Linux host (I’m using Ubuntu, but can be any flavor that has openssl installed)

create a directory which will host CA key, pem, cert as well as Certs directory that will host individual certificates for websites

mkdir -p /home/user/spaceballsCA/certs

generate a Certificate Authority key

openssl genrsa -aes256 -out spaceballsCA.key 2048

enter a passphrase, this is the Key to your entire certification structure, dont share it and dont lose it!

generate a new PEM certificate

openssl req -x509 -new -nodes -key spaceballsCA.key -sha256 -days 1024 -out spaceballsCA.pem

enter the country, state, company name, email, etc (this will be stored as metadata inside every cert you issue inside your company)

Part 2 — install CA certificate into browsers and desktops

To have a browser like Firefox or Chrome verify your website, you must inject the CA.pem cert into its trusted store

for Chrome, in the address bar type:

chrome://settings/certificates

click Manage Certificates > click on Authorities tab and click Import

select the spaceballsCA.pem file and import it

for Firefox open preferences > Privacy & Security > View Certificates

Import the PEM key

Part 3 — generate Key and Cert for internal website

create a new CSR configuration file, this will tell openssl what options to use when generating a new cert

cd /home/user/spaceballsCA
vi csr.cnf

paste the following,

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[dn]
C=US
ST=<INSERT STATE>
L=<INSERT CITY>
O=SpaceBalls, LLC
OU=Spaceballs CA
emailAddress=admin@spaceballs.com
CN = spaceballs
[alt_names]
DNS.1 = lonestar.spaceballs
DNS.2 = lonestar.spaceballs.ny
DNS.3 = lonestar.spaceballs.tx
DNS.4 = lonestar
DNS.5 = somesite.spaceballs

add as many DNS aliases as you need to the alt_names section, any website that matches this name will get certified by our CA

in this example, a website is called ‘lonestar.spaceballs’ or ‘lonestar’

now lets generate a Certificate Signing Request (CSR) plus the private key

cd /home/user/spaceballsCAopenssl req -new -sha256 -nodes -out certs/lonestar.spaceballs.csr -newkey rsa:2048 -keyout certs/lonestar.spaceballs.key -config <(cat csr.cnf)

check the “certs” folder, it will now have 2 files, a CSR and a KEY

now we generate a CRT (certificate)

openssl x509 -req -in certs/lonestar.spaceballs.csr -CA spaceballsCA.pem -CAkey spaceballsCA.key -CAcreateserial -out certs/lonestar.spaceballs.crt -days 1024 -sha256 -extfile csr.cnf

enter the CA passphrase from step 1, this will now generate a .crt file

verify your new certificate, make sure the DNS altnames match up, you will see something similar to this (note the bolded DNS aliases embedded int the cert)

openssl x509 -in certs/lonestar.spaceballs.crt -text -nooutCertificate:
Data:
Version: 3 (0x2)
Serial Number:
56:f1:d2:a9:3d:54:33:b8:cb:c0:24:d9:5b:cd:22:de:47:7a:f3:06
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = NY, L = New York, O = "Spaceballs, LLC", OU = Spaceballs CA, CN = spaceballs, emailAddress = admin@spaceballs.com
Validity
Not Before: Nov 22 20:03:45 2019 GMT
Not After : Sep 11 20:03:45 2022 GMT
Subject: C = US, ST = NY, L = New York, O = "Spaceballs, LLC", OU = Spaceballs CA, emailAddress = admin@spaceballs.com, CN = spaceballs
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:xc:b4:0c:b7:13:2a:cc:b1:dc:82:40:58:56:32:
6a:23:85:cb:e9:67:9a:8d:f1:c0:0a:54:ee:55:e5:
b8:5e:f9:2d:c4:88:f0:ec:56:e9:91:14:78:b5:b3:
92:74:e5:98:d0:7e:ed:fb:2a:25:58:e1:12:86:b4:
f4:0v:38:06:18:af:47:22:2b:59:f0:1a:00:9c:84:
b9:11:85:ba:e9:c3:b7:bc:78:e5:43:cd:46:9f:9a:
74:e3:69:62:42:15:f3:6c:dd:73:17:3f:e6:46:20:
9a:a3:b3:18:4e:fd:39:19:fd:fb:6e:f0:b7:38:03:
e9:12:a2:54:f0:60:93:37:21:4e:05:d3:82:c2:75:
61:d4:fa:2d:12:b3:82:8e:81:c3:60:13:a6:ab:c1:
01:d6:c1:4e:e2:24:b8:13:c6:7b:b1:a6:a4:57:47:
21:22:1b:0e:10:d7:fa:2c:06:84:6d:ca:7a:8e:fb:
46:fe:36:1c:18:5d:8e:77:76:c6:8c:a2:d4:cb:af:
d8:02:4f:e7:b4:4c:3d:57:4e:6d:b7:82:3a:f2:6a:
38:af:57:85:16:3e:2e:05:04:f0:4e:cd:1b:f0:bb:
4e:81:8f:80:00:77:4d:df:8b:50:80:48:41:7c:79:
17:3b:6b:c0:b4:ee:ae:23:90:4b:1a:ce:c9:fb:f4:
53:77
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:EC:AF:3B:86:ED:71:8D:8B:25:F2:FA:6D:D4:0F:F3:F0:D4:29:44:9B
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
X509v3 Subject Alternative Name:
DNS:lonestar.spaceballs, DNS:lonestar.spaceballs.ny, DNS:lonestar.spaceballs.tx, DNS:lonestar
Signature Algorithm: sha256WithRSAEncryption
22:61:bd:09:07:f1:3d:88:d3:29:3a:28:21:01:d2:93:d9:fc:
59:bf:1b:19:80:7b:81:b1:f4:3c:79:c5:eb:be:98:76:29:98:
19:a6:2f:78:51:a0:22:43:62:57:86:3a:2e:e3:3b:29:10:c7:
2e:94:73:bd:60:75:dc:79:a9:06:b6:ae:a5:0a:08:9d:fe:93:
35:4c:a1:75:42:0d:4f:4e:21:86:53:73:23:5a:f6:06:a2:7d:
60:33:63:63:61:80:5f:f3:cd:3f:d1:ef:34:1a:60:da:a7:96:
1e:6f:10:4e:de:48:cc:01:e6:d1:9b:f0:7b:53:9f:f7:92:c6:
aa:e8:e2:7e:0c:25:1a:89:71:a1:82:4a:31:70:a1:52:5f:d8:
78:0e:3b:16:15:59:67:55:88:96:ab:c4:5d:c2:7b:7e:89:e0:
32:7b:87:a9:46:38:85:41:8d:ef:e9:88:20:6d:0e:a9:be:b8:
60:6b:4f:47:8b:bc:25:54:62:0b:73:89:d3:2d:75:3d:cf:90:
1b:6c:3a:1d:a2:33:96:14:6e:7f:85:c6:52:8f:11:4f:3a:bd:
35:c9:f1:05:05:77:bb:80:4d:40:f4:18:6c:f5:0b:7b:4b:03:
b6:5a:5d:a8:d8:4a:27:b3:38:3c:07:c1:a2:c1:60:03:c8:78:
2a:ad:75:2b

rsync or copy both .crt and .key files to your web server (can place them anywhere but usually in /etc/ssl/certs/

Part 4 — configure web server to run with certificates

this will show how to run an Apache web server with your custom certs

on your web server, create a new configuration file for “lonestar.spaceballs”

web1> cd /etc/httpd/conf.d
vi lonestar.conf

add the necessary configuration, in this example, the website is a Flask python process running on port 5300

LoadModule  headers_module        /usr/lib64/httpd/modules/mod_headers.so#### LONESTARProxyRequests Off
RewriteEngine On
ErrorLog /var/log/httpd/lonestar_error.log
<VirtualHost *:80>
ServerName lonestar
ServerAlias lonestar.spaceballs
Redirect / https://lonestar
</VirtualHost><VirtualHost *:443>
ProxyPreserveHost On
ServerName lonestar
ServerAlias lonestar.spaceballs
ServerAlias lonestar.spaceballs.ny
ServerAlias lonestar.spaceballs.tx
SSLEngine On
SSLCertificateKeyFile /etc/ssl/certs/lonestar.key
SSLCertificateFile /etc/ssl/certs/lonestar.crt
AllowEncodedSlashes NoDecode
ProxyPass / http://localhost:5300/ nocanon
ProxyPassReverse / http://localhost:5300/
RequestHeader set X-Forwarded-Proto "https"
</VirtualHost>

restart apache and your browser should now show a green verified Cert sign (on Chrome it will be gray colored, since its an internal CA)

this should also work for any combination of names you put into the DNS alias, “lonestar.spaceballs, lonestar.spaceballs.ny, etc”