How to create self-signed SSL TLS X.509 certificates using BastionXP

Author: Ganesh Velrajan

Last Updated: Tue, Sep 12, 2023

In this article, we’ll discuss how to use BastionXP PKI/CA to create self-signed SSL X.509 certificates. These self-signed SSL X.509 certificates can be used by any HTTPS or TLS server and client applications for secure SSL/TLS connection over the internet.

For example, the generated X.509 certificates can be used to configure any webserver (Apache, NGNIX, Wordpress), Database (MySQL, Postgresql DB, MongoDB, MariaDB), Workloads(Docker containers, Kubernetes Pods, Service Mesh), IoT gateways, devices or even your own web app server(HTTPS) and web app client.

The client SSL/TLS X.509 certificate can be used to enforce mutual TLS (mTLS) authentication between client-server applications in organizations that require Zero Trust Security.

BastionXP is a web based PKI/CA that issues certificates over HTTPS requests. BastionXP CA is very simple and easy to setup. BastionXP is a open source and open standards based CA which is free to download.

Overview:

Following are the steps to generate SSL X.509 self-signed certificates:

  1. We will use the BastionXP Certificate Manager to create a Root CA certificate and private key. And, an intermediate CA certificate and private key pair.
  2. We will use the BastionXP client utility bsh to create X.509 server private key, server certificate signing request(CSR), client private key and client certificate signing request(CSR). The BastionXP client will send the CSR to the BastionXP CA server.
  3. BastionXP CA will use the intermediate CA key to sign the X.509 server certificate signing request and the X.509 client certificate signing request.
  4. Once the certificates are signed successfully, the BastionXP CA will send the self-signed X.509 server and client certificates to the bsh client. The client will store the certificate and the private key in the user’s home directory.

BastionXP Certificate Manager

Follow the steps below to download, install, configure and run BastionXP as SSL/TLS X.509 Certificate Manager.

Prerequisites

You need to have the following to install and run BastionXP Certificate Manager:

  • A Linux VM or server or WSL(Windows Subsystem For Linux).
  • TCP Port: 443

BastionXP PKI/CA VM Setup

Step 1.1 - Download and Install

Follow the instructions here to download and install BastionXP CA in a Linux machine or VM.

Step 1.2 - Configuration File

Create a directory named bastionxp under /etc in your system as shown below:

$ sudo mkdir -p /etc/bastionxp

Create a configuratin file named config.json in the /etc/bastionxp directory with the following contents.

{
    "mode": "auth",
    "gateway_domain": "localhost",
    "email": "[email protected]"
}

Step 1.3 - Restart

Now restart the BastionXP service already running in the background, to pickup the above configuration changes.

$ sudo systemctl restart bastionxp

You can check the bastionxp logs as shown below:

$ tail -f /var/lib/bastionxp/bastionxp.log

You’ll see the following logs in the log file:

Using config file: /etc/bastionxp/config.json
Creating TLS Root CA certificate at:  /var/lib/bastionxp/tls_root_ca.crt
Root CA Fingerprint:  35a85a609a703ab0984ba652ce0d3e0da1397aadc992b0139205f5c45dfd73a5
Creating TLS Intermediate CA certificate at:  /var/lib/bastionxp/tls_intermediate_ca.crt
Creating Auth Server Host Certificate at:  /var/lib/bastionxp/server.crt
...
...

Note the Root CA fingerprint 35a85a609a703ab0984ba652ce0d3e0da1397aadc992b0139205f5c45dfd73a5 in the above log. You’ll use this fingerprint later to establish trust with this CA.

Get a Server Certificate

To get a server certificate from the CA, we need to use the BastionXP client utility: bsh

Step 2.1 - Download BastionXP client

Follow the instructions here to download and install BastionXP Client bsh in your machine.

Step 2.2 - Establish Trust with the Certificate Manager

Before we can get SSL/TLS certificates from the CA, we need to make the bsh client trust the BastionXP CA.

This is required because the Certificate Manager is running locally on localhost and using a self-signed SSL/TLS certificate for the localhost domain name.

Use the fingerprint collected from the BastionXP CA setup logs above and make the client trust the CA.

$ bsh init --auth-server localhost --fingerprint 35a85a609a703ab0984ba652ce0d3e0da1397aadc992b0139205f5c45dfd73a5

Downloading Root CA certificates... Please wait.
Successfully downloaded Root CA TLS certificates.

The above command will download the Root CA’s certificate named tls_root_ca.crt to a local folder named .bsh in your home directory: Eg: /home/bob/.bsh/tls_root_ca.crt

$ ls ~/.bsh

tls_root_ca.crt 

Now you can optionally add the BastionXP Root CA certificate to your system’s certificate trust store, as shown below for debian variants:

$ sudo cp ~/.bsh/tls_root_ca.crt /usr/local/share/ca-certificates/.
$ sudo update-ca-certificates

Here after your system will start trusting all certificates issued by the BastionXP Certificate Manager.

Step 2.3 - Get the Server Cerfiticate

Now, we are ready to get a signed server certificate from the CA using the below command.

$ bsh login  --auth-server localhost   --no-auth --host localhost

Downloaded long-lived SSH & TLS certificates for the host.

You can find the SSL/TLS server certificate and private key in the following location: /home/bob/.bsh

$ ls ~/.bsh
...
tls_server.crt  
tls_server.key
...

Get a Client Certificate

Step 3.1 - Download the Client Certificate

Again, use the bsh client to get a client certificate from the BastionXP CA for a specific user named bob. You can provide any name.

$ bsh login  --auth-server localhost --user bob --no-auth 

Downloading certificates... Please wait.
Successfully downloaded short-lived certificates.
Your roles are: [].  Your access expires in 8 hours.

If you don’t provide a --user in the above CLI, the BastionXP CA will issue the client certificate with CN and SAN fields set to the admin user of the BastionXP CA server (in this case, [email protected]), by default.

Security Note: When OIDC SSO based login is used to issue identity based client certificates, BastionXP CA will not honor the value passed in the --user argument for regular users. Only the CA admin has the previlege to make such requests.

You’ll find the SSL/TLS client certificate and private key in the following location: /home/bob/.bsh

$ ls ~/.bsh
...
tls_client.crt  
tls_client.key
...

View the Issued Certificates:

We’ll use the OpenSSL tool to verify the certificates generated so far.

Root CA Certificate:

$ openssl x509 -in ~/.bsh/tls_root_ca.crt -noout  -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            5f:b4:2a:23:83:bc:11:ba:2b:85:f0:a6:47:76:15:9c
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = localhost
        Validity
            Not Before: Sep 11 05:37:11 2023 GMT
            Not After : Aug 18 05:37:11 2123 GMT
        Subject: CN = localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:ba:06:5b:eb:13:d6:f9:d2:bb:fb:c0:70:86:db:
                    0e:91:79:dd:89:dd:99:26:eb:e6:09:da:77:cc:fe:
                    07:b0:09:21:c2:c7:17:e4:ee:58:d7:ce:9f:96:57:
                    6d:e5:73:8f:e5:23:9e:11:a7:76:de:94:9e:2a:7a:
                    8e:1b:3 ...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier: 
                78:2A:6C:A0:64:AA:59:42:2B:FA:11:25:66:3A:BE:5F:27:EA:6E:17
            X509v3 Subject Alternative Name: 
                DNS:localhost
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        72:3e:3f:8d:b2:72:68:e8:ef:88:b9:0d:d3:db:b0:22:a2:0c:
        7c:93:6b:f6:bf:73:cc:93:62:e5:75:a1:ee:ae:a0:a2:c1:1f:
        16:e4:79:0a:f3:a9:48: ...

Server Certificate:

$ openssl x509 -in ~/.bsh/tls_server.crt -noout  -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            8b:a6:d8:6f:1c:d0:a4:d9:fa:f4:9c:4c:14:41:1f:14
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = localhost
        Validity
            Not Before: Sep 11 06:14:29 2023 GMT
            Not After : Aug 31 06:14:29 2025 GMT
        Subject: CN = localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:db:b9:a4:72:1d:c0:86:52:0a:c1:80:a7:a8:0a:
                    06:2d:62:d4:94:4d:82:bb:0d:99:d9:b9:14:06:ee:
                    d2:22:51:45:fe:dc:9b ...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Alternative Name: 
                DNS:localhost
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        4a:30:7b:01:65:e0:5f:06:e2:f0:12:2e:46:c6:13:92:c9:be:
        a2:e9:dd:45:1d:e3:62:f4:61:90:f6:81:8a:ba:79:30:02:12:
        37:15:d5:a1:7e:d5:a5:07:6a:2a ...

Client Certificate:

$ openssl x509 -in ~/.bsh/tls_client.crt -noout  -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2d:11:ed:0e:e3:47:05:9a:14:05:5a:26:6b:7b:80:83
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = localhost
        Validity
            Not Before: Sep 11 06:13:08 2023 GMT
            Not After : Sep 11 14:13:08 2023 GMT
        Subject: CN = bob
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:e7:d5:cd:79:ba:52:d4:87:9a:0d:8e:30:f4:b2:
                    3d:6d:8e:1d:d9:91:8c:30:ef:94:b8:da:87:2d:f2:
                    96:59:34:c4:c4:ac:63 ...
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
            X509v3 Authority Key Identifier: 
                78:2A:6C:A0:64:AA:59:42:2B:FA:11:25:66:3A:BE:5F:27:EA:6E:17
            X509v3 Subject Alternative Name: 
                email:bob
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        b1:08:8f:90:7f:06:64:89:83:02:49:d0:14:35:45:cb:09:e0:
        b7:61:c8:fd:bc:4f:54:6f:1b:1a:d6:4c:a9:ec:d7:56:26:6e:
        0f:c6:0d:cc:2c:39:77:78:1d ...

Note: BastionXP CA issues short-lived SSL TLS X.509 client certificates [valid for 8 hours only] by default to the end users or clients. Users must renew their client certificates after the expiry period. BastionXP CA provides granular control over who can access what resource and for how long.

Golang based TLS Server Example

We’ll use the below hello world HTTPS web server written in Golang to test the server certificate issued by the BastionXP CA.

go
package main
import (
    "net/http"
    "log"
)
var (
	CertFilePath = "/home/bob/.bsh/tls_server.crt"
	KeyFilePath  = "/home/bob/.bsh/tls_server.key"
)
func helloHandler(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello, world!\n"))
}
func main() {
    http.HandleFunc("/hello", helloHandler)
    err := http.ListenAndServeTLS(":8443", CertFilePath, KeyFilePath, nil)
    if err != nil {
        log.Fatal(err)
    }
}
Execute the above Go program using the following command:

$ go run https_server.go &
Now, try connecting to the above HTTPS server using the following command:

$ curl https://localhost:8443/hello

You’ll see the following error when you run the above command.

curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

This is because the curl command line utility is not aware of the BastionXP Root CA and therefore doesn’t trust the server certificate issued by the CA.

To make the curl utility trust the BastionXP CA and the certificates issued by it, use the --cacert flag in the curl command and provide the CA’s root certificate as shown below:

$ curl --cacert ~/.bsh/tls_root_ca.crt https://localhost:8443/hello

Hello, world!

Congratulations! You have successfully set up a private CA, generated a server certificate and used it for a HTTPS web service.

Next Steps

  • Try the Mutual TLS (mTLS) based HTTPS Web Server and HTTPS Client examples using the SSL/TLS Server and Client certificates geneated above.
  • Configure BastionXP CA to issue server and client certificates after a successful OIDC SSO login based user authentication using Google, Microsoft, Okta, or Keycloak OIDC SSO.
  • Configure BastionXP CA to run on a private or public domain name (Eg: bastionxp.example.com).

Start Your Free Trial Now

Try BastionXP for free with no commitments. No credit card required.