Repository: ambari Updated Branches: refs/heads/trunk 5f3038138 -> dde658303
AMBARI-20385 : Grafana is storing credentials in plain text in its configuration. (avijayan) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/dde65830 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/dde65830 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/dde65830 Branch: refs/heads/trunk Commit: dde6583030ddf3b28d543942b8df0216f3bec826 Parents: 5f30381 Author: Aravindan Vijayan <[email protected]> Authored: Thu Mar 9 14:14:16 2017 -0800 Committer: Aravindan Vijayan <[email protected]> Committed: Thu Mar 9 14:14:16 2017 -0800 ---------------------------------------------------------------------- .../server/upgrade/UpgradeCatalog250.java | 21 +++++ .../0.1.0/configuration/ams-grafana-ini.xml | 2 +- .../0.1.0/package/scripts/metrics_grafana.py | 4 +- .../package/scripts/metrics_grafana_util.py | 42 ++++++++++ .../server/upgrade/UpgradeCatalog250Test.java | 87 ++++++++++++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/dde65830/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java index ca35c52..b217723 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog250.java @@ -79,6 +79,7 @@ public class UpgradeCatalog250 extends AbstractUpgradeCatalog { protected static final String GROUPS_TABLE = "groups"; protected static final String GROUP_TYPE_COL = "group_type"; private static final String AMS_ENV = "ams-env"; + private static final String AMS_GRAFANA_INI = "ams-grafana-ini"; private static final String AMS_SITE = "ams-site"; private static final String AMS_LOG4J = "ams-log4j"; private static final String AMS_HBASE_LOG4J = "ams-hbase-log4j"; @@ -511,6 +512,15 @@ public class UpgradeCatalog250 extends AbstractUpgradeCatalog { updateConfigurationPropertiesForCluster(cluster,AMS_HBASE_LOG4J,newProperties,true,true); } + Config amsGrafanaIni = cluster.getDesiredConfigByType(AMS_GRAFANA_INI); + if (amsGrafanaIni != null) { + Map<String, String> amsGrafanaIniProperties = amsGrafanaIni.getProperties(); + String content = amsGrafanaIniProperties.get("content"); + Map<String, String> newProperties = new HashMap<>(); + newProperties.put("content", updateAmsGrafanaIniContent(content)); + updateConfigurationPropertiesForCluster(cluster, AMS_GRAFANA_INI, newProperties, true, true); + } + } } } @@ -654,6 +664,17 @@ public class UpgradeCatalog250 extends AbstractUpgradeCatalog { } } + protected String updateAmsGrafanaIniContent(String content) { + if (content == null) { + return null; + } + + String toReplace = "admin_password = {{ams_grafana_admin_pwd}}"; + String replaceWith = ";admin_password ="; + content = content.replace(toReplace, replaceWith); + return content; + } + protected String updateAmsEnvContent(String content) { if (content == null) { return null; http://git-wip-us.apache.org/repos/asf/ambari/blob/dde65830/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-grafana-ini.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-grafana-ini.xml b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-grafana-ini.xml index acbdf12..ee0a4ad 100644 --- a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-grafana-ini.xml +++ b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-grafana-ini.xml @@ -162,7 +162,7 @@ cert_key = {{ams_grafana_cert_key}} admin_user = {{ams_grafana_admin_user}} # default admin password, can be changed before first start of grafana, or in profile settings -admin_password = {{ams_grafana_admin_pwd}} +;admin_password = # used for signing ;secret_key = SW2YcwTIb9zpOOhoPsMm http://git-wip-us.apache.org/repos/asf/ambari/blob/dde65830/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana.py b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana.py index a364c72..1f0e049 100644 --- a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana.py +++ b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana.py @@ -22,7 +22,7 @@ from resource_management import Script, Execute from resource_management.libraries.functions import format from status import check_service_status from ams import ams -from metrics_grafana_util import create_ams_datasource, create_ams_dashboards +from metrics_grafana_util import create_ams_datasource, create_ams_dashboards, create_grafana_admin_pwd from resource_management.core.logger import Logger from resource_management.core import sudo @@ -54,6 +54,8 @@ class AmsGrafana(Script): else: Logger.info("Grafana Server has started with pid: {0}".format(sudo.read_file(pidfile).strip())) + #Set Grafana admin pwd + create_grafana_admin_pwd() # Create datasource create_ams_datasource() # Create pre-built dashboards http://git-wip-us.apache.org/repos/asf/ambari/blob/dde65830/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana_util.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana_util.py b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana_util.py index 95424f9..c8d532f 100644 --- a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana_util.py +++ b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/metrics_grafana_util.py @@ -38,6 +38,7 @@ GRAFANA_CONNECT_TRIES = 15 GRAFANA_CONNECT_TIMEOUT = 20 GRAFANA_SEARCH_BUILTIN_DASHBOARDS = "/api/search?tag=builtin" GRAFANA_DATASOURCE_URL = "/api/datasources" +GRAFANA_USER_URL = "/api/user" GRAFANA_DASHBOARDS_URL = "/api/dashboards/db" METRICS_GRAFANA_DATASOURCE_NAME = "AMBARI_METRICS" @@ -222,6 +223,47 @@ def do_ams_collector_post(metric_collector_host, params): post_metrics_to_collector(ams_metrics_post_url, metric_collector_host, params.metric_collector_port, params.metric_collector_https_enabled, metric_json, headers, ca_certs) +def create_grafana_admin_pwd(): + import params + + serverCall1 = Server(protocol = params.ams_grafana_protocol.strip(), + host = params.ams_grafana_host.strip(), + port = params.ams_grafana_port, + user = params.ams_grafana_admin_user, + password = params.ams_grafana_admin_pwd) + + response = perform_grafana_get_call(GRAFANA_USER_URL, serverCall1) + if response and response.status != 200: + + serverCall2 = Server(protocol = params.ams_grafana_protocol.strip(), + host = params.ams_grafana_host.strip(), + port = params.ams_grafana_port, + user = params.ams_grafana_admin_user, + password = 'admin') + + Logger.debug("Setting grafana admin password") + pwd_data = { "oldPassword": "admin", + "newPassword": params.ams_grafana_admin_pwd, + "confirmNew": params.ams_grafana_admin_pwd + } + password_json = json.dumps(pwd_data) + + (response, data) = perform_grafana_put_call(GRAFANA_USER_URL, 'password', password_json, serverCall2) + + if response.status == 200: + Logger.info("Ambari Metrics Grafana password updated.") + + elif response.status == 500: + Logger.info("Ambari Metrics Grafana password update failed. Not retrying.") + raise Fail("Ambari Metrics Grafana password update failed. PUT request status: %s %s \n%s" % + (response.status, response.reason, data)) + else: + raise Fail("Ambari Metrics Grafana password creation failed. " + "PUT request status: %s %s \n%s" % (response.status, response.reason, data)) + else: + Logger.info("Grafana password update not required.") + pass + def create_ams_datasource(): import params server = Server(protocol = params.ams_grafana_protocol.strip(), http://git-wip-us.apache.org/repos/asf/ambari/blob/dde65830/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java index 58c6e07..97832d0 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog250Test.java @@ -707,6 +707,93 @@ public class UpgradeCatalog250Test { } @Test + public void testAmsGrafanaIniUpdateConfigs() throws Exception { + + Map<String, String> oldProperties = new HashMap<String, String>() { + { + put("content", "[security]\n" + + "# default admin user, created on startup\n" + + "admin_user = {{ams_grafana_admin_user}}\n" + + "\n" + + "# default admin password, can be changed before first start of grafana, or in profile settings\n" + + "admin_password = {{ams_grafana_admin_pwd}}\n" + + "\n" + + "# used for signing\n" + + ";secret_key = SW2YcwTIb9zpOOhoPsMm\n" + + "\n" + + "# Auto-login remember days\n" + + ";login_remember_days = 7\n" + + ";cookie_username = grafana_user\n" + + ";cookie_remember_name = grafana_remember\n" + + "\n" + + "# disable gravatar profile images\n" + + ";disable_gravatar = false\n" + + "\n" + + "# data source proxy whitelist (ip_or_domain:port seperated by spaces)\n" + + ";data_source_proxy_whitelist =\n"); + } + }; + Map<String, String> newProperties = new HashMap<String, String>() { + { + put("content", "[security]\n" + + "# default admin user, created on startup\n" + + "admin_user = {{ams_grafana_admin_user}}\n" + + "\n" + + "# default admin password, can be changed before first start of grafana, or in profile settings\n" + + ";admin_password =\n" + + "\n" + + "# used for signing\n" + + ";secret_key = SW2YcwTIb9zpOOhoPsMm\n" + + "\n" + + "# Auto-login remember days\n" + + ";login_remember_days = 7\n" + + ";cookie_username = grafana_user\n" + + ";cookie_remember_name = grafana_remember\n" + + "\n" + + "# disable gravatar profile images\n" + + ";disable_gravatar = false\n" + + "\n" + + "# data source proxy whitelist (ip_or_domain:port seperated by spaces)\n" + + ";data_source_proxy_whitelist =\n"); + } + }; + EasyMockSupport easyMockSupport = new EasyMockSupport(); + + Config mockAmsGrafanaIni = easyMockSupport.createNiceMock(Config.class); + + reset(clusters, cluster); + expect(clusters.getClusters()).andReturn(new HashMap<String, Cluster>() {{ + put("normal", cluster); + }}).once(); + expect(cluster.getDesiredConfigByType("ams-grafana-ini")).andReturn(mockAmsGrafanaIni).atLeastOnce(); + expect(mockAmsGrafanaIni.getProperties()).andReturn(oldProperties).anyTimes(); + + replay(clusters, mockAmsGrafanaIni, cluster); + + AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class) + .addMockedMethod("createConfiguration") + .addMockedMethod("getClusters", new Class[]{}) + .addMockedMethod("createConfig") + .withConstructor(actionManager, clusters, injector) + .createNiceMock(); + + Injector injector2 = easyMockSupport.createNiceMock(Injector.class); + Capture<Map<String, String>> propertiesCapture = EasyMock.newCapture(); + + expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes(); + expect(controller.getClusters()).andReturn(clusters).anyTimes(); + expect(controller.createConfig(anyObject(Cluster.class), anyString(), capture(propertiesCapture), anyString(), + EasyMock.<Map<String, Map<String, String>>>anyObject())).andReturn(config).once(); + + replay(controller, injector2); + new UpgradeCatalog250(injector2).updateAMSConfigs(); + easyMockSupport.verifyAll(); + + Map<String, String> updatedProperties = propertiesCapture.getValue(); + assertTrue(Maps.difference(newProperties, updatedProperties).areEqual()); + } + + @Test public void testAmsHbaseSiteUpdateConfigs() throws Exception { Map<String, String> newProperties = new HashMap<String, String>() {
