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.