Skip to content

Commit

Permalink
ansible-scylla-node: Add support for system resources encryption
Browse files Browse the repository at this point in the history
System encryption is applied to semi-transient on-disk data, such as commit logs, batch
logs, and hinted handoff data.
This patch adds support for it by adding the variables system_info_encryption_local
and system_info_encryption_kmip. The former should be used for a LocalKeyProvider
and the latter for a KMIPKeyProvider.
If the user is using a KMIPKeyProvider the variable kmip_hosts, also added in this
patch, must be set.
The details of how these variables must be used are described in
ansible-scylla-node/defaults/main.yml along with the other variables from the node
role.

Fixes #88
  • Loading branch information
igorribeiroduarte committed Oct 5, 2023
1 parent f7efce8 commit 85c2359
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 1 deletion.
48 changes: 48 additions & 0 deletions ansible-scylla-node/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,54 @@ scylla_ssl:
client:
enabled: true

# Local keys are used for encrypting user data, such as SSTables.
# To use your own key, copy it to {{ localhost_key_dir }} with the name {{ key_name }} and then this key will be copied to all the nodes.
# If you don't provide your own key, the role will automatically generate a new one for you based on the variables under data_encryption_local and at
# the end of the process the role will create {{ localhost_key_dir }} (if it's not already created) and copy the key to it, so you can save it
# somewhere else as a backup.
# Note that the role is responsible only for copying the keys to the nodes. In order to actually encrypt your data you need
# to manually configure your tables as explained in the documentation -> https://enterprise.docs.scylladb.com/stable/operating-scylla/security/encryption-at-rest.html
data_encryption_local:
enabled: false # mandatory
localhost_key_dir: "{{ inventory_dir }}/data_encryption_keys" # mandatory
key_dir: /etc/scylla/data_encryption_keys # mandatory
key_name: data_key # mandatory
cipher_algorithm: AES # mandatory
secret_key_strength: 128 # mandatory
secret_key_block_mode: CBC # mandatory if you're not providing your own key
secret_key_padding: PKCS5 # mandatory if you're not providing your own key

# Encrypt system resources:
# System encryption is applied to semi-transient on-disk data, such as commit logs, batch logs, and hinted handoff data.
# If you'd like to use a LocalKeyProvider, please use the system_info_encrypt_local config
# If you'd like to use a KMIPKeyProvider, please use the system_info_encryption_kmip config

# LocalKeyProvider:
# To use your own key, copy it to {{ localhost_key_dir }} with the name {{ key_name }} and then this key will be copied to all the nodes.
# If you don't provide your own key, the role will automatically generate a new one for you based on the variables under system_info_encryption_local and at
# the end of the process the role will create {{ localhost_key_dir }} (if it's not already created) and copy the key to it, so you can save it
# somewhere else as a backup.
system_info_encryption_local:
enabled: false # mandatory
localhost_key_dir: "{{ inventory_dir }}/system_encryption_keys" # mandatory
key_dir: /etc/scylla/system_encryption_keys # mandatory
key_name: system_key # mandatory
cipher_algorithm: AES # mandatory
secret_key_strength: 128 # mandatory
secret_key_block_mode: CBC # mandatory if you're not providing your own key
secret_key_padding: PKCS5 # mandatory if you're not providing your own key
# complete_cipher_algorithm must is the value that is going to be set as cipher_algorithm in system_info_encryption. It needs to include cipher_algorithm, block_mode, padding and it has to be in the below format.
complete_cipher_algorithm: "AES/CBC/PKCS5Padding" # mandatory

# KMIPKeyProvider:
# All the variables under system_info_encryption_kmip are mandatory
# Make sure you set kmip_hosts accordingly
system_info_encryption_kmip:
enabled: false
cipher_algorithm: AES
secret_key_strength: 128
kmip_host: yourkmipServerIP.com

# If Scylla Manager will be used, set the following variables
scylla_manager_enabled: true
# deprecated in favour of below, it will be dropped soon, below should be used
Expand Down
14 changes: 14 additions & 0 deletions ansible-scylla-node/tasks/common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,20 @@
- (scylla_ssl.internode.enabled|bool) or
(scylla_ssl.client.enabled|bool)

- name: Set up LocalKeyProvider for system info encryption
include_tasks: enable_ear.yml
vars:
_type: "system_info"
_encryption_vars: "{{ system_info_encryption_local }}"
when: system_info_encryption_local.enabled|bool

- name: Copy keys for sstables encryption
include_tasks: enable_ear.yml
vars:
_type: "sstables"
_encryption_vars: "{{ data_encryption_local }}"
when: data_encryption_local.enabled|bool

# scylla_listen_address is a composite indirect value that depends on another per-host value - scylla_nic.
# Therefore in order to be able to get the corresponding value via hostvars[item] later in the play we need to
# have an actual value resolved.
Expand Down
69 changes: 69 additions & 0 deletions ansible-scylla-node/tasks/enable_ear.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
- set_fact:
_remote_key_path: "{{ _encryption_vars.key_dir }}/{{ _encryption_vars.key_name }}"

- set_fact:
_localhost_key_path: "{{ _encryption_vars.localhost_key_dir }}/{{ _encryption_vars.key_name }}"

- name: Check if the keys already exist in the nodes
stat:
path: "{{ _remote_key_path }}"
become: true
register: remote_key_file

- name: Check if the user provided a key
stat:
path: "{{ _localhost_key_path }}"
delegate_to: localhost
register: localhost_key_file

- fail:
msg: "This node already has a key in '{{ _remote_key_path }}'"
when: remote_key_file.stat.exists|bool and localhost_key_file.stat.exists|bool == false

- fail:
msg: "This node already has a key in '{{ _remote_key_path }}' and it's different from the one provided by the user in '{{ _localhost_key_path }}'"
when:
- remote_key_file.stat.exists|bool and localhost_key_file.stat.exists|bool
- remote_key_file.stat.checksum != localhost_key_file.stat.checksum

- name: Create keys dir
file:
path: "{{ _encryption_vars.key_dir }}"
state: directory
owner: scylla
group: scylla
mode: '700'
become: true

- name: Generate key and copy it to localhost
block:
- name: Generate key
shell: "/bin/local_file_key_generator -a {{ _encryption_vars.cipher_algorithm }} -m {{ _encryption_vars.secret_key_block_mode }} -p {{ _encryption_vars.secret_key_padding }} -l {{ _encryption_vars.secret_key_strength }} {{ _remote_key_path }}"
become: true

- name: Create localhost keys dir
file:
path: "{{ _encryption_vars.localhost_key_dir }}"
state: directory
mode: '700'
delegate_to: localhost

- name: Copy key from remote to localhost
fetch:
src: "{{ _remote_key_path }}"
dest: "{{ _localhost_key_path }}"
flat: true
validate_checksum: true
become: true
run_once: true
when: localhost_key_file.stat.exists|bool == false

- name: Copy key from localhost to all nodes
copy:
src: "{{ _localhost_key_path }}"
dest: "{{ _remote_key_path }}"
owner: scylla
group: scylla
mode: '600'
become: true
16 changes: 15 additions & 1 deletion ansible-scylla-node/templates/scylla.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,25 @@ client_encryption_options:
keyfile: {{ scylla_ssl.cert_path }}/{{ inventory_hostname }}.pem
truststore: {{ scylla_ssl.cert_path }}/{{ 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
{% endif %}
{% if system_info_encryption_local.enabled|bool %}
system_info_encryption:
enabled: True
cipher_algorithm: {{ system_info_encryption_local.complete_cipher_algorithm }}
secret_key_strength: {{ system_info_encryption_local.secret_key_strength }}
key_provider: LocalFileSystemKeyProviderFactory
secret_key_file: {{ system_info_encryption_local.key_dir }}/{{ system_info_encryption_local.key_name }}
{% elif system_info_encryption_kmip.enabled|bool %}
system_info_encryption:
enabled: True
cipher_algorithm: {{ system_info_encryption_kmip.cipher_algorithm }}
secret_key_strength: {{ system_info_encryption_kmip.secret_key_strength }}
key_provider: KmipKeyProviderFactory
kmip_host: {{ system_info_encryption_kmip.kmip_host }}
{% endif %}

0 comments on commit 85c2359

Please sign in to comment.