This is an automated email from the ASF dual-hosted git repository. smolnar pushed a commit to branch branch-2.7 in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/branch-2.7 by this push: new 4d9d123 AMBARI-24672. Make sure we regenerate all service specific keytabs on all hosts where they are needed (#2802) 4d9d123 is described below commit 4d9d123320df7f829a4f4175ef7dbb2a2d4b05b3 Author: Sandor Molnar <smol...@apache.org> AuthorDate: Thu Jan 31 17:57:27 2019 +0100 AMBARI-24672. Make sure we regenerate all service specific keytabs on all hosts where they are needed (#2802) --- .../ambari/server/controller/AmbariServer.java | 2 + .../events/publishers/AgentCommandsPublisher.java | 5 ++- .../server/orm/dao/KerberosKeytabPrincipalDAO.java | 10 ++++- .../kerberos/KerberosServerAction.java | 25 ++++-------- .../stageutils/KerberosKeytabController.java | 44 ++++++++++++++++++++-- .../ambari/server/agent/TestHeartbeatHandler.java | 5 ++- .../kerberos/KerberosServerActionTest.java | 4 +- 7 files changed, 68 insertions(+), 27 deletions(-) diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index 07bf2b7..6f5f4e6 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -110,6 +110,7 @@ import org.apache.ambari.server.security.authorization.Users; import org.apache.ambari.server.security.unsecured.rest.CertificateDownload; import org.apache.ambari.server.security.unsecured.rest.CertificateSign; import org.apache.ambari.server.security.unsecured.rest.ConnectionInfo; +import org.apache.ambari.server.serveraction.kerberos.stageutils.KerberosKeytabController; import org.apache.ambari.server.stack.UpdateActiveRepoVersionOnStartup; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.topology.AmbariContext; @@ -942,6 +943,7 @@ public class AmbariServer { ClusterPrivilegeResourceProvider.init(injector.getInstance(ClusterDAO.class)); AmbariPrivilegeResourceProvider.init(injector.getInstance(ClusterDAO.class)); ActionManager.setTopologyManager(injector.getInstance(TopologyManager.class)); + KerberosKeytabController.setKerberosHelper(injector.getInstance(KerberosHelper.class)); StackAdvisorBlueprintProcessor.init(injector.getInstance(StackAdvisorHelper.class)); ThreadPoolEnabledPropertyProvider.init(injector.getInstance(Configuration.class)); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AgentCommandsPublisher.java b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AgentCommandsPublisher.java index 0043f09..231f92c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AgentCommandsPublisher.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/events/publishers/AgentCommandsPublisher.java @@ -50,6 +50,7 @@ import org.apache.ambari.server.serveraction.kerberos.stageutils.KerberosKeytabC import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosKeytab; import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor; import org.apache.ambari.server.utils.StageUtils; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; @@ -245,8 +246,8 @@ public class AgentCommandsPublisher { try { Map<String, ? extends Collection<String>> serviceComponentFilter = getServiceComponentFilter(kerberosCommandParameters.getServiceComponentFilter()); - - Set<ResolvedKerberosKeytab> keytabsToInject = kerberosKeytabController.getFilteredKeytabs(serviceComponentFilter, kerberosCommandParameters.getHostFilter(), kerberosCommandParameters.getIdentityFilter()); + final Collection<KerberosIdentityDescriptor> serviceIdentities = serviceComponentFilter == null ? null : kerberosKeytabController.getServiceIdentities(executionCommand.getClusterName(), serviceComponentFilter.keySet()); + final Set<ResolvedKerberosKeytab> keytabsToInject = kerberosKeytabController.getFilteredKeytabs(serviceIdentities, kerberosCommandParameters.getHostFilter(), kerberosCommandParameters.getIdentityFilter()); for (ResolvedKerberosKeytab resolvedKeytab : keytabsToInject) { for (ResolvedKerberosPrincipal resolvedPrincipal : resolvedKeytab.getPrincipals()) { String hostName = resolvedPrincipal.getHostName(); diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java index 7b1aa45..7a44f2c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/KerberosKeytabPrincipalDAO.java @@ -291,7 +291,11 @@ public class KerberosKeytabPrincipalDAO { private Collection<String> componentNames; private Collection<String> principals; - public KerberosKeytabPrincipalFilter(Collection<String> hostNames, Collection<String> serviceNames, Collection<String> componentNames, Collection<String> principals) { + private KerberosKeytabPrincipalFilter() { + this(null, null, null, null); + } + + private KerberosKeytabPrincipalFilter(Collection<String> hostNames, Collection<String> serviceNames, Collection<String> componentNames, Collection<String> principals) { this.hostNames = hostNames; this.serviceNames = serviceNames; this.componentNames = componentNames; @@ -330,6 +334,10 @@ public class KerberosKeytabPrincipalDAO { this.principals = principals; } + public static KerberosKeytabPrincipalFilter createEmptyFilter() { + return new KerberosKeytabPrincipalFilter(); + } + public static KerberosKeytabPrincipalFilter createFilter(String serviceName, Collection<String> componentNames, Collection<String> hostNames, Collection<String> principalNames) { return new KerberosKeytabPrincipalFilter(hostNames, (serviceName == null) ? null : Collections.singleton(serviceName), diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java index 1748648..b6876c8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java @@ -21,7 +21,6 @@ package org.apache.ambari.server.serveraction.kerberos; import java.io.File; import java.io.IOException; import java.lang.reflect.Type; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -449,11 +448,12 @@ public abstract class KerberosServerAction extends AbstractServerAction { } try { - final Map<String, ? extends Collection<String>> serviceComponentFilter = (pruneServiceFilter()) - ? kerberosKeytabController.adjustServiceComponentFilter(clusters.getCluster(getClusterName()), true, getServiceComponentFilter()) - : getServiceComponentFilter(); - final Collection<KerberosIdentityDescriptor> serviceIdentities = serviceComponentFilter == null ? null : calculateServiceIdentities(getClusterName(), serviceComponentFilter); - for (ResolvedKerberosKeytab rkk : kerberosKeytabController.getFilteredKeytabs(serviceComponentFilter, getHostFilter(), getIdentityFilter())) { + Map<String, Collection<String>> serviceComponentFilter = getServiceComponentFilter(); + if (serviceComponentFilter != null && pruneServiceFilter()) { + kerberosKeytabController.adjustServiceComponentFilter(clusters.getCluster(getClusterName()), true, serviceComponentFilter); + } + final Collection<KerberosIdentityDescriptor> serviceIdentities = serviceComponentFilter == null ? null : kerberosKeytabController.getServiceIdentities(getClusterName(), serviceComponentFilter.keySet()); + for (ResolvedKerberosKeytab rkk : kerberosKeytabController.getFilteredKeytabs(serviceIdentities, getHostFilter(),getIdentityFilter())) { for (ResolvedKerberosPrincipal principal : rkk.getPrincipals()) { commandReport = processIdentity(principal, handler, kerberosConfiguration, isRelevantIdentity(serviceIdentities, principal), requestSharedDataContext); // If the principal processor returns a CommandReport, than it is time to stop @@ -504,17 +504,6 @@ public abstract class KerberosServerAction extends AbstractServerAction { return true; } - private Collection<KerberosIdentityDescriptor> calculateServiceIdentities(String clusterName, Map<String, ? extends Collection<String>> serviceComponentFilter) - throws AmbariException { - final Collection<KerberosIdentityDescriptor> serviceIdentities = new ArrayList<>(); - for (String service : serviceComponentFilter.keySet()) { - for (Collection<KerberosIdentityDescriptor> activeIdentities : kerberosHelper.getActiveIdentities(clusterName, null, service, null, true).values()) { - serviceIdentities.addAll(activeIdentities); - } - } - return serviceIdentities; - } - /** * Processes an identity as necessary. * <p/> @@ -584,7 +573,7 @@ public abstract class KerberosServerAction extends AbstractServerAction { } - protected Map<String, ? extends Collection<String>> getServiceComponentFilter() { + protected Map<String, Collection<String>> getServiceComponentFilter() { String serializedValue = getCommandParameterValue(SERVICE_COMPONENT_FILTER); if (serializedValue != null) { diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java index fd26058..ec01310 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/KerberosKeytabController.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.Set; import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.controller.KerberosHelper; import org.apache.ambari.server.orm.dao.KerberosKeytabDAO; import org.apache.ambari.server.orm.dao.KerberosKeytabPrincipalDAO; import org.apache.ambari.server.orm.entities.KerberosKeytabEntity; @@ -35,6 +36,7 @@ import org.apache.ambari.server.orm.entities.KerberosKeytabPrincipalEntity; import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Service; +import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor; import org.apache.commons.collections.MapUtils; import com.google.common.collect.ImmutableSet; @@ -54,6 +56,13 @@ public class KerberosKeytabController { @Inject private KerberosKeytabPrincipalDAO kerberosKeytabPrincipalDAO; + //TODO: due to circular dependencies in Guice this field cannot be injected with Guice's @Inject annotation; for now we should statically inject in AmbariServer + private static KerberosHelper kerberosHelper; + + public static void setKerberosHelper(KerberosHelper kerberosHelper) { + KerberosKeytabController.kerberosHelper = kerberosHelper; + } + /** * Tries to find keytab by keytab path in destination filesystem. * @@ -102,7 +111,7 @@ public class KerberosKeytabController { * @param identityFilter identity(principal) filter * @return set of keytabs found */ - public Set<ResolvedKerberosKeytab> getFilteredKeytabs(Map<String, ? extends Collection<String>> serviceComponentFilter, + private Set<ResolvedKerberosKeytab> getFilteredKeytabs(Map<String, ? extends Collection<String>> serviceComponentFilter, Set<String> hostFilter, Collection<String> identityFilter) { if (serviceComponentFilter == null && hostFilter == null && identityFilter == null) { return getAllKeytabs(); @@ -125,6 +134,11 @@ public class KerberosKeytabController { return Sets.newHashSet(resultMap.values()); } + public Set<ResolvedKerberosKeytab> getFilteredKeytabs(Collection<KerberosIdentityDescriptor> serviceIdentities, Set<String> hostFilter, Collection<String> identityFilters) { + final Collection<String> enhancedIdentityFilters = populateIdentityFilter(identityFilters, serviceIdentities); + return getFilteredKeytabs((Map<String, ? extends Collection<String>>) null, hostFilter, enhancedIdentityFilters); + } + /** * This function split serviceComponentFilter to two filters, one with specific components, and another one with service * only. Can return only one filter if filter contain only one type of mapping(whole service or component based) @@ -156,7 +170,7 @@ public class KerberosKeytabController { List<KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter> result = new ArrayList<>(); // Handle the service/component filter if (serviceSet.size() > 0) { - result.add(new KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter( + result.add(KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter.createFilter( null, serviceSet, componentSet, @@ -165,7 +179,7 @@ public class KerberosKeytabController { } // Handler the service/* filter if (serviceOnlySet.size() > 0) { - result.add(new KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter( + result.add(KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter.createFilter( null, serviceOnlySet, null, @@ -177,7 +191,7 @@ public class KerberosKeytabController { } } - return Lists.newArrayList(new KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter(null,null,null,null)); + return Lists.newArrayList(KerberosKeytabPrincipalDAO.KerberosKeytabPrincipalFilter.createEmptyFilter()); } private ResolvedKerberosKeytab fromKeytabEntity(KerberosKeytabEntity kke, boolean resolvePrincipals) { @@ -264,4 +278,26 @@ public class KerberosKeytabController { return adjustedFilter; } + + public Collection<KerberosIdentityDescriptor> getServiceIdentities(String clusterName, Collection<String> services) throws AmbariException { + final Collection<KerberosIdentityDescriptor> serviceIdentities = new ArrayList<>(); + for (String service : services) { + for (Collection<KerberosIdentityDescriptor> activeIdentities : kerberosHelper.getActiveIdentities(clusterName, null, service, null, true).values()) { + serviceIdentities.addAll(activeIdentities); + } + } + return serviceIdentities; + } + + private Collection<String> populateIdentityFilter(Collection<String> identityFilters, Collection<KerberosIdentityDescriptor> serviceIdentities) { + if (serviceIdentities != null) { + identityFilters = identityFilters == null ? new HashSet<>() : identityFilters; + for (KerberosIdentityDescriptor serviceIdentity : serviceIdentities) { + if (!KerberosHelper.AMBARI_SERVER_KERBEROS_IDENTITY_NAME.equals(serviceIdentity.getName())) { + identityFilters.add(serviceIdentity.getPrincipalDescriptor().getName()); + } + } + } + return identityFilters; + } } diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java index 3a0b2c0..c5bac8b 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java @@ -104,6 +104,7 @@ import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.State; import org.apache.ambari.server.state.fsm.InvalidStateTransitionException; +import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor; import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEvent; import org.apache.ambari.server.utils.StageUtils; import org.apache.commons.codec.binary.Base64; @@ -1567,7 +1568,7 @@ public class TestHeartbeatHandler { } expect(kerberosKeytabControllerMock.adjustServiceComponentFilter(anyObject(), eq(false), anyObject())).andReturn(filter).once(); - expect(kerberosKeytabControllerMock.getFilteredKeytabs(filter,null,null)).andReturn( + expect(kerberosKeytabControllerMock.getFilteredKeytabs((Collection<KerberosIdentityDescriptor>) EasyMock.anyObject(), EasyMock.eq(null), EasyMock.eq(null))).andReturn( Sets.newHashSet( new ResolvedKerberosKeytab( "/etc/security/keytabs/dn.service.keytab", @@ -1592,6 +1593,8 @@ public class TestHeartbeatHandler { ) ).once(); + expect(kerberosKeytabControllerMock.getServiceIdentities(EasyMock.anyString(), EasyMock.anyObject())).andReturn(Collections.emptySet()).anyTimes(); + replay(kerberosKeytabControllerMock); Field controllerField = agentCommandsPublisher.getClass().getDeclaredField("kerberosKeytabController"); diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java index 246a060..0e438fb 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java @@ -25,6 +25,7 @@ import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import java.io.File; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -46,6 +47,7 @@ import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerbero import org.apache.ambari.server.serveraction.kerberos.stageutils.ResolvedKerberosPrincipal; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor; import org.apache.ambari.server.state.stack.OsFamily; import org.easymock.EasyMockSupport; import org.junit.After; @@ -79,7 +81,7 @@ public class KerberosServerActionTest extends EasyMockSupport { HostRoleCommand mockHostRoleCommand = createMock(HostRoleCommand.class); kerberosKeytabController = createMock(KerberosKeytabController.class); expect(kerberosKeytabController.adjustServiceComponentFilter(anyObject(), eq(true), anyObject())).andReturn(null).anyTimes(); - expect(kerberosKeytabController.getFilteredKeytabs(null, null, null)) + expect(kerberosKeytabController.getFilteredKeytabs((Collection<KerberosIdentityDescriptor>)null, null, null)) .andReturn( Sets.newHashSet(new ResolvedKerberosKeytab( null,