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:
parent
16653c75e1
commit
af80051429
20
config.yaml
20
config.yaml
@ -83,6 +83,26 @@ options:
|
|||||||
default: ""
|
default: ""
|
||||||
description: |
|
description: |
|
||||||
Message of the day settings. Should be in the format "severity|expires|message". Set to "" to disable.
|
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:
|
ssl_cert:
|
||||||
type: string
|
type: string
|
||||||
default:
|
default:
|
||||||
|
@ -18,6 +18,7 @@ series:
|
|||||||
- focal
|
- focal
|
||||||
- groovy
|
- groovy
|
||||||
- hirsute
|
- hirsute
|
||||||
|
- jammy
|
||||||
requires:
|
requires:
|
||||||
dashboard:
|
dashboard:
|
||||||
interface: ceph-dashboard
|
interface: ceph-dashboard
|
||||||
|
39
src/charm.py
39
src/charm.py
@ -14,6 +14,7 @@ from ops.framework import StoredState
|
|||||||
from ops.main import main
|
from ops.main import main
|
||||||
from ops.model import ActiveStatus, BlockedStatus, StatusBase
|
from ops.model import ActiveStatus, BlockedStatus, StatusBase
|
||||||
from ops.charm import ActionEvent
|
from ops.charm import ActionEvent
|
||||||
|
from ops_openstack.core import charm_class, get_charm_class_for_release
|
||||||
from typing import List, Union, Tuple
|
from typing import List, Union, Tuple
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
@ -425,6 +426,7 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
|||||||
ceph_utils.mgr_enable_dashboard()
|
ceph_utils.mgr_enable_dashboard()
|
||||||
self._apply_ceph_config_from_charm_config()
|
self._apply_ceph_config_from_charm_config()
|
||||||
self._configure_tls()
|
self._configure_tls()
|
||||||
|
self._configure_saml()
|
||||||
ceph_utils.mgr_config_set(
|
ceph_utils.mgr_config_set(
|
||||||
'mgr/dashboard/{hostname}/server_addr'.format(
|
'mgr/dashboard/{hostname}/server_addr'.format(
|
||||||
hostname=socket.gethostname()),
|
hostname=socket.gethostname()),
|
||||||
@ -568,6 +570,26 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
|||||||
self.TLS_KEY_PATH)
|
self.TLS_KEY_PATH)
|
||||||
self.kick_dashboard()
|
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:
|
def _gen_user_password(self, length: int = 12) -> str:
|
||||||
"""Generate a password"""
|
"""Generate a password"""
|
||||||
alphabet = (
|
alphabet = (
|
||||||
@ -604,5 +626,20 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
|||||||
event.fail(exc.output)
|
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__":
|
if __name__ == "__main__":
|
||||||
main(CephDashboardCharm)
|
main(get_charm_class_for_release())
|
||||||
|
122
tests/bundles/focal-yoga.yaml
Normal file
122
tests/bundles/focal-yoga.yaml
Normal 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'
|
@ -679,3 +679,31 @@ class TestCephDashboardCharmBase(CharmTestCase):
|
|||||||
self.subprocess.check_output.assert_called_once_with(
|
self.subprocess.check_output.assert_called_once_with(
|
||||||
['ceph', 'dashboard', 'ac-user-delete', 'auser'],
|
['ceph', 'dashboard', 'ac-user-delete', 'auser'],
|
||||||
stderr=self.subprocess.STDOUT)
|
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
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user