You usually need to purchase SSL certificate from companies for your public websites that you host. However, it is not necessary to purchase SSL certificates if the websites (any HTTP based service) are privately hosted never exposed to the outside world. You can be your own Certificate Authority.
SSL Certificate Generation Flow
Here is the diagram that shows the SSL certificate generation flow.
Why HTTPS (SSL) Internally?
Here are some reasons I can think of.
- Malicious attacks can come from internal engineers not just from outside.
- Dev/test/staging environments are better to be tested mirroring the production environment as much as possible.
- It is easier to promote the dev/test/staging environments to production by mirroring the production environment meaning less moving parts between different environments.
- It has been more of a trend in the network security world that encryption must be done from end to end.
How to Create CA Root Certificate
CA stands for Certificate Authority. You can be a small Certificate Authority. Here are the steps.
- Open terminal. (I use Linux Mint as my Linux machine but other distribution should be OK too.)
- Create a directory.
- Navigate to the directory.
- Generate the private key for your CA. Usually 2048 will suffice but we will use 4096 in this example to make it stronger.
openssl genrsa -des3 -out CA.key 4096
- Enter pass phrase when prompted. You can choose whatever you want but do not forget it because you will use it later.
- You now have CA.key (private key) file in ~/CA directory.
- Out of the private key, we will create the root certificate using the command below.
openssl req -x509 -new -nodes -key CA.key -sha256 -days 3650 -out CA.pem
- You will be prompted to enter some information about your root certificate.
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:WA
Locality Name (eg, city) :Seattle
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Hayato Iriumi
Organizational Unit Name (eg, section) :
Common Name (e.g. server FQDN or YOUR name) :hayato-iriumi.net
mail Address :firstname.lastname@example.org
- Now you have the root certificate CA.pem under ~/CA directory.
Download CA Root Certificate
If you have the certificate on a remote machine, you need to download it to a client machine to install it. Follow the steps below.
- Open your terminal on a client machine.
- Navigate to the directory where you want to download the CA.pem file.
- Use scp to download the CA.pem file.
scp amaterasu48@linux-mint:~/CA/CA.pem .
How to Install Root Certificate (on client side)
- If you are on macOS, you can execute the command to trust the root certificate.
sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" CA.pem
- Please refer to this document to install root certificate on Windows.
Create SSL Certificate Request
Now we need to generate CA key signed certificate for your web servers but first, we need to generate CSR (Certificate Signing Request). Please follow the steps below.
- Create another private key. Replace linux-mint.local with whatever the web server you want to enable SSL for.
openssl genrsa -out linux-mint.local.key 4096
- Now generate the CSR file (linux-mint.local.csr).
openssl req -new -key linux-mint.local.key -out linux-mint.local.csr
- Enter information when prompted.
Country Name (2 letter code) :US
State or Province Name (full name) :WA
Locality Name (eg, city) :Covington
Organization Name (eg, company) :Hayato Iriumi
Organizational Unit Name (eg, section) :dev
Common Name (eg, fully qualified host name) :linux-mint.local
Email Address :email@example.com
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password :YourPassword
Create SSL Certificate
We will need CA private key, CA certificate and CSR file to generate an SSL certificate. Please follow the steps below.
- Upload the CSR file from the host where you created it to the CA.
scp yourdomain.csr yourusername@yourhostname:~/CA
- There are CA.key, CA.pem and linux-mint.local.csr in ~/CA directory on the host where CA key was generated.
- Create linux-mint.local.ext file for configuration with the following content on the remote host at ~/CA.
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
DNS.1 = linux-mint.local
- At this point, I have CA.key, CA.pem, linux-mint.local.csr and linux-mint.local.ext.
- Execute the following command.
openssl x509 -req -in linux-mint.local.csr -CA CA.pem -CAkey CA.key -CAcreateserial -out linux-mint.local.crt -days 365 -sha256 -extfile linux-mint.local.ext
- It has generated
linux-mint.local.crtwhich will be used in your web server.
Implementing SSL Certificate on Web Server
There are many types of web servers. I will pick one of the most popular NGINX as an example to implement the SSL certificate that was generated in this process. Obviously, the prerequisite is that you already have NGINX up and running. There are a lot of documents out there on how to install and run NGINX.
Before you implement the SSL certficate, make sure the port 443 is open to your web server. (ufw for Debian descendent distros and firewall-cmd for RedHat descendent distros).
- Create a directory /etc/nginx/conf.d/ssl
sudo mkdir /etc/nginx/conf.d/ssl
- Copy linux-mint.local.key (the original private key that generated the CSR file) and linux-mint.local.crt (the SSL certificate file generated in the previous section) to /etc/nginx/conf.d/ssl on your NGINX server.
- Create file /etc/nginx/conf.d/ssl.conf with the following content. The first server block allows NGINX to redirect the traffic that comes to the port 80 to port 443 (HTTPS). The second server block actually takes care of the SSL part.
return 301 https://linux-mint.local;
listen 443 ssl;
- Restart NGINX.
sudo systemctl restart nginx
Accessing the SSL Enabled Web Server
Back on your client machine, make sure you can resolve whatever the address can resolve to the IP address. I will talk through my case in my private environment.
- Edit your /etc/hosts (or C:\Windows\System32\drivers\etc\hosts on Windows) and add an entry in the file just to simulate DNS server. You can alternatively have your internal DNS server but I will omit it. The following line means if the machine tries to access linux-mint.local, it skips the whole DNS query but just resolves it to 192.168.1.22 which is the IP address of the NGINX I already setup.
- Open your browser and enter linux-mint.local and hit enter.
- Now you can see the website if protected by SSL. If you click on the key icon, you get to see the certificate you created.
In this blog article, I’ve explained how to create your own CA certificate to protect internal HTTP traffic for free.