Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ private OzoneConsts() {
public static final String MAX_PARTS = "maxParts";
public static final String S3_BUCKET = "s3Bucket";
public static final String S3_GETSECRET_USER = "S3GetSecretUser";
public static final String S3_REVOKESECRET_USER = "S3RevokeSecretUser";
public static final String RENAMED_KEYS_MAP = "renamedKeysMap";
public static final String UNRENAMED_KEYS_MAP = "unRenamedKeysMap";
public static final String MULTIPART_UPLOAD_PART_NUMBER = "partNumber";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ public S3SecretValue getS3Secret(String kerberosID) throws IOException {
return proxy.getS3Secret(kerberosID);
}

public void revokeS3Secret(String kerberosID) throws IOException {
proxy.revokeS3Secret(kerberosID);
}

/**
* Returns Iterator to iterate over all the volumes in object store.
* The result can be restricted using volume prefix, will return all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,13 @@ void cancelDelegationToken(Token<OzoneTokenIdentifier> token)
*/
S3SecretValue getS3Secret(String kerberosID) throws IOException;

/**
* Revoke S3 Secret of given kerberos user.
* @param kerberosID
* @throws IOException
*/
void revokeS3Secret(String kerberosID) throws IOException;

/**
* Get KMS client provider.
* @return KMS client provider.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,17 @@ public S3SecretValue getS3Secret(String kerberosID) throws IOException {
return ozoneManagerClient.getS3Secret(kerberosID);
}

/**
* {@inheritDoc}
*/
@Override
public void revokeS3Secret(String kerberosID) throws IOException {
Preconditions.checkArgument(Strings.isNotBlank(kerberosID),
"kerberosID cannot be null or empty.");

ozoneManagerClient.revokeS3Secret(kerberosID);
}

@Override
public void setBucketVersioning(
String volumeName, String bucketName, Boolean versioning)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ public static boolean isReadOnly(
case PurgeKeys:
case RecoverTrash:
case DeleteOpenKeys:
case RevokeS3Secret:
return false;
default:
LOG.error("CmdType {} is not categorized as readOnly or not.", cmdType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ public enum OMAction implements AuditAction {
LOOKUP_FILE,
LIST_STATUS,

GET_S3_SECRET;
GET_S3_SECRET,
REVOKE_S3_SECRET;

@Override
public String getAction() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ OmMultipartUploadListParts listParts(String volumeName, String bucketName,
*/
OmMultipartUploadList listMultipartUploads(String volumeName,
String bucketName, String prefix) throws IOException;

/**
* Gets s3Secret for given kerberos user.
* @param kerberosID
Expand All @@ -380,6 +381,13 @@ OmMultipartUploadList listMultipartUploads(String volumeName,
*/
S3SecretValue getS3Secret(String kerberosID) throws IOException;

/**
* Revokes s3Secret of given kerberos user.
* @param kerberosID
* @throws IOException
*/
void revokeS3Secret(String kerberosID) throws IOException;

/**
* OzoneFS api to get file status for an entry.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RenameKeyRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RenameKeysRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RenewDelegationTokenResponseProto;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RevokeS3SecretRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetAclRequest;
Expand Down Expand Up @@ -848,7 +849,17 @@ public S3SecretValue getS3Secret(String kerberosID) throws IOException {
.getGetS3SecretResponse();

return S3SecretValue.fromProtobuf(resp.getS3Secret());
}

@Override
public void revokeS3Secret(String kerberosID) throws IOException {
RevokeS3SecretRequest request = RevokeS3SecretRequest.newBuilder()
.setKerberosID(kerberosID)
.build();
OMRequest omRequest = createOMRequest(Type.RevokeS3Secret)
.setRevokeS3SecretRequest(request)
.build();
handleError(submitRequest(omRequest));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
import org.junit.After;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -615,7 +616,7 @@ private void setupOm(OzoneConfiguration config) throws Exception {
}

@Test
public void testGetS3Secret() throws Exception {
public void testGetS3SecretAndRevokeS3Secret() throws Exception {

// Setup secure OM for start
setupOm(conf);
Expand Down Expand Up @@ -643,6 +644,17 @@ public void testGetS3Secret() throws Exception {
//access key fetched on both attempts must be same
assertEquals(attempt1.getAwsAccessKey(), attempt2.getAwsAccessKey());

// Revoke the existing secret
omClient.revokeS3Secret(username);

// Get a new secret
S3SecretValue attempt3 = omClient.getS3Secret(username);

// secret should differ because it has been revoked previously
assertNotEquals(attempt3.getAwsSecret(), attempt2.getAwsSecret());

// accessKey is still the same because it is derived from username
assertEquals(attempt3.getAwsAccessKey(), attempt2.getAwsAccessKey());

try {
omClient.getS3Secret("HADOOP/JOHNDOE");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public void testDoGet() throws Exception {
om.getMetadataManager().getStore(),
om.getMetrics().getDBCheckpointMetrics(),
om.getAclsEnabled(),
om.getOzoneAdmins(om.getConfiguration()),
om.getOmAdminUsernames(),
om.isSpnegoEnabled());

doNothing().when(responseMock).setContentType("application/x-tgz");
Expand Down Expand Up @@ -213,7 +213,7 @@ public void testSpnegoEnabled() throws Exception {
setupCluster();

final OzoneManager om = cluster.getOzoneManager();
Collection<String> allowedUsers = om.getOzoneAdmins(om.getConfiguration());
Collection<String> allowedUsers = om.getOmAdminUsernames();
allowedUsers.add("recon");

doCallRealMethod().when(omDbCheckpointServletMock).initialize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ enum Type {

ListTrash = 91;
RecoverTrash = 92;

RevokeS3Secret = 93;
}

message OMRequest {
Expand Down Expand Up @@ -165,6 +167,8 @@ message OMRequest {

optional ListTrashRequest listTrashRequest = 91;
optional RecoverTrashRequest RecoverTrashRequest = 92;

optional RevokeS3SecretRequest RevokeS3SecretRequest = 93;
}

message OMResponse {
Expand Down Expand Up @@ -1202,6 +1206,10 @@ message GetS3SecretResponse {
required S3Secret s3Secret = 2;
}

message RevokeS3SecretRequest {
required string kerberosID = 1;
}

/**
This will be used internally by OM to replicate S3 Secret across quorum of
OM's.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Collection;

/**
Expand Down Expand Up @@ -62,25 +61,21 @@ public void init() throws ServletException {
return;
}

try {
OzoneConfiguration conf = om.getConfiguration();
// Only Ozone Admins and Recon are allowed
Collection<String> allowedUsers = om.getOzoneAdmins(conf);
ReconConfig reconConfig = conf.getObject(ReconConfig.class);
String reconPrincipal = reconConfig.getKerberosPrincipal();
if (!reconPrincipal.isEmpty()) {
UserGroupInformation ugi =
UserGroupInformation.createRemoteUser(reconPrincipal);
allowedUsers.add(ugi.getShortUserName());
}

initialize(om.getMetadataManager().getStore(),
om.getMetrics().getDBCheckpointMetrics(),
om.getAclsEnabled(),
allowedUsers,
om.isSpnegoEnabled());
} catch (IOException e) {
LOG.error("Error in getOzoneAdmins: {}", e.getMessage());
OzoneConfiguration conf = om.getConfiguration();
// Only Ozone Admins and Recon are allowed
Collection<String> allowedUsers = om.getOmAdminUsernames();
ReconConfig reconConfig = conf.getObject(ReconConfig.class);
String reconPrincipal = reconConfig.getKerberosPrincipal();
if (!reconPrincipal.isEmpty()) {
UserGroupInformation ugi =
UserGroupInformation.createRemoteUser(reconPrincipal);
allowedUsers.add(ugi.getShortUserName());
}

initialize(om.getMetadataManager().getStore(),
om.getMetrics().getDBCheckpointMetrics(),
om.getAclsEnabled(),
allowedUsers,
om.isSpnegoEnabled());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@
import org.apache.hadoop.ozone.security.acl.RequestContext;
import org.apache.hadoop.hdds.ExitManager;
import org.apache.hadoop.ozone.util.OzoneVersionInfo;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.SecurityUtil;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
Expand Down Expand Up @@ -201,6 +202,7 @@
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_ENABLED;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_ENABLED_DEFAULT;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS_WILDCARD;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_KEY_PREALLOCATION_BLOCKS_MAX;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_KEY_PREALLOCATION_BLOCKS_MAX_DEFAULT;
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SCM_BLOCK_SIZE;
Expand Down Expand Up @@ -275,6 +277,11 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
private KeyManager keyManager;
private PrefixManagerImpl prefixManager;

/**
* OM super user / admin list.
*/
private final Collection<String> omAdminUsernames;

private final OMMetrics metrics;
private final ProtocolMessageMetrics<ProtocolMessageEnum>
omClientProtocolMetrics;
Expand Down Expand Up @@ -441,6 +448,9 @@ private OzoneManager(OzoneConfiguration conf) throws IOException,
blockTokenMgr = createBlockTokenSecretManager(configuration);
}

// Get admin list
omAdminUsernames = getOzoneAdminsFromConfig(configuration);

instantiateServices();

// Create special volume s3v which is required for S3G.
Expand Down Expand Up @@ -548,7 +558,7 @@ private void instantiateServices() throws IOException {
authorizer.setBucketManager(bucketManager);
authorizer.setKeyManager(keyManager);
authorizer.setPrefixManager(prefixManager);
authorizer.setOzoneAdmins(getOzoneAdmins(configuration));
authorizer.setOzoneAdmins(omAdminUsernames);
authorizer.setAllowListAllVolumes(allowListAllVolumes);
}
} else {
Expand Down Expand Up @@ -2698,6 +2708,15 @@ public S3SecretValue getS3Secret(String kerberosID) throws IOException {
return s3SecretManager.getS3Secret(kerberosID);
}

@Override
/**
* {@inheritDoc}
*/
public void revokeS3Secret(String kerberosID) {
throw new UnsupportedOperationException("OzoneManager does not require " +
"this to be implemented. As write requests use a new approach");
}

@Override
public OmMultipartInfo initiateMultipartUpload(OmKeyArgs keyArgs) throws
IOException {
Expand Down Expand Up @@ -3531,9 +3550,9 @@ public OzoneDelegationTokenSecretManager getDelegationTokenMgr() {
}

/**
* Return list of OzoneAdministrators.
* Return list of OzoneAdministrators from config.
*/
Collection<String> getOzoneAdmins(OzoneConfiguration conf)
Collection<String> getOzoneAdminsFromConfig(OzoneConfiguration conf)
throws IOException {
Collection<String> ozAdmins =
conf.getTrimmedStringCollection(OZONE_ADMINISTRATORS);
Expand All @@ -3544,6 +3563,26 @@ Collection<String> getOzoneAdmins(OzoneConfiguration conf)
return ozAdmins;
}

/**
* Return the list of Ozone administrators in effect.
*/
Collection<String> getOmAdminUsernames() {
return omAdminUsernames;
}

/**
* Return true if remoteUser is OM admin, false otherwise.
* @param remoteUser User name
* @throws AccessControlException
*/
public boolean isAdmin(String remoteUser) throws AccessControlException {
if (remoteUser == null || remoteUser.isEmpty()) {
return false;
}
return omAdminUsernames.contains(remoteUser)
|| omAdminUsernames.contains(OZONE_ADMINISTRATORS_WILDCARD);
}

/**
* Returns true if OzoneNativeAuthorizer is enabled and false if otherwise.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadCommitPartRequest;
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadCompleteRequest;
import org.apache.hadoop.ozone.om.request.s3.security.S3GetSecretRequest;
import org.apache.hadoop.ozone.om.request.s3.security.S3RevokeSecretRequest;
import org.apache.hadoop.ozone.om.request.security.OMCancelDelegationTokenRequest;
import org.apache.hadoop.ozone.om.request.security.OMGetDelegationTokenRequest;
import org.apache.hadoop.ozone.om.request.security.OMRenewDelegationTokenRequest;
Expand Down Expand Up @@ -156,6 +157,8 @@ public static OMClientRequest createClientRequest(OMRequest omRequest) {
return new S3GetSecretRequest(omRequest);
case RecoverTrash:
return new OMTrashRecoverRequest(omRequest);
case RevokeS3Secret:
return new S3RevokeSecretRequest(omRequest);
default:
throw new IllegalStateException("Unrecognized write command " +
"type request" + cmdType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,13 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
String kerberosID = s3GetSecretRequest.getKerberosID();

UserGroupInformation user = ProtobufRpcEngine.Server.getRemoteUser();
if (!user.getUserName().equals(kerberosID)) {
throw new OMException("User mismatch. Requested user name is " +
"mismatched " + kerberosID +", with current user " +
user.getUserName(), OMException.ResultCodes.USER_MISMATCH);
// Permission check. Users need to be themselves or have admin privilege
if (!user.getUserName().equals(kerberosID) &&
!ozoneManager.isAdmin(kerberosID)) {
throw new OMException("Requested user name '" + kerberosID +
"' doesn't match current user '" + user.getUserName() +
"', nor does current user has administrator privilege.",
OMException.ResultCodes.USER_MISMATCH);
}

String s3Secret = DigestUtils.sha256Hex(OmUtils.getSHADigest());
Expand Down
Loading