Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KNOX-2315 - Fix zookeeper Kerberos Auth #304

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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;
moresandeep marked this conversation as resolved.
Show resolved Hide resolved

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()));
pzampino marked this conversation as resolved.
Show resolved Hide resolved
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