Merge "Add role inference calls, domains"
diff --git a/README.rst b/README.rst
index bc98bf2..a171ab2 100644
--- a/README.rst
+++ b/README.rst
@@ -811,6 +811,40 @@
#. Apply the :command:`keystone.client` state.
+Fernet-keys rotation without gluster
+------------------------------------
+
+In the future fernet keys supposed to be rotated with rsync+ssh instead of using glusterfs. By default it is assumed
+that the script will run on primary control node (ctl01) and will rotate and transfer fernet keys to secondary
+controller nodes (ctl02, ctl03). Following parameter should be set on cluster level:
+
+keystone_node_role
+
+and fernet_rotation_driver should be set to 'rsync'
+
+By default this parameter is set to "secondary" on system level along with other parameters:
+.. code-block:: yaml
+
+ keystone:
+ server:
+ role: ${_param:keystone_node_role}
+ tokens:
+ fernet_sync_nodes_list:
+ control02:
+ name: ctl02
+ enabled: True
+ control03:
+ name: ctl03
+ enabled: True
+ fernet_rotation_driver: rsync
+
+Prior to running keystone salt states ssh key should be generated and its public part should be placed on secondary controllers.
+It can be accomplished by running following orchestration state before keystone states:
+
+salt-run state.orchestrate keystone.orchestrate.deploy
+
+Currently the default fernet rotation driver is a shared filesystem
+
Documentation and Bugs
======================
diff --git a/debian/changelog b/debian/changelog
index e1adcff..1270339 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+salt-formula-keystone (2016.12.1) xenial; urgency=medium
+
+ * Switch using 3.0 native source format
+
+ -- devops <devops@mirantis.com> Fri, 10 Aug 2018 15:42:34 +0400
+
salt-formula-keystone (2016.12.1-1xenial2) xenial; urgency=medium
* Add more dependencies
diff --git a/debian/source/format b/debian/source/format
index 163aaf8..89ae9db 100644
--- a/debian/source/format
+++ b/debian/source/format
@@ -1 +1 @@
-3.0 (quilt)
+3.0 (native)
diff --git a/keystone/files/keystone_keys_rotate.sh b/keystone/files/keystone_keys_rotate.sh
new file mode 100644
index 0000000..d71eaff
--- /dev/null
+++ b/keystone/files/keystone_keys_rotate.sh
@@ -0,0 +1,141 @@
+{%- from "keystone/map.jinja" import server with context -%}
+#!/bin/bash
+usage() {
+cat <<EOF
+Script for fernet and credential key rotation and sync
+ For additional help please use: $0 -h or --help
+ example: $0 -s -t fernet
+ exit 1
+EOF
+}
+
+if [ $# -lt "2" ]; then
+ usage
+ exit 1
+fi
+
+help_usage() {
+cat <<EOF
+Following options are supported:
+ -s|--sync Perform keys sync to secondary controller nodes only
+ -r|--rotate Perform keys rotation on primary controller only
+ -t|--type Possible values are "fernet" or "credential"
+EOF
+exit 0
+}
+
+POSITIONAL=()
+while [[ $# -gt 0 ]]
+do
+key="$1"
+
+case $key in
+ -h|--help)
+ help_usage
+ shift # pass argument
+ ;;
+ -s|--sync)
+ SYNC=true
+ shift # pass argument
+ ;;
+ -r|--rotate)
+ ROTATE=true
+ shift
+ ;;
+ -t|--type)
+ TYPE="$2"
+ shift
+ shift
+ ;;
+ *) # unknown option
+ echo "Unknown option. Please refer to help section by passing -h or --help option"
+ exit 1
+ shift # pass argument
+ ;;
+esac
+done
+set -- "${POSITIONAL[@]}" # restore positional parameters
+
+#Setting variables
+START_DATE=`date +%d_%m_%Y-%H_%M`
+KEYSTONE_MANAGE_CMD="/usr/bin/keystone-manage"
+{%- if server.tokens.fernet_sync_nodes_list is defined %}
+ {%- set _nodes = [] %}
+ {%- for node_name, fernet_sync_nodes_list in server.tokens.get('fernet_sync_nodes_list', {}).iteritems() %}
+ {%- if fernet_sync_nodes_list.get('enabled', False) %}
+ {%- do _nodes.append(fernet_sync_nodes_list.name) %}
+ {%- endif %}
+ {%- endfor %}
+NODES="{{ ' '.join(_nodes) }}"
+{%- else %}
+NODES=""
+{%- endif %}
+{%- if server.credential.credential_sync_nodes_list is defined %}
+ {%- set _nodes = [] %}
+ {%- for node_name, credential_sync_nodes_list in server.credential.get('credential_sync_nodes_list', {}).iteritems() %}
+ {%- if credential_sync_nodes_list.get('enabled', False) %}
+ {%- do _nodes.append(credential_sync_nodes_list.name) %}
+ {%- endif %}
+ {%- endfor %}
+CRED_NODES="{{ ' '.join(_nodes) }}"
+{%- else %}
+CRED_NODES=""
+{%- endif %}
+FERNET_DIR="{{ server.get('tokens', {}).get('location', {}) }}/"
+CRED_DIR="{{ server.get('credential', {}).get('location', {}) }}/"
+
+run_rsync () {
+ local sync_dir=$1
+ local sync_node=$2
+ rsync -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' -avz --delete ${sync_dir} keystone@${sync_node}:${sync_dir}
+}
+
+run_keystone () {
+ local keystone_cmd=$1
+ ${KEYSTONE_MANAGE_CMD} --log-file /var/log/keystone/keystone-rotate.log ${keystone_cmd} --keystone-user keystone --keystone-group keystone
+}
+if !([[ ${TYPE} == "fernet" ]] || [[ ${TYPE} == "credential" ]]) ; then
+ echo "Given type is not valid - exiting"
+ exit 1
+fi
+echo "Script started at: ${START_DATE}"
+
+if [[ "${ROTATE}" = true ]] ; then
+ if [[ ${TYPE} == "fernet" ]] ; then
+ echo "Running in Fernet ROTATE mode"
+ run_keystone "fernet_rotate"
+ else
+ echo "Running in Credential ROTATE mode"
+ if !(run_keystone "credential_rotate") ; then
+ echo "Credential rotate exited with fail status, calling credential_migrate and then credential_rotate again"
+ run_keystone "credential_migrate"
+ sleep 5
+ run_keystone "credential_rotate"
+ fi
+ fi
+fi
+if [[ "${SYNC}" = true ]] ; then
+ if [[ ${TYPE} == "fernet" ]] ; then
+ echo "Running in Fernet SYNC mode"
+ if [[ ${NODES} != '' ]]; then
+ for NODE in ${NODES}; do
+ echo "${NODE}"
+ run_rsync "${FERNET_DIR}" "${NODE}"
+ done
+ else
+ echo "List of nodes is not specified, no need for sync, exiting"
+ exit 0
+ fi
+ else
+ echo "Running in Credential SYNC mode"
+ if [[ ${CRED_NODES} != '' ]]; then
+ for NODE in ${CRED_NODES}; do
+ echo "${NODE}"
+ run_rsync "${CRED_DIR}" "${NODE}"
+ done
+ else
+ echo "List of nodes is not specified, no need for sync, exiting"
+ exit 0
+ fi
+ fi
+fi
diff --git a/keystone/meta/salt.yml b/keystone/meta/salt.yml
index 92324e5..554ed23 100644
--- a/keystone/meta/salt.yml
+++ b/keystone/meta/salt.yml
@@ -7,6 +7,12 @@
control:
priority: 520
+orchestration:
+ deploy:
+ applications:
+ keystone:
+ priority: 1000
+
minion:
{%- if pillar.get('keystone', {}).get('server') or pillar.get('keystone', {}).get('client') %}
{%- from "keystone/map.jinja" import server with context %}
diff --git a/keystone/orchestrate/deploy.sls b/keystone/orchestrate/deploy.sls
new file mode 100644
index 0000000..eccbbab
--- /dev/null
+++ b/keystone/orchestrate/deploy.sls
@@ -0,0 +1,36 @@
+{%- set minions = ((salt['cmd.shell']("salt '*' match.pillar 'keystone:server:role:primary' --out=json --static"))|load_json).values() %}
+keystone_ssh_keys:
+ salt.state:
+ - tgt: 'I@keystone:server:role:primary'
+ - tgt_type: compound
+ - sls: keystone.orchestrate.generate_keystone_ssh_keys
+ - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
+
+send_keystone_public_key:
+ salt.state:
+ - tgt: 'I@keystone:server:role:primary'
+ - tgt_type: compound
+ - sls: keystone.orchestrate.send_keystone_public_key
+ - require:
+ - salt: keystone_ssh_keys
+ - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
+
+{%- set minions = ((salt['cmd.shell']("salt '*' match.pillar 'keystone:server' --out=json --static"))|load_json).values() %}
+salt_mine_update:
+ salt.state:
+ - tgt: 'I@keystone:server'
+ - tgt_type: compound
+ - sls: keystone.orchestrate.run_mine_update
+ - require:
+ - salt: send_keystone_public_key
+ - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
+
+{%- set minions = ((salt['cmd.shell']("salt '*' match.pillar 'keystone:server:role:secondary' --out=json --static"))|load_json).values() %}
+get_keystone_public_key:
+ salt.state:
+ - tgt: 'I@keystone:server:role:secondary'
+ - tgt_type: compound
+ - sls: keystone.orchestrate.get_keystone_public_key
+ - require:
+ - salt: salt_mine_update
+ - onlyif: {% if True in minions %}/bin/true{% else %}/bin/false{% endif %}
diff --git a/keystone/orchestrate/generate_keystone_ssh_keys.sls b/keystone/orchestrate/generate_keystone_ssh_keys.sls
new file mode 100644
index 0000000..c5f7ccb
--- /dev/null
+++ b/keystone/orchestrate/generate_keystone_ssh_keys.sls
@@ -0,0 +1,19 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_generate_keystone_ssh_keys_state:
+ test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+keystone_fernet_keys:
+ file.directory:
+ - name: {{ server.tokens.location }}
+ - mode: 750
+ - user: keystone
+ - group: keystone
+
+generate_keystone_ssh_keys:
+ cmd.run:
+ - name: ssh-keygen -q -N '' -f /var/lib/keystone/.ssh/id_rsa
+ - runas: keystone
+ - creates: /var/lib/keystone/.ssh/id_rsa
+ - require:
+ - file: {{ server.tokens.location }}
+{%- endif %}
diff --git a/keystone/orchestrate/get_keystone_public_key.sls b/keystone/orchestrate/get_keystone_public_key.sls
new file mode 100644
index 0000000..ecd66c8
--- /dev/null
+++ b/keystone/orchestrate/get_keystone_public_key.sls
@@ -0,0 +1,44 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_get_keystone_public_key_state:
+ test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+{%- set authorized_keys = salt['mine.get']('I@keystone:server:role:primary', 'keystone_public_key', 'compound') %}
+
+keystone_fernet_keys_dir:
+ file.directory:
+ - name: {{ server.tokens.location }}
+ - mode: 750
+ - user: keystone
+ - group: keystone
+
+keystone_credential_keys_dir:
+ file.directory:
+ - name: {{ server.credential.location }}
+ - mode: 750
+ - user: keystone
+ - group: keystone
+
+/var/lib/keystone/.ssh:
+ file.directory:
+ - user: keystone
+ - group: keystone
+ - file_mode: 600
+ - dir_mode: 700
+ - makedirs: True
+ - recurse:
+ - user
+ - group
+ - mode
+
+ {% if authorized_keys is defined and authorized_keys|length > 0 %}
+put_keystone_file:
+ file.managed:
+ - name: /var/lib/keystone/.ssh/authorized_keys
+ - contents: '{{ authorized_keys.values()[0] }}'
+ - user: keystone
+ - group: keystone
+ - mode: 600
+ - require:
+ - file: /var/lib/keystone/.ssh
+ {%- endif %}
+{%- endif %}
diff --git a/keystone/orchestrate/run_mine_update.sls b/keystone/orchestrate/run_mine_update.sls
new file mode 100644
index 0000000..33e626c
--- /dev/null
+++ b/keystone/orchestrate/run_mine_update.sls
@@ -0,0 +1,8 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_run_mine_update_state:
+ test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+execute_mine_update:
+ module.run:
+ - name: mine.update
+{%- endif %}
diff --git a/keystone/orchestrate/send_keystone_public_key.sls b/keystone/orchestrate/send_keystone_public_key.sls
new file mode 100644
index 0000000..7edaf14
--- /dev/null
+++ b/keystone/orchestrate/send_keystone_public_key.sls
@@ -0,0 +1,13 @@
+{%- from "keystone/map.jinja" import server with context %}
+applying_send_keystone_public_key_state:
+ test.succeed_without_changes
+{% if server.tokens.get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+mine_send_keystone_public_key:
+ module.run:
+ - name: mine.send
+ - func: keystone_public_key
+ - args:
+ - 'cat /var/lib/keystone/.ssh/id_rsa.pub'
+ - kwargs:
+ mine_function: cmd.run
+{%- endif %}
diff --git a/keystone/server.sls b/keystone/server.sls
index 9b43303..4c3e17c 100644
--- a/keystone/server.sls
+++ b/keystone/server.sls
@@ -331,9 +331,35 @@
- onlyif: /bin/false
{%- endif %}
+ {% if server.get('tokens', {}).get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' or server.get('credential', {}).get('credential_rotation_driver', 'shared_filesystem') == 'rsync' %}
+ {% if server.get('role', 'secondary') == 'primary' %}
+/var/lib/keystone/keystone_keys_rotate.sh:
+ file.managed:
+ - source: salt://keystone/files/keystone_keys_rotate.sh
+ - template: jinja
+ - user: keystone
+ - group: keystone
+ - mode: 744
+ - require:
+ - pkg: keystone_packages
+ {%- endif %}
+ {%- endif %}
+
+ {% if server.get('tokens', {}).get('fernet_rotation_driver', 'shared_filesystem') == 'rsync' %}
+ {% if server.get('role', 'secondary') == 'primary' %}
+run_fernet_rotation_sync_only:
+ cmd.run:
+ - name: /var/lib/keystone/keystone_keys_rotate.sh -s -t fernet
+ - runas: keystone
+ - require:
+ - cmd: keystone_fernet_setup
+ - file: /var/lib/keystone/keystone_keys_rotate.sh
+ {%- endif %}
+ {%- endif %}
+
{% endif %}
-{%- if server.version in ['newton', 'ocata', 'pike'] %}
+{%- if server.version not in ['mitaka'] %}
keystone_credential_keys:
file.directory:
- name: {{ server.credential.location }}
@@ -353,6 +379,18 @@
- onlyif: /bin/false
{%- endif %}
+ {% if server.get('credential', {}).get('credential_rotation_driver', 'shared_filesystem') == 'rsync' %}
+ {% if server.get('role', 'secondary') == 'primary' %}
+run_credential_rotation_sync_only:
+ cmd.run:
+ - name: /var/lib/keystone/keystone_keys_rotate.sh -s -t credential
+ - runas: keystone
+ - require:
+ - cmd: keystone_credential_setup
+ - file: /var/lib/keystone/keystone_keys_rotate.sh
+ {%- endif %}
+ {%- endif %}
+
{%- endif %}
{%- if server.version not in ['mitaka', 'newton', 'ocata', 'pike'] %}