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 RSADSAECC 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
      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.

$ cat 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
      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. selfsignedowncaacmeassertonlyentrust) 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
      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/
|-- computingforgeeks.com.csr
|-- computingforgeeks.com_cert.pem
|-- computingforgeeks.com_privkey.pem
`-- [email protected]:39:50~

0 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:
            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=computingforgeeks.com/[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=computingforgeeks.com/[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:computingforgeeks.com
            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.

Ansible online courses:


<img alt="Ansible for the Absolute Beginner – Hands-On – DevOps" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/1209412_842c_6.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>

<img data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/icon_udemy-com.png5f5a1356057f0.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>Udemy.com


<img alt="Mastering Ansible" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/628796_f0b0_9.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>

<img data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/icon_udemy-com.png5f5a1356057f0.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>Udemy.com


<img alt="DevOps Project: CI/CD with Jenkins Ansible Docker Kubernetes" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/2499720_13da_14.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>

<img data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/icon_udemy-com.png5f5a1356057f0.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>Udemy.com


<img alt="Ansible Advanced – Hands-On – DevOps" data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/1313828_b0ab_2.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>

<img data-ezsrc="https://kirelos.com/wp-content/uploads/2020/09/echo/icon_udemy-com.png5f5a1356057f0.jpg" ezimgfmt="rs rscb8 src ng ngcb8" src="data:image/svg xml,”>Udemy.com

Reference: Ansible documentation