You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by si...@apache.org on 2022/05/17 21:36:25 UTC
[ozone] branch HDDS-4944 updated: HDDS-6612. [Multi-Tenant] Add a config key to enable or disable S3 Multi-Tenancy feature (#3397)
This is an automated email from the ASF dual-hosted git repository.
siyao pushed a commit to branch HDDS-4944
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-4944 by this push:
new c55bd0290f HDDS-6612. [Multi-Tenant] Add a config key to enable or disable S3 Multi-Tenancy feature (#3397)
c55bd0290f is described below
commit c55bd0290fdc070577693cb89ec6a46113e65661
Author: Siyao Meng <50...@users.noreply.github.com>
AuthorDate: Tue May 17 14:36:20 2022 -0700
HDDS-6612. [Multi-Tenant] Add a config key to enable or disable S3 Multi-Tenancy feature (#3397)
---
.../common/src/main/resources/ozone-default.xml | 8 +
.../docs/content/feature/S3-Multi-Tenancy-Setup.md | 6 +-
.../org/apache/hadoop/ozone/om/OMConfigKeys.java | 4 +
.../hadoop/ozone/om/exceptions/OMException.java | 4 +-
...OzoneManagerProtocolClientSideTranslatorPB.java | 102 ++++++------
.../src/main/compose/ozonesecure/docker-config | 4 +-
.../om/multitenant/TestMultiTenantVolume.java | 2 +
.../hadoop/ozone/shell/TestOzoneTenantShell.java | 4 +
.../src/main/proto/OmClientProtocol.proto | 2 +
.../hadoop/ozone/om/OMMultiTenantManager.java | 88 ++++++++++-
.../hadoop/ozone/om/OMMultiTenantManagerImpl.java | 9 +-
.../org/apache/hadoop/ozone/om/OzoneAclUtils.java | 7 +-
.../org/apache/hadoop/ozone/om/OzoneManager.java | 42 ++++-
.../om/ratis/utils/OzoneManagerRatisUtils.java | 6 +
.../s3/tenant/OMTenantAssignAdminRequest.java | 16 +-
.../tenant/OMTenantAssignUserAccessIdRequest.java | 20 +--
.../request/s3/tenant/OMTenantCreateRequest.java | 17 +-
.../request/s3/tenant/OMTenantDeleteRequest.java | 2 +-
.../s3/tenant/OMTenantRevokeAdminRequest.java | 29 ++--
.../tenant/OMTenantRevokeUserAccessIdRequest.java | 15 +-
.../protocolPB/OzoneManagerRequestHandler.java | 3 +
.../hadoop/ozone/om/TestOMMultiTenantManager.java | 175 +++++++++++++++++++++
.../ozone/om/request/OMRequestTestUtils.java | 154 ++++++++++++++++++
.../s3/security/TestS3GetSecretRequest.java | 2 -
24 files changed, 593 insertions(+), 128 deletions(-)
diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index 703e3c5c7b..b95f858834 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -3118,4 +3118,12 @@
log level is debug. Ex: "CREATE_CONTAINER,READ_CONTAINER,UPDATE_CONTAINER".
</description>
</property>
+
+ <property>
+ <name>ozone.om.multitenancy.enabled</name>
+ <value>false</value>
+ <tag>OZONE, OM</tag>
+ <description>Enable S3 Multi-Tenancy. If disabled, all S3 multi-tenancy requests are rejected.
+ </description>
+ </property>
</configuration>
diff --git a/hadoop-hdds/docs/content/feature/S3-Multi-Tenancy-Setup.md b/hadoop-hdds/docs/content/feature/S3-Multi-Tenancy-Setup.md
index d6f77e7edf..79e1320045 100644
--- a/hadoop-hdds/docs/content/feature/S3-Multi-Tenancy-Setup.md
+++ b/hadoop-hdds/docs/content/feature/S3-Multi-Tenancy-Setup.md
@@ -42,9 +42,13 @@ Follow [this guide]({{< ref "interface/S3.md" >}}) the cluster to set up at leas
First make sure ACL is enabled, and `RangerOzoneAuthorizer` is the effective ACL authorizer implementation in-use for Ozone.
If that is not the case, [follow this]({{< ref "security/SecurityWithRanger.md" >}}).
-Then simply add the following configs to `ozone-site.xml`:
+Then add the following configs to all Ozone Managers' `ozone-site.xml`:
```xml
+<property>
+ <name>ozone.om.multitenancy.enabled</name>
+ <value>true</value>
+</property>
<property>
<name>ozone.om.ranger.https-address</name>
<value>https://RANGER_HOSTNAME:6182</value>
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
index 13afb39743..f14b7f6239 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
@@ -312,6 +312,10 @@ public final class OMConfigKeys {
public static final int OZONE_OM_UNFLUSHED_TRANSACTION_MAX_COUNT_DEFAULT
= 10000;
+ public static final String OZONE_OM_MULTITENANCY_ENABLED =
+ "ozone.om.multitenancy.enabled";
+ public static final boolean OZONE_OM_MULTITENANCY_ENABLED_DEFAULT = false;
+
/**
* Temporary configuration properties for Ranger REST use in multitenancy.
*/
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java
index f2838f5b51..717df88b48 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java
@@ -254,6 +254,8 @@ public class OMException extends IOException {
TENANT_AUTHORIZER_ERROR,
VOLUME_IS_REFERENCED,
- TENANT_NOT_EMPTY
+ TENANT_NOT_EMPTY,
+
+ FEATURE_NOT_ENABLED
}
}
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
index 6248f27be0..2e77ccd7f5 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
@@ -995,25 +995,28 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
*/
@Override
public void createTenant(OmTenantArgs omTenantArgs) throws IOException {
- final CreateTenantRequest request = CreateTenantRequest.newBuilder()
- .setTenantId(omTenantArgs.getTenantId())
- .setVolumeName(omTenantArgs.getVolumeName())
- // TODO: Add more args like policy names later
- .build();
+ final CreateTenantRequest.Builder requestBuilder =
+ CreateTenantRequest.newBuilder()
+ .setTenantId(omTenantArgs.getTenantId())
+ .setVolumeName(omTenantArgs.getVolumeName());
+ // Can add more args (like policy names) later if needed
final OMRequest omRequest = createOMRequest(Type.CreateTenant)
- .setCreateTenantRequest(request)
+ .setCreateTenantRequest(requestBuilder)
.build();
final OMResponse omResponse = submitRequest(omRequest);
handleError(omResponse);
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public DeleteTenantState deleteTenant(String tenantId) throws IOException {
- final DeleteTenantRequest request = DeleteTenantRequest.newBuilder()
- .setTenantId(tenantId)
- .build();
+ final DeleteTenantRequest.Builder requestBuilder =
+ DeleteTenantRequest.newBuilder()
+ .setTenantId(tenantId);
final OMRequest omRequest = createOMRequest(Type.DeleteTenant)
- .setDeleteTenantRequest(request)
+ .setDeleteTenantRequest(requestBuilder)
.build();
final OMResponse omResponse = submitRequest(omRequest);
final DeleteTenantResponse resp =
@@ -1030,14 +1033,13 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
public S3SecretValue tenantAssignUserAccessId(
String username, String tenantId, String accessId) throws IOException {
- final TenantAssignUserAccessIdRequest request =
+ final TenantAssignUserAccessIdRequest.Builder requestBuilder =
TenantAssignUserAccessIdRequest.newBuilder()
- .setUserPrincipal(username)
- .setTenantId(tenantId)
- .setAccessId(accessId)
- .build();
+ .setUserPrincipal(username)
+ .setTenantId(tenantId)
+ .setAccessId(accessId);
final OMRequest omRequest = createOMRequest(Type.TenantAssignUserAccessId)
- .setTenantAssignUserAccessIdRequest(request)
+ .setTenantAssignUserAccessIdRequest(requestBuilder)
.build();
final OMResponse omResponse = submitRequest(omRequest);
final TenantAssignUserAccessIdResponse resp = handleError(omResponse)
@@ -1053,12 +1055,11 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
public void tenantRevokeUserAccessId(String accessId)
throws IOException {
- final TenantRevokeUserAccessIdRequest request =
+ final TenantRevokeUserAccessIdRequest.Builder requestBuilder =
TenantRevokeUserAccessIdRequest.newBuilder()
- .setAccessId(accessId)
- .build();
+ .setAccessId(accessId);
final OMRequest omRequest = createOMRequest(Type.TenantRevokeUserAccessId)
- .setTenantRevokeUserAccessIdRequest(request)
+ .setTenantRevokeUserAccessIdRequest(requestBuilder)
.build();
final OMResponse omResponse = submitRequest(omRequest);
handleError(omResponse);
@@ -1073,8 +1074,8 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
final TenantAssignAdminRequest.Builder requestBuilder =
TenantAssignAdminRequest.newBuilder()
- .setAccessId(accessId)
- .setDelegated(delegated);
+ .setAccessId(accessId)
+ .setDelegated(delegated);
if (tenantId != null) {
requestBuilder.setTenantId(tenantId);
}
@@ -1114,12 +1115,11 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
public TenantUserInfoValue tenantGetUserInfo(String userPrincipal)
throws IOException {
- final TenantGetUserInfoRequest request =
+ final TenantGetUserInfoRequest.Builder requestBuilder =
TenantGetUserInfoRequest.newBuilder()
- .setUserPrincipal(userPrincipal)
- .build();
+ .setUserPrincipal(userPrincipal);
final OMRequest omRequest = createOMRequest(Type.TenantGetUserInfo)
- .setTenantGetUserInfoRequest(request)
+ .setTenantGetUserInfoRequest(requestBuilder)
.build();
final OMResponse omResponse = submitRequest(omRequest);
final TenantGetUserInfoResponse resp = handleError(omResponse)
@@ -1128,15 +1128,20 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
return TenantUserInfoValue.fromProtobuf(resp);
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public TenantUserList listUsersInTenant(String tenantId, String prefix)
throws IOException {
- TenantListUserRequest.Builder builder =
- TenantListUserRequest.newBuilder().setTenantId(tenantId);
+
+ final TenantListUserRequest.Builder requestBuilder =
+ TenantListUserRequest.newBuilder()
+ .setTenantId(tenantId);
if (prefix != null) {
- builder.setPrefix(prefix);
+ requestBuilder.setPrefix(prefix);
}
- TenantListUserRequest request = builder.build();
+ TenantListUserRequest request = requestBuilder.build();
final OMRequest omRequest = createOMRequest(Type.TenantListUser)
.setTenantListUserRequest(request).build();
@@ -1146,30 +1151,16 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
return TenantUserList.fromProtobuf(resp);
}
- @Override
- public S3VolumeContext getS3VolumeContext() throws IOException {
- final GetS3VolumeContextRequest request = GetS3VolumeContextRequest
- .newBuilder()
- .build();
- final OMRequest omRequest = createOMRequest(Type.GetS3VolumeContext)
- .setGetS3VolumeContextRequest(request)
- .build();
- final OMResponse omResponse = submitRequest(omRequest);
- final GetS3VolumeContextResponse resp =
- handleError(omResponse).getGetS3VolumeContextResponse();
- return S3VolumeContext.fromProtobuf(resp);
- }
-
/**
* {@inheritDoc}
*/
@Override
public TenantStateList listTenant() throws IOException {
- final ListTenantRequest request = ListTenantRequest.newBuilder()
- .build();
+ final ListTenantRequest.Builder requestBuilder =
+ ListTenantRequest.newBuilder();
final OMRequest omRequest = createOMRequest(Type.ListTenant)
- .setListTenantRequest(request)
+ .setListTenantRequest(requestBuilder)
.build();
final OMResponse omResponse = submitRequest(omRequest);
final ListTenantResponse resp = handleError(omResponse)
@@ -1178,6 +1169,23 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
return TenantStateList.fromProtobuf(resp.getTenantStateList());
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public S3VolumeContext getS3VolumeContext() throws IOException {
+
+ final GetS3VolumeContextRequest.Builder requestBuilder =
+ GetS3VolumeContextRequest.newBuilder();
+ final OMRequest omRequest = createOMRequest(Type.GetS3VolumeContext)
+ .setGetS3VolumeContextRequest(requestBuilder)
+ .build();
+ final OMResponse omResponse = submitRequest(omRequest);
+ final GetS3VolumeContextResponse resp =
+ handleError(omResponse).getGetS3VolumeContextResponse();
+ return S3VolumeContext.fromProtobuf(resp);
+ }
+
/**
* Return the proxy object underlying this protocol translator.
*
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config
index 7d916c98b5..e58b7512e4 100644
--- a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config
@@ -133,4 +133,6 @@ OZONE_LOG_DIR=/var/log/hadoop
no_proxy=om,scm,recon,s3g,kdc,localhost,127.0.0.1
OZONE-SITE.XML_ozone.om.ranger.https-address=https://ranger:6182
-
+OZONE-SITE.XML_ozone.om.multitenancy.enabled=true
+OZONE-SITE.XML_ozone.om.ranger.https.admin.api.user=admin
+OZONE-SITE.XML_ozone.om.ranger.https.admin.api.passwd=passwd
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java
index 138ad57470..f2c8567296 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java
@@ -45,6 +45,7 @@ import java.util.concurrent.TimeoutException;
import static org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isDone;
import static org.apache.hadoop.ozone.admin.scm.FinalizeUpgradeCommandUtil.isStarting;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_MULTITENANCY_ENABLED;
/**
* Tests that S3 requests for a tenant are directed to that tenant's volume,
@@ -65,6 +66,7 @@ public class TestMultiTenantVolume {
OzoneConfiguration conf = new OzoneConfiguration();
conf.setBoolean(
OMMultiTenantManagerImpl.OZONE_OM_TENANT_DEV_SKIP_RANGER, true);
+ conf.setBoolean(OZONE_OM_MULTITENANCY_ENABLED, true);
MiniOzoneCluster.Builder builder = MiniOzoneCluster.newBuilder(conf)
.withoutDatanodes()
.setOmLayoutVersion(OMLayoutFeature.INITIAL_VERSION.layoutVersion());
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java
index 0db0c69e45..39bdbaae54 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneTenantShell.java
@@ -59,6 +59,7 @@ import java.util.List;
import java.util.UUID;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_MULTITENANCY_ENABLED;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_USER;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_RANGER_HTTPS_ADDRESS_KEY;
@@ -122,6 +123,9 @@ public class TestOzoneTenantShell {
}
conf = new OzoneConfiguration();
+ conf.setBoolean(
+ OMMultiTenantManagerImpl.OZONE_OM_TENANT_DEV_SKIP_RANGER, true);
+ conf.setBoolean(OZONE_OM_MULTITENANCY_ENABLED, true);
if (USE_ACTUAL_RANGER) {
conf.set(OZONE_RANGER_HTTPS_ADDRESS_KEY, System.getenv("RANGER_ADDRESS"));
diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index ca3f0bd975..750ece9573 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -418,6 +418,8 @@ enum Status {
VOLUME_IS_REFERENCED = 83;
TENANT_NOT_EMPTY = 84;
+
+ FEATURE_NOT_ENABLED = 85;
}
/**
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManager.java
index 3554ab6f29..6d2d2ab0d4 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManager.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManager.java
@@ -19,12 +19,25 @@ package org.apache.hadoop.ozone.om;
import java.io.IOException;
import com.google.common.base.Optional;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.om.helpers.TenantUserList;
import org.apache.hadoop.ozone.om.multitenant.Tenant;
+import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
import org.apache.http.auth.BasicUserPrincipal;
+import org.slf4j.Logger;
+
+import static org.apache.hadoop.ozone.OzoneConsts.TENANT_ID_USERNAME_DELIMITER;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_MULTITENANCY_ENABLED;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_MULTITENANCY_ENABLED_DEFAULT;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_USER;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_RANGER_HTTPS_ADDRESS_KEY;
+import static org.apache.hadoop.ozone.om.OMMultiTenantManagerImpl.OZONE_OM_TENANT_DEV_SKIP_RANGER;
/**
* OM MultiTenant manager interface.
@@ -117,7 +130,9 @@ public interface OMMultiTenantManager {
* @param userPrincipal user name
* @return access ID in the form of tenantName$username
*/
- String getDefaultAccessId(String tenantId, String userPrincipal);
+ static String getDefaultAccessId(String tenantId, String userPrincipal) {
+ return tenantId + TENANT_ID_USERNAME_DELIMITER + userPrincipal;
+ }
/**
* Returns true if user is the tenant's admin or Ozone admin, false otherwise.
@@ -235,4 +250,75 @@ public interface OMMultiTenantManager {
* @throws IOException
*/
boolean isTenantEmpty(String tenantId) throws IOException;
+
+ /**
+ * Returns true if Multi-Tenancy can be successfully enabled given the OM
+ * instance and conf; returns false if ozone.om.multitenancy.enabled = false
+ *
+ * Config validation will be performed on conf if the intent to enable
+ * Multi-Tenancy is specified (i.e. ozone.om.multitenancy.enabled = true),
+ * if the validation failed, an exception will be thrown to prevent OM from
+ * starting up.
+ */
+ static boolean checkAndEnableMultiTenancy(
+ OzoneManager ozoneManager, OzoneConfiguration conf) {
+
+ // Borrow the logger from OM instance
+ final Logger logger = OzoneManager.LOG;
+
+ boolean isS3MultiTenancyEnabled = conf.getBoolean(
+ OZONE_OM_MULTITENANCY_ENABLED, OZONE_OM_MULTITENANCY_ENABLED_DEFAULT);
+
+ final boolean devSkipMTCheck = conf.getBoolean(
+ OZONE_OM_TENANT_DEV_SKIP_RANGER, false);
+
+ // If ozone.om.multitenancy.enabled = false, skip the validation
+ // Or if dev skip check flag is set, skip the validation (used in UT)
+ if (!isS3MultiTenancyEnabled || devSkipMTCheck) {
+ return isS3MultiTenancyEnabled;
+ }
+
+ // Validate configs required to enable S3 multi-tenancy
+ if (!ozoneManager.isSecurityEnabled()) {
+ isS3MultiTenancyEnabled = false;
+ logger.error("Ozone security is required to enable S3 Multi-Tenancy");
+ } else if (!SecurityUtil.getAuthenticationMethod(conf).equals(
+ AuthenticationMethod.KERBEROS)) {
+ isS3MultiTenancyEnabled = false;
+ logger.error("Kerberos authentication is required to enable S3 "
+ + "Multi-Tenancy");
+ }
+
+ // TODO: Validate accessAuthorizer later. We can't do that for now:
+ // 1. Tenant acceptance test env (ozonesecure) uses OzoneNativeAuthorizer
+ // 2. RangerOzoneAuthorizer is external class
+
+ final String rangerAddress = conf.get(OZONE_RANGER_HTTPS_ADDRESS_KEY);
+ if (StringUtils.isBlank(rangerAddress)) {
+ isS3MultiTenancyEnabled = false;
+ logger.error("{} is required to enable S3 Multi-Tenancy but not set",
+ OZONE_RANGER_HTTPS_ADDRESS_KEY);
+ }
+
+ // TODO: Do not check Ranger user/passwd if Ranger Java client is enabled
+ final String rangerUser = conf.get(OZONE_OM_RANGER_HTTPS_ADMIN_API_USER);
+ if (StringUtils.isBlank(rangerUser)) {
+ isS3MultiTenancyEnabled = false;
+ logger.error("{} is required to enable S3 Multi-Tenancy but not set",
+ OZONE_OM_RANGER_HTTPS_ADMIN_API_USER);
+ }
+ final String rangerPw = conf.get(OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD);
+ if (StringUtils.isBlank(rangerPw)) {
+ isS3MultiTenancyEnabled = false;
+ logger.error("{} is required to enable S3 Multi-Tenancy but not set",
+ OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD);
+ }
+
+ if (!isS3MultiTenancyEnabled) {
+ throw new RuntimeException("Failed to meet one or more requirements to "
+ + "enable S3 Multi-Tenancy");
+ }
+
+ return true;
+ }
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManagerImpl.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManagerImpl.java
index 0bc54a6ae4..1c359be888 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManagerImpl.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMultiTenantManagerImpl.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.ozone.om;
-import static org.apache.hadoop.ozone.OzoneConsts.TENANT_ID_USERNAME_DELIMITER;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_ACCESS_ID;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TENANT_AUTHORIZER_ERROR;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TENANT_NOT_FOUND;
@@ -84,8 +83,8 @@ public class OMMultiTenantManagerImpl implements OMMultiTenantManager {
private static final Logger LOG =
LoggerFactory.getLogger(OMMultiTenantManagerImpl.class);
- // TODO: Remove when proper testing infra is deployed.
- // Internal dev flag to skip Ranger communication.
+ // Internal flag to skip Ranger communication,
+ // and to skip Ozone config validation for S3 multi-tenancy
public static final String OZONE_OM_TENANT_DEV_SKIP_RANGER =
"ozone.om.tenant.dev.skip.ranger";
@@ -349,10 +348,6 @@ public class OMMultiTenantManagerImpl implements OMMultiTenantManager {
return null;
}
- public String getDefaultAccessId(String tenantId, String userPrincipal) {
- return tenantId + TENANT_ID_USERNAME_DELIMITER + userPrincipal;
- }
-
/**
* {@inheritDoc}
*/
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java
index 0aab387ea4..b6eaeca0ac 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java
@@ -47,8 +47,11 @@ public final class OzoneAclUtils {
* If the access ID does not belong to a tenant, the access ID is returned
* as is to be used as the principal.
*/
- public static String accessIdToUserPrincipal(String accessID)
- throws IOException {
+ public static String accessIdToUserPrincipal(String accessID) {
+ if (multiTenantManager == null) {
+ return accessID;
+ }
+
String principal = multiTenantManager.getUserNameGivenAccessId(accessID);
if (principal == null) {
principal = accessID;
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 47a2282d87..c8e1ed5a29 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -372,6 +372,8 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
private final boolean useRatisForReplication;
private final String defaultBucketLayout;
+ private boolean isS3MultiTenancyEnabled;
+
private boolean isNativeAuthorizerEnabled;
private ExitManager exitManager;
@@ -534,6 +536,10 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
blockTokenMgr = createBlockTokenSecretManager(configuration);
}
+ // Enable S3 multi-tenancy if config keys are set
+ this.isS3MultiTenancyEnabled =
+ OMMultiTenantManager.checkAndEnableMultiTenancy(this, conf);
+
// Get admin list
omAdminUsernames = getOzoneAdminsFromConfig(configuration);
instantiateServices(false);
@@ -653,8 +659,12 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
private void instantiateServices(boolean withNewSnapshot) throws IOException {
metadataManager = new OmMetadataManagerImpl(configuration);
- multiTenantManager = new OMMultiTenantManagerImpl(this, configuration);
- OzoneAclUtils.setOMMultiTenantManager(multiTenantManager);
+ LOG.info("S3 Multi-Tenancy is {}",
+ isS3MultiTenancyEnabled ? "enabled" : "disabled");
+ if (isS3MultiTenancyEnabled) {
+ multiTenantManager = new OMMultiTenantManagerImpl(this, configuration);
+ OzoneAclUtils.setOMMultiTenantManager(multiTenantManager);
+ }
volumeManager = new VolumeManagerImpl(metadataManager, configuration);
bucketManager = new BucketManagerImpl(metadataManager, getKmsProvider(),
isRatisEnabled);
@@ -756,6 +766,26 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
return grpcBlockTokenEnabled;
}
+ /**
+ * Returns true if S3 multi-tenancy is enabled; false otherwise.
+ */
+ public boolean isS3MultiTenancyEnabled() {
+ return isS3MultiTenancyEnabled;
+ }
+
+ /**
+ * Throws OMException FEATURE_NOT_ENABLED if S3 multi-tenancy is not enabled.
+ */
+ public void checkS3MultiTenancyEnabled() throws OMException {
+ if (isS3MultiTenancyEnabled()) {
+ return;
+ }
+
+ throw new OMException("S3 multi-tenancy feature is not enabled. Please "
+ + "set ozone.om.multitenancy.enabled to true and restart all OMs.",
+ ResultCodes.FEATURE_NOT_ENABLED);
+ }
+
/**
* Return config value of {@link OzoneConfigKeys#OZONE_SECURITY_ENABLED_KEY}.
*/
@@ -3133,8 +3163,10 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
}
} else {
String accessId = s3Auth.getAccessId();
- Optional<String> optionalTenantId =
- multiTenantManager.getTenantForAccessID(accessId);
+ // If S3 Multi-Tenancy is not enabled, all S3 requests will be redirected
+ // to the default s3v for compatibility
+ final Optional<String> optionalTenantId = isS3MultiTenancyEnabled() ?
+ multiTenantManager.getTenantForAccessID(accessId) : Optional.absent();
if (!optionalTenantId.isPresent()) {
final UserGroupInformation s3gUGI =
@@ -3150,6 +3182,8 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
+ "requests to default s3 volume {}.", accessId, s3Volume);
}
} else {
+ // S3 Multi-Tenancy is enabled, and the accessId is assigned to a tenant
+
final String tenantId = optionalTenantId.get();
OmDBTenantState tenantState =
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
index b425ea4424..09b92a22fe 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
@@ -190,16 +190,22 @@ public final class OzoneManagerRatisUtils {
case PurgePaths:
return new OMPathsPurgeRequestWithFSO(omRequest);
case CreateTenant:
+ ozoneManager.checkS3MultiTenancyEnabled();
return new OMTenantCreateRequest(omRequest);
case DeleteTenant:
+ ozoneManager.checkS3MultiTenancyEnabled();
return new OMTenantDeleteRequest(omRequest);
case TenantAssignUserAccessId:
+ ozoneManager.checkS3MultiTenancyEnabled();
return new OMTenantAssignUserAccessIdRequest(omRequest);
case TenantRevokeUserAccessId:
+ ozoneManager.checkS3MultiTenancyEnabled();
return new OMTenantRevokeUserAccessIdRequest(omRequest);
case TenantAssignAdmin:
+ ozoneManager.checkS3MultiTenancyEnabled();
return new OMTenantAssignAdminRequest(omRequest);
case TenantRevokeAdmin:
+ ozoneManager.checkS3MultiTenancyEnabled();
return new OMTenantRevokeAdminRequest(omRequest);
/*
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java
index f9a6a9e467..d301ca963c 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignAdminRequest.java
@@ -74,8 +74,11 @@ public class OMTenantAssignAdminRequest extends OMClientRequest {
@Override
@DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+
+
+ final OMRequest omRequest = super.preExecute(ozoneManager);
final TenantAssignAdminRequest request =
- getOmRequest().getTenantAssignAdminRequest();
+ omRequest.getTenantAssignAdminRequest();
final String accessId = request.getAccessId();
String tenantId = request.getTenantId();
@@ -124,20 +127,13 @@ public class OMTenantAssignAdminRequest extends OMClientRequest {
ozoneManager.getMultiTenantManager().assignTenantAdmin(
request.getAccessId(), delegated);
- final OMRequest.Builder omRequestBuilder = getOmRequest().toBuilder()
- .setUserInfo(getUserInfo())
+ final OMRequest.Builder omRequestBuilder = omRequest.toBuilder()
.setTenantAssignAdminRequest(
TenantAssignAdminRequest.newBuilder()
.setAccessId(accessId)
.setTenantId(tenantId)
.setDelegated(delegated)
- .build())
- .setCmdType(getOmRequest().getCmdType())
- .setClientId(getOmRequest().getClientId());
-
- if (getOmRequest().hasTraceID()) {
- omRequestBuilder.setTraceID(getOmRequest().getTraceID());
- }
+ .build());
return omRequestBuilder.build();
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignUserAccessIdRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignUserAccessIdRequest.java
index 509d5de6ce..053b766168 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignUserAccessIdRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantAssignUserAccessIdRequest.java
@@ -28,6 +28,7 @@ import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.audit.OMAction;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.OMMetrics;
+import org.apache.hadoop.ozone.om.OMMultiTenantManager;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.OmDBAccessIdInfo;
@@ -107,8 +108,10 @@ public class OMTenantAssignUserAccessIdRequest extends OMClientRequest {
@Override
@DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+
+ final OMRequest omRequest = super.preExecute(ozoneManager);
final TenantAssignUserAccessIdRequest request =
- getOmRequest().getTenantAssignUserAccessIdRequest();
+ omRequest.getTenantAssignUserAccessIdRequest();
final String tenantId = request.getTenantId();
@@ -133,8 +136,8 @@ public class OMTenantAssignUserAccessIdRequest extends OMClientRequest {
}
// HDDS-6366: Disallow specifying custom accessId.
- final String expectedAccessId = ozoneManager.getMultiTenantManager()
- .getDefaultAccessId(tenantId, userPrincipal);
+ final String expectedAccessId =
+ OMMultiTenantManager.getDefaultAccessId(tenantId, userPrincipal);
if (!accessId.equals(expectedAccessId)) {
throw new OMException("Invalid accessId '" + accessId + "'. "
+ "Specifying a custom access ID disallowed. "
@@ -166,15 +169,8 @@ public class OMTenantAssignUserAccessIdRequest extends OMClientRequest {
.setAwsSecret(s3Secret)
.setKerberosID(accessId).build();
- final OMRequest.Builder omRequestBuilder = getOmRequest().toBuilder()
- .setUserInfo(getUserInfo())
- .setUpdateGetS3SecretRequest(updateGetS3SecretRequest)
- .setCmdType(getOmRequest().getCmdType())
- .setClientId(getOmRequest().getClientId());
-
- if (getOmRequest().hasTraceID()) {
- omRequestBuilder.setTraceID(getOmRequest().getTraceID());
- }
+ final OMRequest.Builder omRequestBuilder = omRequest.toBuilder()
+ .setUpdateGetS3SecretRequest(updateGetS3SecretRequest);
return omRequestBuilder.build();
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
index 27e25be6fa..b87e76a6e5 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantCreateRequest.java
@@ -118,7 +118,9 @@ public class OMTenantCreateRequest extends OMVolumeRequest {
// Check Ozone cluster admin privilege
ozoneManager.getMultiTenantManager().checkAdmin();
- final CreateTenantRequest request = getOmRequest().getCreateTenantRequest();
+ final OMRequest omRequest = super.preExecute(ozoneManager);
+ final CreateTenantRequest request = omRequest.getCreateTenantRequest();
+ Preconditions.checkNotNull(request);
final String tenantId = request.getTenantId();
// Check tenantId validity
@@ -169,21 +171,14 @@ public class OMTenantCreateRequest extends OMVolumeRequest {
tenantInContext = ozoneManager.getMultiTenantManager()
.createTenantAccessInAuthorizer(tenantId);
- final OMRequest.Builder omRequestBuilder = getOmRequest().toBuilder()
+ final OMRequest.Builder omRequestBuilder = omRequest.toBuilder()
.setCreateTenantRequest(
CreateTenantRequest.newBuilder()
.setTenantId(tenantId)
.setVolumeName(volumeName))
.setCreateVolumeRequest(
- CreateVolumeRequest.newBuilder().setVolumeInfo(updatedVolumeInfo))
- // TODO: Can the three lines below be ignored?
- .setUserInfo(getUserInfo())
- .setCmdType(getOmRequest().getCmdType())
- .setClientId(getOmRequest().getClientId());
-
- if (getOmRequest().hasTraceID()) {
- omRequestBuilder.setTraceID(getOmRequest().getTraceID());
- }
+ CreateVolumeRequest.newBuilder()
+ .setVolumeInfo(updatedVolumeInfo));
return omRequestBuilder.build();
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
index 9e6b146cb0..8bedef485d 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantDeleteRequest.java
@@ -74,7 +74,7 @@ public class OMTenantDeleteRequest extends OMVolumeRequest {
// TODO: TBD: Call ozoneManager.getMultiTenantManager().deleteTenant() ?
- return getOmRequest().toBuilder().setUserInfo(getUserInfo()).build();
+ return super.preExecute(ozoneManager);
}
@Override
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java
index 7d112135a7..991dbe85e3 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeAdminRequest.java
@@ -74,8 +74,10 @@ public class OMTenantRevokeAdminRequest extends OMClientRequest {
@Override
@DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+
+ final OMRequest omRequest = super.preExecute(ozoneManager);
final TenantRevokeAdminRequest request =
- getOmRequest().getTenantRevokeAdminRequest();
+ omRequest.getTenantRevokeAdminRequest();
final String accessId = request.getAccessId();
String tenantId = request.getTenantId();
@@ -114,25 +116,16 @@ public class OMTenantRevokeAdminRequest extends OMClientRequest {
OMException.ResultCodes.INVALID_TENANT_ID);
}
- // TODO: Call OMMTM to remove user from admin group of the tenant.
- // The call should remove user (not accessId) from the tenant's admin group
-// ozoneManager.getMultiTenantManager().revokeTenantAdmin();
+ // Remove user (inferred from access ID) from tenant admin role in Ranger
+ ozoneManager.getMultiTenantManager().revokeTenantAdmin(accessId);
- final OMRequest.Builder omRequestBuilder = getOmRequest().toBuilder()
- .setUserInfo(getUserInfo())
+ final OMRequest.Builder omRequestBuilder = omRequest.toBuilder()
.setTenantRevokeAdminRequest(
- // Regenerate request just in case tenantId is not provided
- // by the client
- TenantRevokeAdminRequest.newBuilder()
- .setTenantId(tenantId)
- .setAccessId(request.getAccessId())
- .build())
- .setCmdType(getOmRequest().getCmdType())
- .setClientId(getOmRequest().getClientId());
-
- if (getOmRequest().hasTraceID()) {
- omRequestBuilder.setTraceID(getOmRequest().getTraceID());
- }
+ // Regen request just in case tenantId is not provided by the client
+ TenantRevokeAdminRequest.newBuilder()
+ .setTenantId(tenantId)
+ .setAccessId(request.getAccessId())
+ .build());
return omRequestBuilder.build();
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java
index e779ec8a1a..24ff96e103 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMTenantRevokeUserAccessIdRequest.java
@@ -82,8 +82,10 @@ public class OMTenantRevokeUserAccessIdRequest extends OMClientRequest {
@Override
@DisallowedUntilLayoutVersion(MULTITENANCY_SCHEMA)
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+
+ final OMRequest omRequest = super.preExecute(ozoneManager);
final TenantRevokeUserAccessIdRequest request =
- getOmRequest().getTenantRevokeUserAccessIdRequest();
+ omRequest.getTenantRevokeUserAccessIdRequest();
final String accessId = request.getAccessId();
@@ -129,19 +131,12 @@ public class OMTenantRevokeUserAccessIdRequest extends OMClientRequest {
// TODO: Check destroyUser() behavior
ozoneManager.getMultiTenantManager().revokeUserAccessId(accessId);
- final Builder omRequestBuilder = getOmRequest().toBuilder()
- .setUserInfo(getUserInfo())
+ final Builder omRequestBuilder = omRequest.toBuilder()
.setTenantRevokeUserAccessIdRequest(
TenantRevokeUserAccessIdRequest.newBuilder()
.setAccessId(accessId)
.setTenantId(tenantId)
- .build())
- .setCmdType(getOmRequest().getCmdType())
- .setClientId(getOmRequest().getClientId());
-
- if (getOmRequest().hasTraceID()) {
- omRequestBuilder.setTraceID(getOmRequest().getTraceID());
- }
+ .build());
return omRequestBuilder.build();
}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
index 5ab4a3b051..4dffc39e22 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
@@ -235,16 +235,19 @@ public class OzoneManagerRequestHandler implements RequestHandler {
responseBuilder.setGetS3VolumeContextResponse(s3VolumeContextResponse);
break;
case TenantGetUserInfo:
+ impl.checkS3MultiTenancyEnabled();
TenantGetUserInfoResponse getUserInfoResponse = tenantGetUserInfo(
request.getTenantGetUserInfoRequest());
responseBuilder.setTenantGetUserInfoResponse(getUserInfoResponse);
break;
case ListTenant:
+ impl.checkS3MultiTenancyEnabled();
ListTenantResponse listTenantResponse = listTenant(
request.getListTenantRequest());
responseBuilder.setListTenantResponse(listTenantResponse);
break;
case TenantListUser:
+ impl.checkS3MultiTenancyEnabled();
TenantListUserResponse listUserResponse = tenantListUsers(
request.getTenantListUserRequest());
responseBuilder.setTenantListUserResponse(listUserResponse);
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMultiTenantManager.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMultiTenantManager.java
new file mode 100644
index 0000000000..8fc0861838
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOMMultiTenantManager.java
@@ -0,0 +1,175 @@
+/*
+ * 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.hadoop.ozone.om;
+
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils;
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status;
+import org.apache.hadoop.ozone.protocolPB.OzoneManagerRequestHandler;
+import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
+import org.apache.hadoop.util.StringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_MULTITENANCY_ENABLED;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RANGER_HTTPS_ADMIN_API_USER;
+import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_RANGER_HTTPS_ADDRESS_KEY;
+import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FEATURE_NOT_ENABLED;
+
+/**
+ * Tests OMMultiTenantManager.
+ */
+public class TestOMMultiTenantManager {
+
+ /**
+ * Try different configs against
+ * OMMultiTenantManager#checkAndEnableMultiTenancy and verify its response.
+ */
+ @Test
+ public void testMultiTenancyCheckConfig() {
+ final OzoneManager ozoneManager = Mockito.mock(OzoneManager.class);
+
+ final OzoneConfiguration conf = new OzoneConfiguration();
+
+ // Case 1: ozone.om.multitenancy.enabled = false
+ conf.setBoolean(OZONE_OM_MULTITENANCY_ENABLED, false);
+ Assert.assertFalse(
+ OMMultiTenantManager.checkAndEnableMultiTenancy(ozoneManager, conf));
+
+ // Case 2: ozone.om.multitenancy.enabled = true
+ // Initially however none of the other essential configs are set.
+ conf.setBoolean(OZONE_OM_MULTITENANCY_ENABLED, true);
+ expectConfigCheckToFail(ozoneManager, conf);
+
+ // "Enable" security
+ Mockito.when(ozoneManager.isSecurityEnabled()).thenReturn(true);
+ expectConfigCheckToFail(ozoneManager, conf);
+
+ // Enable Kerberos auth
+ conf.set(HADOOP_SECURITY_AUTHENTICATION,
+ StringUtils.toLowerCase(AuthenticationMethod.KERBEROS.toString()));
+ expectConfigCheckToFail(ozoneManager, conf);
+
+ // Set essential Ranger conf one by one
+ conf.set(OZONE_RANGER_HTTPS_ADDRESS_KEY, "http://ranger:6080");
+ expectConfigCheckToFail(ozoneManager, conf);
+ conf.set(OZONE_OM_RANGER_HTTPS_ADMIN_API_USER, "admin");
+ expectConfigCheckToFail(ozoneManager, conf);
+ conf.set(OZONE_OM_RANGER_HTTPS_ADMIN_API_PASSWD, "passwd");
+ // At this point the config check should pass. Method returns true
+ Assert.assertTrue(
+ OMMultiTenantManager.checkAndEnableMultiTenancy(ozoneManager, conf));
+ }
+
+ /**
+ * Helper function for testMultiTenancyConfig.
+ */
+ private void expectConfigCheckToFail(OzoneManager ozoneManager,
+ OzoneConfiguration conf) {
+ try {
+ OMMultiTenantManager.checkAndEnableMultiTenancy(ozoneManager, conf);
+ Assert.fail("Should have thrown RuntimeException");
+ } catch (RuntimeException e) {
+ Assert.assertTrue(e.getMessage().contains("Failed to meet"));
+ }
+ }
+
+ /**
+ * Verify that Multi-Tenancy read and write requests are blocked as intended
+ * when the the feature is disabled.
+ */
+ @Test
+ public void testMultiTenancyRequestsWhenDisabled() throws IOException {
+
+ final OzoneManager ozoneManager = Mockito.mock(OzoneManager.class);
+ Mockito.doCallRealMethod().when(ozoneManager).checkS3MultiTenancyEnabled();
+
+ Mockito.when(ozoneManager.isS3MultiTenancyEnabled()).thenReturn(false);
+
+ final String tenantId = "test-tenant";
+ final String userPrincipal = "alice";
+ final String accessId =
+ OMMultiTenantManager.getDefaultAccessId(tenantId, userPrincipal);
+
+ // Check that Multi-Tenancy write requests are blocked when not enabled
+ expectWriteRequestToFail(ozoneManager,
+ OMRequestTestUtils.createTenantRequest(tenantId));
+ expectWriteRequestToFail(ozoneManager,
+ OMRequestTestUtils.deleteTenantRequest(tenantId));
+ expectWriteRequestToFail(ozoneManager,
+ OMRequestTestUtils.tenantAssignUserAccessIdRequest(
+ userPrincipal, tenantId, accessId));
+ expectWriteRequestToFail(ozoneManager,
+ OMRequestTestUtils.tenantRevokeUserAccessIdRequest(accessId));
+ expectWriteRequestToFail(ozoneManager,
+ OMRequestTestUtils.tenantAssignAdminRequest(accessId, tenantId, true));
+ expectWriteRequestToFail(ozoneManager,
+ OMRequestTestUtils.tenantRevokeAdminRequest(accessId, tenantId));
+
+ // Check that Multi-Tenancy read requests are blocked when not enabled
+ final OzoneManagerRequestHandler ozoneManagerRequestHandler =
+ new OzoneManagerRequestHandler(ozoneManager, null);
+
+ expectReadRequestToFail(ozoneManagerRequestHandler,
+ OMRequestTestUtils.listUsersInTenantRequest(tenantId));
+ expectReadRequestToFail(ozoneManagerRequestHandler,
+ OMRequestTestUtils.listTenantRequest());
+ expectReadRequestToFail(ozoneManagerRequestHandler,
+ OMRequestTestUtils.tenantGetUserInfoRequest(tenantId));
+
+ // getS3VolumeContext request does not throw exception when MT is disabled.
+ // Rather, it falls back to the default s3v for backwards compatibility.
+ }
+
+ /**
+ * Helper function for testMultiTenancyRPCWhenDisabled.
+ */
+ private void expectWriteRequestToFail(OzoneManager om, OMRequest omRequest)
+ throws IOException {
+ try {
+ OzoneManagerRatisUtils.createClientRequest(omRequest, om);
+ Assert.fail("Should have thrown OMException");
+ } catch (OMException e) {
+ Assert.assertEquals(FEATURE_NOT_ENABLED, e.getResult());
+ }
+ }
+
+ /**
+ * Helper function for testMultiTenancyRPCWhenDisabled.
+ */
+ private void expectReadRequestToFail(OzoneManagerRequestHandler handler,
+ OMRequest omRequest) {
+
+ // handleReadRequest does not throw
+ OMResponse omResponse = handler.handleReadRequest(omRequest);
+ Assert.assertFalse(omResponse.getSuccess());
+ Assert.assertEquals(Status.FEATURE_NOT_ENABLED, omResponse.getStatus());
+ Assert.assertTrue(omResponse.getMessage()
+ .startsWith("S3 multi-tenancy feature is not enabled"));
+ }
+
+}
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
index 75b486e8e8..1a6b76e1a9 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
@@ -47,6 +47,10 @@ import org.apache.hadoop.ozone.om.helpers.OzoneFSUtils;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3VolumeContextRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ListTenantRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.MultipartUploadAbortRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
@@ -67,6 +71,13 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.RemoveAclRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.SetAclRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantAssignAdminRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantAssignUserAccessIdRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantGetUserInfoRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantListUserRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantRevokeAdminRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantRevokeUserAccessIdRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType;
import org.apache.hadoop.ozone.security.acl.OzoneObj.StoreType;
@@ -899,6 +910,149 @@ public final class OMRequestTestUtils {
.setClientId(UUID.randomUUID().toString()).build();
}
+ public static OMRequest createTenantRequest(String tenantId) {
+
+ final CreateTenantRequest.Builder requestBuilder =
+ CreateTenantRequest.newBuilder()
+ .setTenantId(tenantId)
+ .setVolumeName(tenantId);
+
+ return OMRequest.newBuilder()
+ .setCreateTenantRequest(requestBuilder)
+ .setCmdType(Type.CreateTenant)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest deleteTenantRequest(String tenantId) {
+
+ final DeleteTenantRequest.Builder requestBuilder =
+ DeleteTenantRequest.newBuilder()
+ .setTenantId(tenantId);
+
+ return OMRequest.newBuilder()
+ .setDeleteTenantRequest(requestBuilder)
+ .setCmdType(Type.DeleteTenant)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest tenantAssignUserAccessIdRequest(
+ String username, String tenantId, String accessId) {
+
+ final TenantAssignUserAccessIdRequest.Builder requestBuilder =
+ TenantAssignUserAccessIdRequest.newBuilder()
+ .setUserPrincipal(username)
+ .setTenantId(tenantId)
+ .setAccessId(accessId);
+
+ return OMRequest.newBuilder()
+ .setTenantAssignUserAccessIdRequest(requestBuilder)
+ .setCmdType(Type.TenantAssignUserAccessId)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest tenantRevokeUserAccessIdRequest(String accessId) {
+
+ final TenantRevokeUserAccessIdRequest.Builder requestBuilder =
+ TenantRevokeUserAccessIdRequest.newBuilder()
+ .setAccessId(accessId);
+
+ return OMRequest.newBuilder()
+ .setTenantRevokeUserAccessIdRequest(requestBuilder)
+ .setCmdType(Type.TenantRevokeUserAccessId)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest tenantAssignAdminRequest(
+ String accessId, String tenantId, boolean delegated) {
+
+ final TenantAssignAdminRequest.Builder requestBuilder =
+ TenantAssignAdminRequest.newBuilder()
+ .setAccessId(accessId)
+ .setDelegated(delegated);
+
+ if (tenantId != null) {
+ requestBuilder.setTenantId(tenantId);
+ }
+
+ return OMRequest.newBuilder()
+ .setTenantAssignAdminRequest(requestBuilder)
+ .setCmdType(Type.TenantAssignAdmin)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest tenantRevokeAdminRequest(
+ String accessId, String tenantId) {
+
+ final TenantRevokeAdminRequest.Builder requestBuilder =
+ TenantRevokeAdminRequest.newBuilder()
+ .setAccessId(accessId);
+
+ if (tenantId != null) {
+ requestBuilder.setTenantId(tenantId);
+ }
+
+ return OMRequest.newBuilder()
+ .setTenantRevokeAdminRequest(requestBuilder)
+ .setCmdType(Type.TenantRevokeAdmin)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest tenantGetUserInfoRequest(String userPrincipal) {
+
+ final TenantGetUserInfoRequest.Builder requestBuilder =
+ TenantGetUserInfoRequest.newBuilder()
+ .setUserPrincipal(userPrincipal);
+
+ return OMRequest.newBuilder()
+ .setTenantGetUserInfoRequest(requestBuilder)
+ .setCmdType(Type.TenantGetUserInfo)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest listUsersInTenantRequest(String tenantId) {
+
+ final TenantListUserRequest.Builder requestBuilder =
+ TenantListUserRequest.newBuilder()
+ .setTenantId(tenantId);
+
+ return OMRequest.newBuilder()
+ .setTenantListUserRequest(requestBuilder)
+ .setCmdType(Type.TenantListUser)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest listTenantRequest() {
+
+ final ListTenantRequest.Builder requestBuilder =
+ ListTenantRequest.newBuilder();
+
+ return OMRequest.newBuilder()
+ .setListTenantRequest(requestBuilder)
+ .setCmdType(Type.ListTenant)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ public static OMRequest getS3VolumeContextRequest() {
+
+ final GetS3VolumeContextRequest.Builder requestBuilder =
+ GetS3VolumeContextRequest.newBuilder();
+
+ return OMRequest.newBuilder()
+ .setGetS3VolumeContextRequest(requestBuilder)
+ .setCmdType(Type.GetS3VolumeContext)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
/**
* Add the Key information to OzoneManager DB and cache.
* @param omMetadataManager
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
index 4864de95b1..c7bdd8f994 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
@@ -366,8 +366,6 @@ public class TestS3GetSecretRequest {
// Additional mock setup needed to pass accessId check
when(ozoneManager.getMultiTenantManager()).thenReturn(omMultiTenantManager);
- when(omMultiTenantManager.getDefaultAccessId(TENANT_ID, USER_BOB))
- .thenReturn(ACCESS_ID_BOB);
// Run preExecute
OMTenantAssignUserAccessIdRequest omTenantAssignUserAccessIdRequest =
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org