diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index ba42c2b9f2..ad55c74d64 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -642,6 +642,8 @@ skyline_apiserver_public_port: "{{ haproxy_single_external_frontend_public_port skyline_console_port: "9999" skyline_console_listen_port: "{{ skyline_console_port }}" skyline_console_public_port: "{{ haproxy_single_external_frontend_public_port if haproxy_single_external_frontend | bool else skyline_console_port }}" +skyline_console_public_endpoint: "{{ skyline_console_external_fqdn | kolla_url(public_protocol, skyline_console_public_port) }}" +skyline_enable_sso: "{{ enable_keystone_federation | bool and keystone_identity_providers | selectattr('protocol', 'equalto', 'openid') | list | count > 0 }}" solum_application_deployment_internal_fqdn: "{{ kolla_internal_fqdn }}" solum_application_deployment_external_fqdn: "{{ kolla_external_fqdn }}" diff --git a/ansible/roles/keystone/defaults/main.yml b/ansible/roles/keystone/defaults/main.yml index a99b486157..ff32b40dec 100644 --- a/ansible/roles/keystone/defaults/main.yml +++ b/ansible/roles/keystone/defaults/main.yml @@ -225,7 +225,9 @@ keystone_federation_oidc_additional_options: {} # These variables are used to define multiple trusted Horizon dashboards. # keystone_trusted_dashboards: ['', '', ''] -keystone_trusted_dashboards: "{{ ['%s://%s/auth/websso/' % (public_protocol, kolla_external_fqdn), '%s/auth/websso/' % (horizon_public_endpoint)] if enable_horizon | bool else [] }}" +horizon_trusted_dashboards: "{{ ['%s://%s/auth/websso/' % (public_protocol, kolla_external_fqdn), '%s/auth/websso/' % (horizon_public_endpoint)] if enable_horizon | bool else [] }}" +skyline_trusted_dashboards: "{{ ['%s/api/openstack/skyline/api/v1/websso' % (skyline_console_public_endpoint)] if enable_skyline | bool else [] }}" +keystone_trusted_dashboards: "{{ horizon_trusted_dashboards + skyline_trusted_dashboards }}" keystone_enable_federation_openid: "{{ enable_keystone_federation | bool and keystone_identity_providers | selectattr('protocol', 'equalto', 'openid') | list | count > 0 }}" keystone_should_remove_attribute_mappings: False keystone_should_remove_identity_providers: False diff --git a/ansible/roles/skyline/defaults/main.yml b/ansible/roles/skyline/defaults/main.yml index 12a9ec84db..7a5a633f16 100644 --- a/ansible/roles/skyline/defaults/main.yml +++ b/ansible/roles/skyline/defaults/main.yml @@ -182,6 +182,11 @@ skyline_ks_users: password: "{{ skyline_keystone_password }}" role: "admin" +#################### +# SSO +#################### +skyline_enable_sso: "no" + #################### # TLS #################### diff --git a/ansible/roles/skyline/templates/skyline.yaml.j2 b/ansible/roles/skyline/templates/skyline.yaml.j2 index f998109546..926cab446a 100644 --- a/ansible/roles/skyline/templates/skyline.yaml.j2 +++ b/ansible/roles/skyline/templates/skyline.yaml.j2 @@ -76,6 +76,12 @@ openstack: {% endif %} {% if enable_cinder | bool %} volumev3: cinder +{% endif %} + sso_enabled: {{ skyline_enable_sso | bool }} +{% if skyline_enable_sso | bool %} + sso_protocols: + - openid + sso_region: {{ openstack_region_name }} {% endif %} system_admin_roles: {% for skyline_system_admin_role in skyline_system_admin_roles %} diff --git a/doc/source/reference/shared-services/index.rst b/doc/source/reference/shared-services/index.rst index 89f0830c58..17884cb763 100644 --- a/doc/source/reference/shared-services/index.rst +++ b/doc/source/reference/shared-services/index.rst @@ -11,3 +11,4 @@ like backends, dashboards and so on. glance-guide horizon-guide keystone-guide + skyline-guide diff --git a/doc/source/reference/shared-services/skyline-guide.rst b/doc/source/reference/shared-services/skyline-guide.rst new file mode 100644 index 0000000000..256ee97ed6 --- /dev/null +++ b/doc/source/reference/shared-services/skyline-guide.rst @@ -0,0 +1,26 @@ +.. _skyline-guide: + +=========================== +Skyline OpenStack dashboard +=========================== + +Skyline is a dashboard for Openstack with a modern technology stack. + +Single Sign On (SSO) +~~~~~~~~~~~~~~~~~~~~ + +Skyline supports SSO with an Openid IdP. When you configure an IdP with +protocol openid, Kolla will automatically enable SSO and set up the trusted +dashboard url for Keystone. If you don't want to use SSO in Skyline, you can +disable it by setting ``skyline_enable_sso`` to "no": + +.. code-block:: yaml + + skyline_enable_sso: "no" + +If you want to enable it without setting up the IdP with Kolla you can simply +enable it with: + +.. code-block:: yaml + + skyline_enable_sso: "yes" diff --git a/releasenotes/notes/skyline-sso-2036301-9a2118472dd0d8cf.yaml b/releasenotes/notes/skyline-sso-2036301-9a2118472dd0d8cf.yaml new file mode 100644 index 0000000000..076abbfda0 --- /dev/null +++ b/releasenotes/notes/skyline-sso-2036301-9a2118472dd0d8cf.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Enables SSO in Skyline Console if Keystone federation is enabled and + at least one identity provider with protocol openid is set up. + Skyline Console's redirect URI is added to Keystone's trusted dashboards. diff --git a/tests/run.yml b/tests/run.yml index 9723d2b72b..4fd33e6bcc 100644 --- a/tests/run.yml +++ b/tests/run.yml @@ -577,6 +577,13 @@ chdir: "{{ kolla_ansible_src_dir }}" when: scenario == "skyline" + - name: Run test-skyline-sso.sh script + script: + cmd: test-skyline-sso.sh + executable: /bin/bash + chdir: "{{ kolla_ansible_src_dir }}" + when: scenario == "skyline-sso" + when: scenario != "bifrost" # NOTE(yoctozepto): each host checks itself diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2 index 1c11014083..e154d88556 100644 --- a/tests/templates/globals-default.j2 +++ b/tests/templates/globals-default.j2 @@ -266,6 +266,11 @@ kolla_admin_openrc_cacert: "{% raw %}{{ kolla_certificates_dir }}{% endraw %}/ca enable_skyline: "yes" {% endif %} +{% if scenario == "skyline-sso" %} +enable_skyline: "yes" +skyline_enable_sso: "yes" +{% endif %} + {# Workaround for https://github.com/rabbitmq/rabbitmq-server/issues/10728 #} {% if address_family == 'ipv6' %} {% raw %} diff --git a/tests/test-skyline-sso.sh b/tests/test-skyline-sso.sh new file mode 100644 index 0000000000..c2b06f2139 --- /dev/null +++ b/tests/test-skyline-sso.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -o xtrace +set -o pipefail + +# Enable unbuffered output +export PYTHONUNBUFFERED=1 + +function check_skyline_sso_enabled { + skyline_endpoint=$(openstack endpoint list --interface public --service skyline -f value -c URL) + # 9998 is the default port for skyline apiserver. + # 9999 is the default port for skyline console. + skyline_sso_url="${skyline_endpoint//9998/9999}/api/openstack/skyline/api/v1/sso" + + output_path=$1 + if ! curl -k --include --fail $skyline_sso_url -H "Accept: application/json" -H "Content-Type: application/json" > $output_path; then + return 1 + fi + if ! grep -E '"enable_sso":true' $output_path >/dev/null; then + return 1 + fi +} + +function test_skyline_sso { + . /etc/kolla/admin-openrc.sh + . ~/openstackclient-venv/bin/activate + test_skyline_sso_enabled +} + +function test_skyline_sso_enabled { + echo "TESTING: Skyline SSO enabled" + output_path=$(mktemp) + attempt=1 + while ! check_skyline_sso_enabled $output_path; do + echo "Skyline not accessible yet" + attempt=$((attempt+1)) + if [[ $attempt -eq 12 ]]; then + echo "FAILED: Skyline did not become accessible or SSO not enabled. Response:" + cat $output_path + return 1 + fi + sleep 10 + done + echo "SUCCESS: Skyline SSO enabled" +} + +function test_skyline_sso_scenario { + echo "Testing Skyline SSO" + test_skyline_sso > /tmp/logs/ansible/test-skyline-sso 2>&1 + result=$? + if [[ $result != 0 ]]; then + echo "Testing Skyline SSO failed. See ansible/test-skyline-sso for details" + else + echo "Successfully tested Skyline SSO. See ansible/test-skyline-sso for details" + fi + return $result +} + +test_skyline_sso_scenario diff --git a/tests/test-skyline.sh b/tests/test-skyline.sh index 5b276392e2..6216799d16 100644 --- a/tests/test-skyline.sh +++ b/tests/test-skyline.sh @@ -22,6 +22,21 @@ function check_skyline { fi } +function check_skyline_sso_disabled { + skyline_endpoint=$(openstack endpoint list --interface public --service skyline -f value -c URL) + # 9998 is the default port for skyline apiserver. + # 9999 is the default port for skyline console. + skyline_sso_url="${skyline_endpoint//9998/9999}/api/openstack/skyline/api/v1/sso" + + output_path=$1 + if ! curl -k --include --fail $skyline_sso_url -H "Accept: application/json" -H "Content-Type: application/json" > $output_path; then + return 1 + fi + if ! grep -E '"enable_sso":false' $output_path >/dev/null; then + return 1 + fi +} + function test_skyline { echo "TESTING: Skyline" output_path=$(mktemp) @@ -45,9 +60,26 @@ function test_skyline_logged { test_skyline } +function test_skyline_sso_disabled { + echo "TESTING: Skyline SSO disabled" + output_path=$(mktemp) + attempt=1 + while ! check_skyline_sso_disabled $output_path; do + echo "Skyline not accessible yet" + attempt=$((attempt+1)) + if [[ $attempt -eq 12 ]]; then + echo "FAILED: Skyline did not become accessible or SSO enabled. Response:" + cat $output_path + return 1 + fi + sleep 10 + done + echo "SUCCESS: Skyline SSO disabled" +} + function test_skyline_scenario { echo "Testing Skyline" - test_skyline_logged > /tmp/logs/ansible/test-skyline 2>&1 + test_skyline_logged > /tmp/logs/ansible/test-skyline 2>&1 && test_skyline_sso_disabled >> /tmp/logs/ansible/test-skyline 2>&1 result=$? if [[ $result != 0 ]]; then echo "Testing Skyline failed. See ansible/test-skyline for details" diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml index bc7f9d65eb..31cb6cdb25 100644 --- a/zuul.d/base.yaml +++ b/zuul.d/base.yaml @@ -321,3 +321,14 @@ - ^tests/test-skyline.sh vars: scenario: skyline + +- job: + name: kolla-ansible-skyline-sso-base + parent: kolla-ansible-base + voting: false + files: + - ^requirements-core.yml + - ^ansible/roles/skyline/ + - ^tests/test-skyline-sso.sh + vars: + scenario: skyline-sso diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index af1a01fa44..59d6f79528 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -563,3 +563,17 @@ nodeset: kolla-ansible-rocky9 vars: base_distro: rocky + +- job: + name: kolla-ansible-ubuntu-skyline-sso + parent: kolla-ansible-skyline-sso-base + nodeset: kolla-ansible-jammy + vars: + base_distro: ubuntu + +- job: + name: kolla-ansible-rocky9-skyline-sso + parent: kolla-ansible-skyline-sso-base + nodeset: kolla-ansible-rocky9 + vars: + base_distro: rocky diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index 028984584d..f2c95b21ec 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -71,6 +71,8 @@ - kolla-ansible-rocky9-lets-encrypt - kolla-ansible-ubuntu-skyline - kolla-ansible-rocky9-skyline + - kolla-ansible-ubuntu-skyline-sso + - kolla-ansible-rocky9-skyline-sso check-arm64: jobs: - kolla-ansible-debian-aarch64