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