Home SAN certificates for local development
Post
Cancel

SAN certificates for local development

Generate and trust your own SAN certificates with OpenSSL to replicate HTTPS in a local development environment.

Using SSL/TLS certificates in a local development environment might seem like an optional step, but it brings real, practical benefits: it helps us get comfortable configuring and handling HTTPS, allows us to catch security issues early, and smooths the transition to production. In this article, we’ll walk through how to generate SAN (Subject Alternative Name) certificates with OpenSSL and act as our own private Certificate Authority (CA) — a free solution that stays compatible with modern browsers and systems.

Although the term “SSL certificate” remains in common use for historical reasons, modern certificates are actually “SSL/TLS certificates.” TLS is a newer version of SSL that addresses some of its security vulnerabilities.

How to get an SSL certificate

When obtaining an SSL certificate for an application or service, there are three main options:

  • a self-signed certificate
  • a certificate issued by a public CA
  • a certificate signed by a private CA

Choosing the right SSL certificate always depends on your specific needs. Although all three can be used in a local development environment, they are not equally suitable for every purpose. Let’s look at them one by one.

Self-signed certificates

Self-signed certificates are signed by the user or entity that created them. This means that they have not been validated by a trusted third party, such as a Certificate Authority (CA). Although they are free and easy to create, they also have the following disadvantages:

  • Web browsers and most applications display a security alert, forcing you to explicitly ignore the warning or configure applications not to verify the CA by default, which encourages insecure behavior.
  • They cannot prevent spoofing (nor can they be revoked), allowing for man-in-the-middle attacks, where an attacker intercepts and possibly alters communication between the two parties.

Self-signed certificates are signed with their own private key.

Certificates issued by a public CA

Public CAs are audited and approved by independent organizations to ensure that they meet security standards. As a result, certificates issued by these CAs are considered trustworthy by both servers and clients. Although this option is indispensable for publishing services on the Internet, it has the following drawbacks in a local environment:

  • You need to own a domain name through a domain registrar, whether free or paid, for which to issue the certificate.
  • Private keys may be accidentally exposed, allowing an attacker to impersonate the server or access confidential information.
  • Issuing these certificates usually involves a licensing fee, which can increase development costs.

What about Let’s Encrypt? Although certificates issued by Let’s Encrypt are completely free, both issuance and renewal (required every 90 days) still require domain validation, which is usually a problem if:

  • The local development environment cannot be publicly accessed (usual scenario).
  • The domain registrar does not offer a REST API to automate the process without user interaction.

Certificates issued by a public CA can technically be signed either by its root certificate or by an intermediate one. However, the common practice is to use the intermediate certificate as a bridge to keep the private key of the root certificate secure.

It is important to note that a public CA is not the same as a trusted CA, so it is crucial to make sure that the CA of choice has a good reputation for security standards. Some of the most reputable public CAs are, among others: Comodo, DigiCert, GoDaddy, GeoTrust and Let’s Encrypt.

Certificates issued by a private CA

Certificates issued by a private CA (also known as an internal or enterprise CA) are intended for internal use, such as within a specific organization or local network where you can control which certificates are trusted. Because they are free and do not require domain registration, they are ideal for local development environments.

They do, however, introduce an additional layer of management:

  • Installing the private CA’s root and intermediate certificates, if any, in each client’s certificate store. They are not included in the trust lists of web browsers and operating systems—in other words, they are not trusted on the Internet.
  • Configuring the local hosts file or internal DNS to resolve domain names to the correct IP addresses, because internally used domain names may not be publicly resolvable.

Certificates issued by a private CA can be signed by either its root certificate or an intermediate certificate. Whether to issue intermediate certificates depends on the security needs, structure, and size of the internal environment.

The terms self-signed and self-issued are sometimes incorrectly interchanged. The key point is that, while self-signed certificates explicitly refer to a certificate where the entity signs itself, self-issued certificates can imply both a self-signed certificate and a certificate issued by a private CA. In short, all self-signed certificates are self-issued, but not all self-issued certificates are self-signed.

A little background

The first SSL certificates, introduced in 1994, only supported the Common Name (CN) attribute in the subject field to identify the primary domain. However, relying solely on the CN attribute for domain validation had the following limitations:

  • It can contain only one domain name or wildcard, making it unsuitable for certificates that need to secure multiple domains or subdomains.
  • It does not clearly specify the purpose or use of the name, which has led to ambiguity and security errors in the past.
  • It is limited to 64 characters, which may not be sufficient for some descriptive names or titles.

In 1999, the Subject Alternative Name (SAN) extension was introduced as part of the X.509 standard for digital certificates to address the limitations of the CN field. Since then, modern browsers and systems have increasingly adopted it, as highlighted in the following RFCs:

  • RFC 2818 (May 2000): recommends using the Subject Alternative Name (SAN) extension of the DNS name type instead of CN.
  • RFC 5280 (May 2008): states that the subject name MAY be carried in the subject field and/or the subjectAltName extension.
  • RFC 6125 (March 2011): states that the validator must check SAN first, and if SAN exists, then CN should not be checked.

Since version 58 (April 2017), Chrome has used the SAN extension exclusively for domain validation, returning an ERR_CERT_COMMON_NAME_INVALID error when it is missing.

Issuing a SAN certificate through a private CA

In general, issuing a CA-signed certificate involves the following steps:

  1. Create a private key (KEY) in a secure environment.
  2. Create a Certificate Signing Request (CSR) using the KEY.
  3. Create a certificate (CRT) by having the CA sign the CSR.

Because we are going to act as a private CA, we first need to create its root certificate. In the following sections, feel free to choose the validity period and the file and domain names that work best for you.

Always remember to keep your private keys and CSRs secure. Anyone with access to them can impersonate your servers.

Issuing the private CA

Because no higher authority can sign the CA’s root certificate, it must be self-signed. As a result, there is no need to generate a CSR: both the private key and the self-signed root certificate can be created in a single step.

1
2
3
4
5
openssl req -x509 -sha256 -newkey rsa:2048 -nodes \
	-keyout ca.key \
	-out ca.crt \
	-days 365 \
	-subj '/CN=Homenet CA'

The command creates a self-signed certificate with a 2048-bit RSA private key that has no passphrase and is valid for one year. The certificate and private key are stored in ca.crt and ca.key, respectively.

Root certificates, whether public or private, are not signed by another CA; they are self-signed. A public CA’s trustworthiness depends on the trust placed in it by independent entities.

Issuing the SAN certificate

First, create the Certificate Signing Request (CSR), which contains the information that the CA will use to sign the certificate.

1
2
3
4
5
openssl req -newkey rsa:2048 -nodes \
	-keyout star_home_arpa.key \
	-out star_home_arpa.csr \
	-subj '/CN=*.home.arpa' \
	-addext 'subjectAltName=DNS:*.home.arpa'

The CSR and private key are stored in star_home_arpa.csr and star_home_arpa.key, respectively. The certificate’s common name is the wildcard domain *.home.arpa, which is also added as a Subject Alternative Name.

You can add as many additional domains as you need by adding more DNS:FQDN pairs separated by commas in the subjectAltName field. If you use an IP address, prefix it with IP: instead of DNS:.

Finally, send the CSR to the private CA to obtain the signed certificate.

1
2
3
4
5
6
openssl x509 -req -sha256 -CAcreateserial -copy_extensions copy \
	-days 365 \
	-in star_home_arpa.csr \
	-CA ca.crt \
	-CAkey ca.key \
	-out star_home_arpa.crt

The command takes star_home_arpa.csr, signs it with the CA’s private key ca.key, and writes a new X.509 certificate to star_home_arpa.crt. The new certificate is valid for one year and includes any extensions present in the CSR.

The use of the home.arpa name for local domains is recommended by RFC 8375 because routers and DNS servers are, in theory, aware that ARPA requests they do not understand should not be forwarded to the public Internet. This helps avoid conflicts with public Internet domain names and provides a secure namespace for local networks.

Verifying the SAN extensions in the certificate

To confirm that the certificate includes the SAN extension, look for the X509v3 extensions section in the output of the following command:

1
openssl x509 -noout -text -in star_home_arpa.crt

If the certificate includes the extension, you will see a line starting with X509v3 Subject Alternative Name, followed by the configured domains. In this case:

1
2
3
4
5
...
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:*.home.arpa
...

Installing the root CA certificate

Keep in mind that the certificate generated above is signed by your private CA, which clients do not trust by default. To establish a chain of trust for certificates signed by it, install the root CA certificate in every operating system where those certificates must be trusted.

Windows

On Windows, you can install the certificate at either scope: on the local machine, which requires administrator privileges, or for the current user. The following steps use either the PowerShell CLI or the Certificate Manager Console GUI.

PowerShell

  • User scope: This installs the certificate for a specific user account on the system, making it only accessible to that particular user and any applications they run.

    1
    
      Import-Certificate -FilePath .\ca.crt -CertStoreLocation Cert:\CurrentUser\Root
    
  • Machine scope (as administrator): This installs the certificate for the entire computer, making it accessible to all user accounts and applications running on that machine. This is the most common option for certificates essential to system-wide security.

    1
    
      Import-Certificate -FilePath .\ca.crt -CertStoreLocation Cert:\LocalMachine\Root
    

Certificate Manager Console

The installation procedure is the same for both scopes; only the shortcut used to open the console differs in step 1:

  1. Press the Windows Key + R to open the ‘Run’ dialog box and type:
    • certmgr.msc for user scope
    • certlm.msc for machine scope (as admin)
  2. Expand ‘Certificates’ / ‘Trusted Root Certification Authorities’ / ‘Certificates’.
  3. Right-click the ‘Trusted Root Certification Authorities’ folder and select ‘All tasks’ / ‘Import…’.
  4. Type the file name or click Browse and select the certificate you want to import.
  5. Select ‘Place all certificates in the following store’ and use ‘Trusted Root Certification Authorities’ as the ‘Certificate store’.

Linux

Unlike Windows, Linux does not have a unified user-level certificate store. Instead, certificates are usually stored in specific directories on the file system. To install a certificate in the system certificate store, follow these steps as an administrator:

  1. Copy the ca.crt certificate to the CA store directory.

    1
    
     sudo cp ca.crt /usr/local/share/ca-certificates/ca.crt
    
  2. Set the appropriate permissions on the ca.crt certificate.

    1
    
     sudo chmod 664 /usr/local/share/ca-certificates/ca.crt
    

    755: Directories should be accessible by anyone but only writable by the root user.
    644: Certificates need to be readable by any user or service that needs to verify authenticity.
    600: Private keys associated with certificates should only be readable by the root user.

  3. Finally, update the CA store for the changes to take effect.

    1
    
     sudo update-ca-certificates
    

Some programs may have their own certificate store, and you may need to import your certificate into those specific certificate stores, such as with Firefox or Chrome.

Editing your hosts file

The hosts file is a simple file that maps domain names to IP addresses. When your browser or another application uses a domain name, it checks the hosts file first for an entry. If one exists, the associated IP address is used to access the website. Otherwise, the application queries the local DNS resolver, or a public one if the local resolver does not exist or is not authoritative for the requested domain.

Because local domains are not registered on public DNS servers, you can edit your system’s hosts file if you do not have, or do not want to use, a local DNS server. This provides a manual way to map local domain names to IP addresses.

The hosts file paths for most Linux distributions and Windows systems are:

  • Linux: /etc/hosts
  • Windows: C:\Windows\System32\drivers\etc\hosts

A typical hosts file might look something like this:

1
2
3
4
5
6
7
8
127.0.0.1       localhost
::1             localhost

# Example entry for a local server
192.168.1.100   www.home.arpa

# Example of blocking a web site
0.0.0.0         www.example.com

In this example, localhost is associated with the IP addresses 127.0.0.1 and ::1, which are the standard loopback IP addresses for IPv4 and IPv6, respectively.

The line 192.168.1.100 www.home.arpa shows how to associate a local domain name with an IP address on your local network.

The line 0.0.0.0 www.example.com shows how to block access to a specific website by redirecting its domain name to an invalid IP address.

Lines beginning with # are comments and do not affect hostname resolution. You can use comments to add notes or to temporarily disable certain entries.

Conclusion

In this post, we’ve covered how to act as a private certificate authority and issue basic SAN-signed certificates in just a few steps. This lets us obtain certificates for local development without relying on third parties, in a lightweight and free way, while respecting current standards and staying compatible with modern browsers and systems. We’ve also seen how to make clients trust these certificates and how to map local domains by editing the hosts file.

These certificates can also be useful, for example, in TLS Secret objects within an on-premises Kubernetes cluster, letting us assign domain names to the services running there. In an upcoming post, I’ll explain how to automate this process using a load-balancer-type Ingress Controller.

This post is licensed under CC BY 4.0 by the author.
Contents