Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 6 additions & 0 deletions hadoop-hdds/framework/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ozone</groupId>
<artifactId>ozone-interface-client</artifactId>
<version>1.4.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.google.protobuf.ByteString;
import org.apache.hadoop.hdds.protocol.proto.SCMSecretKeyProtocolProtos;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
import org.apache.hadoop.security.token.TokenIdentifier;
import org.apache.hadoop.util.ProtobufUtils;

Expand Down Expand Up @@ -151,4 +152,29 @@ public static ManagedSecretKey fromProtobuf(
message.getAlgorithm());
return new ManagedSecretKey(id, creationTime, expiryTime, secretKey);
}

public static ManagedSecretKey fromProtobuf(
OzoneManagerProtocolProtos.GetCurrentSecretKeyResponse response) {
UUID id = ProtobufUtils.fromProtobuf(response.getSecretKey().getId());
Instant creationTime =
Instant.ofEpochMilli(response.getSecretKey().getCreationTime());
Instant expiryTime =
Instant.ofEpochMilli(response.getSecretKey().getExpiryTime());
SecretKey secretKey =
new SecretKeySpec(response.getSecretKey().getEncoded().toByteArray(),
response.getSecretKey().getAlgorithm());
return new ManagedSecretKey(id, creationTime, expiryTime, secretKey);
}

public static OzoneManagerProtocolProtos.ManagedSecretKey toProto(
ManagedSecretKey secretKey) {
OzoneManagerProtocolProtos.ManagedSecretKey.Builder builder =
OzoneManagerProtocolProtos.ManagedSecretKey.newBuilder();
builder.setId(ProtobufUtils.toProtobuf(secretKey.getId()))
.setCreationTime(secretKey.getCreationTime().toEpochMilli())
.setExpiryTime(secretKey.getExpiryTime().toEpochMilli())
.setAlgorithm(secretKey.getSecretKey().getAlgorithm())
.setEncoded(ByteString.copyFrom(secretKey.getSecretKey().getEncoded()));
return builder.build();
}
}
4 changes: 4 additions & 0 deletions hadoop-ozone/common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ https://maven.apache.org/xsd/maven-4.0.0.xsd">
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ozone</groupId>
<artifactId>hdds-server-framework</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ public static boolean isReadOnly(
case TenantListUser:
case ListSnapshot:
case EchoRPC:
case GetCurrentSecretKey:
case RangerBGSync:
// RangerBGSync is a read operation in the sense that it doesn't directly
// write to OM DB. And therefore it doesn't need a OMClientRequest.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;

import org.apache.hadoop.hdds.scm.container.common.helpers.ExcludeList;
import org.apache.hadoop.hdds.security.symmetric.ManagedSecretKey;
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.om.IOmMetadataReader;
import org.apache.hadoop.ozone.om.OMConfigKeys;
Expand Down Expand Up @@ -995,4 +996,6 @@ EchoRPCResponse echoRPCReq(byte[] payloadReq,
*/
boolean recoverLease(String volumeName, String bucketName,
String keyName) throws IOException;

ManagedSecretKey getCurrentSecretKey() throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.apache.hadoop.hdds.protocol.proto.HddsProtos
.UpgradeFinalizationStatus;
import org.apache.hadoop.hdds.scm.container.common.helpers.ExcludeList;
import org.apache.hadoop.hdds.security.symmetric.ManagedSecretKey;
import org.apache.hadoop.hdds.tracing.TracingUtil;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.ozone.ClientVersion;
Expand Down Expand Up @@ -104,6 +105,8 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.FinalizeUpgradeResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetAclRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetAclResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetCurrentSecretKeyRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetCurrentSecretKeyResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetDelegationTokenResponseProto;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusResponse;
Expand Down Expand Up @@ -1355,6 +1358,19 @@ public S3VolumeContext getS3VolumeContext() throws IOException {
return S3VolumeContext.fromProtobuf(resp);
}

@Override
public ManagedSecretKey getCurrentSecretKey() throws IOException {
final GetCurrentSecretKeyRequest.Builder requestBuilder =
GetCurrentSecretKeyRequest.newBuilder();
final OMRequest omRequest = createOMRequest(Type.GetCurrentSecretKey)
.setGetCurrentSecretKeyRequest(requestBuilder)
.build();
final OMResponse omResponse = submitRequest(omRequest);
final GetCurrentSecretKeyResponse resp =
handleError(omResponse).getGetCurrentSecretKeyResponse();
return ManagedSecretKey.fromProtobuf(resp);
}

/**
* Return the proxy object underlying this protocol translator.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.hadoop.hdds.annotation.InterfaceAudience;
import org.apache.hadoop.hdds.cli.OzoneAdmin;
import org.apache.hadoop.hdds.conf.DefaultConfigManager;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.scm.ScmConfig;
Expand Down Expand Up @@ -55,10 +56,15 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.SecretKey;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.Base64;
import java.util.Objects;
import java.util.Properties;
import java.util.UUID;
Expand Down Expand Up @@ -112,6 +118,7 @@ public final class TestBlockTokens {
public Timeout timeout = Timeout.seconds(180);

private static MiniKdc miniKdc;
private static OzoneAdmin ozoneAdmin;
private static OzoneConfiguration conf;
private static File workDir;
private static File ozoneKeytab;
Expand All @@ -121,6 +128,7 @@ public final class TestBlockTokens {
private static String host;
private static String clusterId;
private static String scmId;
private static String omServiceId;
private static MiniOzoneHAClusterImpl cluster;
private static OzoneClient client;
private static BlockInputStreamFactory blockInputStreamFactory =
Expand All @@ -137,13 +145,15 @@ public static void init() throws Exception {
GenericTestUtils.getTestDir(TestBlockTokens.class.getSimpleName());
clusterId = UUID.randomUUID().toString();
scmId = UUID.randomUUID().toString();
omServiceId = "om-service-test";

startMiniKdc();
setSecureConfig();
createCredentialsInKDC();
setSecretKeysConfig();
startCluster();
client = cluster.newClient();
ozoneAdmin = new OzoneAdmin(conf);
createTestData();
}

Expand Down Expand Up @@ -271,6 +281,37 @@ public void blockTokenFailsOnWrongPassword() throws Exception {
assertExceptionContains("Invalid token for user", ex);
}

@Test
public void testGetCurrentSecretKey() throws UnsupportedEncodingException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(outputStream, true, "UTF-8");
System.setOut(printStream);

String[] args =
new String[]{"om", "fetch-key", "--service-id=" + omServiceId};
ozoneAdmin.execute(args);

String actualOutput = outputStream.toString("UTF-8");
System.setOut(System.out);

String actualCurrentKey = testGetCurrentSecretKeyUtil(actualOutput);
SecretKey key =
getScmSecretKeyManager().getCurrentSecretKey().getSecretKey();
byte[] encodedKey = key.getEncoded();
String expectedCurrentKey = Base64.getEncoder().encodeToString(encodedKey);
assertEquals(expectedCurrentKey, actualCurrentKey);
}

private String testGetCurrentSecretKeyUtil(String output) {
// Extract the current secret key from the output
String[] lines = output.split(System.lineSeparator());
for (String line : lines) {
if (line.startsWith("Current Secret Key: ")) {
return line.substring("Current Secret Key: ".length()).trim();
}
}
return null;
}

private UUID extractSecretKeyId(OmKeyInfo keyInfo) throws IOException {
OmKeyLocationInfo locationInfo =
Expand Down Expand Up @@ -383,6 +424,7 @@ private static void startCluster()
MiniOzoneCluster.Builder builder = MiniOzoneCluster.newHABuilder(conf)
.setClusterId(clusterId)
.setSCMServiceId("TestSecretKey")
.setOMServiceId("om-service-test")
.setScmId(scmId)
.setNumDatanodes(3)
.setNumOfStorageContainerManagers(3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ enum Type {
TransferLeadership = 117;
SnapshotPurge = 118;
RecoverLease = 119;
GetCurrentSecretKey = 120;
}

message OMRequest {
Expand Down Expand Up @@ -252,6 +253,7 @@ message OMRequest {
optional SnapshotPurgeRequest SnapshotPurgeRequest = 118;

optional RecoverLeaseRequest RecoverLeaseRequest = 119;
optional GetCurrentSecretKeyRequest GetCurrentSecretKeyRequest = 120;
}

message OMResponse {
Expand Down Expand Up @@ -362,6 +364,7 @@ message OMResponse {
optional hdds.TransferLeadershipResponseProto TransferOmLeadershipResponse = 117;
optional SnapshotPurgeResponse SnapshotPurgeResponse = 118;
optional RecoverLeaseResponse RecoverLeaseResponse = 119;
optional GetCurrentSecretKeyResponse GetCurrentSecretKeyResponse = 120;
}

enum Status {
Expand Down Expand Up @@ -589,6 +592,22 @@ message SetVolumePropertyResponse {
optional bool response = 1;
}

message GetCurrentSecretKeyRequest {

}

message ManagedSecretKey {
required hdds.UUID id = 1;
required uint64 creationTime = 2;
required uint64 expiryTime = 3;
required string algorithm = 4;
required bytes encoded = 5;
}

message GetCurrentSecretKeyResponse {
required ManagedSecretKey secretKey = 1;
}

/**
* Checks if the user has specified permissions for the volume
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import org.apache.hadoop.hdds.ratis.RatisHelper;
import org.apache.hadoop.hdds.scm.ScmInfo;
import org.apache.hadoop.hdds.scm.client.HddsClientUtils;
import org.apache.hadoop.hdds.security.symmetric.ManagedSecretKey;
import org.apache.hadoop.hdds.server.OzoneAdmins;
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.hdds.utils.db.Table.KeyValue;
Expand Down Expand Up @@ -1064,6 +1065,10 @@ private void stopSecretManager() {
}
}

public ManagedSecretKey getCurrentSecretKey() {
return secretKeyClient.getCurrentSecretKey();
}

@VisibleForTesting
public void startSecretManager() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.apache.hadoop.hdds.protocol.proto.HddsProtos.TransferLeadershipResponseProto;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos.UpgradeFinalizationStatus;
import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.security.symmetric.ManagedSecretKey;
import org.apache.hadoop.hdds.utils.db.SequenceNumberNotFoundException;
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.om.OzoneManager;
Expand Down Expand Up @@ -78,6 +79,8 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetFileStatusResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetKeyInfoRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetKeyInfoResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetCurrentSecretKeyRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetCurrentSecretKeyResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.InfoBucketRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.InfoBucketResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.InfoVolumeRequest;
Expand Down Expand Up @@ -310,6 +313,12 @@ public OMResponse handleReadRequest(OMRequest request) {
responseBuilder.setTransferOmLeadershipResponse(transferLeadership(
request.getTransferOmLeadershipRequest()));
break;
case GetCurrentSecretKey:
GetCurrentSecretKeyResponse getCurrentSecretKeyResponse =
getCurrentSecretKey(request.getGetCurrentSecretKeyRequest());
responseBuilder.setGetCurrentSecretKeyResponse(
getCurrentSecretKeyResponse);
break;
default:
responseBuilder.setSuccess(false);
responseBuilder.setMessage("Unrecognized Command Type: " + cmdType);
Expand Down Expand Up @@ -944,6 +953,16 @@ private RangerBGSyncResponse triggerRangerBGSync(
return RangerBGSyncResponse.newBuilder().setRunSuccess(res).build();
}

private GetCurrentSecretKeyResponse getCurrentSecretKey(
GetCurrentSecretKeyRequest request) {
ManagedSecretKey managedSecretKey = impl.getCurrentSecretKey();
GetCurrentSecretKeyResponse response =
GetCurrentSecretKeyResponse.newBuilder()
.setSecretKey(ManagedSecretKey.toProto(managedSecretKey))
.build();
return response;
}

@RequestFeatureValidator(
conditions = ValidationCondition.OLDER_CLIENT_REQUESTS,
processingPhase = RequestProcessingPhase.POST_PROCESS,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.admin.om;

import java.util.Base64;
import java.util.concurrent.Callable;
import org.apache.hadoop.hdds.cli.HddsVersionProvider;
import org.apache.hadoop.hdds.security.symmetric.ManagedSecretKey;
import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
import picocli.CommandLine;

import javax.crypto.SecretKey;

/**
* Handler of ozone admin om fetch-key command.
*/
@CommandLine.Command(
name = "fetch-key",
description = "CLI command to fetch the latest key",
mixinStandardHelpOptions = true,
versionProvider = HddsVersionProvider.class
)
public class FetchKeySubCommand implements Callable<Void> {
@CommandLine.ParentCommand
private OMAdmin parent;

@CommandLine.Option(
names = {"-id", "--service-id"},
description = "Ozone Manager Service ID",
required = true
)
private String omServiceId;

@Override
public Void call() throws Exception {
try (OzoneManagerProtocol client = parent.createOmClient(omServiceId)) {
ManagedSecretKey managedSecretKey = client.getCurrentSecretKey();
SecretKey key = managedSecretKey.getSecretKey();
byte[] encodedKey = key.getEncoded();
String keyString = Base64.getEncoder().encodeToString(encodedKey);
System.out.println("Current Secret Key: " + keyString);
}
return null;
}
}

Loading