OpenSSL is a robust, commercial-grade, and full-featured toolkit for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols. It is a library that provides cryptographic protocols to application. The process of generating self-signed certificates on a Linux machine can be challenging especially for new Linux users. Considering this could be a frequent requirement there is a need to automate certificates generation. In today’s guide I’ll walk you through the process of generating Self-Signed SSL Certificates with Ansible on a Linux machine.
When working with OpenSSL, the public keys are derived from the corresponding private key. The first step will always be generating the private key using a particular algorithm. For production use there will be a certificate authority (CA) who is responsible for signing the certificate to be trusted in the internet. Since this is meant for Dev and Lab use cases, we are generating a Self-Signed certificate.
Generate OpenSSL Self-Signed Certificate with Ansible
In the examples shown in this article the private key is referred to as hostname_privkey.pem, certificate file is hostname_fullchain.pem and CSR file is hostname.csr where hostname is the actual DNS whose certificate is generated.
Before you begin
Before you get started Ansible is required installed in your Local machine.
### Install Ansible on Fedora ###
sudo dnf install ansible tree vim python3 python3-pip
### Install Ansible on CentOS 8/9 ###
sudo yum -y install epel-release
sudo yum install ansible tree vim python3 python3-pip
### Install Ansible on Ubuntu ####
sudo apt update
sudo apt install software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt update
sudo apt install ansible tree vim python3 python3-pip
### Install Ansible on Debian ###
echo "deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main" | sudo tee -a /etc/apt/sources.list
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 93C4A3FD7BB9C367
sudo apt update && sudo apt install ansible tree vim python3 python3-pip
### Install Ansible on Arch Linux ###
pacman -S ansible
Confirm Ansible installation by checking the version.
$ ansible --version
ansible 2.10.8
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
executable location = /usr/bin/ansible
python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
Install Dependencies
pyOpenSSL is required for generation of keys and certificates with Ansible.
### Install with pip3 ###
sudo pip3 install pyOpenSSL
### Install with pip2 ###
sudo pip install pyOpenSSL
If you’re new to Pip check documentation for usage heads up.
Writing Ansible Playbook for Self-Signed Certificate generation
With the dependency installed we should be on a ride to generating self-signed certificate with Ansible. We will do a single playbook with tasks for Private key, CSR and Certificate generation. I’ll cover each function as a block and then later we will combine to have a functioning playbook.
Create Project folders:
$ mkdir -p ~/projects/ansible/{certificates,files,templates}
$ cd ~/projects/
$ tree
.
`-- ansible
|-- certificates
|-- files
`-- templates
4 directories, 0 files
Create a Playbook schema.
vim ~/projects/ansible/openssl_certificates.yml
Add below standard sections.
---
- hosts: localhost
vars:
Generating OpenSSL Private Key with Ansible
Add a task to generate Private key. We are using openssl_privatekey module to generate OpenSSL Private keys. This module can generate RSA, DSA, ECC or EdDSA private keys in PEM format. Options such as passphrase and keysize should not be changed if you don’t want keys regeneration on a rerun.
You can get documentation of this module by using the command:
ansible-doc openssl_privatekey
The options I’ll use are:
- Key size: 4096 bits
- Key type: RSA
- backup: yes
You can optional set a passphrase for the key if this is something you want.
cd ~/projects/ansible/
vim openssl_certificates.yml
This is how my private key generation task looks like.
---
- hosts: localhost
vars:
- server_hostname: computingforgeeks.com
- key_size: 4096
- passphrase: # Set if you want passphrase
- key_type: DSA # Others include DSA, ECC, Ed25519, Ed448, X25519, X448
tasks:
- name: Generate an OpenSSL private key
community.crypto.openssl_privatekey:
path: "./certificates/{{ server_hostname }}_privkey.pem"
size: "{{ key_size }}"
type: "{{ key_type }}"
backup: yes
Run the playbook for private key to be generated.
$ ansible-playbook openssl_certificates.yml
PLAY [localhost] *************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************
ok: [localhost]
TASK [Generate an OpenSSL private key] ***************************************************************************************************************************
changed: [localhost]
PLAY RECAP *******************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Confirm key generation.
$ ls certificates/
computingforgeeks.com_privkey.pem
Generating OpenSSL CSR with Ansible
The next task we’ll add is for generating OpenSSL certificate signing request(CSR). This can be used to request for certificate signing by a certified CA. The module use for this operation is openssl_csr.
This Ansible module supports the subjectAltName, keyUsage, extendedKeyUsage, basicConstraints and OCSP Must Staple extensions.
These are the options I’ll use:
- common_name: The countryName field of the certificate signing request subject.
- privatekey_path: The path to the private key to use when signing the certificate signing request.
- path: The name of the file into which the generated OpenSSL certificate signing request will be written.
- country_name: The countryName field of the certificate signing request subject.
- email_address: The emailAddress field of the certificate signing request subject.
- organization_name: The organizationName field of the certificate signing request subject.
- organizational_unit_name: The organizationalUnitName field of the certificate signing request subject.
This is how the updated Playbook file looks like.
$ vim openssl_certificates.yml
---
- hosts: localhost
vars:
- server_hostname: computingforgeeks.com
- key_size: 4096
- passphrase: # Set if you want passphrase
- key_type: RSA # Others include DSA, ECC, Ed25519, Ed448, X25519, X448
- country_name: KE
- email_address: [email protected]
- organization_name: ComputingForGeeks
tasks:
- name: Generate an OpenSSL private key
community.crypto.openssl_privatekey:
path: "./certificates/{{ server_hostname }}_privkey.pem"
size: "{{ key_size }}"
type: "{{ key_type }}"
backup: yes
- name: Generate an OpenSSL Certificate Signing Request with Subject information
community.crypto.openssl_csr:
path: "./certificates/{{ server_hostname }}.csr"
privatekey_path: "./certificates/{{ server_hostname }}_privkey.pem"
country_name: "{{ country_name }}"
organization_name: "{{ organization_name }}"
email_address: "{{ email_address }}"
common_name: "{{ server_hostname }}"
Check playbook syntax before execution:
$ ansible-playbook --syntax-check openssl_certificates.yml
playbook: openssl_certificates.yml
Generating OpenSSL Certificate with Ansible
The openssl_certificate Ansible module is used to generate OpenSSL certificates. This module implements a notion of provider (ie. selfsigned
, ownca
, acme
, assertonly
, entrust
) for your certificate.
We will be generating Self-signed certificate but you can use other providers.
This is my updated Playbook contents:
---
- hosts: localhost
vars:
- server_hostname: computingforgeeks.com
- key_size: 4096
- passphrase: # Set if you want passphrase
- key_type: RSA # Others include DSA, ECC, Ed25519, Ed448, X25519, X448
- country_name: KE
- email_address: [email protected]
- organization_name: ComputingForGeeks
tasks:
- name: Generate an OpenSSL private key
community.crypto.openssl_privatekey:
path: "./certificates/{{ server_hostname }}_privkey.pem"
size: "{{ key_size }}"
type: "{{ key_type }}"
backup: yes
- name: Generate an OpenSSL Certificate Signing Request with Subject information
community.crypto.openssl_csr:
path: "./certificates/{{ server_hostname }}.csr"
privatekey_path: "./certificates/{{ server_hostname }}_privkey.pem"
country_name: "{{ country_name }}"
organization_name: "{{ organization_name }}"
email_address: "{{ email_address }}"
common_name: "{{ server_hostname }}"
- name: Generate a Self Signed OpenSSL certificate
community.crypto.x509_certificate:
path: "./certificates/{{ server_hostname }}_cert.pem"
privatekey_path: "./certificates/{{ server_hostname }}_privkey.pem"
csr_path: "./certificates/{{ server_hostname }}.csr"
provider: selfsigned
Lastly we’ll validate syntax and execute playbook to generate certificate.
$ ansible-playbook --syntax-check openssl_certificates.yml
playbook: openssl_certificates.yml
Run the Playbook.
$ ansible-playbook openssl_certificates.yml
Execution output:
PLAY [localhost] *************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************
ok: [localhost]
TASK [Generate an OpenSSL private key] ***************************************************************************************************************************
changed: [localhost]
TASK [Generate an OpenSSL Certificate Signing Request with Subject information] **********************************************************************************
changed: [localhost]
TASK [Generate a Self Signed OpenSSL certificate] ****************************************************************************************************************
changed: [localhost]
PLAY RECAP *******************************************************************************************************************************************************
localhost : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
List file to check created ones.
$ tree certificates/
.
├── certificates
│ ├── computingforgeeks.com_cert.pem
│ ├── computingforgeeks.com.csr
│ └── computingforgeeks.com_privkey.pem
├── files
├── openssl_certificates.yml
└── templates
3 directories, 4 files
You can check certificate information with openssl command.
$ openssl x509 -in certificates/computingforgeeks.com_cert.pem -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
52:95:75:1f:cc:1a:cf:cb:4a:f7:da:d6:a5:92:f2:ea:b8:21:e8:08
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = KE, O = ComputingForGeeks, CN = computingforgeeks.com, emailAddress = [email protected]
Validity
Not Before: Feb 15 17:21:14 2024 GMT
Not After : Feb 12 17:21:14 2034 GMT
Subject: C = KE, O = ComputingForGeeks, CN = computingforgeeks.com, emailAddress = [email protected]
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:ad:e6:70:59:5b:2a:b1:d3:1a:6e:79:90:65:a7:
03:55:90:b1:4d:81:e1:cb:d0:7a:25:16:67:c1:9f:
ba:c7:6d:6a:ad:d0:a2:06:57:3e:34:d0:6b:97:9b:
d8:d6:68:65:06:b9:8b:c8:0e:c3:65:11:a1:e6:f1:
ab:dd:b7:f5:9b:7a:ad:1a:8e:7f:da:d9:7c:77:98:
89:bd:54:a3:d2:12:41:a1:48:8b:cf:a9:d2:40:a7:
25:93:70:02:2f:dd:fa:85:f9:3a:c9:3e:c5:ca:5e:
88:6f:e0:14:31:0f:74:21:42:e1:e2:8a:07:eb:a5:
fa:5b:08:e8:ad:ba:d9:b6:9a:7b:da:76:95:e3:36:
d0:23:8e:18:9c:f5:a6:7e:9c:d3:20:ac:02:50:0b:
32:c5:de:f2:55:cf:70:ca:42:74:e3:00:21:35:f1:
f1:b9:f7:c0:06:28:bc:ac:05:f1:3c:41:17:fc:ad:
bb:cf:7b:92:f9:19:60:6d:66:f1:7d:c1:ad:ba:6b:
60:80:a6:66:77:6f:f4:54:00:b1:20:5c:2a:1f:06:
f1:6b:4c:16:7d:95:72:98:f6:5f:7c:d5:0f:89:28:
31:d6:33:50:e6:d1:41:17:b3:1c:96:86:24:dc:7e:
5b:ba:e9:3a:97:f7:31:e2:0c:57:e3:37:f3:37:03:
60:22:d7:a6:60:81:33:a5:21:21:b0:f9:02:19:ae:
ef:9c:c6:a6:7b:88:96:f7:30:c6:30:40:db:53:1e:
16:21:d8:25:b1:ed:22:25:48:02:f4:fd:da:1d:ed:
87:25:db:c2:5a:e7:f5:d0:73:12:68:9c:83:ff:ee:
62:00:7b:2a:31:91:05:25:b8:ac:67:49:76:82:77:
c7:ef:25:23:02:66:c0:f3:a4:a2:0a:82:ae:ec:df:
e8:38:c1:c0:81:93:ab:d7:cc:48:fb:13:42:bf:00:
22:43:07:35:5e:b5:31:78:19:7c:b0:0c:a7:b1:4f:
e3:28:ee:fa:f2:b0:0f:c5:af:0e:d0:bd:43:fe:38:
eb:07:5b:04:83:cd:76:19:48:6c:2c:0b:50:68:51:
52:91:cf:2d:6e:05:a8:d6:08:0b:81:57:31:2c:3a:
b9:ee:8a:6a:26:a2:59:7d:ed:aa:f5:eb:50:37:91:
e9:1b:3e:15:f3:96:8c:8a:36:aa:8d:ea:e8:b8:29:
65:16:95:ac:77:ec:8d:b5:1a:8a:a1:9f:8d:db:74:
a9:1a:49:10:d8:0e:d2:a6:cf:8d:24:3c:78:fc:d8:
d6:7a:eb:07:ce:a4:b6:20:55:44:29:21:58:c2:1f:
89:ad:92:8b:14:9b:cb:75:41:3d:79:34:0b:f6:95:
67:3b:35
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:computingforgeeks.com
X509v3 Subject Key Identifier:
5D:46:95:5D:7E:F5:9A:F1:32:85:D7:19:AE:27:FA:D6:BD:07:0B:95
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
39:ad:48:85:89:40:c4:6b:7f:42:fe:ed:31:fd:ae:a6:a8:4d:
61:08:98:e3:7a:cf:b7:79:ff:2d:07:a5:c7:56:0c:78:ea:65:
af:1c:fc:a6:5e:5b:77:fe:36:ba:e4:0b:1d:c1:37:68:c1:e5:
6f:f1:c0:81:e9:60:d9:40:54:94:34:37:29:10:15:19:f2:99:
99:dc:bf:83:7d:49:95:92:39:e9:89:e3:c2:6a:bf:d7:32:d1:
0a:09:2c:20:fb:ba:a0:13:37:ab:30:8b:05:2c:37:54:36:e7:
15:29:23:3e:b9:ba:68:2f:59:e4:ab:fa:8c:91:7a:3d:bd:36:
db:8e:8c:f7:73:64:b0:ac:39:7b:2c:a6:b2:15:db:a0:44:8f:
e7:89:4d:17:82:6a:21:e1:0b:e5:b6:94:24:fe:23:6f:ee:bf:
db:8a:24:6f:fc:cc:cc:b9:ca:42:55:43:5b:d7:c3:5d:ed:cf:
5f:87:0f:fd:eb:cd:2b:25:99:29:2a:e1:17:cf:be:ab:38:57:
d4:04:27:2e:97:bf:4b:6a:7b:81:97:b7:1a:b7:93:3e:1b:38:
7a:c1:b9:ee:9a:04:dc:43:98:a8:aa:e6:9c:d1:67:9d:dc:56:
c0:77:05:10:c7:14:12:e4:92:d6:cc:86:06:63:92:21:af:95:
7e:00:74:da:00:63:35:f7:cd:b4:c1:e3:0c:68:8e:52:8b:fa:
75:65:78:ed:f9:c4:0c:62:2b:c7:74:a8:b4:c9:24:5b:4f:f8:
a0:a9:81:f0:00:78:f4:57:ea:35:17:e2:86:7b:15:cc:e0:71:
69:d0:a0:5d:53:26:3e:05:06:f3:75:14:0f:a6:52:a2:14:11:
96:29:a5:8b:d4:37:96:e4:44:ed:b7:06:5b:fc:12:da:44:2b:
46:28:51:61:54:20:a8:bd:56:da:53:2f:81:d8:6c:94:70:39:
cb:17:d9:de:03:6f:44:9a:4f:15:6f:b8:1c:fc:f9:08:f0:01:
15:5b:95:eb:ce:38:16:9e:3f:06:c4:56:f5:35:27:56:7a:c2:
78:41:ff:42:83:f1:3c:90:cf:5f:13:dc:02:bb:a8:74:e3:bc:
0f:5a:91:ef:6b:40:bb:92:06:9a:26:5c:4b:26:50:e7:d7:b2:
6b:75:e3:04:54:95:21:fc:58:fa:1f:b2:69:6c:96:05:84:f2:
68:dd:0f:a3:a4:7e:67:d5:44:c8:0d:b0:42:07:eb:0c:ce:52:
0e:80:46:f1:4d:f4:d7:6b:db:0c:eb:f0:0c:f6:7d:d1:e2:01:
95:53:5a:a1:76:29:c3:82:86:5c:98:aa:a4:38:71:84:fe:4e:
f1:2f:f6:c0:24:3c:6a:c2
-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIUUpV1H8waz8tK99rWpZLy6rgh6AgwDQYJKoZIhvcNAQEL
BQAwdTELMAkGA1UEBhMCS0UxGjAYBgNVBAoMEUNvbXB1dGluZ0ZvckdlZWtzMR4w
HAYDVQQDDBVjb21wdXRpbmdmb3JnZWVrcy5jb20xKjAoBgkqhkiG9w0BCQEWG2Fk
bWluQGNvbXB1dGluZ2ZvcmdlZWtzLmNvbTAeFw0yNDAyMTUxNzIxMTRaFw0zNDAy
MTIxNzIxMTRaMHUxCzAJBgNVBAYTAktFMRowGAYDVQQKDBFDb21wdXRpbmdGb3JH
ZWVrczEeMBwGA1UEAwwVY29tcHV0aW5nZm9yZ2Vla3MuY29tMSowKAYJKoZIhvcN
AQkBFhthZG1pbkBjb21wdXRpbmdmb3JnZWVrcy5jb20wggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCt5nBZWyqx0xpueZBlpwNVkLFNgeHL0HolFmfBn7rH
bWqt0KIGVz400GuXm9jWaGUGuYvIDsNlEaHm8avdt/Wbeq0ajn/a2Xx3mIm9VKPS
EkGhSIvPqdJApyWTcAIv3fqF+TrJPsXKXohv4BQxD3QhQuHiigfrpfpbCOitutm2
mnvadpXjNtAjjhic9aZ+nNMgrAJQCzLF3vJVz3DKQnTjACE18fG598AGKLysBfE8
QRf8rbvPe5L5GWBtZvF9wa26a2CApmZ3b/RUALEgXCofBvFrTBZ9lXKY9l981Q+J
KDHWM1Dm0UEXsxyWhiTcflu66TqX9zHiDFfjN/M3A2Ai16ZggTOlISGw+QIZru+c
xqZ7iJb3MMYwQNtTHhYh2CWx7SIlSAL0/dod7Ycl28Ja5/XQcxJonIP/7mIAeyox
kQUluKxnSXaCd8fvJSMCZsDzpKIKgq7s3+g4wcCBk6vXzEj7E0K/ACJDBzVetTF4
GXywDKexT+Mo7vrysA/Frw7QvUP+OOsHWwSDzXYZSGwsC1BoUVKRzy1uBajWCAuB
VzEsOrnuimomoll97ar161A3kekbPhXzloyKNqqN6ui4KWUWlax37I21Goqhn43b
dKkaSRDYDtKmz40kPHj82NZ66wfOpLYgVUQpIVjCH4mtkosUm8t1QT15NAv2lWc7
NQIDAQABo0MwQTAgBgNVHREEGTAXghVjb21wdXRpbmdmb3JnZWVrcy5jb20wHQYD
VR0OBBYEFF1GlV1+9ZrxMoXXGa4n+ta9BwuVMA0GCSqGSIb3DQEBCwUAA4ICAQA5
rUiFiUDEa39C/u0x/a6mqE1hCJjjes+3ef8tB6XHVgx46mWvHPymXlt3/ja65Asd
wTdoweVv8cCB6WDZQFSUNDcpEBUZ8pmZ3L+DfUmVkjnpiePCar/XMtEKCSwg+7qg
EzerMIsFLDdUNucVKSM+ubpoL1nkq/qMkXo9vTbbjoz3c2SwrDl7LKayFdugRI/n
iU0Xgmoh4QvltpQk/iNv7r/biiRv/MzMucpCVUNb18Nd7c9fhw/9680rJZkpKuEX
z76rOFfUBCcul79LanuBl7cat5M+Gzh6wbnumgTcQ5ioquac0Wed3FbAdwUQxxQS
5JLWzIYGY5Ihr5V+AHTaAGM19820weMMaI5Si/p1ZXjt+cQMYivHdKi0ySRbT/ig
qYHwAHj0V+o1F+KGexXM4HFp0KBdUyY+BQbzdRQPplKiFBGWKaWL1DeW5ETttwZb
/BLaRCtGKFFhVCCovVbaUy+B2GyUcDnLF9neA29Emk8Vb7gc/PkI8AEVW5XrzjgW
nj8GxFb1NSdWesJ4Qf9Cg/E8kM9fE9wCu6h047wPWpHva0C7kgaaJlxLJlDn17Jr
deMEVJUh/Fj6H7JpbJYFhPJo3Q+jpH5n1UTIDbBCB+sMzlIOgEbxTfTXa9sM6/AM
9n3R4gGVU1qhdinDgoZcmKqkOHGE/k7xL/bAJDxqwg==
-----END CERTIFICATE-----
With the OpenSSL key and certificate generated you can begin to use it with your applications. For Root CA signing provide the generated CSR.
Best Security Books to read:
- Best Penetration Testing Books
- Best Cybersecurity Books To Read
- Best CompTIA Security+ (SY0-601) Certification Books
- Best Books To Learn Data Security & Encryption
- Top Certified Information Security Manager (CISM) study books
Reference: Ansible documentation