Skip to content

Commit

Permalink
HDDS-5206. Addendum: Support revoking S3 secret (#2270)
Browse files Browse the repository at this point in the history
  • Loading branch information
smengcl committed May 24, 2021
1 parent 9080fc3 commit e00fa80
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 18 deletions.
21 changes: 21 additions & 0 deletions hadoop-hdds/docs/content/interface/S3.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,27 @@ export AWS_SECRET_ACCESS_KEY=c261b6ecabf7d37d5f9ded654b1c724adac9bd9f13e247a235e
aws s3api --endpoint http://localhost:9878 create-bucket --bucket bucket1
```

To invalidate/revoke the secret, use `ozone s3 revokesecret` command. Parameter '-y' can be appended to skip the interactive confirmation.

```bash
ozone s3 revokesecret
Enter 'y' to confirm S3 secret revocation for 'testuser/scm@EXAMPLE.COM': y
S3 secret revoked.
```

Ozone Manager administrators can run `ozone s3 getsecret` and `ozone s3 revokesecret` command with `-u` parameter to specify another users.

```bash
# Obtained Kerberos TGT for testuser/scm@EXAMPLE.COM with kinit,
# testuser/scm@EXAMPLE.COM is an OM admin.
ozone s3 getsecret -u om/om@EXAMPLE.COM
awsAccessKey=om/om@EXAMPLE.COM
awsSecret=1e9379d0424cce6669b1a501ff14834e46dee004ee868b41a313b49eabcfb68f

ozone s3 revokesecret -u om/om@EXAMPLE.COM -y
S3 secret revoked.
```

## Expose any volume

Ozone has one more element in the name-space hierarchy compared to S3: the volumes. By default, all the buckets of the `/s3v` volume can be accessed with S3 interface but only the (Ozone) buckets of the `/s3v` volumes are exposed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -656,12 +656,36 @@ public void testGetS3SecretAndRevokeS3Secret() throws Exception {
// accessKey is still the same because it is derived from username
assertEquals(attempt3.getAwsAccessKey(), attempt2.getAwsAccessKey());

// Admin can get and revoke other users' secrets
// omClient's ugi is current user, which is added as an OM admin
omClient.getS3Secret("HADOOP/ALICE");
omClient.revokeS3Secret("HADOOP/ALICE");

// testUser is not an admin
final UserGroupInformation ugiNonAdmin =
UserGroupInformation.loginUserFromKeytabAndReturnUGI(
testUserPrincipal, testUserKeytab.getCanonicalPath());
final OzoneManagerProtocolClientSideTranslatorPB omClientNonAdmin =
new OzoneManagerProtocolClientSideTranslatorPB(
OmTransportFactory.create(conf, ugiNonAdmin, null),
RandomStringUtils.randomAscii(5));

try {
omClient.getS3Secret("HADOOP/JOHNDOE");
fail("testGetS3Secret failed");
omClientNonAdmin.getS3Secret("HADOOP/JOHN");
// Expected to fail because current ugi isn't an admin
fail("non-admin getS3Secret didn't fail as intended");
} catch (IOException ex) {
GenericTestUtils.assertExceptionContains("USER_MISMATCH", ex);
}

try {
omClientNonAdmin.revokeS3Secret("HADOOP/DOE");
// Expected to fail because current ugi isn't an admin
fail("non-admin revokeS3Secret didn't fail as intended");
} catch (IOException ex) {
GenericTestUtils.assertExceptionContains("USER_MISMATCH", ex);
}

} finally {
IOUtils.closeQuietly(om);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@
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 @@ -3571,15 +3570,16 @@ Collection<String> getOmAdminUsernames() {
}

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

return omAdminUsernames.contains(callerUgi.getShortUserName())
|| omAdminUsernames.contains(callerUgi.getUserName())
|| omAdminUsernames.contains(OZONE_ADMINISTRATORS_WILDCARD);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
// Generate S3 Secret to be used by OM quorum.
String kerberosID = s3GetSecretRequest.getKerberosID();

UserGroupInformation user = ProtobufRpcEngine.Server.getRemoteUser();
final UserGroupInformation ugi = ProtobufRpcEngine.Server.getRemoteUser();
final String username = ugi.getUserName();
// Permission check. Users need to be themselves or have admin privilege
if (!user.getUserName().equals(kerberosID) &&
!ozoneManager.isAdmin(kerberosID)) {
if (!username.equals(kerberosID) &&
!ozoneManager.isAdmin(ugi)) {
throw new OMException("Requested user name '" + kerberosID +
"' doesn't match current user '" + user.getUserName() +
"' doesn't match current user '" + username +
"', nor does current user has administrator privilege.",
OMException.ResultCodes.USER_MISMATCH);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
final RevokeS3SecretRequest s3RevokeSecretRequest =
getOmRequest().getRevokeS3SecretRequest();
final String kerberosID = s3RevokeSecretRequest.getKerberosID();
final UserGroupInformation user = ProtobufRpcEngine.Server.getRemoteUser();

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

0 comments on commit e00fa80

Please sign in to comment.