From 771fc31828a006b65cdc94d747f9ae4ccccc527b Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Tue, 29 Oct 2019 12:11:49 -0400 Subject: [PATCH] Add role to add ipa services for tls-everywhere This role adds required IPA services given the server metadata and registers the base host as an ipa client. To be used when novajoin is not available, that is: * in the standalone node (to be used in TLS Everywhere CI), * when using pre-provisioned nodes. This commit also ensure we don't attempt to register a server/host that's already enrolled. This code requires the ansible-freeipa package to be installed. Co-Authored-By: Grzegorz Grasza Change-Id: Ie7fa5e1e83a3b015fd1e86c4666ace575e99833e --- molecule-requirements.txt | 1 + tox.ini | 3 + tripleo_ipa/defaults/main.yml | 2 - tripleo_ipa/handlers/main.yml | 2 - tripleo_ipa/meta/main.yml | 45 ----- tripleo_ipa/molecule/default/Dockerfile | 37 ++++ tripleo_ipa/molecule/default/converge.yml | 142 ++++++++++++++- tripleo_ipa/molecule/default/molecule.yml | 45 ++++- tripleo_ipa/molecule/default/prepare.yml | 74 ++++++++ .../molecule/default/tests/test_default.py | 168 ++++++++++++++++++ .../defaults/main.yml | 23 +++ .../tripleo_ipa_registration/meta/main.yml | 44 +++++ .../tripleo_ipa_registration/tasks/main.yml | 63 +++++++ .../tasks/services.yml | 55 ++++++ .../roles/tripleo_ipa_setup/meta/main.yml | 44 +++++ .../tripleo_ipa_setup/tasks/add_ipa_user.yml | 39 ++++ .../tasks/get_ipa_user_keytab.yml | 44 +++++ .../roles/tripleo_ipa_setup/tasks/main.yml | 23 +++ .../roles/tripleo_ipa_setup/tasks/setup.yml | 84 +++++++++ tripleo_ipa/tasks/main.yml | 2 - tripleo_ipa/vars/main.yml | 2 - zuul.d/base.yaml | 2 + zuul.d/playbooks/post.yml | 34 ++++ 23 files changed, 916 insertions(+), 62 deletions(-) delete mode 100644 tripleo_ipa/defaults/main.yml delete mode 100644 tripleo_ipa/handlers/main.yml delete mode 100644 tripleo_ipa/meta/main.yml create mode 100644 tripleo_ipa/molecule/default/Dockerfile create mode 100644 tripleo_ipa/molecule/default/prepare.yml create mode 100644 tripleo_ipa/molecule/default/tests/test_default.py create mode 100644 tripleo_ipa/roles/tripleo_ipa_registration/defaults/main.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_registration/meta/main.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_registration/tasks/main.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_registration/tasks/services.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_setup/meta/main.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_setup/tasks/add_ipa_user.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_setup/tasks/get_ipa_user_keytab.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_setup/tasks/main.yml create mode 100644 tripleo_ipa/roles/tripleo_ipa_setup/tasks/setup.yml delete mode 100644 tripleo_ipa/tasks/main.yml delete mode 100644 tripleo_ipa/vars/main.yml create mode 100644 zuul.d/playbooks/post.yml diff --git a/molecule-requirements.txt b/molecule-requirements.txt index 26c4f50..31b6292 100644 --- a/molecule-requirements.txt +++ b/molecule-requirements.txt @@ -1,3 +1,4 @@ ansible docker molecule>=3.0,<3.1 +testinfra diff --git a/tox.ini b/tox.ini index c16cc4e..96fe8b6 100644 --- a/tox.ini +++ b/tox.ini @@ -17,6 +17,9 @@ whitelist_externals = tox [testenv:molecule] +setenv = + ANSIBLE_FILTER_PLUGINS={toxinidir}/tripleo_ipa/ansible_plugins/filter + ANSIBLE_ROLES_PATH={toxinidir}/tripleo_ipa/roles.galaxy:{toxinidir}/tripleo_ipa/roles deps = -r {toxinidir}/molecule-requirements.txt changedir = {toxinidir}/tripleo_ipa diff --git a/tripleo_ipa/defaults/main.yml b/tripleo_ipa/defaults/main.yml deleted file mode 100644 index f0d7148..0000000 --- a/tripleo_ipa/defaults/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# defaults file for tripleo_ipa \ No newline at end of file diff --git a/tripleo_ipa/handlers/main.yml b/tripleo_ipa/handlers/main.yml deleted file mode 100644 index 94606e9..0000000 --- a/tripleo_ipa/handlers/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# handlers file for tripleo_ipa \ No newline at end of file diff --git a/tripleo_ipa/meta/main.yml b/tripleo_ipa/meta/main.yml deleted file mode 100644 index 639e13c..0000000 --- a/tripleo_ipa/meta/main.yml +++ /dev/null @@ -1,45 +0,0 @@ -galaxy_info: - author: OpenStack - description: This role is used to integrate TripleO with FreeIPA. - company: Red Hat - - # If the issue tracker for your role is not on github, uncomment the - # next line and provide a value - # issue_tracker_url: http://example.com/issue/tracker - - # Choose a valid license ID from https://spdx.org - some suggested licenses: - # - BSD-3-Clause (default) - # - MIT - # - GPL-2.0-or-later - # - GPL-3.0-only - # - Apache-2.0 - # - CC-BY-4.0 - license: Apache-2.0 - - min_ansible_version: 2.9 - - # If this a Container Enabled role, provide the minimum Ansible Container version. - # min_ansible_container_version: - - # - # Provide a list of supported platforms, and for each platform a list of versions. - # If you don't wish to enumerate all versions for a particular platform, use 'all'. - # To view available platforms and versions (or releases), visit: - # https://galaxy.ansible.com/api/v1/platforms/ - # - platforms: - - name: CentOS - versions: - - 8 - - galaxy_tags: [] - # List tags for your role here, one per line. A tag is a keyword that describes - # and categorizes the role. Users find roles by searching for tags. Be sure to - # remove the '[]' above, if you add tags to this list. - # - # NOTE: A tag is limited to a single word comprised of alphanumeric characters. - # Maximum 20 tags per role. - -dependencies: [] - # List your role dependencies here, one per line. Be sure to remove the '[]' above, - # if you add dependencies to this list. diff --git a/tripleo_ipa/molecule/default/Dockerfile b/tripleo_ipa/molecule/default/Dockerfile new file mode 100644 index 0000000..86294ca --- /dev/null +++ b/tripleo_ipa/molecule/default/Dockerfile @@ -0,0 +1,37 @@ +# Molecule managed +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash {{ item.pkg_extras | default('') }} && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl python-setuptools bash {{ item.pkg_extras | default('') }} && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml {{ item.pkg_extras | default('') }} && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates {{ item.pkg_extras | default('') }}; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates {{ item.pkg_extras | default('') }} && xbps-remove -O; fi + +{% for pkg in item.easy_install | default([]) %} +# install pip for centos where there is no python-pip rpm in default repos +RUN easy_install {{ pkg }} +{% endfor %} + + +CMD ["/sbin/init"] diff --git a/tripleo_ipa/molecule/default/converge.yml b/tripleo_ipa/molecule/default/converge.yml index 2dda268..0ae0d4a 100644 --- a/tripleo_ipa/molecule/default/converge.yml +++ b/tripleo_ipa/molecule/default/converge.yml @@ -1,7 +1,143 @@ --- -- name: Converge +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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: Setup server hosts: all + vars: + ipa_domain: example.test + ipa_server_ip: 172.18.0.22 + ipa_server_user: admin + ipa_server_password: password123 + ipa_server_hostname: ipa.example.test + undercloud_fqdn: test-0.example.test tasks: - - name: "Include tripleo_ipa" + - name: install python urllib gssapi + pip: + name: urllib_gssapi + - name: install ipa client + package: + name: ipa-client + state: present + + - name: set resolv.conf to point to the ipa server + shell: + cmd: cat > /etc/resolv.conf + stdin: | + search {{ ipa_domain }} + nameserver {{ ipa_server_ip }} + - name: Set fqdn in /etc/hosts + shell: + cmd: cat > /etc/hosts + - name: Set fqdn in /etc/hosts + shell: + cmd: cat > /etc/hosts + stdin: | + 127.0.0.1 test-0.example.test test-0 localhost localhost.localdomain + + - name: enroll the server as an ipa client using admin creds + shell: | + ipa-client-install -U \ + --server "{{ ipa_server_hostname }}" \ + --domain "{{ ipa_domain }}" \ + --realm "{{ ipa_domain | upper }}" \ + --principal "{{ ipa_server_user }}" \ + --password "{{ ipa_server_password }}" \ + --no-ntp --force-join --no-nisdomain + args: + creates: /etc/ipa/default.conf + + # we need this keytab for operations that we cannot do yet with ansible + - name: kinit to get admin creds + command: kinit "{{ ipa_server_user }}" + args: + stdin: "{{ ipa_server_password }}" + + - name: Ensure "tripleo-admin" group exists + group: + name: tripleo-admin + state: present + + - name: create users, perms, get keytab include_role: - name: "tripleo_ipa" + name: tripleo_ipa_setup + apply: + environment: + IPA_USER: "{{ ipa_server_user }}" + IPA_HOST: "{{ ipa_server_hostname }}" + IPA_PASS: "{{ ipa_server_password }}" + +- name: Converge - add host and relevant services + hosts: all + vars: + tripleo_ipa_enroll_base_server: true + tripleo_ipa_base_server_fqdn: test-0.example.test + tripleo_ipa_base_server_short_name: test-0 + tripleo_ipa_base_server_domain: example.test + tripleo_ipa_delegate_server: localhost + tripleo_ipa_server_metadata: | + { + "compact_service_HTTP": [ + "ctlplane", + "storage", + "storagemgmt", + "internalapi", + "external" + ], + "compact_service_haproxy": [ + "ctlplane", + "storage", + "storagemgmt", + "internalapi" + ], + "compact_service_libvirt-vnc": [ + "internalapi" + ], + "compact_service_mysql": [ + "internalapi" + ], + "compact_service_neutron_ovn": [ + "internalapi" + ], + "compact_service_novnc-proxy": [ + "internalapi" + ], + "compact_service_ovn_controller": [ + "internalapi" + ], + "compact_service_ovn_dbs": [ + "internalapi" + ], + "compact_service_rabbitmq": [ + "internalapi" + ], + "compact_service_redis": [ + "internalapi" + ], + "managed_service_haproxyctlplane": "haproxy/test-0.ctlplane.example.test", + "managed_service_haproxyexternal": "haproxy/test-0.example.test", + "managed_service_haproxyinternal_api": "haproxy/test-0.internalapi.example.test", + "managed_service_haproxystorage": "haproxy/test-0.storage.example.test", + "managed_service_haproxystorage_mgmt": "haproxy/test-0.storagemgmt.example.test", + "managed_service_mysqlinternal_api": "mysql/test-0.internalapi.example.test", + "managed_service_ovn_dbsinternal_api": "ovn_dbs/test-0.internalapi.example.test", + "managed_service_redisinternal_api": "redis/test-0.internalapi.example.test" + } + roles: + - name: tripleo_ipa_registration + environment: + IPA_USER: admin + IPA_HOST: ipa.example.test + IPA_PASS: password123 diff --git a/tripleo_ipa/molecule/default/molecule.yml b/tripleo_ipa/molecule/default/molecule.yml index aafdc9d..a77ae8f 100644 --- a/tripleo_ipa/molecule/default/molecule.yml +++ b/tripleo_ipa/molecule/default/molecule.yml @@ -1,13 +1,46 @@ --- -dependency: - name: galaxy driver: name: docker + +log: true + platforms: - - name: instance - image: docker.io/pycontribs/centos:7 - pre_build_image: true + - name: centos7 + hostname: test-0.example.test + image: centos:7 + security_opts: + - seccomp=unconfined + command: /sbin/init + tmpfs: + - /run + - /tmp + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + dockerfile: Dockerfile + network_mode: host + easy_install: + - pip + environment: &env + http_proxy: "{{ lookup('env', 'http_proxy') }}" + https_proxy: "{{ lookup('env', 'https_proxy') }}" + provisioner: name: ansible + log: true + env: + ANSIBLE_STDOUT_CALLBACK: yaml + ANSIBLE_ROLES_PATH: "${ANSIBLE_ROLES_PATH:-/usr/share/ansible/roles}:${HOME}/zuul-jobs/roles" + ANSIBLE_LIBRARY: "${ANSIBLE_LIBRARY:-/usr/share/ansible/plugins/modules}" + ANSIBLE_FILTER_PLUGINS: "${ANSIBLE_FILTER_PLUGINS:-/usr/share/ansible/plugins/filter}" + +scenario: + test_sequence: + - destroy + - create + - prepare + - converge + - verify + - destroy + verifier: - name: ansible + name: testinfra diff --git a/tripleo_ipa/molecule/default/prepare.yml b/tripleo_ipa/molecule/default/prepare.yml new file mode 100644 index 0000000..8cac5b3 --- /dev/null +++ b/tripleo_ipa/molecule/default/prepare.yml @@ -0,0 +1,74 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + +- hosts: localhost + connection: local + tasks: + - name: set facts for domains + set_fact: + domain: example.test + ipa_password: password123 + + - name: Download FreeIPA Container + docker_image: + name: freeipa/freeipa-server:fedora-28 + source: pull + + - name: Make IPA data dir + file: + path: /tmp/ipa-data + state: directory + + - name: Toggle SELinux boolean + seboolean: + name: container_manage_cgroup + state: true + persistent: true + become: true + + - name: Remove any old IPA container + docker_container: + name: freeipa-server-container + state: absent + + - name: Create network + docker_network: + name: ipa_network + ipam_config: + - subnet: 172.18.0.0/16 + + - name: Configure FreeIPA + shell: > + docker run --name freeipa-server-container + --sysctl net.ipv6.conf.lo.disable_ipv6=0 + --security-opt seccomp=unconfined + --net ipa_network --ip 172.18.0.22 + -e IPA_SERVER_IP={{ ansible_default_ipv4.address | default('127.0.0.1') }} + -e PASSWORD={{ ipa_password }} + -h ipa.{{ domain }} + --read-only --tmpfs /run --tmpfs /tmp + -v /sys/fs/cgroup:/sys/fs/cgroup:ro + -v /tmp/ipa-data:/data:Z freeipa/freeipa-server:fedora-28 exit-on-finished + -U -r {{ domain | upper }} --setup-dns --no-reverse --no-ntp + --forwarder={{ unbound_primary_nameserver_v4 | default('1.1.1.1') }} + --forwarder={{ unbound_secondary_nameserver_v4 | default('8.8.8.8') }} & + + - name: Wait for FreeIPA server install + wait_for: + path: "/tmp/ipa-data/var/log/ipaserver-install.log" + search_regex: "(INFO The ipa-server-install command was successful|ERROR The ipa-server-install command failed)" + timeout: 900 + become: true diff --git a/tripleo_ipa/molecule/default/tests/test_default.py b/tripleo_ipa/molecule/default/tests/test_default.py new file mode 100644 index 0000000..c6a5f8c --- /dev/null +++ b/tripleo_ipa/molecule/default/tests/test_default.py @@ -0,0 +1,168 @@ +import os + +import pytest +import testinfra +import testinfra.utils.ansible_runner + +inventory = os.environ['MOLECULE_INVENTORY_FILE'] +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + inventory).get_hosts('all') + + +def setup_module(module): + for host in testinfra_hosts: + testinfra.get_host('ansible://' + host, + ansible_inventory=inventory + ).check_output('echo password123 | kinit admin') + + +def teardown_module(module): + for host in testinfra_hosts: + testinfra.get_host('ansible://' + host, + ansible_inventory=inventory + ).check_output('kdestroy') + + +@pytest.mark.parametrize('pkg', [ + 'ipa-client', +]) +def test_pkg(host, pkg): + package = host.package(pkg) + + assert package.is_installed + + +@pytest.mark.parametrize('svc', [ + 'dbus', + 'sssd', +]) +def test_svc(host, svc): + service = host.service(svc) + + assert service.is_running + assert service.is_enabled + + +@pytest.mark.parametrize('file, content', [ + ("/etc/ipa/default.conf", "ipa.example.test"), + ("/etc/hosts", "test-0.example.test"), + ("/etc/resolv.conf", "172.18.0.22"), + ("/etc/novajoin/krb5.keytab", "test-0.example.test"), +]) +def test_files(host, file, content): + file = host.file(file) + + assert file.exists + assert file.contains(content) + + +@pytest.mark.parametrize('perm', [ + {'name': 'Modify host password', 'right': "write", + 'type': "host", 'attrs': "userpassword"}, + {'name': 'Write host certificate', 'right': "write", + 'type': "host", 'attrs': "usercertificate"}, + {'name': 'Modify host userclass', 'right': "write", + 'type': "host", 'attrs': "userclass"}, + {'name': 'Modify service managedBy attribute', 'right': "write", + 'type': "service", 'attrs': "managedby"}, +]) +def test_permissions(host, perm): + result = host.check_output('ipa permission-find "{name}"'.format(**perm)) + assert '1 permission matched' in result + assert 'Granted rights: {right}'.format(**perm) in result + assert 'Type: {type}'.format(**perm) in result + assert 'Effective attributes: {attrs}'.format(**perm) in result + + +@pytest.mark.parametrize('pri', [ + 'Nova Host Management', +]) +def test_privilages(host, pri): + result = host.check_output('ipa privilege-find "{}"'.format(pri)) + assert '1 privilege matched' in result + assert 'Privilege name: {}'.format(pri) in result + assert 'Description: {}'.format(pri) in result + + +def test_privilege_permissions(host): + pri = 'Nova Host Management' + perms = [ + 'System: add hosts', + 'System: remove hosts', + 'Modify host password', + 'Modify host userclass', + 'System: Modify hosts', + 'Modify service managedBy attribute', + 'System: Add krbPrincipalName to a Host', + 'System: Add Services', + 'System: Remove Services', + 'Revoke certificate', + 'System: manage host keytab', + 'System: Manage host certificates', + 'System: modify services', + 'System: manage service keytab', + 'System: read dns entries', + 'System: remove dns entries', + 'System: add dns entries', + 'System: update dns entries', + 'Retrieve Certificates from the CA', + ] + result = host.check_output('ipa privilege-show "{}"'.format(pri)) + assert 'Privilege name: {}'.format(pri) in result + for perm in perms: + assert perm.lower() in result.lower() + + +def test_role(host): + role = 'Nova Host Manager' + pri = 'Nova Host Management' + result = host.check_output('ipa role-show "{}"'.format(role)) + assert 'Role name: {}'.format(role) in result + assert 'Description: {}'.format(role) in result + assert 'Privileges: {}'.format(pri) in result + assert 'Member services: nova/test-0.example.test@EXAMPLE.TEST' in result + + +@pytest.mark.parametrize('name', [ + 'test-0.example.test', + 'test-0.ctlplane.example.test', + 'test-0.external.example.test', + 'test-0.internalapi.example.test', + 'test-0.storage.example.test', + 'test-0.storagemgmt.example.test', +]) +def test_hosts(host, name): + result = host.check_output('ipa host-find {}'.format(name)) + assert '1 host matched' in result + + +@pytest.mark.parametrize('service, subhost', [ + ('HTTP', 'ctlplane'), + ('HTTP', 'external'), + ('HTTP', 'internalapi'), + ('HTTP', 'storage'), + ('HTTP', 'storagemgmt'), + ('haproxy', 'ctlplane'), + ('haproxy', 'internalapi'), + ('haproxy', 'storage'), + ('haproxy', 'storagemgmt'), + ('libvirt-vnc', 'internalapi'), + ('mysql', 'internalapi'), + ('neutron_ovn', 'internalapi'), + ('novnc-proxy', 'internalapi'), + ('ovn_controller', 'internalapi'), + ('ovn_dbs', 'internalapi'), + ('rabbitmq', 'internalapi'), + ('redis', 'internalapi'), +]) +def test_services(host, service, subhost): + result = host.check_output( + 'ipa service-show {}/test-0.{}.example.test@EXAMPLE.TEST'.format( + service, subhost)) + assert 'Principal name: {}/test-0.{}.example.test@EXAMPLE.TEST'.format( + service, subhost) in result + assert 'Principal alias: {}/test-0.{}.example.test@EXAMPLE.TEST'.format( + service, subhost) in result + 'Roles: Nova Host Manager' in result + assert 'Managed by: test-0.{}.example.test, test-0.example.test'.format( + subhost) in result diff --git a/tripleo_ipa/roles/tripleo_ipa_registration/defaults/main.yml b/tripleo_ipa/roles/tripleo_ipa_registration/defaults/main.yml new file mode 100644 index 0000000..5ac41c2 --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_registration/defaults/main.yml @@ -0,0 +1,23 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +# All variables intended for modification should place placed in this file. + +# All variables within this role should have a prefix of "tripleo_ipa" + +# enroll base server +tripleo_ipa_enroll_base_server: false diff --git a/tripleo_ipa/roles/tripleo_ipa_registration/meta/main.yml b/tripleo_ipa/roles/tripleo_ipa_registration/meta/main.yml new file mode 100644 index 0000000..5e60245 --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_registration/meta/main.yml @@ -0,0 +1,44 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +galaxy_info: + author: OpenStack + description: TripleO OpenStack Role -- tripleo_ipa_registration + company: Red Hat + license: Apache-2.0 + min_ansible_version: 2.7 + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + platforms: + - name: Fedora + versions: + - 28 + - name: CentOS + versions: + - 7 + + galaxy_tags: + - tripleo + + +# List your role dependencies here, one per line. Be sure to remove the '[]' above, +# if you add dependencies to this list. +dependencies: [] diff --git a/tripleo_ipa/roles/tripleo_ipa_registration/tasks/main.yml b/tripleo_ipa/roles/tripleo_ipa_registration/tasks/main.yml new file mode 100644 index 0000000..112fedb --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_registration/tasks/main.yml @@ -0,0 +1,63 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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 role adds a host and its required sub-hosts and services to +# FreeIPA as defined in the ServerMetadata. +# +# The following variables are required: +# - tripleo_ipa_enroll_base_server (True if base server must be enrolled) +# - tripleo_ipa_base_server_fqdn (FQDN of base host eg. controller-0.example.com) +# - tripleo_ipa_base_server_otp (OTP for enrollment, only required if enroll_server is True) +# - tripleo_ipa_delegate_server (Server for OTP delegation, only required if enroll_server is True) +# - tripleo_ipa_server_metadata (server metadata, which includes required services) + +- name: set main facts + set_fact: + base_server_fqdn: "{{ tripleo_ipa_base_server_fqdn }}" + base_server_short_name: "{{ tripleo_ipa_base_server_fqdn.split('.')[0] }}" + base_server_domain: "{{ tripleo_ipa_base_server_fqdn.split('.', 1)[1] }}" + enroll_base_server: "{{ tripleo_ipa_enroll_base_server }}" + +- name: add main host to IPA with OTP + when: enroll_base_server|bool + block: + - name: get host raw data and keytab info + command: "ipa host-show --raw --all {{ base_server_fqdn }}" + register: host_raw_data + changed_when: false + failed_when: false + + - name: confirm that host is not already registered with current keytab + when: '"has_keytab: TRUE" not in host_raw_data.stdout' + block: + - name: add new host with random otp + ipa_host: + fqdn: "{{ base_server_fqdn }}" + random_password: true + force: true + register: ipa_host + ignore_errors: true + + - name: set otp as a host fact + set_fact: + ipa_host_otp: "{{ ipa_host.host.randompassword | default(omit) }}" + no_log: true + delegate_facts: true + delegate_to: "{{ tripleo_ipa_delegate_server }}" + +- name: add required services + include: services.yml + loop: "{{ tripleo_ipa_server_metadata | from_json | parse_service_metadata(base_server_fqdn) }}" diff --git a/tripleo_ipa/roles/tripleo_ipa_registration/tasks/services.yml b/tripleo_ipa/roles/tripleo_ipa_registration/tasks/services.yml new file mode 100644 index 0000000..2d5c624 --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_registration/tasks/services.yml @@ -0,0 +1,55 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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. +# +# The tasks in this file perform the registration process for a service. +# +# The following variable are required: +# - {item} : which is an ordered tuple of the form: +# -- { sub_host, service } +# +# An example of this is: +# { "controller-5.storagemgmt.example.com", "haproxy" } +# +# At this time, the final value in the tuple is unused. + +- name: set variables + set_fact: + sub_host: "{{ item.0 }}" + service: "{{ item.1 }}" + +- name: add sub_host + ipa_host: + fqdn: "{{ sub_host }}" + force: true + state: present + validate_certs: false + +- name: add service + ipa_service: + name: "{{ service }}/{{ sub_host }}" + force: true + state: present + validate_certs: false + register: my_service + +- name: add host to managed_hosts if needed + when: base_server_fqdn not in my_service['host']['managedby_host'] + ipa_service: + name: "{{ service }}/{{ sub_host }}" + force: true + state: present + hosts: "{{ my_service['host']['managedby_host'] + [ base_server_fqdn ] }}" + validate_certs: false diff --git a/tripleo_ipa/roles/tripleo_ipa_setup/meta/main.yml b/tripleo_ipa/roles/tripleo_ipa_setup/meta/main.yml new file mode 100644 index 0000000..d7a5d03 --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_setup/meta/main.yml @@ -0,0 +1,44 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +galaxy_info: + author: OpenStack + description: TripleO-IPA Role -- tripleo_ipa_setup + company: Red Hat + license: Apache-2.0 + min_ansible_version: 2.7 + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + platforms: + - name: Fedora + versions: + - 28 + - name: CentOS + versions: + - 7 + + galaxy_tags: + - tripleo + + +# List your role dependencies here, one per line. Be sure to remove the '[]' above, +# if you add dependencies to this list. +dependencies: [] diff --git a/tripleo_ipa/roles/tripleo_ipa_setup/tasks/add_ipa_user.yml b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/add_ipa_user.yml new file mode 100644 index 0000000..ff0300a --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/add_ipa_user.yml @@ -0,0 +1,39 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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 playbook creates the nova user and adds it to the Nova Host Manager IPA +# role. This needs to be executed by a user that has permissions to add services +# and to add them to roles. +# + +- name: set nova service user facts + set_fact: + nova_service: "nova/{{ undercloud_fqdn }}" + +- name: add nova service + ipa_service: + name: "{{ nova_service }}" + state: present + force: true + +- name: add Nova Host Manager role + ipa_role: + name: Nova Host Manager + description: Nova Host Manager + privilege: + - Nova Host Management + service: + - "{{ nova_service }}" diff --git a/tripleo_ipa/roles/tripleo_ipa_setup/tasks/get_ipa_user_keytab.yml b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/get_ipa_user_keytab.yml new file mode 100644 index 0000000..d5ac629 --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/get_ipa_user_keytab.yml @@ -0,0 +1,44 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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 role is supposed to be run on the undercloud. In this role, +# we retrieve a keytab for the previously created nova user/service. +# The undercloud is assumed to be enrolled as an ipa client +# + +- name: set keytab permissions facts + set_fact: + nova_service: "nova/{{ undercloud_fqdn }}" + nova_keytab: "/etc/novajoin/krb5.keytab" + nova_keytab_group: "tripleo-admin" + +- name: add directory for keytab + file: + path: "/etc/novajoin" + state: directory + mode: '0755' + +- name: get a keytab for the novajoin service + shell: | + ipa-getkeytab \ + -p "{{ nova_service }}" \ + -k "{{ nova_keytab }}" + +- name: chgrp and chmod the keytab + file: + path: "{{ nova_keytab }}" + group: "{{ nova_keytab_group }}" + mode: "g+r" diff --git a/tripleo_ipa/roles/tripleo_ipa_setup/tasks/main.yml b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/main.yml new file mode 100644 index 0000000..ad599c0 --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/main.yml @@ -0,0 +1,23 @@ +--- +# Copyright 2019 Red Hat, 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: create ipa_user_role + include: setup.yml + +- name: create ipa_user for this undercloud + include: add_ipa_user.yml + +- name: get keytab for this user + include: get_ipa_user_keytab.yml diff --git a/tripleo_ipa/roles/tripleo_ipa_setup/tasks/setup.yml b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/setup.yml new file mode 100644 index 0000000..5918782 --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_setup/tasks/setup.yml @@ -0,0 +1,84 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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 playbook adds the privileges and IPA role needed to do the things that +# tripleo wants to do in FreeIPA to add hosts and services. The operations in +# this playbook likely need admin privileges and should be executed on an +# IPA client. +# + +- name: set keytab permissions facts + set_fact: + novajoin_perms: + - {name: 'Modify host password', right: "write", type: "host", attrs: "userpassword"} + - {name: 'Write host certificate', right: "write", type: "host", attrs: "usercertificate"} + - {name: 'Modify host userclass', right: "write", type: "host", attrs: "userclass"} + - {name: 'Modify service managedBy attribute', right: "write", type: "service", attrs: "managedby"} + novajoin_privilege_perms: + - 'System: add hosts' + - 'System: remove hosts' + - 'Modify host password' + - 'Modify host userclass' + - 'System: Modify hosts' + - 'Modify service managedBy attribute' + - 'System: Add krbPrincipalName to a Host' + - 'System: Add Services' + - 'System: Remove Services' + - 'Revoke certificate' + - 'System: manage host keytab' + - 'System: Manage host certificates' + - 'System: modify services' + - 'System: manage service keytab' + - 'System: read dns entries' + - 'System: remove dns entries' + - 'System: add dns entries' + - 'System: update dns entries' + - 'Retrieve Certificates from the CA' + +# unfortunately we don't have ansible module yet to create perms +- name: add nova host managedment permissions + shell: | + ipa permission-find "{{ item.name }}" + if [ $? -ne 0 ]; then + ipa permission-add "{{ item.name }}" --right "{{ item.right }}" \ + --type "{{ item.type }}" --attrs "{{ item.attrs }}" + fi + loop: "{{ novajoin_perms|flatten(levels=1) }}" + +# unfortunately we don't have ansible module yet to create privileges +- name: add Nova Host privilege + shell: | + ipa privilege-find 'Nova Host Management' + if [ $? -ne 0 ]; then + ipa privilege-add --desc='Nova Host Management' 'Nova Host Management' + fi + +- name: add permissions to the Nova Host privilege + shell: | + ipa privilege-add-permission 'Nova Host Management' \ + --permission "{{ item }}" + register: add_perm_command + failed_when: + - add_perm_command.rc !=0 + - '"This entry is already a member" not in add_perm_command.stdout' + loop: "{{ novajoin_privilege_perms|flatten(levels=1) }}" + +- name: add Nova Host Manager role + ipa_role: + name: Nova Host Manager + description: Nova Host Manager + privilege: + - Nova Host Management diff --git a/tripleo_ipa/tasks/main.yml b/tripleo_ipa/tasks/main.yml deleted file mode 100644 index c1840e6..0000000 --- a/tripleo_ipa/tasks/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# tasks file for tripleo_ipa \ No newline at end of file diff --git a/tripleo_ipa/vars/main.yml b/tripleo_ipa/vars/main.yml deleted file mode 100644 index 1ed37c4..0000000 --- a/tripleo_ipa/vars/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -# vars file for tripleo_ipa \ No newline at end of file diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml index ab6cdef..7c9826b 100644 --- a/zuul.d/base.yaml +++ b/zuul.d/base.yaml @@ -10,5 +10,7 @@ - zuul.d/playbooks/pre.yml run: - zuul.d/playbooks/run.yml + post-run: + - zuul.d/playbooks/post.yml timeout: 1800 voting: true diff --git a/zuul.d/playbooks/post.yml b/zuul.d/playbooks/post.yml new file mode 100644 index 0000000..f3f3fca --- /dev/null +++ b/zuul.d/playbooks/post.yml @@ -0,0 +1,34 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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: TripleO IPA Post + hosts: all + tasks: + + - name: Make ipaserver-install log readable + file: + path: "/tmp/ipa-data/var/log/ipaserver-install.log" + mode: 0644 + become: true + failed_when: false + + - name: Collect ipaserver-install logs + synchronize: + dest: "{{ zuul.executor.log_root }}" + mode: pull + src: "/tmp/ipa-data/var/log/ipaserver-install.log" + verify_host: true + failed_when: false