diff --git a/defaults/main.yml b/defaults/main.yml index 3230d071..9d7d4d35 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -76,6 +76,13 @@ keystone_fernet_tokens_max_active_keys: 7 keystone_fernet_rotation: daily keystone_fernet_auto_rotation_script: /opt/keystone-fernet-rotate.sh +## Credentials config vars +keystone_credential_key_repository: /etc/keystone/credential-keys +# Any of the following rotation times are valid: +# reboot, yearly, annually, monthly, weekly, daily, hourly +keystone_credential_rotation: weekly +keystone_credential_auto_rotation_script: /opt/keystone-credential-rotate.sh + keystone_assignment_driver: sql keystone_resource_cache_time: 3600 diff --git a/tasks/keystone_credential.yml b/tasks/keystone_credential.yml new file mode 100644 index 00000000..7b3d79e2 --- /dev/null +++ b/tasks/keystone_credential.yml @@ -0,0 +1,24 @@ +--- +# Copyright 2016, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- include: keystone_credential_create.yml + when: > + inventory_hostname == groups['keystone_all'][0] + +- include: keystone_credential_distribute.yml + when: > + inventory_hostname == groups['keystone_all'][0] + +- include: keystone_credential_autorotate.yml diff --git a/tasks/keystone_credential_autorotate.yml b/tasks/keystone_credential_autorotate.yml new file mode 100644 index 00000000..6e1895cb --- /dev/null +++ b/tasks/keystone_credential_autorotate.yml @@ -0,0 +1,47 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is being created with mode 0755 intentionally. This is so that the +# script can be executed by root to rotate the keys as needed. The script being +# executed will always change it's user context to the keystone user before +# execution and while the script may be world read/executable its contains only +# the necessary bits that are required to run the rotate and sync commands. +- name: Drop credential key auto rotate script + template: + src: "keystone-credential-rotate.sh.j2" + dest: "{{ keystone_credential_auto_rotation_script }}" + owner: "{{ keystone_system_user_name }}" + group: "{{ keystone_system_group_name }}" + mode: "0755" + +# This creates the auto rotation job on the first keystone host. +- name: Create auto rotation job + cron: + name: "Credential auto rotate job" + special_time: "{{ keystone_credential_rotation }}" + user: "{{ keystone_system_user_name }}" + job: "{{ keystone_credential_auto_rotation_script }}" + cron_file: keystone-credential-rotate + when: > + inventory_hostname == groups['keystone_all'][0] + +# This makes sure that no auto rotation jobs are on any other hosts. +- name: Remove extra auto rotation job + cron: + name: "Credential auto rotate job" + cron_file: keystone-credential-rotate + state: "absent" + when: > + inventory_hostname != groups['keystone_all'][0] diff --git a/tasks/keystone_credential_create.yml b/tasks/keystone_credential_create.yml new file mode 100644 index 00000000..06d63f24 --- /dev/null +++ b/tasks/keystone_credential_create.yml @@ -0,0 +1,46 @@ +--- +# Copyright 2016, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Check if credential keys already exist + stat: + path: "{{ keystone_credential_key_repository }}/0" + register: _credential_keys + +- name: Create credential keys for Keystone + command: > + {{ keystone_bin }}/keystone-manage credential_setup + --keystone-user "{{ keystone_system_user_name }}" + --keystone-group "{{ keystone_system_group_name }}" + become: yes + become_user: "{{ keystone_system_user_name }}" + when: not _credential_keys.stat.exists + +- name: Ensure newest key is used for credential in Keystone + command: > + {{ keystone_bin }}/keystone-manage credential_migrate + --keystone-user "{{ keystone_system_user_name }}" + --keystone-group "{{ keystone_system_group_name }}" + become: yes + become_user: "{{ keystone_system_user_name }}" + when: _credential_keys.stat.exists + +- name: Rotate credential keys for Keystone + command: > + {{ keystone_bin }}/keystone-manage credential_rotate + --keystone-user "{{ keystone_system_user_name }}" + --keystone-group "{{ keystone_system_group_name }}" + become: yes + become_user: "{{ keystone_system_user_name }}" + when: _credential_keys.stat.exists diff --git a/tasks/keystone_credential_distribute.yml b/tasks/keystone_credential_distribute.yml new file mode 100644 index 00000000..1239de8a --- /dev/null +++ b/tasks/keystone_credential_distribute.yml @@ -0,0 +1,25 @@ +--- +# Copyright 2016, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Distribute the credential key repository + shell: | + rsync -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \ + -avz \ + --delete \ + {{ keystone_credential_key_repository }}/ \ + {{ keystone_system_user_name }}@{{ hostvars[item]['ansible_ssh_host'] }}:{{ keystone_credential_key_repository }}/ + become: yes + become_user: "{{ keystone_system_user_name }}" + with_items: "{{ groups['keystone_all'][1:] }}" diff --git a/tasks/main.yml b/tasks/main.yml index c4580cfa..bc9f08d4 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -79,6 +79,12 @@ - "'fernet' in keystone_token_provider" - keystone_service_setup | bool +- include: keystone_credential.yml + when: + - keystone_service_setup | bool + tags: + - keystone-install + - include: keystone_federation_sp_setup.yml tags: - keystone-install diff --git a/templates/keystone-credential-rotate.sh.j2 b/templates/keystone-credential-rotate.sh.j2 new file mode 100644 index 00000000..5cc07650 --- /dev/null +++ b/templates/keystone-credential-rotate.sh.j2 @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# Copyright 2016, Rackspace US, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# {{ ansible_managed }} + +# This script is being created with mode 0755 intentionally. This is so that the +# script can be executed by root to rotate the keys as needed. The script being +# executed will always change it's user context to the keystone user before +# execution and while the script may be world read/executable its contains only +# the necessary bits that are required to run the rotate and sync commands. + +function autorotate { + # Ensure all credentials are encrypted with the newest primary key so the rotation doesn't fail. + {{ keystone_bin }}/keystone-manage credential_migrate \ + --keystone-user "{{ keystone_system_user_name }}" \ + --keystone-group "{{ keystone_system_group_name }}" + + # Rotate the keys + {{ keystone_bin }}/keystone-manage credential_rotate \ + --keystone-user "{{ keystone_system_user_name }}" \ + --keystone-group "{{ keystone_system_group_name }}" + + # Ensure all credentials are encrypted with the new primary key + {{ keystone_bin }}/keystone-manage credential_migrate \ + --keystone-user "{{ keystone_system_user_name }}" \ + --keystone-group "{{ keystone_system_group_name }}" + + {% for host in groups['keystone_all'] %} + + {% if inventory_hostname != host %} + + # Fernet sync job to "{{ host }}" + rsync -e 'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' \ + -avz \ + --delete \ + {{ keystone_credential_key_repository }}/ \ + {{ keystone_system_user_name }}@{{ hostvars[host]['ansible_ssh_host'] }}:{{ keystone_credential_key_repository }}/ + + {%- endif %} + + {%- endfor %} + +} + +if [ "$(id -u)" == "0" ];then +# Change the script context to always execute as the "{{ keystone_system_user_name }}" user. +su - "{{ keystone_system_user_name }}" -s "/bin/bash" -c bash << EOC + {{ keystone_credential_auto_rotation_script }} +EOC +elif [ "$(whoami)" == "{{ keystone_system_user_name }}" ];then + logger $(autorotate) +else + echo "Failed - you do not have permission to rotate, or you've executed the job as the wrong user." + exit 99 +fi diff --git a/templates/keystone.conf.j2 b/templates/keystone.conf.j2 index 5bf10702..dea63b5e 100644 --- a/templates/keystone.conf.j2 +++ b/templates/keystone.conf.j2 @@ -159,7 +159,8 @@ admin_bind_host = {{ keystone_bind_address }} admin_port = {{ keystone_admin_port }} public_port = {{ keystone_service_port }} - +[credential] +key_repository = {{ keystone_credential_key_repository }} {% if keystone_sp != {} %} [federation] diff --git a/tests/test-keystone-functional.yml b/tests/test-keystone-functional.yml index cd336137..66733431 100644 --- a/tests/test-keystone-functional.yml +++ b/tests/test-keystone-functional.yml @@ -78,11 +78,10 @@ user: root gather_facts: false tasks: - # TODO(andymccr): add credentials functionality to keystone and remove the "credentials" exclusion. - name: Run tempest shell: | . {{ tempest_venv_bin }}/activate - {{ tempest_venv_bin | dirname }}/run_tempest.sh --no-virtual-env ${RUN_TEMPEST_OPTS} '^tempest.api.identity((?!credentials).)*$' + {{ tempest_venv_bin | dirname }}/run_tempest.sh --no-virtual-env ${RUN_TEMPEST_OPTS} '^tempest.api.identity.*' environment: RUN_TEMPEST_OPTS: "--serial"