From 524868c632b23385145d140e5e6abab82cda50cf Mon Sep 17 00:00:00 2001 From: Shaun Smekel Date: Fri, 5 Aug 2016 07:44:42 +1000 Subject: Add dockerfiles for keystone fernet This adds the docker aspects of fernet key bootstrapping as well as distributed key rotation. - Bootstrapping is handled in the same way as keystone bootstrap. - A new keystone-fernet and keystone-ssh container is created to allow the nodes to communicate with each other (taken from nova-ssh). - The keystone-fernet is a keystone container with crontab installed. This will handle key rotations through keystone-manage and trigger an rsync to push new tokens to other nodes. The Ansible component is implemented in: https://review.openstack.org/#/c/349366 Change-Id: Id610e00e8c63c7f1bc0974c0aa1b3f44c18e1019 Partially-Implements: blueprint keystone-fernet-token Partially-Implements: blueprint third-party-plugin-support --- docker/keystone/Dockerfile.j2 | 84 ---------------------- docker/keystone/extend_start.sh | 52 -------------- docker/keystone/keystone-base/Dockerfile.j2 | 76 ++++++++++++++++++++ docker/keystone/keystone-fernet/Dockerfile.j2 | 25 +++++++ docker/keystone/keystone-fernet/extend_start.sh | 12 ++++ .../keystone-fernet/fetch_fernet_tokens.py | 84 ++++++++++++++++++++++ .../keystone/keystone-fernet/keystone_bootstrap.sh | 43 +++++++++++ docker/keystone/keystone-ssh/Dockerfile.j2 | 21 ++++++ docker/keystone/keystone-ssh/extend_start.sh | 20 ++++++ docker/keystone/keystone/Dockerfile.j2 | 10 +++ docker/keystone/keystone/extend_start.sh | 52 ++++++++++++++ docker/keystone/keystone/keystone_bootstrap.sh | 68 ++++++++++++++++++ docker/keystone/keystone_bootstrap.sh | 68 ------------------ kolla/common/config.py | 2 +- 14 files changed, 412 insertions(+), 205 deletions(-) delete mode 100644 docker/keystone/Dockerfile.j2 delete mode 100644 docker/keystone/extend_start.sh create mode 100644 docker/keystone/keystone-base/Dockerfile.j2 create mode 100644 docker/keystone/keystone-fernet/Dockerfile.j2 create mode 100644 docker/keystone/keystone-fernet/extend_start.sh create mode 100644 docker/keystone/keystone-fernet/fetch_fernet_tokens.py create mode 100644 docker/keystone/keystone-fernet/keystone_bootstrap.sh create mode 100644 docker/keystone/keystone-ssh/Dockerfile.j2 create mode 100644 docker/keystone/keystone-ssh/extend_start.sh create mode 100644 docker/keystone/keystone/Dockerfile.j2 create mode 100644 docker/keystone/keystone/extend_start.sh create mode 100644 docker/keystone/keystone/keystone_bootstrap.sh delete mode 100644 docker/keystone/keystone_bootstrap.sh diff --git a/docker/keystone/Dockerfile.j2 b/docker/keystone/Dockerfile.j2 deleted file mode 100644 index e4a37baab..000000000 --- a/docker/keystone/Dockerfile.j2 +++ /dev/null @@ -1,84 +0,0 @@ -FROM {{ namespace }}/{{ image_prefix }}openstack-base:{{ tag }} -MAINTAINER {{ maintainer }} - -{% import "macros.j2" as macros with context %} - -{% if install_type == 'binary' %} - {% if base_distro in ['fedora', 'centos', 'oraclelinux', 'rhel'] %} - {% set keystone_packages = [ - 'openstack-keystone', - 'python-keystoneclient', - 'httpd', - 'mod_wsgi', - 'python-ldappool' - ] %} - -{{ macros.install_packages(keystone_packages | customizable("packages")) }} -RUN mkdir -p /var/www/cgi-bin/keystone \ - && cp -a /usr/share/keystone/keystone.wsgi /var/www/cgi-bin/keystone/main \ - && cp -a /usr/share/keystone/keystone.wsgi /var/www/cgi-bin/keystone/admin \ - && sed -i -r 's,^(Listen 80),#\1,' /etc/httpd/conf/httpd.conf - - {% elif base_distro in ['ubuntu'] %} - - {% set keystone_packages = [ - 'keystone', - 'apache2', - 'libapache2-mod-wsgi', - 'python-ldappool' - ] %} - -{{ macros.install_packages(keystone_packages | customizable("packages")) }} -RUN mkdir -p /var/www/cgi-bin/keystone \ - && cp -a /usr/share/keystone/wsgi.py /var/www/cgi-bin/keystone/main \ - && cp -a /usr/share/keystone/wsgi.py /var/www/cgi-bin/keystone/admin \ - && echo > /etc/apache2/ports.conf \ - && rm /etc/apache2/sites-enabled/keystone.conf - - {% endif %} -{% elif install_type == 'source' %} - {% if base_distro in ['fedora', 'centos', 'oraclelinux', 'rhel'] %} - - {% set keystone_packages = [ - 'httpd', - 'mod_wsgi', - 'python-ldappool' - ] %} -{{ macros.install_packages(keystone_packages | customizable("packages")) }} -RUN sed -i -r 's,^(Listen 80),#\1,' /etc/httpd/conf/httpd.conf - - {% elif base_distro in ['ubuntu', 'debian'] %} - - {% set keystone_packages = [ - 'apache2', - 'libapache2-mod-wsgi', - 'python-ldappool' - ] %} -{{ macros.install_packages(keystone_packages | customizable("packages")) }} -RUN echo > /etc/apache2/ports.conf - - {% endif %} -ADD keystone-archive /keystone-source -RUN ln -s keystone-source/* keystone \ - && useradd --user-group keystone \ - && /var/lib/kolla/venv/bin/pip --no-cache-dir install --upgrade -c requirements/upper-constraints.txt /keystone \ - && mkdir -p /etc/keystone /var/www/cgi-bin/keystone /var/log/apache2 /home/keystone \ - && cp -r /keystone/etc/* /etc/keystone/ \ - && cp /var/lib/kolla/venv/bin/keystone-wsgi-admin /var/www/cgi-bin/keystone/admin \ - && cp /var/lib/kolla/venv/bin/keystone-wsgi-public /var/www/cgi-bin/keystone/main \ - && chown -R keystone: /etc/keystone /var/www/cgi-bin/keystone /var/log/apache2 /home/keystone - -{% endif %} - -RUN usermod -a -G kolla keystone \ - && chown -R keystone: /var/www/cgi-bin/keystone \ - && chmod 755 /var/www/cgi-bin/keystone/* - -COPY keystone_bootstrap.sh /usr/local/bin/kolla_keystone_bootstrap -COPY extend_start.sh /usr/local/bin/kolla_extend_start -RUN chmod 755 /usr/local/bin/kolla_extend_start /usr/local/bin/kolla_keystone_bootstrap - -{% block keystone_footer %}{% endblock %} -{% block footer %}{% endblock %} - -{{ include_footer }} diff --git a/docker/keystone/extend_start.sh b/docker/keystone/extend_start.sh deleted file mode 100644 index 992885691..000000000 --- a/docker/keystone/extend_start.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -function kolla_kubernetes { - KUBE_TOKEN=$( /etc/apache2/ports.conf \ + && rm /etc/apache2/sites-enabled/keystone.conf + + {% endif %} +{% elif install_type == 'source' %} + {% if base_distro in ['fedora', 'centos', 'oraclelinux', 'rhel'] %} + {% set keystone_base_packages = [ + 'httpd', + 'mod_wsgi', + 'python-ldappool' + ] %} +{{ macros.install_packages(keystone_base_packages | customizable("packages")) }} +RUN sed -i -r 's,^(Listen 80),#\1,' /etc/httpd/conf/httpd.conf + + {% elif base_distro in ['ubuntu', 'debian'] %} + {% set keystone_base_packages = [ + 'apache2', + 'libapache2-mod-wsgi', + 'python-ldappool' + ] %} +{{ macros.install_packages(keystone_base_packages | customizable("packages")) }} +RUN echo > /etc/apache2/ports.conf + + {% endif %} + +ADD keystone-base-archive /keystone-base-source +RUN ln -s keystone-base-source/* keystone \ + && useradd --user-group keystone \ + && /var/lib/kolla/venv/bin/pip --no-cache-dir install --upgrade -c requirements/upper-constraints.txt /keystone \ + && mkdir -p /etc/keystone /var/www/cgi-bin/keystone /var/log/apache2 /home/keystone \ + && cp -r /keystone/etc/* /etc/keystone/ \ + && cp /var/lib/kolla/venv/bin/keystone-wsgi-admin /var/www/cgi-bin/keystone/admin \ + && cp /var/lib/kolla/venv/bin/keystone-wsgi-public /var/www/cgi-bin/keystone/main \ + && chown -R keystone: /etc/keystone /var/www/cgi-bin/keystone /var/log/apache2 /home/keystone + +{% endif %} + +RUN usermod -a -G kolla keystone \ + && chown -R keystone: /var/www/cgi-bin/keystone \ + && chmod 755 /var/www/cgi-bin/keystone/* + +{% block keystone_base_footer %}{% endblock %} +{% block footer %}{% endblock %} +{{ include_footer }} \ No newline at end of file diff --git a/docker/keystone/keystone-fernet/Dockerfile.j2 b/docker/keystone/keystone-fernet/Dockerfile.j2 new file mode 100644 index 000000000..0488ceb91 --- /dev/null +++ b/docker/keystone/keystone-fernet/Dockerfile.j2 @@ -0,0 +1,25 @@ +FROM {{ namespace }}/{{ image_prefix }}keystone-base:{{ tag }} +MAINTAINER {{ maintainer }} +{% import "macros.j2" as macros with context %} + +{% if base_distro in ['fedora', 'centos', 'oraclelinux', 'rhel'] %} + {% set keystone_fernet_packages = [ + 'cronie', + 'rsync' + ] %} +{% elif base_distro in ['ubuntu', 'debian'] %} + {% set keystone_fernet_packages = [ + 'cron', + 'rsync' + ] %} +{% endif %} +{{ macros.install_packages(keystone_fernet_packages | customizable("packages")) }} + +COPY fetch_fernet_tokens.py /usr/bin/ +COPY keystone_bootstrap.sh /usr/local/bin/kolla_keystone_bootstrap +COPY extend_start.sh /usr/local/bin/kolla_extend_start +RUN chmod 755 /usr/local/bin/kolla_extend_start /usr/local/bin/kolla_keystone_bootstrap /usr/bin/fetch_fernet_tokens.py + +{% block keystone_fernet_footer %}{% endblock %} +{% block footer %}{% endblock %} +{{ include_footer }} diff --git a/docker/keystone/keystone-fernet/extend_start.sh b/docker/keystone/keystone-fernet/extend_start.sh new file mode 100644 index 000000000..0d6a3a539 --- /dev/null +++ b/docker/keystone/keystone-fernet/extend_start.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +FERNET_SYNC=/usr/bin/fernet-node-sync.sh +FERNET_TOKEN_DIR="/etc/keystone/fernet-keys" + +if [[ -f "${FERNET_SYNC}" ]]; then + ${FERNET_SYNC} +fi + +if [[ $(stat -c %U:%G ${FERNET_TOKEN_DIR}) != "keystone:keystone" ]]; then + chown keystone:keystone ${FERNET_TOKEN_DIR} +fi \ No newline at end of file diff --git a/docker/keystone/keystone-fernet/fetch_fernet_tokens.py b/docker/keystone/keystone-fernet/fetch_fernet_tokens.py new file mode 100644 index 000000000..7ef7be085 --- /dev/null +++ b/docker/keystone/keystone-fernet/fetch_fernet_tokens.py @@ -0,0 +1,84 @@ +#!/usr/bin/python + +# 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. + +# Basically this module will fetch the fernet tokens and compare them to the +# required time constrains to determine whether the host needs to resync with +# other nodes in the cluster. + +from __future__ import print_function +import argparse +from datetime import datetime +from datetime import timedelta +import json +import os +import sys + +TOKEN_PATH = '/etc/keystone/fernet-keys' + + +def json_exit(msg=None, failed=False, changed=False): + if type(msg) is not dict: + msg = {'msg': str(msg)} + msg.update({'failed': failed, 'changed': changed}) + print(json.dumps(msg)) + sys.exit() + + +def has_file(filename_path): + if not os.path.exists(filename_path): + return False + return True + + +def num_tokens(): + _, _, files = os.walk(TOKEN_PATH).next() + return len(files) + + +def tokens_populated(expected): + return num_tokens() == int(expected) + + +def token_stale(seconds, filename='0'): + max_token_age = datetime.now() - timedelta(seconds=int(seconds)) + filename_path = os.path.join(TOKEN_PATH, filename) + + if not has_file(filename_path): + return True + modified_date = datetime.fromtimestamp(os.path.getmtime(filename_path)) + return modified_date < max_token_age + + +def main(): + parser = argparse.ArgumentParser(description='''Checks to see if a fernet + token no older than a desired time.''') + parser.add_argument('-t', '--time', + help='Time in seconds for a token rotation', + required=True) + parser.add_argument('-f', '--filename', + help='Filename of token to check', + default='0') + parser.add_argument('-n', '--number', + help='Number of tokens that should exist', + required=True) + args = parser.parse_args() + + json_exit({ + 'populated': tokens_populated(args.number), + 'update_required': token_stale(args.time, args.filename), + }) + + +if __name__ == '__main__': + main() diff --git a/docker/keystone/keystone-fernet/keystone_bootstrap.sh b/docker/keystone/keystone-fernet/keystone_bootstrap.sh new file mode 100644 index 000000000..d361767bb --- /dev/null +++ b/docker/keystone/keystone-fernet/keystone_bootstrap.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# 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. + +set -x + +USERNAME=$1 +GROUP=$2 + +function fail_json { + echo '{"failed": true, "msg": "'$1'", "changed": true}' + exit 1 +} + +function exit_json { + echo '{"failed": false, "changed": '"${changed}"'}' +} + +changed="false" +keystone_bootstrap=$(keystone-manage --config-file /etc/keystone/keystone.conf fernet_setup --keystone-user ${USERNAME} --keystone-group ${GROUP} 2>&1) +if [[ $? != 0 ]]; then + fail_json "${keystone_bootstrap}" +fi + +changed=$(echo "${keystone_bootstrap}" | awk ' + /Key repository is already initialized/ {count++} + END { + if (count == 1) changed="true"; else changed="false" + print changed + }' +) + +exit_json diff --git a/docker/keystone/keystone-ssh/Dockerfile.j2 b/docker/keystone/keystone-ssh/Dockerfile.j2 new file mode 100644 index 000000000..2f5389742 --- /dev/null +++ b/docker/keystone/keystone-ssh/Dockerfile.j2 @@ -0,0 +1,21 @@ +FROM {{ namespace }}/{{ image_prefix }}keystone-base:{{ tag }} +MAINTAINER {{ maintainer }} +{% import "macros.j2" as macros with context %} + +{% if base_distro in ['centos', 'fedora', 'oraclelinux', 'rhel'] %} + {% set keystone_ssh_packages = ['openssh-server'] %} +{% elif base_distro in ['ubuntu', 'debian'] %} + {% set keystone_ssh_packages = ['openssh-server'] %} + +RUN mkdir -p /var/run/sshd \ + && chmod 0755 /var/run/sshd + +{% endif %} +{{ macros.install_packages(keystone_ssh_packages | customizable("packages")) }} + +COPY extend_start.sh /usr/local/bin/kolla_extend_start +RUN chmod 755 /usr/local/bin/kolla_extend_start + +{% block keystone_ssh_footer %}{% endblock %} +{% block footer %}{% endblock %} +{{ include_footer }} diff --git a/docker/keystone/keystone-ssh/extend_start.sh b/docker/keystone/keystone-ssh/extend_start.sh new file mode 100644 index 000000000..23744cead --- /dev/null +++ b/docker/keystone/keystone-ssh/extend_start.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [[ ! -L /dev/log ]]; then + ln -sf /var/lib/kolla/heka/log /dev/log +fi + +SSH_HOST_KEY_TYPES=( "rsa" "dsa" "ecdsa" "ed25519" ) + +for key_type in ${SSH_HOST_KEY_TYPES[@]}; do + KEY_PATH=/etc/ssh/ssh_host_${key_type}_key + if [[ ! -f "${KEY_PATH}" ]]; then + ssh-keygen -q -t ${key_type} -f ${KEY_PATH} -N "" + fi +done + +mkdir -p /var/lib/keystone/.ssh + +if [[ $(stat -c %U:%G /var/lib/keystone/.ssh) != "keystone:keystone" ]]; then + sudo chown keystone: /var/lib/keystone/.ssh +fi diff --git a/docker/keystone/keystone/Dockerfile.j2 b/docker/keystone/keystone/Dockerfile.j2 new file mode 100644 index 000000000..e6baa9349 --- /dev/null +++ b/docker/keystone/keystone/Dockerfile.j2 @@ -0,0 +1,10 @@ +FROM {{ namespace }}/{{ image_prefix }}keystone-base:{{ tag }} +MAINTAINER {{ maintainer }} + +COPY keystone_bootstrap.sh /usr/local/bin/kolla_keystone_bootstrap +COPY extend_start.sh /usr/local/bin/kolla_extend_start +RUN chmod 755 /usr/local/bin/kolla_extend_start /usr/local/bin/kolla_keystone_bootstrap + +{% block keystone_footer %}{% endblock %} +{% block footer %}{% endblock %} +{{ include_footer }} \ No newline at end of file diff --git a/docker/keystone/keystone/extend_start.sh b/docker/keystone/keystone/extend_start.sh new file mode 100644 index 000000000..992885691 --- /dev/null +++ b/docker/keystone/keystone/extend_start.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +function kolla_kubernetes { + KUBE_TOKEN=$(&1) +if [[ $? != 0 ]]; then + fail_json "${keystone_bootstrap}" +fi + +changed=$(echo "${keystone_bootstrap}" | awk ' + /Domain default already exists, skipping creation./ || + /Project '"${PROJECT}"' already exists, skipping creation./ || + /User '"${USERNAME}"' already exists, skipping creation./ || + /Role '"${ROLE}"' exists, skipping creation./ || + /User '"${USERNAME}"' already has '"${ROLE}"' on '"${PROJECT}"'./ || + /Region '"${REGION}"' exists, skipping creation./ || + /Skipping admin endpoint as already created/ || + /Skipping internal endpoint as already created/ || + /Skipping public endpoint as already created/ {count++} + END { + if (count == 9) changed="false"; else changed="true" + print changed + }' +) + +exit_json diff --git a/docker/keystone/keystone_bootstrap.sh b/docker/keystone/keystone_bootstrap.sh deleted file mode 100644 index 1c822d0d6..000000000 --- a/docker/keystone/keystone_bootstrap.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash - -set -x - -# NOTE(SamYaple): Kolla needs to wraps `keystone-manage bootstrap` to ensure -# any change is reported correctly for idempotency. This script will exit with -# valid json that can be parsed with information about if the task has failed -# and if anything changed. - -USERNAME=$1 -PASSWORD=$2 -PROJECT=$3 -ROLE=$4 -ADMIN_URL=$5 -INTERNAL_URL=$6 -PUBLIC_URL=$7 -REGION=$8 - -function fail_json { - echo '{"failed": true, "msg": "'$1'", "changed": true}' - exit 1 -} - -function exit_json { - echo '{"failed": false, "changed": '"${changed}"'}' -} - -function kolla_kubernetes { - KUBE_TOKEN=$(&1) -if [[ $? != 0 ]]; then - fail_json "${keystone_bootstrap}" -fi - -changed=$(echo "${keystone_bootstrap}" | awk ' - /Domain default already exists, skipping creation./ || - /Project '"${PROJECT}"' already exists, skipping creation./ || - /User '"${USERNAME}"' already exists, skipping creation./ || - /Role '"${ROLE}"' exists, skipping creation./ || - /User '"${USERNAME}"' already has '"${ROLE}"' on '"${PROJECT}"'./ || - /Region '"${REGION}"' exists, skipping creation./ || - /Skipping admin endpoint as already created/ || - /Skipping internal endpoint as already created/ || - /Skipping public endpoint as already created/ {count++} - END { - if (count == 9) changed="false"; else changed="true" - print changed - }' -) - -exit_json diff --git a/kolla/common/config.py b/kolla/common/config.py index 4be0bebce..687b425cb 100644 --- a/kolla/common/config.py +++ b/kolla/common/config.py @@ -207,7 +207,7 @@ SOURCES = { 'type': 'url', 'location': ('http://tarballs.openstack.org/ironic/' 'ironic-master.tar.gz')}, - 'keystone': { + 'keystone-base': { 'type': 'url', 'location': ('http://tarballs.openstack.org/keystone/' 'keystone-master.tar.gz')}, -- cgit v1.2.3