Add SAML support to ceph-dashboard

This patchset adds support to setup authentication via the
SAML protocol for the ceph-dashboard.

Change-Id: I96c0d856d173a76739a6d2a9d4ad4811d3d196c3
func-test-pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/741
This commit is contained in:
Luciano Lo Giudice 2022-03-28 15:15:49 -03:00
parent 16653c75e1
commit af80051429
5 changed files with 209 additions and 1 deletions

View File

@ -83,6 +83,26 @@ options:
default: ""
description: |
Message of the day settings. Should be in the format "severity|expires|message". Set to "" to disable.
saml-base-url:
type: string
default: ""
description: |
The base URL from where the Ceph dashboard is accessed. Must support the SAML protocol.
saml-idp-metadata:
type: string
default: ""
description: |
URL that points to the IdP metadata XML. Can be remote or local.
saml-username-attribute:
type: string
default: ""
description: |
The attribute that is used to get the username from the authentication response.
saml-idp-entity-id:
type: string
default: "uid"
description: |
Unique ID to disambiguate when more than one entity id exists on the IdP metadata.
ssl_cert:
type: string
default:

View File

@ -18,6 +18,7 @@ series:
- focal
- groovy
- hirsute
- jammy
requires:
dashboard:
interface: ceph-dashboard

View File

@ -14,6 +14,7 @@ from ops.framework import StoredState
from ops.main import main
from ops.model import ActiveStatus, BlockedStatus, StatusBase
from ops.charm import ActionEvent
from ops_openstack.core import charm_class, get_charm_class_for_release
from typing import List, Union, Tuple
import base64
@ -425,6 +426,7 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
ceph_utils.mgr_enable_dashboard()
self._apply_ceph_config_from_charm_config()
self._configure_tls()
self._configure_saml()
ceph_utils.mgr_config_set(
'mgr/dashboard/{hostname}/server_addr'.format(
hostname=socket.gethostname()),
@ -568,6 +570,26 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
self.TLS_KEY_PATH)
self.kick_dashboard()
def _configure_saml(self) -> None:
if 'python3-onelogin-saml2' not in self.PACKAGES:
return
base_url = self.config.get('saml-base-url')
idp_metadata = self.config.get('saml-idp-metadata')
if not base_url or not idp_metadata:
return
cmd = ['ceph', 'dashboard', 'sso', 'setup', 'saml2',
base_url, idp_metadata]
username_attr = self.config.get('saml-username-attribute')
if username_attr:
cmd.append(username_attr)
idp_entity_id = self.config.get('saml-idp-entity-id')
if idp_entity_id:
cmd.append(idp_entity_id)
self._run_cmd(cmd)
def _gen_user_password(self, length: int = 12) -> str:
"""Generate a password"""
alphabet = (
@ -604,5 +626,20 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
event.fail(exc.output)
@charm_class
class CephDashboardCharmOctopus(CephDashboardCharm):
_stored = StoredState()
release = 'octopus'
@charm_class
class CephDashboardCharmQuincy(CephDashboardCharm):
_stored = StoredState()
PACKAGES = ['ceph-mgr-dashboard', 'python3-onelogin-saml2']
release = 'quincy'
if __name__ == "__main__":
main(CephDashboardCharm)
main(get_charm_class_for_release())

View File

@ -0,0 +1,122 @@
local_overlay_enabled: False
series: focal
variables:
openstack-origin: &openstack-origin cloud:focal-yoga
applications:
ceph-osd:
charm: ch:ceph-osd
num_units: 6
storage:
osd-devices: 'cinder,10G'
options:
osd-devices: '/dev/test-non-existent'
source: *openstack-origin
channel: quincy/edge
ceph-mon:
charm: ch:ceph-mon
num_units: 3
options:
monitor-count: '3'
source: *openstack-origin
channel: quincy/edge
vault:
num_units: 1
charm: ch:vault
channel: latest/edge
mysql-innodb-cluster:
charm: ch:mysql-innodb-cluster
constraints: mem=3072M
num_units: 3
options:
source: *openstack-origin
channel: latest/edge
vault-mysql-router:
charm: ch:mysql-router
channel: latest/edge
ceph-dashboard:
charm: ../../ceph-dashboard.charm
options:
public-hostname: 'ceph-dashboard.zaza.local'
source: *openstack-origin
prometheus:
charm: cs:prometheus2
num_units: 1
grafana:
# SSL and allow_embedding are not released into cs:grafana yet, due
# October 2021
charm: ch:grafana
num_units: 1
options:
anonymous: True
install_plugins: https://storage.googleapis.com/plugins-community/vonage-status-panel/release/1.0.11/vonage-status-panel-1.0.11.zip,https://storage.googleapis.com/plugins-community/grafana-piechart-panel/release/1.6.2/grafana-piechart-panel-1.6.2.zip
install_method: snap
allow_embedding: True
telegraf:
charm: telegraf
channel: stable
options:
hostname: "{host}"
prometheus-alertmanager:
charm: cs:prometheus-alertmanager
num_units: 1
ceph-radosgw:
charm: ch:ceph-radosgw
num_units: 3
channel: latest/edge
ceph-fs:
charm: ch:ceph-fs
num_units: 1
channel: latest/edge
ceph-iscsi:
charm: ch:ceph-iscsi
num_units: 2
options:
gateway-metadata-pool: iscsi-foo-metadata
channel: latest/edge
relations:
- - 'ceph-osd:mon'
- 'ceph-mon:osd'
- - 'vault:shared-db'
- 'vault-mysql-router:shared-db'
- - 'vault-mysql-router:db-router'
- 'mysql-innodb-cluster:db-router'
- - 'ceph-dashboard:dashboard'
- 'ceph-mon:dashboard'
- - 'ceph-dashboard:certificates'
- 'vault:certificates'
- - 'ceph-mon:prometheus'
- 'prometheus:target'
- - 'grafana:grafana-source'
- 'prometheus:grafana-source'
- - 'grafana:certificates'
- 'vault:certificates'
- - 'ceph-osd:juju-info'
- 'telegraf:juju-info'
- - 'ceph-mon:juju-info'
- 'telegraf:juju-info'
- - 'telegraf:prometheus-client'
- 'prometheus:target'
- - 'telegraf:dashboards'
- 'grafana:dashboards'
- - 'ceph-dashboard:grafana-dashboard'
- 'grafana:dashboards'
- - 'ceph-dashboard:alertmanager-service'
- 'prometheus-alertmanager:alertmanager-service'
- - 'ceph-dashboard:prometheus'
- 'prometheus:website'
- - 'prometheus:alertmanager-service'
- 'prometheus-alertmanager:alertmanager-service'
- - 'ceph-radosgw:mon'
- 'ceph-mon:radosgw'
- - 'ceph-radosgw:certificates'
- 'vault:certificates'
- - 'ceph-dashboard:radosgw-dashboard'
- 'ceph-radosgw:radosgw-user'
- - 'ceph-mon:mds'
- 'ceph-fs:ceph-mds'
- - 'ceph-mon:client'
- 'ceph-iscsi:ceph-client'
- - 'vault:certificates'
- 'ceph-iscsi:certificates'
- - 'ceph-dashboard:iscsi-dashboard'
- 'ceph-iscsi:admin-access'

View File

@ -679,3 +679,31 @@ class TestCephDashboardCharmBase(CharmTestCase):
self.subprocess.check_output.assert_called_once_with(
['ceph', 'dashboard', 'ac-user-delete', 'auser'],
stderr=self.subprocess.STDOUT)
def test_saml(self):
self.subprocess.check_output.return_value = b''
self.harness.begin()
self.harness.charm.PACKAGES.append('python3-onelogin-saml2')
self.harness.charm._configure_saml()
self.subprocess.check_output.assert_not_called()
base_url = 'https://saml-base'
idp_meta = 'file://idp.xml'
username_attr = 'uid'
entity_id = 'some_id'
self.harness.update_config(
key_values={
'saml-base-url': base_url,
'saml-idp-metadata': idp_meta,
'saml-username-attribute': username_attr,
'saml-idp-entity-id': entity_id,
}
)
self.harness.charm._configure_saml()
self.subprocess.check_output.assert_called_with(
['ceph', 'dashboard', 'sso', 'setup', 'saml2',
base_url, idp_meta, username_attr, entity_id],
stderr=ANY
)