Skip to content
This repository was archived by the owner on Jan 5, 2025. It is now read-only.

Update role using community.crypto #1

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/.vagrant/
/certs/
109 changes: 51 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Generates self-signed CA, client and server certificates. Runs locally on contro

Notes:
- Will not overwrite any files in output cert dir
- Ansible crypto modules do not support signing certs with own CA yet, using `shell` command instead. Should be resolved in Ansible 2.7 using the [ownca provider](https://github.com/ansible/ansible/commit/b61b113fb9e3fcfcb25f4a8aaabad618e3209ce1).
- Will not copy the files to the remote servers if the local files are unchanged
- Will optionally (see `gen_tls_populate_etc_hosts` variable) add to each machine's `/etc/hosts`
a line for each host in the inventory.


Requirements
Expand All @@ -19,68 +21,59 @@ See `defaults/main.yml`

Dependencies
------------
- Refer to [Ansible Crypto modules](http://docs.ansible.com/ansible/latest/modules/list_of_crypto_modules.html)

Install dependencies via

Example Playbook
----------------
**generate-certs.yaml:**
```
---

# ansible-playbook generate-certs.yaml -i localhost,
# ansible-playbook generate-certs.yaml -i inventory.yaml

- hosts: all

gather_facts: false

tasks:
- include_vars: vars.yaml
$ ansible-galaxy collection install community.crypto
```

- name: Generate certs
import_role:
name: generate-tls-certs
Example Playbook
----------------

```
The provided example `playbook.yml` targets two hosts (take a look at the
`Vagrantfile`).

All the cryptographic relevant operations are performed on the host machine and
the resulting relevant files are `copy`ed to the remote target machine.

- `playbook.yml`
```yaml
---
- name: Run role
hosts: all
roles:
- role: generate-tls-certs
```

- `inventory.yml`
```yaml
---
all:
hosts:
srv1:
ansible_host: 192.168.123.30
srv2:
ansible_host: 192.168.123.31
vars:
gen_tls_cert_dir: ./certs
gen_tls_generate_ca_cert: true
gen_tls_generate_client_cert: true
gen_tls_generate_server_cert: true
gen_tls_ca_email: me@example.org
gen_tls_ca_country: EU
gen_tls_ca_state: Italy
gen_tls_ca_locality: Rome
gen_tls_ca_organization: Example Inc.
gen_tls_ca_organizationalunit: SysAdmins
gen_tls_populate_etc_hosts: yes
```

If you want to tinker, you can use `vagrant` with the provided `Vagrantfile`.
It assumes `vagrant-libvirt` is installed (along with `libvirt`, of course).

Run it like this:

**vars.yaml:**
```
---
cert_dir: ./certs
generate_ca_cert: true
generate_client_cert: true
generate_server_cert: true

# -------
# CA CERT
# -------
tls_ca_cert: my-ca.pem
tls_ca_csr: my-ca.csr
tls_ca_key: my-ca.key
tls_ca_country: CA
tls_ca_state: Ontario
tls_ca_locality: Toronto
tls_ca_organization: My Company Inc.
tls_ca_organizationalunit: IT
tls_ca_commonname: My Certificate Authority

# -----------
# CLIENT CERT
# -----------
tls_client_cert: my-client.pem
tls_client_key: my-client.key
tls_client_csr: my-client.csr
tls_client_commonname: My Client

$ vagrant up --provider=libvirt --provision
```


License
-------
BSD


Author Information
------------------
[EasyPath IT Solutions Inc.](https://www.easypath.ca)
35 changes: 35 additions & 0 deletions Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This guide is optimized for Vagrant 1.7 and above.
# Although versions 1.6.x should behave very similarly, it is recommended
# to upgrade instead of disabling the requirement below.
Vagrant.require_version ">= 1.7.0"

Vagrant.configure(2) do |config|

config.vm.box = "debian/buster64"
config.vm.synced_folder ".", "/vagrant", disabled: true
# Disable the new default behavior introduced in Vagrant 1.7, to
# ensure that all Vagrant machines will use the same SSH key pair.
# See https://github.com/mitchellh/vagrant/issues/5005
config.ssh.insert_key = false

config.vm.provider :libvirt do |lv|
lv.cpus = 1
lv.memory = 512
end

config.vm.define "srv1" do |m|
m.vm.hostname = "srv1"
m.vm.network :private_network, ip: "192.168.123.30", libvirt__dhcp_enabled: false
end
config.vm.define "srv2" do |m|
m.vm.hostname = "srv2"
m.vm.network :private_network, ip: "192.168.123.31", libvirt__dhcp_enabled: false
end

config.vm.provision "ansible" do |ansible|
#ansible.become = true
ansible.verbose = "v"
ansible.playbook = "playbook.yml"
ansible.inventory_path = "inventory.yml"
end
end
2 changes: 2 additions & 0 deletions ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[defaults]
roles_path = /root/.ansible/roles/:../
Empty file added certs/.gitkeep
Empty file.
62 changes: 35 additions & 27 deletions defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,46 +1,54 @@
---
# defaults file for generate-tls-certs
generate_tls_certs: true
gen_tls_generate_certs: true
# Do not put trailing slash "/"
cert_dir: ./certs
generate_ca_cert: false
generate_client_cert: false
generate_server_cert: false
gen_tls_cert_dir: ./certs
gen_tls_remote_certs_dir: /etc/ssl
gen_tls_remote_ca_certs_dir: /etc/ssl/certs
gen_tls_generate_ca_cert: false
gen_tls_generate_client_cert: false
gen_tls_generate_server_cert: false
gen_tls_force_copy: false

# -------
# CA CERT
# -------
tls_ca_cert: ca.pem
tls_ca_csr: ca.csr
tls_ca_key: ca.key
tls_ca_key_size: 4096
gen_tls_ca_cert: ca.crt
gen_tls_ca_csr: ca.csr
gen_tls_ca_key: ca.key
gen_tls_ca_key_size: 4096
# 10 years
tls_ca_valid_days: 3650
# tls_ca_country:
# tls_ca_state:
# tls_ca_locality:
# tls_ca_organization:
# tls_ca_organizationalunit:
tls_ca_commonname: Certificate Authority
#tls_ca_email:
gen_tls_ca_valid_days: 3650
# gen_tls_ca_country:
# gen_tls_ca_state:
# gen_tls_ca_locality:
# gen_tls_ca_organization:
# gen_tls_ca_organizationalunit:
gen_tls_ca_commonname: Certificate Authority
#gen_tls_ca_email:

# -----------
# CLIENT CERT
# -----------
tls_client_cert: client.pem
tls_client_key: client.key
tls_client_csr: client.csr
tls_client_key_size: 4096
tls_client_commonname: Client
tls_client_extfile: extfile-client.cnf
gen_tls_client_cert: client.pem
gen_tls_client_key: client.key
gen_tls_client_csr: client.csr
gen_tls_client_key_size: 4096
gen_tls_client_commonname: Client
# 2 years
tls_client_valid_days: 730
gen_tls_client_valid_days: 730

# -----------
# SERVER CERT
# -----------
# 2 years
tls_server_valid_days: 730
tls_server_key_size: 4096
gen_tls_server_valid_days: 730
gen_tls_server_key_size: 4096
# Enable Subject Alternate Name (SAN)
tls_server_enable_san: true
gen_tls_server_enable_san: true

# -------------------
# POPULATE /etc/hosts
# -------------------
gen_tls_populate_etc_hosts: false
# gen_tls_tld:
20 changes: 20 additions & 0 deletions inventory.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
all:
hosts:
srv1:
ansible_host: 192.168.123.30
srv2:
ansible_host: 192.168.123.31
vars:
gen_tls_cert_dir: ./certs
gen_tls_generate_ca_cert: true
gen_tls_generate_client_cert: true
gen_tls_generate_server_cert: true
gen_tls_ca_email: me@example.org
gen_tls_ca_country: EU
gen_tls_ca_state: Italy
gen_tls_ca_locality: Rome
gen_tls_ca_organization: Example Inc.
gen_tls_ca_organizationalunit: SysAdmins
gen_tls_populate_etc_hosts: yes
gen_tls_tld: example
5 changes: 5 additions & 0 deletions playbook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
- name: Run role
hosts: all
roles:
- role: generate-tls-certs
3 changes: 3 additions & 0 deletions requirements.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
collections:
- community.crypto
81 changes: 63 additions & 18 deletions tasks/generate-ca-cert.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,65 @@
---
- name: Generate CA private key
local_action:
module: openssl_privatekey
path: "{{cert_dir}}/{{tls_ca_key}}"
size: "{{tls_ca_key_size}}"
run_once: true
- name: Check if the CA private key exists
delegate_to: localhost
ansible.builtin.stat:
path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_key }}"
register: ca_key

- name: Generate self-signed cert for CA
local_action:
module: |
shell if [ ! -e {{cert_dir}}/{{tls_ca_cert}} ]
then
openssl req -x509 -new -days {{tls_ca_valid_days}} -sha256 -nodes -key {{cert_dir}}/{{tls_ca_key}} -out {{cert_dir}}/{{tls_ca_cert}} \
-subj "{% if tls_ca_country is defined%}/C={{tls_ca_country}}{% endif %}{% if tls_ca_state is defined%}/ST={{tls_ca_state}}{% endif %}{% if tls_ca_locality is defined %}/L={{tls_ca_locality}}{% endif %}{% if tls_ca_organization is defined %}/O={{tls_ca_organization}}{% endif %}{% if tls_ca_organizationalunit is defined %}/OU={{tls_ca_organizationalunit}}{% endif %}/CN={{tls_ca_commonname}}{% if tls_ca_email is defined %}/emailAddress={{tls_ca_email}}{% endif %}"
fi
args:
executable: /bin/bash
ignore_errors: true
run_once: true
- name: Generate CA private key
delegate_to: localhost
community.crypto.openssl_privatekey:
path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_key }}"
size: "{{ gen_tls_ca_key_size }}"
run_once: true
when: not ca_key.stat.exists

- name: Check if the CA CSR exists
delegate_to: localhost
stat:
path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_csr }}"
register: ca_csr

- name: Create CSR for CA
delegate_to: localhost
community.crypto.openssl_csr:
path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_csr }}"
privatekey_path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_key }}"
basic_constraints:
- "CA:TRUE"
common_name: "{{ gen_tls_ca_commonname|default('') }}"
country_name: "{{ gen_tls_ca_country|default('') }}"
state_or_province_name: "{{ gen_tls_ca_state|default('') }}"
locality_name: "{{ gen_tls_ca_locality|default('') }}"
organization_name: "{{ gen_tls_ca_organization|default('') }}"
organizational_unit_name: "{{ gen_tls_ca_organizationalunit|default('') }}"
email_address: "{{ gen_tls_ca_email }}"
use_common_name_for_san: no
when: not ca_csr.stat.exists

- name: Check if the CA cert exists
delegate_to: localhost
stat:
path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_cert }}"
register: ca_cert

- name: Create and sign server cert for CA
delegate_to: localhost
community.crypto.x509_certificate:
path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_cert }}"
privatekey_path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_key }}"
csr_path: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_csr }}"
selfsigned_not_after: "+{{ gen_tls_ca_valid_days }}d"
provider: selfsigned
when: not ca_cert.stat.exists
register: ca_cert_file

- name: Copy the CA certificate to the remote machine
copy:
src: "{{ gen_tls_cert_dir }}/{{ gen_tls_ca_cert }}"
dest: "{{ gen_tls_remote_ca_certs_dir }}"
mode: 0644
owner: root
group: root
force: yes
backup: yes
when: ca_cert_file.changed
Loading