Testing Multi-Domain Subject Alternative Names Certificates
by Ramses Soto-Navarro ramses@sotosystems.com, 3/2/2023
Overview
Setup Apache
Certificate Script
Create Certificate
Second Virtual Host
Overview
Brief notes on how to create and verify multi-domain SSL certificates using the subject alternative names extension. Useful for Apache web URLs that require many different subdomains, while using one certificate. The same technique can be used for OpenSSL self-signed test certificates or official certificate signing requests, which service multiple domains with one certificate. Here we will use a Linux Red Hat 9 test scenario. The audience is experienced Linux administrators.
Setup Apache
First, modify all /etc/hosts to resolve the same test static IP address for: myexample.com, www.myexample.com, sales.myexample.com, blog.myexample.com
# vi /etc/hosts 172.24.150.154 rhel9 myexample.com sales.myexample.com blog.myexample.com
Setup Apache:
# yum install httpd mod_ssl # system enable httpd --now # systemctl status httpd
Create the welcome page:
# echo "Welcome to the myexample.com page." >> /var/www/html/index.html
Disable the firewall for test purposes:
# systemctl disable firewalld # systemctl stop firewalld
Verify that mod_ssl and https are enabled:
# httpd -M | grep ssl # netstat -tulpn | grep -i 443
Configure Apache for myexample.com as the main web page:
# vi /etc/httpd/conf/httpd.conf<!DOCTYPE html> ServerName myexample.com ServerRoot "/etc/httpd" Listen 80 Include conf.modules.d/*.conf User apache Group apache ServerAdmin root@myexample.com <Directory /> AllowOverride none Require all denied </Directory> DocumentRoot "/var/www/html" <Directory "/var/www"> AllowOverride None Require all granted </Directory> <Directory "/var/www/html"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> ... IncludeOptional conf.d/*.conf </html>
Configure the default SSL virtual host for the same URL:
# vi s/etc/httpd/conf.d/ssl.conf<!DOCTYPE html> ... Listen 443 https <VirtualHost _default_:443> ErrorLog logs/ssl_error_log TransferLog logs/ssl_access_log LogLevel warn SSLEngine on SSLHonorCipherOrder on SSLCipherSuite PROFILE=SYSTEM SSLProxyCipherSuite PROFILE=SYSTEM SSLCertificateFile /etc/httpd/certs/myexample.com.crt SSLCertificateKeyFile /etc/httpd/certs/myexample.com.priv.key ... </VirtualHost> </html>
Certificate Script
Modify a custom certificate script in order to make it easier to create the certificates. The script is configured to add the subject alternative names extensions. You will need to modify the variables for each subdomain to be created. The script also has examples of how to verify the certificate and its extensions.
# vi ~/bin/create-cert.sh<!DOCTYPE html> #!/bin/bash # by Ramses Soto-Navarro <ramses@sotosystems.com>, 3/1/2023 # Create a self-signed certificate with subject alternative name # in order to server URLs with the same domain suffix. # Also create the private key, public key and CSR. # Modify the variable below: # === VARIABLES === export DOMAIN="myexample.com" cat > req.cnf <<EOF [ req ] prompt = no default_bits = 4096 distinguished_name = req_distinguished_name req_extensions = req_ext [ req_distinguished_name ] C=US ST=FL L=Bartow O=Example LLC OU=IT Dept CN=myexample.com emailAddress=info@myexample.com [ req_ext ] subjectAltName = @alt_names [alt_names] DNS.1 = myexample.com DNS.2 = *.myexample.com IP.1 = 172.24.150.154 EOF # === Do not modify below === # Create priv key f_privkey () { echo -e "nn=== Generating private key $DOMAIN.priv.key ===" openssl genrsa -out $DOMAIN.priv.key 2048 # Verify: openssl rsa -in privateKey.key -check } # Create public key f_pubkey () { echo -e "nn=== Generating public key $DOMAIN.pub.pem ===" openssl rsa -in $DOMAIN.priv.key -pubout -out $DOMAIN.pub.pem # Verify: cat example.pub.pem } # Create CSR f_csr () { echo -e "nn=== Creating CSR $DOMAIN.csr ===" openssl req -new -key $DOMAIN.priv.key -config req.cnf -out $DOMAIN.csr # Verify: openssl req -text -noout -verify -in myexample.com.csr # Verify CSR subjectAltName: openssl req -in myexample.com.csr -text -noout | grep DNS } # Create self-signed cert f_cert () { echo -e "nn=== Generating Self-signed Certificate $DOMAIN.crt ===" openssl x509 -signkey $DOMAIN.priv.key -in $DOMAIN.csr -req -days 365 -extfile req.cnf -extensions req_ext -out $DOMAIN.crt # Verify: openssl x509 -text -noout -in myexample.com.crt } f_privkey f_pubkey f_csr f_cert </html># chmod 0755 ~/bin/create-cert.sh
Create Certificate
# mkdir -p /etc/httpd/certs # cd /etc/httpd/certs # create-cert.sh # ls -lh total 20K -rw-r--r-- 1 root root 1.4K Mar 2 07:13 myexample.com.crt -rw-r--r-- 1 root root 1.2K Mar 2 07:13 myexample.com.csr -rw------- 1 root root 1.7K Mar 2 07:13 myexample.com.priv.key -rw-r--r-- 1 root root 451 Mar 2 07:13 myexample.com.pub.pem -rw-r--r-- 1 root root 345 Mar 2 07:13 req.cnf
Now test Apache, both port 80 and 443, and verify the SSL certificate. Preferably open the web pages using Firefox. You should be able to open both ports. Inspect the certificate via Firefox afterward.
Second Virtual Host
Now let’s add and verify the second Apache virtual host, sales.myexample.com, which will use the same certificate but with a different subdomain and URL.
# cd /etc/httpd/conf.d # cp ../conf/httpd.conf sales.myexample.com.conf # cp ssl.conf sales.myexample.com-ssl.conf -i # vi sales.myexample.com.conf<!DOCTYPE html> <VirtualHost *:80> ServerName sales.myexample.com ServerRoot "/etc/httpd" ServerAdmin root@myexample.com DocumentRoot "/var/www/html/sales.myexample.com" <Directory "/var/www"> AllowOverride None # Allow open access: Require all granted </Directory> <Directory "/var/www/html/sales.myexample.com"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory> ... </VirtualHost> </html>
Next add the test Apache, port 443 virtual host.
# vi sales.myexample.com-ssl.conf<!DOCTYPE html> ... <VirtualHost *:443> DocumentRoot "/var/www/html/sales.myexample.com" ServerName sales.myexample.com:443 ... SSLEngine on SSLCertificateFile /etc/httpd/certs/myexample.com.crt SSLCertificateKeyFile /etc/httpd/certs/myexample.com.priv.key ... </VirtualHost> </html>
Create the document for the new virtual host.
# mkdir -p /var/www/html/sales.myexample.com # echo "Welcome to sales.myexample.com" >> /var/www/html/sales.myexample.com/index.html # systemctl restart httpd # systemctl status httpd
Using firefox browse to http://sales.myexample.com and https://sales.myexample.com. It should display “Welcome to sales.myexample.com”.
Now follow the logic and try blog.myexample.com and it should display another page as well. They are three separate web virtual hosts using the same certificate.
For official Root CA certificates send the CSR and insert the returned certificate instead.
The End.