Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ansible-scylla-node: Allow the user to use a same certificate for all the nodes #427

Merged
merged 4 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
20 changes: 9 additions & 11 deletions ansible-scylla-node/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -275,21 +275,19 @@ scylla_yaml_params:
internode_compression: all

# SSL configuration for Scylla nodes:
# localhost_cert_path is the path where the certificates will be stored in the localhost before they're coppied to the nodes. If not set,
# the playbook will consider it to be the same path where the inventory is located.
# localhost_cert_path and localhost_cert_key_path are the paths where the certificates and keys will be stored in the localhost before they're coppied to the nodes.
# cert_path is the path where the certificates will be placed in the scylla nodes.
# If no certificates are present, this playbook will generate a selfsigned CA and node certificates locally and push them out to all the nodes.
# WARNING: if a local ${localhost_cert_path}/ssl/ directory is not present and populated by existing certificates for all nodes, it will be generated
# and certificates on the nodes can get overwritten with new certificates.
# WARNING: if certs are no given by the user they will be automatically generated if scylla_ssl is enabled and certificates on the nodes can get overwritten
# To use existing certificates:
# 1. To use your own CA, place it in ${localhost_cert_path}/ssl/ca/{{ scylla_cluster_name }}-ca.crt and its respective key in
# ${localhost_cert_path}/ssl/ca/{{ scylla_cluster_name }}-ca.pem and derived per-node certificates will be generated from it, if they are not present.
# 2. To use your own node certificates, create a directory per hostname (same as in the inventory) in ${localhost_cert_path}/ssl/{{ hostname }}
# and place the .pem and .crt files as {{ hostname }}.pem and {{ hostname }}.crt respectively and then place the CA you used to sign the certificates in
# ${localhost_cert_path}/ssl/ca/{{ scylla_cluster_name }}-ca.crt and its respective key in ${localhost_cert_path}/ssl/ca/{{ scylla_cluster_name }}-ca.pem.
# To skip this configuration entirely, set enabled: false for both options or comment out the scylla_ssl variable.
# 1. To use your own CA, place it in ${inventory_dir}/ssl/ca/{{ scylla_cluster_name }}-ca.crt and its respective key in
# ${inventory_dir}/ssl/ca/{{ scylla_cluster_name }}-ca.pem and derived per-node certificates will be generated from it, if they are not present.
# 2. To use your own node certificates and keys, just place them in 'localhost_cert_path' and 'localhost_cert_key_path'
# To skip this configuration entirely, set enabled: false for both options
scylla_ssl:
# localhost_cert_path: path/to/certificates
localhost_cert_path: "{{ inventory_dir }}/ssl/scylla.crt"
localhost_cert_key_path: "{{ inventory_dir }}/scylla.pem"
localhost_ca_cert_path: "{{ inventory_dir }}/ssl/ca/"
cert_path: /etc/scylla
internode:
enabled: true
Expand Down
61 changes: 38 additions & 23 deletions ansible-scylla-node/tasks/ssl.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
---

- set_fact:
_localhost_cert_path: "{{ scylla_ssl.localhost_cert_path | default(inventory_dir) }}"
_localhost_cert_path: "{{ scylla_ssl.localhost_cert_path | default(inventory_dir + '/ssl/' + inventory_hostname + '/' + inventory_hostname + '.crt') }}"
_localhost_cert_key_path: "{{ scylla_ssl.localhost_cert_key_path | default(inventory_dir + '/ssl/' + inventory_hostname + '/' + inventory_hostname + '.pem') }}"
tarzanek marked this conversation as resolved.
Show resolved Hide resolved

- name: For every node, check if crt file exists
stat:
path: "{{ _localhost_cert_path }}/ssl/{{ hostvars[item]['inventory_hostname'] }}/{{ hostvars[item]['inventory_hostname'] }}.crt"
path: "{{ hostvars[item]['_localhost_cert_path'] }}"
register: _node_crt
loop: "{{ groups['scylla'] }}"
delegate_to: localhost
run_once: true

- name: For every node, check if key file exists
stat:
path: "{{ _localhost_cert_path }}/ssl/{{ hostvars[item]['inventory_hostname'] }}/{{ hostvars[item]['inventory_hostname'] }}.pem"
path: "{{ hostvars[item]['_localhost_cert_key_path'] }}"
register: _node_key
loop: "{{ groups['scylla'] }}"
delegate_to: localhost
Expand All @@ -25,39 +27,46 @@
when: _crt_and_key_exist is not defined or _crt_and_key_exist == True
run_once: true

- name: Check if at least one crt was provided
set_fact:
_some_crt_and_key_exist: "{{ item.stat.exists }}"
loop: "{{ _node_crt.results + _node_key.results }}"
when: _some_crt_and_key_exist is not defined or _some_crt_and_key_exist == False

- name: Check if CA exists
block:
- name: Check if CA crt file exists
stat:
path: "{{ _localhost_cert_path }}/ssl/ca/{{ scylla_cluster_name }}-ca.crt"
path: "{{ inventory_dir }}/ssl/ca/{{ scylla_cluster_name }}-ca.crt"
tarzanek marked this conversation as resolved.
Show resolved Hide resolved
register: _ca_crt
- name: Check if CA key file exists
stat:
path: "{{ _localhost_cert_path }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
path: "{{ inventory_dir }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
register: _ca_key
- set_fact:
_ca_crt_and_key_exist: "{{ _ca_crt.stat.exists|bool and _ca_key.stat.exists|bool }}"
delegate_to: localhost
run_once: true

- fail:
msg: "If you want to use your own node certificates you also have to provide a CA"
when: _crt_and_key_exist and not _ca_crt_and_key_exist
msg: "You've provided crts only for a subset of your nodes. Either provide a CA that should be used for generating equivalent certificates for the others or delete the existing crts in order for the role to generate a new self-signed CA and certs for all the nodes"
run_once: true
when: not _crt_and_key_exist and _some_crt_and_key_exist and not _ca_crt_and_key_exist

- name: If crt and keys were not provided for all nodes and no CA was provided, generate a self-signed CA
block:
- name: Create dir for the CA
file:
path: "{{ _localhost_cert_path }}/ssl/ca"
path: "{{ inventory_dir }}/ssl/ca"
state: directory

- name: Generate an OpenSSL private key for the CA.
openssl_privatekey:
path: "{{ _localhost_cert_path }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
path: "{{ inventory_dir }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"

- name: Generate an OpenSSL Certificate Signing Request for the CA
community.crypto.openssl_csr_pipe:
privatekey_path: "{{ _localhost_cert_path }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
privatekey_path: "{{ inventory_dir }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
common_name: "{{ scylla_cluster_name }}.internal"
use_common_name_for_san: false # since we do not specify SANs, don't use CN as a SAN
basic_constraints:
Expand All @@ -70,8 +79,8 @@

- name: Generate a Self Signed OpenSSL certificate for the CA
community.crypto.x509_certificate:
path: "{{ _localhost_cert_path }}/ssl/ca/{{scylla_cluster_name }}-ca.crt"
privatekey_path: "{{ _localhost_cert_path }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
path: "{{ inventory_dir }}/ssl/ca/{{scylla_cluster_name }}-ca.crt"
privatekey_path: "{{ inventory_dir }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
csr_content: "{{ ca_csr.csr }}"
provider: selfsigned
when: _crt_and_key_exist == False and _ca_crt_and_key_exist == False
Expand All @@ -80,30 +89,36 @@

- name: Generate keys signed by the local CA
block:
- name: Create a directory for the crt
file:
path: "{{ _localhost_cert_path | dirname }}"
state: directory
delegate_to: localhost

- name: Create a directory for the key
file:
path: "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}"
path: "{{ _localhost_cert_key_path | dirname }}"
state: directory
delegate_to: localhost

- name: Generate an OpenSSL private key.
openssl_privatekey:
path: "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}/{{ inventory_hostname }}.pem"
path: "{{ _localhost_cert_key_path }}"
delegate_to: localhost

- name: Generate an OpenSSL Certificate Signing Request
openssl_csr:
path: "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}/{{ inventory_hostname }}.csr"
privatekey_path: "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}/{{ inventory_hostname }}.pem"
path: "{{ _localhost_cert_path }}.csr"
privatekey_path: "{{ _localhost_cert_key_path }}"
common_name: "{{ inventory_hostname }}.{{ scylla_cluster_name }}.internal"
delegate_to: localhost

- name: Generate an OpenSSL certificate signed with our CA certificate
openssl_certificate:
path: "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}/{{ inventory_hostname }}.crt"
csr_path: "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}/{{ inventory_hostname }}.csr"
ownca_path: "{{ _localhost_cert_path }}/ssl/ca/{{scylla_cluster_name }}-ca.crt"
ownca_privatekey_path: "{{ _localhost_cert_path }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
path: "{{ _localhost_cert_path }}"
csr_path: "{{ _localhost_cert_path }}.csr"
ownca_path: "{{ inventory_dir }}/ssl/ca/{{scylla_cluster_name }}-ca.crt"
ownca_privatekey_path: "{{ inventory_dir }}/ssl/ca/{{ scylla_cluster_name }}-ca.pem"
provider: ownca
delegate_to: localhost
when: _crt_and_key_exist == False
Expand All @@ -118,13 +133,13 @@
become: true
loop:
- "{{ _localhost_cert_path }}/ssl/ca/{{ scylla_cluster_name }}-ca.crt"
- "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}/{{ inventory_hostname }}.crt"
- "{{ _localhost_cert_path }}/ssl/{{ inventory_hostname }}/{{ inventory_hostname }}.pem"
- "{{ _localhost_cert_path }}"
- "{{ _localhost_cert_key_path }}"

- name: Generate cqlshrc
template:
src: templates/cqlshrc.j2
dest: "{{ _localhost_cert_path }}/cqlshrc"
dest: "{{ inventory_dir }}/cqlshrc"
delegate_to: localhost
run_once: true

12 changes: 6 additions & 6 deletions ansible-scylla-node/templates/scylla.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ native_shard_aware_transport_port_ssl: 19142

client_encryption_options:
enabled: true
certificate: {{ scylla_ssl.cert_path }}/{{ inventory_hostname }}.crt
keyfile: {{ scylla_ssl.cert_path }}/{{ inventory_hostname }}.pem
truststore: {{ scylla_ssl.cert_path }}/{{ scylla_cluster_name }}-ca.crt
certificate: {{ scylla_ssl.cert_path }}/{{ _localhost_cert_path | basename }}
keyfile: {{ scylla_ssl.cert_path }}/{{ _localhost_cert_key_path | basename }}
truststore: {{ inventory_hostname }}/{{ scylla_cluster_name }}-ca.crt
{% endif %}

{% if scylla_ssl is defined and scylla_ssl.internode.enabled %}
server_encryption_options:
internode_encryption: {{ scylla_ssl.internode.internode_encryption }}
certificate: {{ scylla_ssl.cert_path }}/{{ inventory_hostname }}.crt
keyfile: {{ scylla_ssl.cert_path }}/{{ inventory_hostname }}.pem
truststore: {{ scylla_ssl.cert_path }}/{{ scylla_cluster_name }}-ca.crt
certificate: {{ scylla_ssl.cert_path }}/{{ _localhost_cert_path | basename }}
keyfile: {{ scylla_ssl.cert_path }}/{{ _localhost_cert_key_path | basename }}
truststore: {{ inventory_hostname }}/{{ scylla_cluster_name }}-ca.crt
{% endif %}
{% if handle_system_keys|bool %}
system_key_directory: {{ system_key_directory }}
Expand Down