diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index fa40744836b0e4c9dc6ddd5be0cd4c2e8ed8cc5c..c0a2640abb1ee2b5efadf4fee4ee9604fb133347 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -641,6 +641,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 a99b486157bacf05434a9d856dcd87e188716486..ff32b40dec6e85a6d22abda3a0e74772c0961fd6 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: ['<https://dashboardServerOne/auth/websso/>', '<https://dashboardServerTwo/auth/websso/>', '<https://dashboardServerN/auth/websso/>']
-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 12a9ec84dbc60fdf1f3197df4821223e84c0e395..7a5a633f16d2530da88dceee1a1ef3684712ebbf 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 b6bb53b577f34065d1603082de54e3590a4b7b4e..4bcc9a056f41035f515c8448e39da086d402733a 100644
--- a/ansible/roles/skyline/templates/skyline.yaml.j2
+++ b/ansible/roles/skyline/templates/skyline.yaml.j2
@@ -82,6 +82,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 89f0830c5883509bb832ae467496622c215481ab..17884cb763e648d56d719951195203d6a7f8ede5 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 0000000000000000000000000000000000000000..256ee97ed6cc735160b97bc57286d3ebb89a2185
--- /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 0000000000000000000000000000000000000000..076abbfda06df10811e7dc090655dd974baea8a0
--- /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 9723d2b72b1be8749bb1c33276bd412cf5cf24c4..4fd33e6bcca0cf841ffe2d7fc88df29fd4d7fb08 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 75316e5f27913c713dfa625080b50b7a7da9b9f0..0502b253c40a5f79453b9e13025fdbd576e2302c 100644
--- a/tests/templates/globals-default.j2
+++ b/tests/templates/globals-default.j2
@@ -263,6 +263,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 0000000000000000000000000000000000000000..c2b06f2139b221111afea54f166c699399b4de2f
--- /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 5b276392e2d94f346c334ec95434de89bb0d775d..6216799d1659ab1ae9553db0e5dfcc3dfd459cff 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 296ad316be00fa6ddd57a0d3048de168f0c7d20c..caf592f730547a3d6ce7d43146ffbb2f50e8efa1 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 af1a01fa44528a90c1bc90f304f04b1553bd5e79..59d6f79528baaf8987b023b299ccf8b1340152d4 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 ae3d17f1220bf2005e1982b9c680d20b00ebe053..e63357809a9041c2e2371db2b21ab5cadc6fbae6 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -75,6 +75,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