AMBARI-22390. Implement many-to-many relation between keytabs and principals (echekanskiy)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/18e54903 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/18e54903 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/18e54903 Branch: refs/heads/branch-feature-AMBARI-22008 Commit: 18e549034e893aac4ade80e49bda70604d5147f3 Parents: 6e706d4 Author: Eugene Chekanskiy <echekans...@hortonworks.com> Authored: Mon Nov 13 17:01:16 2017 +0200 Committer: Eugene Chekanskiy <echekans...@hortonworks.com> Committed: Mon Nov 13 17:01:29 2017 +0200 ---------------------------------------------------------------------- .../server/controller/KerberosHelperImpl.java | 59 ++++++++++++++------ .../AbstractPrepareKerberosServerAction.java | 23 +++----- .../kerberos/CreatePrincipalsServerAction.java | 6 +- .../kerberos/KerberosServerAction.java | 21 +++++++ .../stageutils/ResolvedKerberosKeytab.java | 16 +++--- 5 files changed, 82 insertions(+), 43 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/18e54903/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java index f913831..474c335 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java @@ -1546,19 +1546,21 @@ public class KerberosHelperImpl implements KerberosHelper { keytabFileOwnerAccess, keytabFileGroupName, keytabFileGroupAccess, - Sets.newHashSet(Pair.of(hostId, evaluatedPrincipal)), + Sets.newHashSet(Pair.of(hostId, Pair.of(evaluatedPrincipal, principalType))), serviceName.equalsIgnoreCase("AMBARI"), componentName.equalsIgnoreCase("AMBARI_SERVER_SELF") ); if (resolvedKeytabs.containsKey(keytabFilePath)) { ResolvedKerberosKeytab sameKeytab = resolvedKeytabs.get(keytabFilePath); // validating owner and group - String warnTemplate = "Keytab '{}' on host '{}' have different {}, originally set to '{}' and '{}:{}' has '{}', using '{}'"; + boolean differentOwners = false; + String warnTemplate = "Keytab '{}' on host '{}' has different {}, originally set to '{}' and '{}:{}' has '{}', using '{}'"; if (!resolvedKeytab.getOwnerName().equals(sameKeytab.getOwnerName())) { LOG.warn(warnTemplate, keytabFilePath, hostname, "owners", sameKeytab.getOwnerName(), serviceName, componentName, resolvedKeytab.getOwnerName(), sameKeytab.getOwnerName()); + differentOwners = true; } if (!resolvedKeytab.getOwnerAccess().equals(sameKeytab.getOwnerAccess())) { LOG.warn(warnTemplate, @@ -1570,16 +1572,39 @@ public class KerberosHelperImpl implements KerberosHelper { // TODO with different owners, so make sure that keytabs are accessible through group acls // TODO this includes same group name and group 'r' mode if (!resolvedKeytab.getGroupName().equals(sameKeytab.getGroupName())) { - LOG.warn(warnTemplate, - keytabFilePath, hostname, "groups", sameKeytab.getGroupName(), - serviceName, componentName, resolvedKeytab.getGroupName(), - sameKeytab.getGroupName()); + if(differentOwners) { + LOG.error(warnTemplate, + keytabFilePath, hostname, "groups", sameKeytab.getGroupName(), + serviceName, componentName, resolvedKeytab.getGroupName(), + sameKeytab.getGroupName()); + } else { + LOG.warn(warnTemplate, + keytabFilePath, hostname, "groups", sameKeytab.getGroupName(), + serviceName, componentName, resolvedKeytab.getGroupName(), + sameKeytab.getGroupName()); + } } if (!resolvedKeytab.getGroupAccess().equals(sameKeytab.getGroupAccess())) { - LOG.warn(warnTemplate, - keytabFilePath, hostname, "group access", sameKeytab.getGroupAccess(), - serviceName, componentName, resolvedKeytab.getGroupAccess(), - sameKeytab.getGroupAccess()); + if(differentOwners) { + if (!sameKeytab.getGroupAccess().contains("r")) { + LOG.error("Keytab '{}' on host '{}' referenced by multiple identities which have different owners," + + "but 'r' attribute missing for group. Make sure all users (that need this keytab) are in '{}' +" + + "group and keytab can be read by this group", + keytabFilePath, + hostname, + sameKeytab.getGroupName() + ); + } + LOG.error(warnTemplate, + keytabFilePath, hostname, "group access", sameKeytab.getGroupAccess(), + serviceName, componentName, resolvedKeytab.getGroupAccess(), + sameKeytab.getGroupAccess()); + } else { + LOG.warn(warnTemplate, + keytabFilePath, hostname, "group access", sameKeytab.getGroupAccess(), + serviceName, componentName, resolvedKeytab.getGroupAccess(), + sameKeytab.getGroupAccess()); + } } // end validating // merge principal to keytab @@ -1877,15 +1902,17 @@ public class KerberosHelperImpl implements KerberosHelper { if (kerberosKeytabDAO.find(resolvedKerberosKeytab.getFile()) == null) { kerberosKeytabDAO.create(resolvedKerberosKeytab.getFile()); } - for (Pair<Long, String> principalPair : resolvedKerberosKeytab.getMappedPrincipals()) { - String principal = principalPair.getRight(); + for (Pair<Long, Pair<String, String>> principalPair : resolvedKerberosKeytab.getMappedPrincipals()) { + Pair<String, String> principal = principalPair.getRight(); + String principalName = principal.getLeft(); + String principalType = principal.getRight(); Long hostId = principalPair.getLeft(); - if (!kerberosPrincipalDAO.exists(principal)) { - kerberosPrincipalDAO.create(principal, false); + if (!kerberosPrincipalDAO.exists(principalName)) { + kerberosPrincipalDAO.create(principalName, "service".equalsIgnoreCase(principalType)); } if (hostId != null) { - if(!kerberosPrincipalHostDAO.exists(principal, hostId, resolvedKerberosKeytab.getFile())) { - kerberosPrincipalHostDAO.create(principal, hostId, resolvedKerberosKeytab.getFile()); + if(!kerberosPrincipalHostDAO.exists(principalName, hostId, resolvedKerberosKeytab.getFile())) { + kerberosPrincipalHostDAO.create(principalName, hostId, resolvedKerberosKeytab.getFile()); } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/18e54903/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java index 1dc8ca8..4008620 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java @@ -196,7 +196,7 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer List<KerberosIdentityDescriptor> componentIdentities = Collections.singletonList(identity); kerberosHelper.addIdentities(kerberosIdentityDataFileWriter, componentIdentities, - identityFilter, StageUtils.getHostName(), ambariServerHostID(), "AMBARI",componentName, kerberosConfigurations, currentConfigurations, + identityFilter, StageUtils.getHostName(), ambariServerHostID(), "AMBARI", componentName, kerberosConfigurations, currentConfigurations, resolvedKeytabs, realm); propertiesToIgnore = gatherPropertiesToIgnore(componentIdentities, propertiesToIgnore); } @@ -236,19 +236,9 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer protected Map<String, ? extends Collection<String>> getServiceComponentFilter() { String serializedValue = getCommandParameterValue(SERVICE_COMPONENT_FILTER); - if(serializedValue != null) { - Type type = new TypeToken<Map<String, ? extends Collection<String>>>() {}.getType(); - return StageUtils.getGson().fromJson(serializedValue, type); - } else { - return null; - } - } - - protected Set<String> getHostFilter() { - String serializedValue = getCommandParameterValue(HOST_FILTER); - - if(serializedValue != null) { - Type type = new TypeToken<Set<String>>() {}.getType(); + if (serializedValue != null) { + Type type = new TypeToken<Map<String, ? extends Collection<String>>>() { + }.getType(); return StageUtils.getGson().fromJson(serializedValue, type); } else { return null; @@ -258,8 +248,9 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer protected Collection<String> getIdentityFilter() { String serializedValue = getCommandParameterValue(IDENTITY_FILTER); - if(serializedValue != null) { - Type type = new TypeToken<Collection<String>>() {}.getType(); + if (serializedValue != null) { + Type type = new TypeToken<Collection<String>>() { + }.getType(); return StageUtils.getGson().fromJson(serializedValue, type); } else { return null; http://git-wip-us.apache.org/repos/asf/ambari/blob/18e54903/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java index 59d5327..0c90659 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java @@ -135,10 +135,11 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { KerberosPrincipalEntity kerberosPrincipalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal); boolean regenerateKeytabs = getOperationType(getCommandParameters()) == OperationType.RECREATE_ALL; - + boolean servicePrincipal = "service".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.PRINCIPAL_TYPE)); if (regenerateKeytabs) { // force recreation of principal due to keytab regeneration - processPrincipal = true; + // regenerate only service principals if request filtered by hosts + processPrincipal = !hasHostFilters() || servicePrincipal; } else if (kerberosPrincipalEntity == null) { // This principal has not been processed before, process it. processPrincipal = true; @@ -156,7 +157,6 @@ public class CreatePrincipalsServerAction extends KerberosServerAction { String password = principalPasswordMap.get(evaluatedPrincipal); if (password == null) { - boolean servicePrincipal = "service".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.PRINCIPAL_TYPE)); CreatePrincipalResult result = createPrincipal(evaluatedPrincipal, servicePrincipal, kerberosConfiguration, operationHandler, regenerateKeytabs, actionLog); if (result == null) { commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr()); http://git-wip-us.apache.org/repos/asf/ambari/blob/18e54903/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java ---------------------------------------------------------------------- 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 3491f18..ff5f5ce 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 @@ -22,8 +22,10 @@ import static org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDat import java.io.File; import java.io.IOException; +import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; +import java.util.Set; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.actionmanager.HostRoleStatus; @@ -42,6 +44,7 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.reflect.TypeToken; import com.google.inject.Inject; /** @@ -579,6 +582,24 @@ public abstract class KerberosServerAction extends AbstractServerAction { } } + + protected Set<String> getHostFilter() { + String serializedValue = getCommandParameterValue(HOST_FILTER); + + if (serializedValue != null) { + Type type = new TypeToken<Set<String>>() { + }.getType(); + return StageUtils.getGson().fromJson(serializedValue, type); + } else { + return null; + } + } + + protected boolean hasHostFilters() { + Set<String> hostFilers = getHostFilter(); + return hostFilers != null && hostFilers.size() > 0; + } + protected Long ambariServerHostID(){ String ambariServerHostName = StageUtils.getHostName(); HostEntity ambariServerHostEntity = hostDAO.findByName(ambariServerHostName); http://git-wip-us.apache.org/repos/asf/ambari/blob/18e54903/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java index f66d273..17e484a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/stageutils/ResolvedKerberosKeytab.java @@ -40,7 +40,7 @@ public class ResolvedKerberosKeytab { private String groupName = null; private String groupAccess = null; private String file = null; - private Set<Pair<Long, String>> mappedPrincipals = null; + private Set<Pair<Long, Pair<String, String>>> mappedPrincipals = null; private boolean isAmbariServerKeytab = false; private boolean mustWriteAmbariJaasFile = false; @@ -50,7 +50,7 @@ public class ResolvedKerberosKeytab { String ownerAccess, String groupName, String groupAccess, - Set<Pair<Long, String>> mappedPrincipals, + Set<Pair<Long, Pair<String, String>>> mappedPrincipals, boolean isAmbariServerKeytab, boolean writeAmbariJaasFile ) { @@ -177,7 +177,7 @@ public class ResolvedKerberosKeytab { * * @return a Set with mappedPrincipals associated with given keytab */ - public Set<Pair<Long, String>> getMappedPrincipals() { + public Set<Pair<Long, Pair<String, String>>> getMappedPrincipals() { return mappedPrincipals; } @@ -186,7 +186,7 @@ public class ResolvedKerberosKeytab { * * @param mappedPrincipals a Map with host-to-principal mapping associated with given keytab */ - public void setMappedPrincipals(Set<Pair<Long, String>> mappedPrincipals) { + public void setMappedPrincipals(Set<Pair<Long, Pair<String, String>>> mappedPrincipals) { this.mappedPrincipals = mappedPrincipals; } @@ -197,7 +197,7 @@ public class ResolvedKerberosKeytab { */ public Set<Long> getHosts() { ImmutableSet.Builder<Long> builder = ImmutableSet.builder(); - for (Pair<Long, String> principal : getMappedPrincipals()) { + for (Pair<Long, Pair<String, String>> principal : getMappedPrincipals()) { if (principal.getLeft() != null) { builder.add(principal.getLeft()); } @@ -210,9 +210,9 @@ public class ResolvedKerberosKeytab { * * @return a Set of principals */ - public Set<String> getPrincipals() { - ImmutableSet.Builder<String> builder = ImmutableSet.builder(); - for (Pair<Long, String> principal : getMappedPrincipals()) { + public Set<Pair<String, String>> getPrincipals() { + ImmutableSet.Builder<Pair<String, String>> builder = ImmutableSet.builder(); + for (Pair<Long, Pair<String, String>> principal : getMappedPrincipals()) { builder.add(principal.getRight()); } return builder.build();