Skip to content

Commit

Permalink
KNOX-2315 - Fix zookeeper Kerberos Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
moresandeep committed Apr 7, 2020
1 parent fd8e1bb commit 5287838
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 19 deletions.
Expand Up @@ -22,6 +22,7 @@
import org.apache.knox.gateway.GatewayMessages;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.service.config.remote.zk.ZooKeeperClientService;
import org.apache.knox.gateway.services.ServiceLifecycleException;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
Expand Down Expand Up @@ -79,6 +80,35 @@ public boolean canWrite() {
}
};

/* permissions when kerberos authentication is enabled */
private static final RemoteConfigurationRegistryClient.EntryACL KERBEROS_KNOX_ALL =
new RemoteConfigurationRegistryClient.EntryACL() {
@Override
public String getId() {
return "knox";
}

@Override
public String getType() {
return "sasl";
}

@Override
public Object getPermissions() {
return ZooDefs.Perms.ALL;
}

@Override
public boolean canRead() {
return true;
}

@Override
public boolean canWrite() {
return true;
}
};

private final AliasService localAliasService;
private final MasterService ms;
private final RemoteConfigurationRegistryClientService remoteConfigurationRegistryClientService;
Expand Down Expand Up @@ -127,9 +157,17 @@ private static void ensureEntry(final String path, final RemoteConfigurationRegi
// content may not be trustworthy.
if (remoteClient.isAuthenticationConfigured()) {
LOG.correctingSuspectWritableRemoteConfigurationEntry(path);

// Replace the existing ACL with one that permits only authenticated users
remoteClient.setACL(path, Collections.singletonList(AUTHENTICATED_USERS_ALL));
if(ZooKeeperClientService.AUTH_TYPE_KERBEROS.equalsIgnoreCase(remoteClient.authenticationType()) &&
!remoteClient.isBackwardsCompatible()) {
// Replace the existing ACL with one that permits only kerberos authenticated knox user
remoteClient.setACL(path,
Collections.singletonList(KERBEROS_KNOX_ALL));
} else {
// Replace the existing ACL with one that permits only authenticated users
remoteClient.setACL(path, Collections
.singletonList(AUTHENTICATED_USERS_ALL));
}
}
}
}
Expand Down
Expand Up @@ -266,6 +266,16 @@ public void addEntryListener(String path, EntryListener listener) throws Excepti
public void removeEntryListener(String path) throws Exception {
// N/A
}

@Override
public String authenticationType() {
return null;
}

@Override
public boolean isBackwardsCompatible() {
return false;
}
};
}

Expand Down
5 changes: 5 additions & 0 deletions gateway-service-remoteconfig/pom.xml
Expand Up @@ -70,6 +70,11 @@
<artifactId>commons-io</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>

<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
Expand Down
Expand Up @@ -40,4 +40,7 @@ public interface RemoteConfigurationRegistryConfig {

boolean isUseKeyTab();

/* If true ensures that the auth scheme used to create znodes is `auth` and not `sasl` */
boolean isBackwardsCompatible();

}
Expand Up @@ -69,7 +69,7 @@ private static RemoteConfigurationRegistry extractConfigForRegistry(GatewayConfi
result.setKeytab(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_KEYTAB));
result.setUseKeytab(Boolean.valueOf(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_USE_KEYTAB)));
result.setUseTicketCache(Boolean.valueOf(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_USE_TICKET_CACHE)));

result.setBackwardsCompatible(Boolean.valueOf(properties.getOrDefault(GatewayConfig.ZOOKEEPER_REMOTE_CONFIG_REGISTRY_BACKWARDS_COMPATIBLE, "false")));
return result;
}

Expand Down
Expand Up @@ -32,6 +32,8 @@ class RemoteConfigurationRegistry implements RemoteConfigurationRegistryConfig {
private String keyTab;
private boolean useKeyTab;
private boolean useTicketCache;
/* If true ensures that the auth scheme used to create znodes is `auth` and not `sasl` */
private boolean isBackwardsCompatible;

RemoteConfigurationRegistry() {
}
Expand Down Expand Up @@ -76,6 +78,10 @@ public void setKeytab(String keytab) {
this.keyTab = keytab;
}

public void setBackwardsCompatible(boolean backwardsCompatible) {
isBackwardsCompatible = backwardsCompatible;
}

@Override
@XmlElement(name="name")
public String getName() {
Expand Down Expand Up @@ -130,6 +136,7 @@ public boolean isUseKeyTab() {
return useKeyTab;
}


@Override
@XmlElement(name="keytab")
public String getKeytab() {
Expand All @@ -141,4 +148,9 @@ public boolean isSecureRegistry() {
return (getAuthType() != null);
}

@Override
@XmlElement(name="backwards-compatible")
public boolean isBackwardsCompatible() {
return isBackwardsCompatible;
}
}
Expand Up @@ -31,12 +31,12 @@
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.service.config.remote.RemoteConfigurationMessages;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.EntryListener;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryConfig;
import org.apache.knox.gateway.service.config.remote.config.RemoteConfigurationRegistriesAccessor;
import org.apache.knox.gateway.services.ServiceLifecycleException;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener;
import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.EntryListener;
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.client.ZKClientConfig;
Expand Down Expand Up @@ -124,7 +124,13 @@ private RemoteConfigurationRegistryClient createClient(RemoteConfigurationRegist
ACLProvider aclProvider;
if (config.isSecureRegistry()) {
configureSasl(config);
aclProvider = new SASLOwnerACLProvider();
if(AUTH_TYPE_KERBEROS.equalsIgnoreCase(config.getAuthType()) &&
!config.isBackwardsCompatible()) {
aclProvider = new SASLOwnerACLProvider(true);
} else {
aclProvider = new SASLOwnerACLProvider(false);
}

} else {
// Clear SASL system property
System.clearProperty(LOGIN_CONTEXT_NAME_PROPERTY);
Expand All @@ -136,6 +142,7 @@ private RemoteConfigurationRegistryClient createClient(RemoteConfigurationRegist
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.aclProvider(aclProvider)
.build();

client.start();

return (new ClientAdapter(client, config));
Expand Down Expand Up @@ -260,6 +267,16 @@ public void removeEntryListener(String path) throws Exception {
}
}

@Override
public String authenticationType() {
return config.getAuthType();
}

@Override
public boolean isBackwardsCompatible() {
return config.isBackwardsCompatible();
}

@Override
public String getEntryData(String path) {
return getEntryData(path, StandardCharsets.UTF_8.name());
Expand Down Expand Up @@ -347,10 +364,14 @@ public void close() throws Exception {
*/
private static class SASLOwnerACLProvider implements ACLProvider {

private final List<ACL> saslACL;
private final List<ACL> saslACL = new ArrayList();

SASLOwnerACLProvider() {
this.saslACL = ZooDefs.Ids.CREATOR_ALL_ACL; // All permissions for any authenticated user
SASLOwnerACLProvider(boolean isKerberos) {
if(isKerberos) {
saslACL.add(new ACL(ZooDefs.Perms.ALL, new Id("sasl", "knox")));
} else {
this.saslACL.addAll(ZooDefs.Ids.CREATOR_ALL_ACL); // All permissions for any authenticated user
}
}

@Override
Expand Down
Expand Up @@ -164,8 +164,8 @@ private AppConfigurationEntry createEntry(RemoteConfigurationRegistryConfig conf
}
break;
case Kerberos:
opts.put("isUseTicketCache", String.valueOf(config.isUseTicketCache()));
opts.put("isUseKeyTab", String.valueOf(config.isUseKeyTab()));
opts.put("useTicketCache", String.valueOf(config.isUseTicketCache()));
opts.put("useKeyTab", String.valueOf(config.isUseKeyTab()));
opts.put("keyTab", config.getKeytab());
opts.put("principal", config.getPrincipal());
default:
Expand Down
Expand Up @@ -22,4 +22,6 @@ public interface ZooKeeperClientService extends RemoteConfigurationRegistryClien

String TYPE = "ZooKeeper";

String AUTH_TYPE_KERBEROS = "Kerberos";

}
Expand Up @@ -29,17 +29,15 @@

import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;

import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.startsWith;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
Expand Down Expand Up @@ -344,7 +342,7 @@ private static void validateKerberosContext(RemoteConfigurationRegistryJAASConfi
Map<String, ?> entryOpts = entry.getOptions();
assertEquals(principal, entryOpts.get("principal"));
assertEquals(keyTab, entryOpts.get("keyTab"));
assertEquals(useKeyTab, Boolean.valueOf((String)entryOpts.get("isUseKeyTab")));
assertEquals(useTicketCache, Boolean.valueOf((String)entryOpts.get("isUseTicketCache")));
assertEquals(useKeyTab, Boolean.valueOf((String)entryOpts.get("useKeyTab")));
assertEquals(useTicketCache, Boolean.valueOf((String)entryOpts.get("useTicketCache")));
}
}
Expand Up @@ -95,8 +95,10 @@ public interface GatewayConfig {
String REMOTE_CONFIG_REGISTRY_PRINCIPAL = "principal";
String REMOTE_CONFIG_REGISTRY_CREDENTIAL_ALIAS = "credentialAlias";
String REMOTE_CONFIG_REGISTRY_KEYTAB = "keytab";
String REMOTE_CONFIG_REGISTRY_USE_KEYTAB = "useKeytab";
String REMOTE_CONFIG_REGISTRY_USE_KEYTAB = "useKeyTab";
String REMOTE_CONFIG_REGISTRY_USE_TICKET_CACHE = "useTicketCache";
/* If true ensures that the auth scheme used to create znodes is `auth` and not `sasl` */
String ZOOKEEPER_REMOTE_CONFIG_REGISTRY_BACKWARDS_COMPATIBLE = "backwardsCompatible";

String PROXYUSER_SERVICES_IGNORE_DOAS = "gateway.proxyuser.services.ignore.doas";

Expand Down
Expand Up @@ -54,6 +54,10 @@ public interface RemoteConfigurationRegistryClient extends AutoCloseable {

void removeEntryListener(String path) throws Exception;

String authenticationType();

boolean isBackwardsCompatible();

interface ChildEntryListener {

enum Type {
Expand Down

0 comments on commit 5287838

Please sign in to comment.