]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/cephadm: allow configuring anonymous access for grafana
authorAdam King <adking@redhat.com>
Tue, 21 Mar 2023 18:12:03 +0000 (14:12 -0400)
committerAdam King <adking@redhat.com>
Sat, 20 May 2023 16:40:55 +0000 (12:40 -0400)
In case users want to not allow anonymous viewers
to view the grafana dashboard but don't want to use
a full custom config

Fixes: https://tracker.ceph.com/issues/59117
Signed-off-by: Adam King <adking@redhat.com>
(cherry picked from commit e6690dde7b384d7d13e1a17119c648acfadee638)

doc/cephadm/services/monitoring.rst
src/pybind/mgr/cephadm/services/monitoring.py
src/pybind/mgr/cephadm/templates/services/grafana/grafana.ini.j2
src/pybind/mgr/cephadm/tests/test_services.py
src/pybind/mgr/cephadm/tests/test_spec.py
src/python-common/ceph/deployment/service_spec.py
src/python-common/ceph/tests/test_service_spec.py

index 560a95b5146134dc2cbf26fe8844419f545eefa5..a17a5ba039bdecbc740228f1e02c2719ee375d82 100644 (file)
@@ -467,6 +467,28 @@ Then apply this specification:
 Grafana will now create an admin user called ``admin`` with the
 given password.
 
+Turning off anonymous access
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, cephadm allows anonymous users (users who have not provided any
+login information) limited, viewer only access to the grafana dashboard. In
+order to set up grafana to only allow viewing from logged in users, you can
+set ``anonymous_access: False`` in your grafana spec.
+
+.. code-block:: yaml
+
+  service_type: grafana
+  placement:
+    hosts:
+    - host1
+  spec:
+    anonymous_access: False
+    initial_admin_password: "mypassword"
+
+Since deploying grafana with anonymous access set to false without an initial
+admin password set would make the dashboard inaccessible, cephadm requires
+setting the ``initial_admin_password`` when ``anonymous_access`` is set to false.
+
 
 Setting up Alertmanager
 -----------------------
index 6c63ef6436a105f8307511c05ab38e2113778785..e0c0640ae49bf1a482f63a05d1a09aba199d7268 100644 (file)
@@ -68,6 +68,7 @@ class GrafanaService(CephadmService):
             GrafanaSpec, self.mgr.spec_store.active_specs[daemon_spec.service_name])
         grafana_ini = self.mgr.template.render(
             'services/grafana/grafana.ini.j2', {
+                'anonymous_access': spec.anonymous_access,
                 'initial_admin_password': spec.initial_admin_password,
                 'http_port': daemon_spec.ports[0] if daemon_spec.ports else self.DEFAULT_SERVICE_PORT,
                 'protocol': spec.protocol,
index 9d74ccd039c3062046621a05500fa67279427f03..e6c7bce15245148047d9788d8de7e893ad2fc193 100644 (file)
@@ -1,10 +1,12 @@
 # {{ cephadm_managed }}
 [users]
   default_theme = light
+{% if anonymous_access %}
 [auth.anonymous]
   enabled = true
   org_name = 'Main Org.'
   org_role = 'Viewer'
+{% endif %}
 [server]
   domain = 'bootstrap.storage.lab'
   protocol = {{ protocol }}
index b6172e45af08c09a1b56042094ccc0bcfdc9dc23..7d545431873cd1c76ea0aa820a7fb7e10c8993a8 100644 (file)
@@ -911,6 +911,54 @@ class TestMonitoring:
                                 'certs/cert_file': ANY,
                                 'certs/cert_key': ANY}}, ['secure_monitoring_stack:False'])
 
+    @patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}'))
+    def test_grafana_no_anon_access(self, cephadm_module: CephadmOrchestrator):
+        # with anonymous_access set to False, expecting the [auth.anonymous] section
+        # to not be present in the grafana config. Note that we require an initial_admin_password
+        # to be provided when anonymous_access is False
+        with with_host(cephadm_module, 'test'):
+            with with_service(cephadm_module, ServiceSpec('mgr')) as _, \
+                    with_service(cephadm_module, GrafanaSpec(anonymous_access=False, initial_admin_password='secure')):
+                out = cephadm_module.cephadm_services['grafana'].generate_config(
+                    CephadmDaemonDeploySpec('test', 'daemon', 'grafana'))
+                assert out == (
+                    {
+                        'files':
+                            {
+                                'grafana.ini':
+                                    '# This file is generated by cephadm.\n'
+                                    '[users]\n'
+                                    '  default_theme = light\n'
+                                    '[server]\n'
+                                    "  domain = 'bootstrap.storage.lab'\n"
+                                    '  protocol = https\n'
+                                    '  cert_file = /etc/grafana/certs/cert_file\n'
+                                    '  cert_key = /etc/grafana/certs/cert_key\n'
+                                    '  http_port = 3000\n'
+                                    '  http_addr = \n'
+                                    '[snapshots]\n'
+                                    '  external_enabled = false\n'
+                                    '[security]\n'
+                                    '  admin_user = admin\n'
+                                    '  admin_password = secure\n'
+                                    '  cookie_secure = true\n'
+                                    '  cookie_samesite = none\n'
+                                    '  allow_embedding = true',
+                                'provisioning/datasources/ceph-dashboard.yml':
+                                    "# This file is generated by cephadm.\n"
+                                    "apiVersion: 1\n\n"
+                                    'deleteDatasources:\n\n'
+                                    'datasources:\n\n'
+                                    "  - name: 'Loki'\n"
+                                    "    type: 'loki'\n"
+                                    "    access: 'proxy'\n"
+                                    "    url: ''\n"
+                                    '    basicAuth: false\n'
+                                    '    isDefault: false\n'
+                                    '    editable: false',
+                                'certs/cert_file': ANY,
+                                'certs/cert_key': ANY}}, ['secure_monitoring_stack:False'])
+
     @patch("cephadm.serve.CephadmServe._run_cephadm")
     def test_monitoring_ports(self, _run_cephadm, cephadm_module: CephadmOrchestrator):
         _run_cephadm.side_effect = async_side_effect(('{}', '', 0))
index 5e2a479d9f5137615d4d0f923f33a9bce25d0567..78a2d73118fe71799e51c629d358df28bbe21ba2 100644 (file)
@@ -117,6 +117,7 @@ def test_spec_octopus(spec_json):
                 ]
         j_c.pop('objectstore', None)
         j_c.pop('filter_logic', None)
+        j_c.pop('anonymous_access', None)
         return j_c
 
     assert spec_json == convert_to_old_style_json(spec.to_json())
index a94704d822820740a58fae3d96c7cc5f12e5be82..9773b6facc0b4ba4a508c6c44fe68bf91f72b78b 100644 (file)
@@ -1292,6 +1292,7 @@ class GrafanaSpec(MonitoringSpec):
                  port: Optional[int] = None,
                  protocol: Optional[str] = 'https',
                  initial_admin_password: Optional[str] = None,
+                 anonymous_access: Optional[bool] = True,
                  extra_container_args: Optional[List[str]] = None,
                  extra_entrypoint_args: Optional[List[str]] = None,
                  custom_configs: Optional[List[CustomConfig]] = None,
@@ -1305,6 +1306,7 @@ class GrafanaSpec(MonitoringSpec):
             custom_configs=custom_configs)
 
         self.initial_admin_password = initial_admin_password
+        self.anonymous_access = anonymous_access
         self.protocol = protocol
 
     def validate(self) -> None:
@@ -1313,6 +1315,12 @@ class GrafanaSpec(MonitoringSpec):
             err_msg = f"Invalid protocol '{self.protocol}'. Valid values are: 'http', 'https'."
             raise SpecValidationError(err_msg)
 
+        if not self.anonymous_access and not self.initial_admin_password:
+            err_msg = ('Either initial_admin_password must be set or anonymous_access '
+                       'must be set to true. Otherwise the grafana dashboard will '
+                       'be inaccessible.')
+            raise SpecValidationError(err_msg)
+
 
 yaml.add_representer(GrafanaSpec, ServiceSpec.yaml_representer)
 
index 041cbbbd4ec79215d74c6c826e11dbe7f6456e26..a0e0be2aa815be6c84cb67e5b7b588766469829f 100644 (file)
@@ -53,6 +53,8 @@ def test_parse_host_placement_specs(test_input, expected, require_network):
         (GrafanaSpec(protocol='-https'), True, '^Invalid protocol'),
         (GrafanaSpec(protocol='http'), False, ''),
         (GrafanaSpec(protocol='https'), False, ''),
+        (GrafanaSpec(anonymous_access=False), True, '^Either initial'),  # we require inital_admin_password if anonymous_access is False
+        (GrafanaSpec(anonymous_access=False, initial_admin_password='test'), False, ''),
     ])
 def test_apply_grafana(spec: GrafanaSpec, raise_exception: bool, msg: str):
     if  raise_exception:
@@ -341,12 +343,14 @@ spec:
 service_type: grafana
 service_name: grafana
 spec:
+  anonymous_access: true
   port: 1234
   protocol: https
 ---
 service_type: grafana
 service_name: grafana
 spec:
+  anonymous_access: true
   initial_admin_password: secure
   port: 1234
   protocol: https