You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by is...@apache.org on 2020/11/05 17:08:55 UTC
[airavata-custos] branch develop updated: Adding shamir secret
sharing
This is an automated email from the ASF dual-hosted git repository.
isjarana pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git
The following commit(s) were added to refs/heads/develop by this push:
new aedfab1 Adding shamir secret sharing
new a10ce8a Merge pull request #121 from isururanawaka/vault_ssl
aedfab1 is described below
commit aedfab1cdd2bff487c67f6c7bb0aa8a795961747
Author: Isuru Ranawaka <ir...@gmail.com>
AuthorDate: Wed Nov 4 14:53:41 2020 -0500
Adding shamir secret sharing
---
.../client/ResourceSecretManagementClient.java | 27 +++++-
.../src/main/proto/ResourceSecretService.proto | 16 ++++
custos-integration-core/pom.xml | 4 +
.../core/exceptions/InValidParameterException.java | 27 ++++++
.../core/utils/ShamirSecretHandler.java | 72 ++++++++++++++++
.../service/ResourceSecretManagementService.java | 98 +++++++++++++++++++++-
pom.xml | 9 ++
7 files changed, 247 insertions(+), 6 deletions(-)
diff --git a/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java b/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java
index a43639a..359356b 100644
--- a/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java
+++ b/custos-client-sdks/custos-java-clients/resource-secret-management-client/src/main/java/org/apache/custos/resource/secret/management/client/ResourceSecretManagementClient.java
@@ -19,6 +19,7 @@
package org.apache.custos.resource.secret.management.client;
+import com.google.protobuf.ByteString;
import com.google.protobuf.Struct;
import io.grpc.ManagedChannel;
import io.grpc.netty.GrpcSslContexts;
@@ -26,6 +27,7 @@ import io.grpc.netty.NettyChannelBuilder;
import io.grpc.stub.MetadataUtils;
import org.apache.custos.clients.core.ClientUtils;
import org.apache.custos.identity.service.GetJWKSRequest;
+import org.apache.custos.integration.core.utils.ShamirSecretHandler;
import org.apache.custos.resource.secret.management.service.ResourceSecretManagementServiceGrpc;
import org.apache.custos.resource.secret.service.*;
@@ -41,6 +43,9 @@ public class ResourceSecretManagementClient {
private ResourceSecretManagementServiceGrpc.ResourceSecretManagementServiceBlockingStub blockingStub;
+ private int defaultNumOfShares = 5;
+ private int defaultThreshold = 3;
+
public ResourceSecretManagementClient(String serviceHost, int servicePort, String clientId,
String clientSecret) throws IOException {
@@ -185,15 +190,29 @@ public class ResourceSecretManagementClient {
* @param token
* @return SSHCredential
*/
- public SSHCredential getSSHCredential(String clientId, String token) {
+ public SSHCredential getSSHCredential(String clientId, String token, boolean useShamirSecret) {
+
GetResourceCredentialByTokenRequest tokenRequest = GetResourceCredentialByTokenRequest
.newBuilder()
.setClientId(clientId)
.setToken(token)
.build();
-
-
- return blockingStub.getSSHCredential(tokenRequest);
+ if (useShamirSecret) {
+ tokenRequest = tokenRequest.toBuilder()
+ .setUseShamirsSecretSharingWithEncryption(true)
+ .setNumOfShares(defaultNumOfShares)
+ .setThreshold(defaultThreshold)
+ .build();
+ }
+
+ SSHCredential sshCredential = blockingStub.getSSHCredential(tokenRequest);
+
+ if (useShamirSecret) {
+ List<ByteString> shares = sshCredential.getPrivateKeySharesList();
+ String secret = ShamirSecretHandler.generateSecret(shares, defaultNumOfShares, defaultThreshold);
+ sshCredential = sshCredential.toBuilder().setPrivateKey(secret).build();
+ }
+ return sshCredential;
}
diff --git a/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto b/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto
index 0ca5a8d..b247990 100644
--- a/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto
+++ b/custos-core-services/resource-secret-core-service/src/main/proto/ResourceSecretService.proto
@@ -82,11 +82,19 @@ message CertificateCredential {
string private_key = 5;
int64 life_time = 6;
string not_before = 7;
+ bool useShamirsSecretSharingWithEncryption = 8;
+ int32 numOfShares = 9;
+ int32 threshold = 10;
+ repeated bytes private_key_shares = 11;
}
message PasswordCredential {
SecretMetadata metadata = 1;
string password = 3;
+ bool useShamirsSecretSharingWithEncryption = 4;
+ int32 numOfShares = 5;
+ int32 threshold = 6;
+ repeated bytes secret_shares = 7;
}
message SSHCredential {
@@ -94,6 +102,10 @@ message SSHCredential {
string passphrase = 3;
string public_key = 4;
string private_key = 5;
+ bool useShamirsSecretSharingWithEncryption = 6;
+ int32 numOfShares = 7;
+ int32 threshold = 8;
+ repeated bytes private_key_shares = 9;
}
@@ -102,6 +114,10 @@ message GetResourceCredentialByTokenRequest {
string token = 2;
string performed_by = 3;
string client_id = 4;
+ bool useShamirsSecretSharingWithEncryption = 5;
+ int32 numOfShares = 6;
+ int32 threshold = 7;
+
}
message GetResourceCredentialSummariesRequest {
diff --git a/custos-integration-core/pom.xml b/custos-integration-core/pom.xml
index a7f394c..7fb086d 100644
--- a/custos-integration-core/pom.xml
+++ b/custos-integration-core/pom.xml
@@ -56,6 +56,10 @@
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.codahale</groupId>
+ <artifactId>shamir</artifactId>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/custos-integration-core/src/main/java/org/apache/custos/integration/core/exceptions/InValidParameterException.java b/custos-integration-core/src/main/java/org/apache/custos/integration/core/exceptions/InValidParameterException.java
new file mode 100644
index 0000000..bfd8721
--- /dev/null
+++ b/custos-integration-core/src/main/java/org/apache/custos/integration/core/exceptions/InValidParameterException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.custos.integration.core.exceptions;
+
+public class InValidParameterException extends RuntimeException {
+
+ public InValidParameterException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/custos-integration-core/src/main/java/org/apache/custos/integration/core/utils/ShamirSecretHandler.java b/custos-integration-core/src/main/java/org/apache/custos/integration/core/utils/ShamirSecretHandler.java
new file mode 100644
index 0000000..3ad2374
--- /dev/null
+++ b/custos-integration-core/src/main/java/org/apache/custos/integration/core/utils/ShamirSecretHandler.java
@@ -0,0 +1,72 @@
+/*
+ * 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.custos.integration.core.utils;
+
+import com.codahale.shamir.Scheme;
+import com.google.protobuf.ByteString;
+import org.apache.custos.integration.core.exceptions.InValidParameterException;
+
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ShamirSecretHandler {
+
+ public static Map<Integer, byte[]> splitSecret(String secret, int numOfsplits, int threshold) {
+
+ if (numOfsplits >= threshold) {
+ Scheme scheme = new Scheme(new SecureRandom(), numOfsplits, threshold);
+ byte[] secretArray = secret.getBytes(StandardCharsets.UTF_8);
+ final Map<Integer, byte[]> parts = scheme.split(secretArray);
+ final Map<Integer, byte[]> selectedParts = new HashMap<>();
+ int count = 1;
+ for (Integer integer : parts.keySet()){
+ selectedParts.put(integer, parts.get(integer));
+ count ++;
+ if (count == threshold){
+ break;
+ }
+ }
+ return selectedParts;
+ } else {
+ throw new
+ InValidParameterException(
+ "Cannot split message number of splits should be greater than threshold", null);
+ }
+ }
+
+
+ public static String generateSecret(List<ByteString> byteStringList, int numOfsplits, int threshold) {
+ Scheme scheme = new Scheme(new SecureRandom(), numOfsplits, threshold);
+ Map<Integer, byte[]> selectedSplits = new HashMap<>();
+ AtomicInteger count = new AtomicInteger();
+ byteStringList.forEach(str-> {
+ selectedSplits.put(count.get(), str.toByteArray());
+ count.getAndIncrement();
+ });
+
+ final byte[] recovered = scheme.join(selectedSplits);
+ return new String(recovered, StandardCharsets.UTF_8);
+ }
+
+}
diff --git a/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java b/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java
index ee48a50..8bfd682 100644
--- a/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java
+++ b/custos-integration-services/resource-secret-management-service-parent/resource-secret-management-service/src/main/java/org/apache/custos/resource/secret/management/service/ResourceSecretManagementService.java
@@ -19,6 +19,7 @@
package org.apache.custos.resource.secret.management.service;
+import com.google.protobuf.ByteString;
import com.google.protobuf.Struct;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
@@ -27,6 +28,7 @@ import org.apache.custos.cluster.management.service.GetServerCertificateRequest;
import org.apache.custos.cluster.management.service.GetServerCertificateResponse;
import org.apache.custos.identity.client.IdentityClient;
import org.apache.custos.identity.service.GetJWKSRequest;
+import org.apache.custos.integration.core.utils.ShamirSecretHandler;
import org.apache.custos.resource.secret.client.ResourceSecretClient;
import org.apache.custos.resource.secret.management.service.ResourceSecretManagementServiceGrpc.ResourceSecretManagementServiceImplBase;
import org.apache.custos.resource.secret.service.*;
@@ -35,6 +37,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.apache.custos.integration.core.utils.ShamirSecretHandler.splitSecret;
+
@GRpcService
public class ResourceSecretManagementService extends ResourceSecretManagementServiceImplBase {
@@ -128,6 +137,16 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
LOGGER.debug("Request received to add SSHCredential ");
try {
+ if (request.getUseShamirsSecretSharingWithEncryption()){
+ List<ByteString> byteStringList = request.getPrivateKeySharesList();
+ if (byteStringList != null && byteStringList.size()>0){
+
+ String secret = ShamirSecretHandler.
+ generateSecret(byteStringList, request.getNumOfShares(), request.getThreshold());
+ request = request.toBuilder().setPrivateKey(secret).build();
+ }
+ }
+
AddResourceCredentialResponse response = resourceSecretClient.addSSHCredential(request);
responseObserver.onNext(response);
@@ -143,6 +162,15 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
public void addPasswordCredential(PasswordCredential request, StreamObserver<AddResourceCredentialResponse> responseObserver) {
LOGGER.debug("Request received to add PasswordCredential ");
try {
+ if (request.getUseShamirsSecretSharingWithEncryption()){
+ List<ByteString> byteStringList = request.getSecretSharesList();
+ if (byteStringList != null && byteStringList.size()>0){
+
+ String secret = ShamirSecretHandler.
+ generateSecret(byteStringList, request.getNumOfShares(), request.getThreshold());
+ request = request.toBuilder().setPassword(secret).build();
+ }
+ }
AddResourceCredentialResponse response = resourceSecretClient.addPasswordCredential(request);
responseObserver.onNext(response);
@@ -158,7 +186,15 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
public void addCertificateCredential(CertificateCredential request, StreamObserver<AddResourceCredentialResponse> responseObserver) {
LOGGER.debug("Request received to add CertificateCredential ");
try {
-
+ if (request.getUseShamirsSecretSharingWithEncryption()){
+ List<ByteString> byteStringList = request.getPrivateKeySharesList();
+ if (byteStringList != null && byteStringList.size()>0){
+
+ String secret = ShamirSecretHandler.
+ generateSecret(byteStringList, request.getNumOfShares(), request.getThreshold());
+ request = request.toBuilder().setPrivateKey(secret).build();
+ }
+ }
AddResourceCredentialResponse response = resourceSecretClient.addCertificateCredential(request);
responseObserver.onNext(response);
responseObserver.onCompleted();
@@ -175,8 +211,28 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
public void getSSHCredential(GetResourceCredentialByTokenRequest request, StreamObserver<SSHCredential> responseObserver) {
LOGGER.debug("Request received to get SSHCredential ");
try {
-
SSHCredential response = resourceSecretClient.getSSHCredential(request);
+
+ if (request.getUseShamirsSecretSharingWithEncryption()) {
+
+ int numberOfShares = response.getNumOfShares();
+ int threshold = response.getThreshold();
+
+ String privateKey = response.getPrivateKey();
+
+ if (privateKey != null && privateKey.trim().equals("")){
+ Map<Integer, byte[]> shares = ShamirSecretHandler.splitSecret(privateKey, numberOfShares, threshold);
+
+ List<ByteString> byteStringList = shares.values().stream().
+ map(val->ByteString.copyFromUtf8(new String(val))).collect(Collectors.toList());
+
+ response = response.toBuilder().addAllPrivateKeyShares(byteStringList)
+ .setPrivateKey("")
+ .build();
+
+ }
+ }
+
responseObserver.onNext(response);
responseObserver.onCompleted();
} catch (Exception ex) {
@@ -192,6 +248,25 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
try {
PasswordCredential response = resourceSecretClient.getPasswordCredential(request);
+ if (request.getUseShamirsSecretSharingWithEncryption()) {
+
+ int numberOfShares = response.getNumOfShares();
+ int threshold = response.getThreshold();
+
+ String privateKey = response.getPassword();
+
+ if (privateKey != null && privateKey.trim().equals("")){
+ Map<Integer, byte[]> shares = ShamirSecretHandler.splitSecret(privateKey, numberOfShares, threshold);
+
+ List<ByteString> byteStringList = shares.values().stream().
+ map(val->ByteString.copyFromUtf8(new String(val))).collect(Collectors.toList());
+
+ response = response.toBuilder().addAllSecretShares(byteStringList)
+ .setPassword("")
+ .build();
+
+ }
+ }
responseObserver.onNext(response);
responseObserver.onCompleted();
@@ -208,6 +283,25 @@ public class ResourceSecretManagementService extends ResourceSecretManagementSer
try {
CertificateCredential response = resourceSecretClient.getCertificateCredential(request);
+ if (request.getUseShamirsSecretSharingWithEncryption()) {
+
+ int numberOfShares = response.getNumOfShares();
+ int threshold = response.getThreshold();
+
+ String privateKey = response.getPrivateKey();
+
+ if (privateKey != null && privateKey.trim().equals("")){
+ Map<Integer, byte[]> shares = ShamirSecretHandler.splitSecret(privateKey, numberOfShares, threshold);
+
+ List<ByteString> byteStringList = shares.values().stream().
+ map(val->ByteString.copyFromUtf8(new String(val))).collect(Collectors.toList());
+
+ response = response.toBuilder().addAllPrivateKeyShares(byteStringList)
+ .setPrivateKey("")
+ .build();
+
+ }
+ }
responseObserver.onNext(response);
responseObserver.onCompleted();
} catch (Exception ex) {
diff --git a/pom.xml b/pom.xml
index 4b810fd..9c2e088 100644
--- a/pom.xml
+++ b/pom.xml
@@ -242,6 +242,13 @@
<version>${io.commons.version}</version>
</dependency>
+ <!-- Secret handling dependencies -->
+ <dependency>
+ <groupId>com.codahale</groupId>
+ <artifactId>shamir</artifactId>
+ <version>${com.codahale.version}</version>
+ </dependency>
+
</dependencies>
</dependencyManagement>
@@ -527,6 +534,8 @@
<io.commons.version>2.7</io.commons.version>
+ <com.codahale.version>0.7.0</com.codahale.version>
+
</properties>