You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2018/05/22 12:28:09 UTC
[ambari] branch trunk updated: [AMBARI-23921] If Kerberos is
enabled,
then stack upgrade prerequisite check should ensure the KDC admin credential
is persisted
This is an automated email from the ASF dual-hosted git repository.
rlevas pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new ceaf5cf [AMBARI-23921] If Kerberos is enabled, then stack upgrade prerequisite check should ensure the KDC admin credential is persisted
ceaf5cf is described below
commit ceaf5cfb1b79a973724bbe13596213555c5c1893
Author: Robert Levas <rl...@hortonworks.com>
AuthorDate: Mon May 21 22:30:19 2018 -0400
[AMBARI-23921] If Kerberos is enabled, then stack upgrade prerequisite check should ensure the KDC admin credential is persisted
---
.../ambari/server/checks/CheckDescription.java | 13 ++
.../KerberosAdminPersistedCredentialCheck.java | 104 ++++++++++
.../KerberosAdminPersistedCredentialCheckTest.java | 229 +++++++++++++++++++++
3 files changed, 346 insertions(+)
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
index 4ef5d50..76b8e23 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java
@@ -379,6 +379,19 @@ public class CheckDescription {
"Hence need to migrate existing data to newer formats post upgrade. " +
"To migrate existing data, Kindly refer and follow Apache Atlas documentation for 1.0 release.").build());
+ public static CheckDescription KERBEROS_ADMIN_CREDENTIAL_CHECK = new CheckDescription("KERBEROS_ADMIN_CREDENTIAL_CHECK",
+ PrereqCheckType.CLUSTER,
+ "The KDC administrator credentials need to be stored in Ambari persisted credential store.",
+ new ImmutableMap.Builder<String, String>()
+ .put(KerberosAdminPersistedCredentialCheck.KEY_PERSISTED_STORE_NOT_CONFIGURED,
+ "Ambari's credential store has not been configured. " +
+ "This is needed so the KDC administrator credential may be stored long enough to ensure it will be around if needed during the upgrade process.")
+ .put(KerberosAdminPersistedCredentialCheck.KEY_CREDENTIAL_NOT_STORED,
+ "The KDC administrator credential has not been stored in the persisted credential store. " +
+ "Visit the Kerberos administrator page to set the credential. " +
+ "This is needed so the KDC administrator credential may be stored long enough to ensure it will be around if needed during the upgrade process.")
+ .build());
+
private String m_name;
private PrereqCheckType m_type;
private String m_description;
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheck.java
new file mode 100644
index 0000000..1e5821d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheck.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.checks;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.security.encryption.CredentialStoreService;
+import org.apache.ambari.server.security.encryption.CredentialStoreType;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.SecurityType;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
+
+import com.google.inject.Inject;
+
+/**
+ * The {@link KerberosAdminPersistedCredentialCheck} class is used to check that the Kerberos
+ * administrator credentials are stored in the persisted credential store when Kerberos is enabled.
+ * <p>
+ * This is needed so that if Kerberos principals and/or keytab files need to be created during a stack
+ * upgrade, the KDC administrator credentials are guaranteed to be available. If the temporary store
+ * is used, the credential may have expired before needed.
+ */
+@UpgradeCheck(
+ group = UpgradeCheckGroup.KERBEROS,
+ required = {UpgradeType.ROLLING, UpgradeType.NON_ROLLING, UpgradeType.HOST_ORDERED})
+public class KerberosAdminPersistedCredentialCheck extends AbstractCheckDescriptor {
+
+ public static final String KEY_PERSISTED_STORE_NOT_CONFIGURED = "persisted_store_no_configured";
+
+ public static final String KEY_CREDENTIAL_NOT_STORED = "admin_credential_not_stored";
+
+ @Inject
+ private CredentialStoreService credentialStoreService;
+
+ /**
+ * Constructor.
+ */
+ @Inject
+ public KerberosAdminPersistedCredentialCheck() {
+ super(CheckDescription.KERBEROS_ADMIN_CREDENTIAL_CHECK);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<String> getApplicableServices() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException {
+
+ final String clusterName = request.getClusterName();
+ final Cluster cluster = clustersProvider.get().getCluster(clusterName);
+
+ // Perform the check only if Kerberos is enabled
+ if (cluster.getSecurityType() != SecurityType.KERBEROS) {
+ return;
+ }
+
+ // Perform the check only if Ambari is managing the Kerberos identities
+ if (!"true".equalsIgnoreCase(getProperty(request, "kerberos-env", "manage_identities"))) {
+ return;
+ }
+
+ if (!credentialStoreService.isInitialized(CredentialStoreType.PERSISTED)) {
+ // The persisted store is not available
+ prerequisiteCheck.setFailReason(getFailReason(KEY_PERSISTED_STORE_NOT_CONFIGURED, prerequisiteCheck, request));
+ prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
+ prerequisiteCheck.getFailedOn().add(request.getClusterName());
+ } else if (credentialStoreService.getCredential(clusterName, KerberosHelper.KDC_ADMINISTRATOR_CREDENTIAL_ALIAS, CredentialStoreType.PERSISTED) == null) {
+ // The KDC administrator credential has not been stored in the persisted credential store
+ prerequisiteCheck.setFailReason(getFailReason(KEY_CREDENTIAL_NOT_STORED, prerequisiteCheck, request));
+ prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL);
+ prerequisiteCheck.getFailedOn().add(request.getClusterName());
+ }
+
+ }
+}
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheckTest.java
new file mode 100644
index 0000000..46184ec
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheckTest.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.checks;
+
+import static org.easymock.EasyMock.expect;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.EntityManager;
+
+import org.apache.ambari.server.actionmanager.ActionDBAccessor;
+import org.apache.ambari.server.actionmanager.ActionDBAccessorImpl;
+import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.actionmanager.HostRoleCommandFactory;
+import org.apache.ambari.server.actionmanager.HostRoleCommandFactoryImpl;
+import org.apache.ambari.server.actionmanager.StageFactory;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.controller.AbstractRootServiceResponseFactory;
+import org.apache.ambari.server.controller.AmbariCustomCommandExecutionHelper;
+import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.PrereqCheckRequest;
+import org.apache.ambari.server.controller.RootServiceResponseFactory;
+import org.apache.ambari.server.hooks.HookService;
+import org.apache.ambari.server.hooks.users.UserHookService;
+import org.apache.ambari.server.metadata.CachedRoleCommandOrderProvider;
+import org.apache.ambari.server.metadata.RoleCommandOrderProvider;
+import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.orm.dao.ArtifactDAO;
+import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
+import org.apache.ambari.server.scheduler.ExecutionScheduler;
+import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
+import org.apache.ambari.server.security.SecurityHelper;
+import org.apache.ambari.server.security.credential.Credential;
+import org.apache.ambari.server.security.encryption.CredentialStoreService;
+import org.apache.ambari.server.security.encryption.CredentialStoreType;
+import org.apache.ambari.server.stack.StackManagerFactory;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.DesiredConfig;
+import org.apache.ambari.server.state.SecurityType;
+import org.apache.ambari.server.state.ServiceComponentHostFactory;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.apache.ambari.server.state.stack.PrereqCheckStatus;
+import org.apache.ambari.server.state.stack.PrerequisiteCheck;
+import org.apache.ambari.server.state.stack.UpgradePack;
+import org.apache.ambari.server.testutils.PartialNiceMockBinder;
+import org.apache.ambari.server.topology.PersistedState;
+import org.apache.ambari.server.topology.PersistedStateImpl;
+import org.easymock.EasyMockSupport;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Provider;
+
+public class KerberosAdminPersistedCredentialCheckTest extends EasyMockSupport {
+
+ @Test
+ public void testMissingCredentialStoreKerberosEnabledManagingIdentities() throws Exception {
+ PrerequisiteCheck result = executeCheck(true, true, false, false);
+ Assert.assertEquals(PrereqCheckStatus.FAIL, result.getStatus());
+ Assert.assertTrue(result.getFailReason().startsWith("Ambari's credential store has not been configured."));
+ }
+
+ @Test
+ public void testMissingCredentialStoreKerberosEnabledNotManagingIdentities() throws Exception {
+ PrerequisiteCheck result = executeCheck(true, false, false, false);
+ Assert.assertEquals(PrereqCheckStatus.PASS, result.getStatus());
+ }
+
+ @Test
+ public void testMissingCredentialStoreKerberosNotEnabled() throws Exception {
+ PrerequisiteCheck result = executeCheck(false, false, false, false);
+ Assert.assertEquals(PrereqCheckStatus.PASS, result.getStatus());
+ }
+
+ @Test
+ public void testMissingCredentialKerberosEnabledManagingIdentities() throws Exception {
+ PrerequisiteCheck result = executeCheck(true, true, true, false);
+ Assert.assertEquals(PrereqCheckStatus.FAIL, result.getStatus());
+ Assert.assertTrue(result.getFailReason().startsWith("The KDC administrator credential has not been stored in the persisted credential store."));
+ }
+
+ @Test
+ public void testMissingCredentialKerberosEnabledNotManagingIdentities() throws Exception {
+ PrerequisiteCheck result = executeCheck(true, false, true, false);
+ Assert.assertEquals(PrereqCheckStatus.PASS, result.getStatus());
+ }
+
+ @Test
+ public void testMissingCredentialKerberosNotEnabled() throws Exception {
+ PrerequisiteCheck result = executeCheck(false, true, true, false);
+ Assert.assertEquals(PrereqCheckStatus.PASS, result.getStatus());
+ }
+
+ @Test
+ public void testCredentialsSetKerberosNotEnabled() throws Exception {
+ PrerequisiteCheck result = executeCheck(false, false, true, true);
+ Assert.assertEquals(PrereqCheckStatus.PASS, result.getStatus());
+ }
+
+ @Test
+ public void testCredentialsSetKerberosEnabledNotManagingIdentities() throws Exception {
+ PrerequisiteCheck result = executeCheck(true, false, true, true);
+ Assert.assertEquals(PrereqCheckStatus.PASS, result.getStatus());
+ }
+
+ @Test
+ public void testCredentialsSetKerberosEnabledManagingIdentities() throws Exception {
+ PrerequisiteCheck result = executeCheck(true, true, true, true);
+ Assert.assertEquals(PrereqCheckStatus.PASS, result.getStatus());
+ }
+
+ private PrerequisiteCheck executeCheck(boolean kerberosEnabled, boolean manageIdentities, boolean credentialStoreInitialized, boolean credentialSet) throws Exception {
+
+ String clusterName = "c1";
+
+ Map<String, String> checkProperties = new HashMap<>();
+
+ UpgradePack.PrerequisiteCheckConfig prerequisiteCheckConfig = createMock(UpgradePack.PrerequisiteCheckConfig.class);
+ expect(prerequisiteCheckConfig.getCheckProperties(KerberosAdminPersistedCredentialCheck.class.getName())).andReturn(checkProperties).anyTimes();
+
+ PrerequisiteCheck prerequisiteCheck = new PrerequisiteCheck(null, null);
+ PrereqCheckRequest request = new PrereqCheckRequest(clusterName);
+ request.setPrerequisiteCheckConfig(prerequisiteCheckConfig);
+
+ DesiredConfig desiredKerberosEnv = createMock(DesiredConfig.class);
+ expect(desiredKerberosEnv.getTag()).andReturn("tag").anyTimes();
+
+ Map<String, DesiredConfig> desiredConfigs = Collections.singletonMap("kerberos-env", desiredKerberosEnv);
+
+ Config kerberosEnv = createMock(Config.class);
+ expect(kerberosEnv.getProperties()).andReturn(Collections.singletonMap("manage_identities", manageIdentities ? "true" : "false")).anyTimes();
+
+ Cluster cluster = createMock(Cluster.class);
+ expect(cluster.getSecurityType()).andReturn(kerberosEnabled ? SecurityType.KERBEROS : SecurityType.NONE).anyTimes();
+ expect(cluster.getDesiredConfigs()).andReturn(desiredConfigs).anyTimes();
+ expect(cluster.getConfig("kerberos-env", "tag")).andReturn(kerberosEnv).anyTimes();
+
+ Clusters clusters = createMock(Clusters.class);
+ expect(clusters.getCluster(clusterName)).andReturn(cluster).anyTimes();
+
+ Credential credential = createMock(Credential.class);
+
+ Injector injector = getInjector();
+ CredentialStoreService credentialStoreProvider = injector.getInstance(CredentialStoreService.class);
+ expect(credentialStoreProvider.isInitialized(CredentialStoreType.PERSISTED)).andReturn(credentialStoreInitialized).anyTimes();
+ expect(credentialStoreProvider.getCredential(clusterName, KerberosHelper.KDC_ADMINISTRATOR_CREDENTIAL_ALIAS, CredentialStoreType.PERSISTED)).andReturn(credentialSet ? credential : null).anyTimes();
+
+ Provider<Clusters> clustersProvider = () -> clusters;
+
+ replayAll();
+
+ injector.getInstance(AmbariMetaInfo.class).init();
+
+ KerberosAdminPersistedCredentialCheck check = new KerberosAdminPersistedCredentialCheck();
+ injector.injectMembers(check);
+
+ check.clustersProvider = clustersProvider;
+ check.perform(prerequisiteCheck, request);
+
+ verifyAll();
+
+ return prerequisiteCheck;
+ }
+
+
+ Injector getInjector() {
+ return Guice.createInjector(new AbstractModule() {
+
+ @Override
+ protected void configure() {
+ PartialNiceMockBinder.newBuilder().addActionDBAccessorConfigsBindings().addFactoriesInstallBinding()
+ .build().configure(binder());
+
+ bind(ExecutionScheduler.class).toInstance(createNiceMock(ExecutionSchedulerImpl.class));
+ bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
+ bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class));
+ bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
+ bind(HostRoleCommandDAO.class).toInstance(createNiceMock(HostRoleCommandDAO.class));
+ bind(HostRoleCommandFactory.class).toInstance(createNiceMock(HostRoleCommandFactoryImpl.class));
+ bind(ActionDBAccessor.class).to(ActionDBAccessorImpl.class);
+ bind(AbstractRootServiceResponseFactory.class).to(RootServiceResponseFactory.class);
+ bind(ServiceComponentHostFactory.class).toInstance(createNiceMock(ServiceComponentHostFactory.class));
+ bind(PasswordEncoder.class).toInstance(createNiceMock(PasswordEncoder.class));
+ bind(HookService.class).to(UserHookService.class);
+ bind(PersistedState.class).to(PersistedStateImpl.class);
+ bind(SecurityHelper.class).toInstance(createNiceMock(SecurityHelper.class));
+ bind(AmbariCustomCommandExecutionHelper.class).toInstance(createNiceMock(AmbariCustomCommandExecutionHelper.class));
+ bind(AmbariManagementController.class).toInstance(createNiceMock(AmbariManagementController.class));
+ bind(AmbariMetaInfo.class).toInstance(createNiceMock(AmbariMetaInfo.class));
+ bind(ActionManager.class).toInstance(createNiceMock(ActionManager.class));
+ bind(StageFactory.class).toInstance(createNiceMock(StageFactory.class));
+ bind(Clusters.class).toInstance(createNiceMock(Clusters.class));
+ bind(ConfigHelper.class).toInstance(createNiceMock(ConfigHelper.class));
+ bind(StackManagerFactory.class).toInstance(createNiceMock(StackManagerFactory.class));
+ bind(AuditLogger.class).toInstance(createNiceMock(AuditLogger.class));
+ bind(ArtifactDAO.class).toInstance(createNiceMock(ArtifactDAO.class));
+ bind(RoleCommandOrderProvider.class).to(CachedRoleCommandOrderProvider.class);
+
+ bind(CredentialStoreService.class).toInstance(createMock(CredentialStoreService.class));
+ }
+ });
+ }
+}
--
To stop receiving notification emails like this one, please contact
rlevas@apache.org.