Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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());
}

}
}
Original file line number Diff line number Diff line change
@@ -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));
}
});
}
}