🏡 Home > 📍
Create Certificates for Secure API Over TLS
Environments
I did these steps, below, both on my Mac OS 11 and GCP Debian 10 Buster. They work and behave almost exactly the same.
Steps
Create Self-Signed Certificate (CA) for clients
Note: in this article, YOU
are the Certificate Authority (CA) - hence the keyword self-signed
.
The certificates generated here are good for TEST and DEVELOPMENT purposes.
For PRODUCTION, please get your certificates signed and verified by trust
Certificate Authorities.
Step 1 - Generate CA key
$ openssl genrsa -out development-ca.key 4096
The above openssl genrsa
command generates RSA key (4096 bit in this case) and saves the output
to ‘development-ca.key’.
All the key files should be kept securely and should not be shared.
Step 2 - Create and process certificate request
$ openssl req -x509 -new -nodes -key development-ca.key -sha256 -days 365 -out development-ca.crt
openssl req
creates and processes certificate requests. The input to this command is the private CA
key created from step 1. This command saves the certificate into an output file (.crt). The option -x509
specifies
that it creates a self-signed certificate instead of a certificate request.
That’s it! Now you have a self-signed
certificate that can be distributed onto your test/dev client devices.
Step 3 - Install self-signed certificate on clients
Install CA certificate on Mac OS devices
Install CA certificate on iOS devices
Create Certificates for Server Side
Step 4 - Generate Server Key
$ openssl genrsa -out development.key 4096
Step 5 - Prepare Config File (.cnf)
[ req ]
prompt = no
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext
[ req_distinguished_name ]
countryName = <YOUR_COUNTRY_CODE>
localityName = <YOUR_LOCALITY_NAME>
organizationName = <YOUR_ORGANIZATION_NAME>
commonName = <CERT_COMMON_NAME>
[ req_ext ]
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = <YOUR_SERVER_IP_ADDRESS_1>
IP.2 = 127.0.0.1
IP.3 = <YOUR_SERVER_IP_ADDRESS_2>
The [ req_distinguished_name ]
block is pretty much standard info. However,
I had to add IP addresses of all my servers under [alt_names]
block.
In my case, IP.1
is the ip address of my python/flask server running at home, i.e. 192.168.0.10. Whereas, my IP.3
is the external ip address of my server
running on GCP.
This .cnf file will be used as one of the inputs in the next step.
Step 6 - Generate Certificate Request (.csr)
$ openssl req -new -key development.key -config config.cnf -out development.csr
Note, you pass in the server key (from step 4) and the config file from previous step as inputs.
Step 7 - Generate Server Certificate (.crt)
$ openssl x509 -req \
-in development.csr \
-CA development-ca.crt \
-CAkey development-ca.key \
-CAcreateserial \
-out development.crt \
-days 365 -sha256 \
-extfile config.cnf \
-extensions req_ext
Input files:
-in development.csr
- from step 6-CA development-ca.crt
- from step 2-CAkey development-ca.key
- from step 1-extfile config.cnf
- from step 5
Output file:
-out development.crt
Step 8 - Install certificate on your server
Finally, install server key and certificate on your web/API server. In my case, I ran Python/Flask, my start-up python file is, for example:
if __name__ == '__main__':
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain("certs/development.crt",
"certs/development.key")
app.run(debug=False, host="192.168.0.112", port=5000, ssl_context=context)
Re-generate Certificate(.crt) for Server
See: Re-generate Self-Sign Certificate
Appreciations
My work here relies a lot on work done by Jaanus (see: [1]), and Grinberg [3], see References below.
I would like to thank them both for their excellent posts.
References
- How to configure development server certificates for iOS 13 and Mac clients, by Jaanus, Jaanus.com
- Technical Note TN2232, HTTPS Server Trust Evaluation, Apple Developer, developer.apple.com
- Running Your Flask Application Over HTTPS, by Miguel Grinberg
- HTTPS and Trush Chain in Flask, by Carolina Fernandez