Although it may seem unnecessary, the use of SSL certificates in a local development environment is actually of crucial importance in order to promote good development practices. Their use allows us to familiarize ourselves with the configuration and handling of HTTPS, helping to identify security-related errors in advance, and thus facilitating the transition to future real production environments. Keep in mind that errors in SSL certificates can have serious consequences in terms of functionality and security, affecting end-user confidence and the reputation of your applications and services.
Although the terminology “SSL certificate” has remained in use for historical reasons, today’s certificates are actually “SSL/TLS certificates”, where TLS is simply a newer version of SSL that fixes some security vulnerabilities.
How to get an SSL certificate
When it comes to getting an SSL certificate for an application or service, we can think of using mainly one of the following options:
- a self-signed certificate
- a certificate issued by a public CA
- a certificate signed by a private CA
Choosing the right SSL certificate depends always on the specific needs, although all of them could be used in a local development environment, not all of them may suit our purpose equally well. Let’s look at them one by one.
Self-signed certificates
Self-signed certificates are certificates that have been signed by the same user or entity that created them, meaning that they have not been validated by a trusted third party, such as a Certificate Authority (CA from now on). Although they are free and easy to create or obtain, they also have the following disadvantages:
- Web browsers and most applications display a security alert inviting you to abort the connection, forcing you to explicitly ignore these warnings or configure applications to not 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 those that have been audited and approved by independent organizations to ensure security standards. This means that certificates issued by these CAs are considered trustworthy by both servers and clients. While this option is indispensable for publishing services on the Internet, they have the following drawbacks when it comes to using them in a local environment:
- Need to own a domain name through a domain registrar (whether free or not), for which to issue the certificate.
- Risk of private keys being accidentally exposed, allowing an attacker to impersonate the server or access confidential information.
- Issuance of these certificates usually involves a licensing fee, which can increase the costs of the development project.
And what about Let’s Encrypt? Well, while it is true that certificates issued by Let’s Encrypt are completely free, there is still the disadvantage that for the issuance and renewal of the certificate (required every 90 days), it is necessary to validate the domain, which is usually a problem if:
- The local development environment cannot be publicly accessed (usual scenario).
- The domain registrar does not offer an API Rest to automate the process in an unattended manner.
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 internal or enterprise CAs) are digital certificates intended for internal use only, such as a specific organization or local network, where you can control which certificates are trusted. This fact, in addition to being free and not requiring the registration of a domain name, makes them ideal for local development environments.
In exchange, however, we have to assume that they introduce an additional layer of management consisting of:
- Installation of the root and intermediate certificate (if any) of the private CA in the certificate store of each client, since they are not included in the trust list of web browsers and operating systems (in other words, they are not valid on the Internet).
- Configuration of the local hosts file or internal DNS to resolve domain names to the correct IP addresses, as domain names being used internally may not be publicly resolvable.
Certificates issued by a private CA can be signed either by its root certificate or by an intermediate certificate, the issuance of the intermediate ones will depend 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 of the Subject Property field to identify the primary domain. However, relying solely on the CN attribute for domain validation had the following main limitations:
- It can only contain one domain name or wildcard, not suitable 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 and, since then, modern browsers and systems are increasingly adhering to its use 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.
Chrome, for example, since its version 58 (April 2017) started to exclusively use the SAN extension for domain validation, throwing an
ERR_CERT_COMMON_NAME_INVALIDerror in case this is not found.
Issuing a SAN certificate through a private CA
In general, the basic steps to issue a certificate signed by a CA are:
- Creation of a private key (KEY) in a secure environment.
- Creation of the Certificate Signing Request (CSR) using the KEY.
- Creation of a certificate (CRT) signed by the CA from the CSR.
Since we are going to act as a private CA, we will have to create its root certificate first. Feel free during the following sections to choose the validity period and the file and domain names that you think are right 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
As such, there is no superior entity that can sign the CA root certificate, so it has to sign itself. For this reason it is not necessary to generate a CSR, and both the private key and the self-signed root certificate can be obtained 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'
After executing the above command, a new self-signed certificate is created with a 2048-bit RSA private key without passphrase and a validity of 1 year. The certificate and private key are stored in the ca.crt and ca.key files, respectively.
Remember, the root certificates of CAs (whether public or private) are not signed by anyone, these certificates are self-signed, and it is up to the acknowledgments of independent entities to endorse the reliability of a CA.
Issuing the SAN certificate
First of all, it will be necessary to create the certificate request (CSR), which will contain 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 the files star_home_arpa.csr and star_home_arpa.key, respectively. The common name of the certificate is the widldcar domain *.home.arpa which is also added as an alternative domain name.
You can add as many additional domains as you need by adding more
DNS:FQDNpairs separated by commas in thesubjectAltNamefield. If you use an IP address, prefix it withIP:instead ofDNS:.
Finally, the CSR created above can be sent to our 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 above takes the CSR star_home_arpa.csr, signs it with the CA’s private key ca.key, and outputs a new X.509 certificate star_home_arpa.crt. The new certificate is valid for 1 year and includes any extensions that were in the CSR.
The use of the
home.arpaname for local domains is recommended by RFC 8375, becouse routers and DNS servers are, in theory, aware not to forward ARPA requests they don’t understand to the public Internet. This helps to avoid conflicts with domain names on the public Internet and provides a secure namespace for use on local networks.
Verifying the SAN extensions in the certificate
To check if the certificate actually includes the SAN extensions, you can 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 such extensions, you will see a line starting with X509v3 Subject Alternative Name followed by the defined domains, in our 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 steps above generate a certificate signed by your own private CA, which (by sure!) is not trusted by any client as a confiable CA. Thus, in order to establish a chain of trust for the certificates signed by it, it is necessary to install the root CA certificate in the operating systems of any environment where these certificates need to be trusted.
Windows
For Windows clients we can perform the installation at both scopes, on the local machine (requires administrator privileges), or on the current user. In turn, we will see how to do this either via the PowerShell CLI or via 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 admin): This installs the certificate for the entire computer system, making it accessible to all user accounts and applications running on that machine (the most common for certificates that are essential for system-wide security).
1
Import-Certificate -FilePath .\ca.crt -CertStoreLocation Cert:\LocalMachine\Root
Certificate Manager Console
The procedure to perform the installation is the same for both scopes, depending only on which shortcut is used to access the console (step 1):
- Press the Windows Key + R to open the ‘Run’ dialog box and type:
certmgr.mscfor user scopecertlm.mscfor machine scope (as admin)
- Expand ‘Certificates’ / ‘Trusted Root Certification Authorities’ / ‘Certificates’.
- Right-click the ‘Trusted Rool Certification Authorities’ folder, select ‘All tasks’ / ‘Import…’.
- Type the file name or click Browse and select the certificate you want to import.
- Select ‘Place all certificates in the following store’ and use ‘Trusted Rool Certification Authorities’ as the ‘Certificate store’.
Linux
Linux does not have a unified user-level certificate store like Windows, instead they are usually stored in specific directories on the file system. To install a certificate in the system certificate store, you can follow these steps (as admin):
-
Copy the
ca.crtcertificate to the CA store directory.1
sudo cp ca.crt /usr/local/share/ca-certificates/ca.crt -
Make sure the permissions are right for the
ca.crtcertificate.1
sudo chmod 664 /usr/local/share/ca-certificates/ca.crt755: 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. -
Finally, update the CA store on the system to changes 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 a domain name is used by your browser or any other application, they query the hosts file first to see if there is an entry for that name. If there is, the associated IP address is used to access the web site. If there is not, either the local DNS name resolution server will be asked, or a public one, if the local one does not exist or is not authoritative for the requested domain.
So, since local domains are not registered on public DNS servers, in case you do not have or do not want to use a local DNS you can still edit the hosts file of your system by providing a manual way to map local domain names to IP addresses.
The hosts file paths for most Linux distributions, as well as for 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 is an example of how you might associate a local domain name with an IP address on your local network.
The line 0.0.0.0.0 www.example.com is an example of how you could block access to a specific web site 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.
Summary
In this post I have tried to explain how to act as a private certification authority and generate basic certificates signed by itself in a small number of steps, so that we can get certificates for local development without dependencies with third parties, and in a light and free way. All this while respecting the current standards that make it compatible with the most modern browsers and systems. We have also seen how to make our clients trust our certificates and how to get local access to the domains they represent.
These certificates can be very useful to use, for example, in TLS secret objects within our on-premise Kubernetes cluster and thus be able to give domain names to the services set up there. In a future post I will try to explain how to achieve this by means of an Ingress Controller of Load Balancer type.

Comments powered by Disqus.