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
### Install Ansible on CentOS 8 / CentOS 7 ###
sudo yum -y install epel-release
sudo yum install ansible
### Install Ansible on Ubuntu ####
sudo apt update
sudo apt install software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install ansible
### 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
### Install Ansible on Arch Linux ###
pacman -S ansible
Confirm Ansible installation by checking the version.
$ ansible --version
ansible --version
ansible 2.9.11
config file = None
configured module search path = ['/Users/jkmutai/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/Cellar/ansible/2.9.11/libexec/lib/python3.8/site-packages/ansible
executable location = /usr/local/bin/ansible
python version = 3.8.5 (default, Jul 21 2020, 10:48:26) [Clang 11.0.3 (clang-1103.0.32.62)]
Install Dependencies
pyOpenSSL is required for generation of keys and certificates with Ansible.
### Install with pip2 ###
sudo pip install pyOpenSSL
### Install with pip3 ###
sudo pip3 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: geeksforgeeks.org
- 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
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/
geeksforgeeks.org_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.
$ cat openssl_certificates.yml
---
- hosts: localhost
vars:
- server_hostname: geeksforgeeks.org
- 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
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
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: geeksforgeeks.org
- 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
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
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
openssl_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/
|-- neveropen.tech.csr
|-- geeksforgeeks.org_cert.pem
|-- geeksforgeeks.org_privkey.pem
`-- geeksforgeeks.org_privkey.pem.56610.2020-09-10@00:39:50~
0 directories, 4 files
You can check certificate information with openssl command.
$ openssl x509 -in certificates/geeksforgeeks.org_cert.pem -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
49:90:1b:9a:7c:24:c1:d2:7e:b4:ba:70:66:46:cb:e9:52:63:ae:f9
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=KE, O=Computingforgeeks, CN=geeksforgeeks.org/[email protected]
Validity
Not Before: Sep 9 21:39:52 2020 GMT
Not After : Sep 7 21:39:52 2030 GMT
Subject: C=KE, O=Computingforgeeks, CN=geeksforgeeks.org/[email protected]
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Modulus:
00:d8:82:6e:d9:c6:1d:7d:86:0b:96:37:5e:6c:78:
09:83:35:be:a0:44:73:c4:f6:cb:f3:50:a1:09:3e:
4a:3c:43:74:64:8c:c5:77:de:a6:bf:28:ba:53:a4:
c2:a5:41:5a:63:bd:f7:f4:0a:1e:21:d7:52:e9:30:
a0:1b:b7:c0:2f:c6:3a:3b:81:03:1e:d5:47:8b:43:
98:5d:cb:2e:a7:7b:90:a4:b8:54:37:e5:e4:da:85:
61:1d:49:da:6b:72:48:a4:af:72:d0:26:27:7d:e2:
1b:ec:40:0f:96:55:44:87:69:1d:30:8a:c7:51:da:
19:c2:cc:08:9f:73:f5:56:f8:26:ab:d3:e9:7e:87:
9c:05:9a:14:e7:6d:fe:88:3c:f3:6a:aa:26:e6:6c:
bf:82:58:19:1d:66:80:3e:69:f1:05:97:92:43:df:
f9:66:8f:b7:b1:b8:db:c3:3a:c6:87:ec:0a:d0:84:
19:cc:2c:ca:28:a6:44:0c:96:3b:45:4a:79:1e:6d:
04:75:b2:8d:f0:b7:dc:00:9f:21:36:22:42:ff:da:
ec:36:da:70:83:11:d6:67:4b:b6:26:03:6d:6c:d5:
7d:bb:7c:11:8a:c8:b8:d3:6d:37:5b:b8:63:48:e4:
3a:62:a7:ec:18:50:bf:1e:19:75:97:2f:06:de:e8:
5e:03:a6:67:4e:99:31:1c:6a:db:ad:82:9c:a8:ff:
21:f4:e9:f9:0d:92:40:ec:db:42:05:8f:af:65:0f:
60:1f:d8:36:1f:9a:94:30:3e:32:bb:61:fd:8f:7f:
ae:00:a2:73:cd:1c:2c:31:69:0f:f0:2e:c7:db:e5:
77:71:09:32:72:33:85:26:84:7a:6d:07:7e:ed:a6:
6c:ef:87:fa:3e:a4:a7:5a:b5:5a:91:b0:74:f1:3d:
e6:01:45:6d:ab:74:e3:be:25:28:f7:6e:68:52:e1:
91:41:d6:8f:4a:d9:ed:e0:35:55:51:23:1b:dd:9d:
4c:0b:b9:df:7e:ff:84:64:80:78:09:6a:a0:1c:f6:
ce:91:56:34:96:43:84:90:72:57:bd:dd:e3:24:02:
ad:4d:5b:81:bf:55:45:34:a9:b2:0c:91:02:34:09:
da:4e:0b:95:e1:90:f0:ff:b6:17:70:6f:b5:6a:5e:
b0:40:51:e3:a2:0a:c5:57:e9:49:db:1a:d3:bf:ca:
72:cd:13:5e:2e:1f:28:83:7a:82:ff:dc:07:6d:90:
b4:15:3d:c3:27:f9:23:7c:fc:d1:8d:56:89:40:5a:
cd:d6:a5:48:22:b2:84:df:6e:bd:65:df:5b:6c:a4:
62:36:23:a1:c7:5c:b1:18:1e:9f:2a:99:d0:2a:08:
5d:b1:39
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:geeksforgeeks.org
X509v3 Subject Key Identifier:
61:1D:2F:F8:CC:9F:86:65:07:C9:9A:0E:07:6C:97:A5:30:96:A5:0D
Signature Algorithm: sha256WithRSAEncryption
84:49:cd:dd:2d:7c:5e:02:b1:3c:96:36:a8:79:2a:b4:f4:dc:
ae:63:84:31:86:de:bf:e5:f0:f4:30:84:f1:8f:99:31:c1:d6:
45:37:c3:dc:ad:16:0f:13:27:ed:75:98:4e:01:88:ec:1c:e4:
7c:63:e2:06:5f:bc:61:11:3a:22:f4:48:f7:f2:af:a9:83:81:
0b:2e:09:19:90:3b:a5:77:eb:3a:4d:cf:96:e2:e4:74:f3:79:
4a:88:96:1d:c8:3a:44:a6:6e:00:d3:fe:d8:f9:1a:d7:f4:14:
b4:75:0f:a4:4a:0e:4d:6a:de:73:f0:10:e2:9c:7d:19:88:1d:
20:a9:b2:96:65:62:12:18:e7:f3:0a:5f:8c:e6:18:82:97:24:
f5:2f:78:8e:51:5c:b0:53:a6:aa:41:1d:ac:3d:e3:34:8c:13:
6e:b2:4d:e0:f9:be:10:40:a3:de:ea:e7:81:4a:b8:05:15:ed:
3f:72:52:60:a4:f5:b5:81:fa:8d:a9:d7:ec:54:0f:01:ec:06:
d2:05:5f:c3:d4:ad:66:eb:be:3b:37:c1:55:a1:00:3c:54:4f:
c2:0e:2b:d1:85:6c:a2:bf:6b:8a:37:e2:22:a0:74:18:12:68:
34:1b:e1:f4:e5:b3:21:f1:a4:40:cc:15:09:e8:96:4a:d9:46:
5b:32:7f:cb:e1:ca:17:f0:cf:af:60:e1:41:60:58:6f:1a:96:
96:80:a8:2b:c1:91:e7:b4:a8:e5:02:ed:78:fc:8e:76:32:90:
38:64:e3:cc:72:5d:e9:1b:6b:68:d0:47:78:5d:b1:8c:1a:ba:
7f:96:3f:7c:67:86:f1:62:6a:64:d5:fe:7f:5e:22:c4:51:ae:
6d:05:e5:87:f8:df:25:28:f9:fd:f2:b3:a3:8a:08:e8:c6:21:
0d:6d:85:fc:89:10:31:8f:e1:7b:c7:77:b2:32:fc:0c:b2:13:
6a:c3:18:a8:54:80:5c:54:49:98:19:09:d1:88:51:0d:df:29:
f7:e3:c2:96:13:dc:fa:15:0b:8e:4c:79:9a:00:8c:8a:6f:4d:
96:12:e3:2a:13:e4:70:d4:3e:33:70:d3:1f:81:67:a2:85:90:
0b:99:fc:14:cb:41:f2:8b:64:b5:51:38:63:1c:e2:a3:c2:9e:
2e:e9:8e:86:d7:75:ab:7f:e7:a6:12:b7:e5:3d:14:4a:6e:65:
65:c2:fd:c9:7f:bf:ee:8c:61:b7:1d:f7:2a:22:00:34:38:5c:
72:4c:74:a1:b6:bd:3e:4f:9a:01:91:3f:58:51:d6:23:36:a9:
ae:ed:84:5d:ce:96:c5:3b:0b:06:50:81:85:be:1e:eb:66:dd:
a4:d2:98:41:50:55:1c:d4
-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIUSZAbmnwkwdJ+tLpwZkbL6VJjrvkwDQYJKoZIhvcNAQEL
BQAwdTELMAkGA1UEBhMCS0UxGjAYBgNVBAoMEUNvbXB1dGluZ2ZvcmdlZWtzMR4w
HAYDVQQDDBVjb21wdXRpbmdmb3JnZWVrcy5jb20xKjAoBgkqhkiG9w0BCQEWG2Fk
bWluQGNvbXB1dGluZ2ZvcmdlZWtzLmNvbTAeFw0yMDA5MDkyMTM5NTJaFw0zMDA5
MDcyMTM5NTJaMHUxCzAJBgNVBAYTAktFMRowGAYDVQQKDBFDb21wdXRpbmdmb3Jn
ZWVrczEeMBwGA1UEAwwVY29tcHV0aW5nZm9yZ2Vla3MuY29tMSowKAYJKoZIhvcN
AQkBFhthZG1pbkBjb21wdXRpbmdmb3JnZWVrcy5jb20wggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDYgm7Zxh19hguWN15seAmDNb6gRHPE9svzUKEJPko8
Q3RkjMV33qa/KLpTpMKlQVpjvff0Ch4h11LpMKAbt8Avxjo7gQMe1UeLQ5hdyy6n
e5CkuFQ35eTahWEdSdprckikr3LQJid94hvsQA+WVUSHaR0wisdR2hnCzAifc/VW
+Car0+l+h5wFmhTnbf6IPPNqqibmbL+CWBkdZoA+afEFl5JD3/lmj7exuNvDOsaH
7ArQhBnMLMoopkQMljtFSnkebQR1so3wt9wAnyE2IkL/2uw22nCDEdZnS7YmA21s
1X27fBGKyLjTbTdbuGNI5Dpip+wYUL8eGXWXLwbe6F4DpmdOmTEcatutgpyo/yH0
6fkNkkDs20IFj69lD2Af2DYfmpQwPjK7Yf2Pf64AonPNHCwxaQ/wLsfb5XdxCTJy
M4UmhHptB37tpmzvh/o+pKdatVqRsHTxPeYBRW2rdOO+JSj3bmhS4ZFB1o9K2e3g
NVVRIxvdnUwLud9+/4RkgHgJaqAc9s6RVjSWQ4SQcle93eMkAq1NW4G/VUU0qbIM
kQI0CdpOC5XhkPD/thdwb7VqXrBAUeOiCsVX6UnbGtO/ynLNE14uHyiDeoL/3Adt
kLQVPcMn+SN8/NGNVolAWs3WpUgisoTfbr1l31tspGI2I6HHXLEYHp8qmdAqCF2x
OQIDAQABo0MwQTAgBgNVHREEGTAXghVjb21wdXRpbmdmb3JnZWVrcy5jb20wHQYD
VR0OBBYEFGEdL/jMn4ZlB8maDgdsl6UwlqUNMA0GCSqGSIb3DQEBCwUAA4ICAQCE
Sc3dLXxeArE8ljaoeSq09NyuY4Qxht6/5fD0MITxj5kxwdZFN8PcrRYPEyftdZhO
AYjsHOR8Y+IGX7xhEToi9Ej38q+pg4ELLgkZkDuld+s6Tc+W4uR083lKiJYdyDpE
pm4A0/7Y+RrX9BS0dQ+kSg5Nat5z8BDinH0ZiB0gqbKWZWISGOfzCl+M5hiClyT1
L3iOUVywU6aqQR2sPeM0jBNusk3g+b4QQKPe6ueBSrgFFe0/clJgpPW1gfqNqdfs
VA8B7AbSBV/D1K1m6747N8FVoQA8VE/CDivRhWyiv2uKN+IioHQYEmg0G+H05bMh
8aRAzBUJ6JZK2UZbMn/L4coX8M+vYOFBYFhvGpaWgKgrwZHntKjlAu14/I52MpA4
ZOPMcl3pG2to0Ed4XbGMGrp/lj98Z4bxYmpk1f5/XiLEUa5tBeWH+N8lKPn98rOj
igjoxiENbYX8iRAxj+F7x3eyMvwMshNqwxioVIBcVEmYGQnRiFEN3yn348KWE9z6
FQuOTHmaAIyKb02WEuMqE+Rw1D4zcNMfgWeihZALmfwUy0Hyi2S1UThjHOKjwp4u
6Y6G13Wrf+emErflPRRKbmVlwv3Jf7/ujGG3HfcqIgA0OFxyTHShtr0+T5oBkT9Y
UdYjNqmu7YRdzpbFOwsGUIGFvh7rZt2k0phBUFUc1A==
-----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 Courses to Learn Ansible Automation:
- Dive Into Ansible – From Beginner to Expert in Ansible
- Ansible Essentials with Hands-on Labs
- Ansible for the Absolute Beginner – Hands-On – DevOps
- Mastering Ansible
- Ansible Advanced – Hands-On – DevOps
- Ansible for the DevOps Beginners & System Admins
- Ansible for Network Engineers: Quick Start GNS3 & Ansible
Reference: Ansible documentation