Skip to content

Commit

Permalink
Merge pull request #4 from GEANT/dv_use_community_crypto
Browse files Browse the repository at this point in the history
Replace shell commands with native ansible modules
  • Loading branch information
dnmvisser authored Feb 14, 2022
2 parents b3bcd9c + 93aecb4 commit 7e65bbc
Show file tree
Hide file tree
Showing 11 changed files with 504 additions and 491 deletions.
107 changes: 73 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,101 @@
tls_cert
=========

Deploys TLS server certificates and their corresponding CA certificate chain to a host.
Deploys TLS server certificates and their corresponding CA certificate chain
onto a host.

Certificates from the TCS service are either regular (i.e. Domain Validated) certificates, or EV (Extended Validation) certificates.
This role deploys:
Certificates from the [TCS service](https://security.geant.org/trusted-certificate-services/)
can be OV (Organization Validated) or EV (Extended Validation) certificates. This role:

* the key pair
* the chain that belongs to it
* a single file containing private key, cert, and chain
* Check if the supplied key and certificate match
* Deploys the key pair
* Deploys the CA chain that corresponds to the certificate
* Deploys a single file containing private key, cert, and chain

TODO: generate pkcs12/jks key stores based on defined keystore password.


Requirements
------------

OpenSSL
Ansible 3.0+

Role Variables
--------------

A hosts' host_vars should contain these two vars contain the certificate and the private key:

```yaml
# PEM formatted X.509 certificate
# tls_cert_crt:
# PEM formatted X.509 private key
# tls_cert_key:

# Key vars
tls_cert_key_dest_dir: /etc/ssl/private
tls_cert_key_dest_name: server.key
# all-in-one file name (key+crt+chain)
tls_cert_allinone_dest_name: server.pem
tls_cert_key_owner: root
tls_cert_key_group: ssl-cert
tls_cert_key_mode: 0640

# Cert vars
tls_cert_crt_dest_dir: /etc/ssl/certs
tls_cert_crt_dest_name: server.crt
tls_cert_full_dest_name: server_full.crt
tls_cert_crt_owner: root
tls_cert_crt_group: root
tls_cert_crt_mode: 0644

# CA vars
tls_cert_ca_alias: chain.crt

# Reload services upon changes
tls_cert_reload_services: []
# tls_cert_reload_services:
# - apache2
# - postfix
# - postgresql
# - nginx
```
tls_cert_crt: |
-----BEGIN CERTIFICATE-----
MIIEYzCCA0ugAwIBAgIQBp43Tw4JNie9o9zO/cKbCzANBgkqhkiG9w0BAQ0FADBk
MQswCQYDVQQGEwJOTDEWMBQGA1UECBMNTm9vcmQtSG9sbGFuZDESMBAGA1UEBxMJ
QW1zdGVyZGFtMQ8wDQYDVQQKEwZURVJFTkExGDAWBgNVBAMTD1RFUkVOQSBTU0wg
Q0EgMzAeFw0xNjExMjgwMDAwMDBaFw0xOTEyMDMxMjAwMDBaMHMxCzAJBgNVBAYT
Ak5MMRYwFAYDVQQIEw1Ob29yZC1Ib2xsYW5kMRIwEAYDVQQHEwlBbXN0ZXJkYW0x
GzAZBgNVBAoMEkfDiUFOVCBBc3NvY2lhdGlvbjEbMBkGA1UEAxMSd2lraS11YXQu
Z2VhbnQub3JnMFkwEwYHKoZIzj0CAQYI..... etc
-----END CERTIFICATE-----
tls_cert_key: |
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQn3F4SqdSOARpOd2
5YcHDPZh6bIpb79BRdHONCAASx1IjoG......etc
-----END PRIVATE KEY-----

It is advisable to use `ansible-vault` or similar to encrypt your private key.

Dependencies
------------

A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
It is advisable to use `ansible-vault` or similar to encrypt your private key.


Example Playbook
----------------

```yaml
- hosts: myserver
become: true
roles:
- role: ansible_role_tls_cert
vars:
tls_cert_crt: |
-----BEGIN CERTIFICATE-----
MIIBkTCCATegAwIBAgIUc9C1CPsz7HvWYeeeCZKPjtB/RSkwCgYIKoZIzj0EAwIw
HjEcMBoGA1UEAwwTZ2l0aHViLWRlbW8ta2V5cGFpcjAeFw0yMjAyMTQxMjI2MzJa
Fw0zODAxMTcxMjI2MzJaMB4xHDAaBgNVBAMME2dpdGh1Yi1kZW1vLWtleXBhaXIw
WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATivAvRWOtdjXxCB8DAEs65jArkLdti
q5goH9bmZ/p/+KLWAHaXAYBhrZv7+SSrwD3tvCqpY9iFh9ZliifOBA4qo1MwUTAd
BgNVHQ4EFgQUOhDZkevX/EQQGoLQ3NNaEe3RPfswHwYDVR0jBBgwFoAUOhDZkevX
/EQQGoLQ3NNaEe3RPfswDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBF
AiAywXHOtuwTDFuuJJAkIkhUNZIsXJeM5ahcTFJreSS/jwIhANsxaApk3ZTDaTTP
GtO4FXcc9ErXjjBZcSU8165lHMFG
-----END CERTIFICATE-----
tls_cert_key: |
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgl2A5ivqCUWowxKji
ss76xTmPDCWumExO8v9srPEArYWhRANCAATivAvRWOtdjXxCB8DAEs65jArkLdti
q5goH9bmZ/p/+KLWAHaXAYBhrZv7+SSrwD3tvCqpY9iFh9ZliifOBA4q
-----END PRIVATE KEY-----
tls_cert_restart_services:
- apache2
- postgresql
- postfix
```
- hosts: servers
become: true
roles:
- tls_cert
License
-------
Expand Down
21 changes: 18 additions & 3 deletions defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
---
# defaults file for tls_cert
#

# PEM formatted X.509 certificate
# tls_cert_crt:


# PEM formatted X.509 private key
# tls_cert_key:

# Key vars
tls_cert_key_dest_dir: /etc/ssl/private
tls_cert_key_dest_name: server.key
tls_cert_pem_dest_name: server.pem
# all-in-one file name (key+crt+chain)
tls_cert_allinone_dest_name: server.pem
tls_cert_key_owner: root
tls_cert_key_group: ssl-cert
tls_cert_key_mode: 0640
Expand All @@ -19,3 +26,11 @@ tls_cert_crt_mode: 0644

# CA vars
tls_cert_ca_alias: chain.crt

# Reload services upon changes
tls_cert_reload_services: []
# tls_cert_reload_services:
# - apache2
# - postfix
# - postgresql
# - nginx
20 changes: 4 additions & 16 deletions handlers/main.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
---
- name: Check status of services that can use certificates
command: service "{{ item }}" status
with_items: "{{ tls_cert_services }}"
failed_when: false
changed_when: false
register: svcs
check_mode: no
listen: restart_services

- name: Reload any running services
- name: Reload services
service:
name: "{{ item.item }}"
name: "{{ item }}"
state: reloaded
with_items: "{{ svcs.results }}"
when: item.rc == 0
ignore_errors: "{{ ansible_check_mode }}"
listen: restart_services

loop: "{{ tls_cert_reload_services }}"
listen: reload_services
78 changes: 64 additions & 14 deletions tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,69 @@
---
- name: Load disto specific vars
include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_distribution }}-{{ ansible_distribution_release }}.yml"
- "{{ ansible_os_family }}.yml"
tags: [always]

- import_tasks: packages.yml
tags: [crt]
- name: Ensure neccessary packages are available
apt:
name:
- ssl-cert

- import_tasks: verify_pair.yml
tags: [crt,verify]
delegate_to: localhost
become: false

# Find CA certificate, based on the authority key identifier
- set_fact:
# This list of supported CAs is in vars/main.yml.
tls_cert_ca: "{{ ca_certs|json_query('[?key_id==`' ~ _crt.authority_key_identifier ~ '`].cert|[0]') }}"
tls_cert_ca_file: "{{ tls_cert_crt_dest_dir ~ '/' ~ ( _crt.issuer.commonName | regex_replace(' ', '_')) }}.crt"

- name: Ensure PEM encoded CA chain is available as {{ tls_cert_ca_name }}
copy:
content: "{{ tls_cert_ca }}"
dest: "{{ tls_cert_ca_file }}"
mode: 0644
owner: root
group: root

- name: "Ensure CA chain file is symlinked to {{ tls_cert_ca_file }}"
file:
src: "{{ tls_cert_ca_file }}"
dest: "{{ tls_cert_crt_dest_dir }}/{{ tls_cert_ca_alias }}"
state: link
notify: reload_services

- name: Ensure PEM encoded private key is available
copy:
content: "{{ tls_cert_key }}"
dest: "{{ tls_cert_key_dest_dir }}/{{ tls_cert_key_dest_name }}"
owner: "{{ tls_cert_key_owner }}"
group: "{{ tls_cert_key_group }}"
mode: "{{ tls_cert_key_mode }}"
notify: reload_services

# See https://www.digicert.com/ssl-support/pem-ssl-creation.htm#4in1
# TODO: add the root the bottom
- name: Ensure PEM encoded all-in-one file (key/crt/ca) is available
copy:
content: "{{ tls_cert_key }}{{ tls_cert_crt }}{{ tls_cert_ca }}"
dest: "{{ tls_cert_key_dest_dir }}/{{ tls_cert_allinone_dest_name }}"
owner: "{{ tls_cert_key_owner }}"
group: "{{ tls_cert_key_group }}"
mode: "{{ tls_cert_key_mode }}"
notify: reload_services

- name: Ensure PEM encoded certificate is available
copy:
content: "{{ tls_cert_crt }}"
dest: "{{ tls_cert_crt_dest_dir }}/{{ tls_cert_crt_dest_name }}"
owner: "{{ tls_cert_crt_owner }}"
group: "{{ tls_cert_crt_group }}"
mode: "{{ tls_cert_crt_mode }}"
notify: reload_services

- name: Ensure PEM encoded certficate + CA is available
copy:
content: "{{ tls_cert_crt }}\n{{ tls_cert_ca }}"
dest: "{{ tls_cert_crt_dest_dir }}/{{ tls_cert_full_dest_name }}"
owner: "{{ tls_cert_crt_owner }}"
group: "{{ tls_cert_crt_group }}"
mode: "{{ tls_cert_crt_mode }}"
notify: reload_services

- import_tasks: materials.yml
# Only when key matches cert
when: pubkey_crt.stdout == pubkey_key.stdout
tags: [crt,ca,chain,key,cert]
68 changes: 0 additions & 68 deletions tasks/materials.yml

This file was deleted.

5 changes: 0 additions & 5 deletions tasks/packages.yml

This file was deleted.

29 changes: 12 additions & 17 deletions tasks/verify_pair.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
---
- name: Establish public key from certificate
become: false
shell: echo "{{ tls_cert_crt }}" | openssl x509 -pubkey -noout
register: pubkey_crt
changed_when: false
check_mode: false
- name: Fetch certificate info
community.crypto.x509_certificate_info:
content: "{{ tls_cert_crt }}"
register: _crt

- name: Establish public key from private key
become: false
shell: echo "{{ tls_cert_key }}" | openssl pkey -pubout -outform PEM
register: pubkey_key
changed_when: false
check_mode: false
no_log: true
- name: Fetch private key info
community.crypto.openssl_privatekey_info:
content: "{{ tls_cert_key }}"
register: _key

- debug:
msg: "Private key and certificate do NOT belong together, there is no use in continuing as it will break your applications"
failed_when: pubkey_crt.stdout != pubkey_key.stdout
when: pubkey_crt.stdout != pubkey_key.stdout
- name: Safety check
assert:
that: _crt.public_key == _key.public_key
fail_msg: "Private key and certificate do NOT belong together, there is no use in continuing as it will break your applications"
8 changes: 0 additions & 8 deletions vars/Debian.yml

This file was deleted.

1 change: 0 additions & 1 deletion vars/Mandrake.yml

This file was deleted.

Loading

0 comments on commit 7e65bbc

Please sign in to comment.