Skip to content

Commit

Permalink
Support multiple values from same secret name in AWS bulk mode (#707)
Browse files Browse the repository at this point in the history
* Updating signers version to 2.2.5 that provides support for using multiple values from same secret in AWS
* Changelog
* AT for AWS multi-values
  • Loading branch information
usmansaleem authored Feb 8, 2023
1 parent 6c11036 commit 73f71dd
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 1 deletion.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 23.2.0
### Features Added
- AWS Secrets Manager bulkload mode can now load multiple keys from same secret where keys are separated by line terminating
character (such as `\n`). [#706](https://github.com/ConsenSys/web3signer/issues/706)


## 23.1.0
### Features Added
- Multiple Signing Key configurations can be specified in single YAML file using triple-dash `---` separator.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright 2023 ConsenSys AG.
*
* Licensed 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 tech.pegasys.web3signer.tests.bulkloading;

import static org.hamcrest.Matchers.containsInAnyOrder;

import tech.pegasys.teku.bls.BLSKeyPair;
import tech.pegasys.teku.bls.BLSPublicKey;
import tech.pegasys.web3signer.AwsSecretsManagerUtil;
import tech.pegasys.web3signer.BLSTestUtil;
import tech.pegasys.web3signer.dsl.signer.SignerConfigurationBuilder;
import tech.pegasys.web3signer.signing.KeyType;
import tech.pegasys.web3signer.signing.config.AwsAuthenticationMode;
import tech.pegasys.web3signer.signing.config.AwsSecretsManagerParameters;
import tech.pegasys.web3signer.signing.config.AwsSecretsManagerParametersBuilder;
import tech.pegasys.web3signer.tests.AcceptanceTestBase;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import io.restassured.http.ContentType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

@EnabledIfEnvironmentVariable(
named = "RW_AWS_ACCESS_KEY_ID",
matches = ".*",
disabledReason = "RW_AWS_ACCESS_KEY_ID env variable is required")
@EnabledIfEnvironmentVariable(
named = "RW_AWS_SECRET_ACCESS_KEY",
matches = ".*",
disabledReason = "RW_AWS_SECRET_ACCESS_KEY env variable is required")
@EnabledIfEnvironmentVariable(
named = "AWS_ACCESS_KEY_ID",
matches = ".*",
disabledReason = "AWS_ACCESS_KEY_ID env variable is required")
@EnabledIfEnvironmentVariable(
named = "AWS_SECRET_ACCESS_KEY",
matches = ".*",
disabledReason = "AWS_SECRET_ACCESS_KEY env variable is required")
@EnabledIfEnvironmentVariable(
named = "AWS_REGION",
matches = ".*",
disabledReason = "AWS_REGION env variable is required")
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // same instance is shared across test methods
public class AwsSecretsManagerMultiValueAcceptanceTest extends AcceptanceTestBase {
private static final Logger LOG = LogManager.getLogger();
private static final String RW_AWS_ACCESS_KEY_ID = System.getenv("RW_AWS_ACCESS_KEY_ID");
private static final String RW_AWS_SECRET_ACCESS_KEY = System.getenv("RW_AWS_SECRET_ACCESS_KEY");
private static final String RO_AWS_ACCESS_KEY_ID = System.getenv("AWS_ACCESS_KEY_ID");
private static final String RO_AWS_SECRET_ACCESS_KEY = System.getenv("AWS_SECRET_ACCESS_KEY");
private static final String AWS_REGION =
Optional.ofNullable(System.getenv("AWS_REGION")).orElse("us-east-2");
private AwsSecretsManagerUtil awsSecretsManagerUtil;
private final List<BLSKeyPair> blsKeyPairList = new ArrayList<>(400);

@BeforeAll
void setupAwsResources() {
for (int i = 0; i < 400; i++) {
blsKeyPairList.add(BLSTestUtil.randomKeyPair(i));
}

awsSecretsManagerUtil =
new AwsSecretsManagerUtil(AWS_REGION, RW_AWS_ACCESS_KEY_ID, RW_AWS_SECRET_ACCESS_KEY);

for (int i = 0; i < 4; i++) {
String multilinePrivKeys =
blsKeyPairList.subList(i * 100, (i + 1) * 100).stream()
.map(bls -> bls.getSecretKey().toBytes().toString())
.collect(Collectors.joining(System.lineSeparator()));
awsSecretsManagerUtil.createSecret(
"multi" + i, multilinePrivKeys, Map.of("multivalue", "true"));
}
}

@ParameterizedTest(name = "{index} -> use config file: {0}")
@ValueSource(booleans = {true, false})
void secretsAreLoadedFromAWSSecretsManagerAndReportedByPublicApi(final boolean useConfigFile) {
final AwsSecretsManagerParameters awsSecretsManagerParameters =
AwsSecretsManagerParametersBuilder.anAwsSecretsManagerParameters()
.withAuthenticationMode(AwsAuthenticationMode.SPECIFIED)
.withRegion(AWS_REGION)
.withAccessKeyId(RO_AWS_ACCESS_KEY_ID)
.withSecretAccessKey(RO_AWS_SECRET_ACCESS_KEY)
.withPrefixesFilter(List.of(awsSecretsManagerUtil.getSecretsManagerPrefix()))
.withTagNamesFilter(List.of("multivalue"))
.build();

final SignerConfigurationBuilder configBuilder =
new SignerConfigurationBuilder()
.withUseConfigFile(useConfigFile)
.withMode("eth2")
.withAwsSecretsManagerParameters(awsSecretsManagerParameters);

startSigner(configBuilder.build());

final List<String> publicKeys =
blsKeyPairList.stream()
.map(BLSKeyPair::getPublicKey)
.map(BLSPublicKey::toHexString)
.collect(Collectors.toList());

signer
.callApiPublicKeys(KeyType.BLS)
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("", containsInAnyOrder(publicKeys.toArray(String[]::new)));
}

@AfterAll
void cleanUpAwsResources() {
if (awsSecretsManagerUtil != null) {
for (int i = 0; i < 4; i++) {
final String secretName = "multi" + i;
try {
awsSecretsManagerUtil.deleteSecret(secretName);
} catch (final RuntimeException e) {
LOG.warn(
"Unexpected error while deleting key {}{}: {}",
awsSecretsManagerUtil.getSecretsManagerPrefix(),
secretName,
e.getMessage());
}
}
awsSecretsManagerUtil.close();
}
}
}
1 change: 1 addition & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies {
implementation 'org.jdbi:jdbi3-core'
implementation 'tech.pegasys.signers.internal:bls-keystore'
implementation 'tech.pegasys.signers.internal:keystorage-aws'
implementation 'tech.pegasys.signers.internal:keystorage-common'
implementation 'tech.pegasys.signers.internal:keystorage-azure'
implementation 'tech.pegasys.signers.internal:keystorage-hashicorp'
implementation 'tech.pegasys.signers.internal:signing-secp256k1-api'
Expand Down
3 changes: 2 additions & 1 deletion gradle/versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@ dependencyManagement {

dependency 'tech.pegasys:jblst:0.3.8'

dependencySet(group: 'tech.pegasys.signers.internal', version: '2.2.4') {
dependencySet(group: 'tech.pegasys.signers.internal', version: '2.2.5') {
entry 'bls-keystore'
entry 'keystorage-hashicorp'
entry 'keystorage-azure'
entry 'keystorage-aws'
entry 'keystorage-common'
entry 'keystorage-interlock'
entry 'keystorage-yubihsm2'
entry 'signing-secp256k1-api'
Expand Down
1 change: 1 addition & 0 deletions signing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {
implementation 'org.web3j:core'
implementation 'tech.pegasys.signers.internal:bls-keystore'
implementation 'tech.pegasys.signers.internal:keystorage-aws'
implementation 'tech.pegasys.signers.internal:keystorage-common'
implementation 'tech.pegasys.signers.internal:keystorage-azure'
implementation 'tech.pegasys.signers.internal:keystorage-hashicorp'
implementation 'tech.pegasys.signers.internal:keystorage-interlock'
Expand Down

0 comments on commit 73f71dd

Please sign in to comment.