Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: AWS KMS for delegation #1435

Merged
merged 39 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
44ff4ef
feat: first commit
freemanzMrojo Oct 21, 2024
706c68e
feat: second commit
freemanzMrojo Oct 21, 2024
d45caaf
feat: second commit
freemanzMrojo Oct 21, 2024
6940798
feat: second commit
freemanzMrojo Oct 21, 2024
64b375f
feat: second commit
freemanzMrojo Oct 21, 2024
fbf7a6b
feat: second commit
freemanzMrojo Oct 21, 2024
b2a10d9
feat: more changes
freemanzMrojo Oct 22, 2024
987f0e4
feat: more changes
freemanzMrojo Oct 22, 2024
9c1864b
feat: more changes
freemanzMrojo Oct 22, 2024
e981f81
feat: more changes
freemanzMrojo Oct 22, 2024
e445381
feat: more changes
freemanzMrojo Oct 22, 2024
c0dd185
feat: more changes
freemanzMrojo Oct 22, 2024
e6fe929
feat: more changes
freemanzMrojo Oct 22, 2024
465a9c6
feat: more changes
freemanzMrojo Oct 22, 2024
929df4e
feat: scaffolding for testing
freemanzMrojo Oct 22, 2024
fd29372
feat: scaffolding for testing
freemanzMrojo Oct 22, 2024
efa6946
feat: scaffolding for testing
freemanzMrojo Oct 22, 2024
2393dd6
feat: added gitleaks exceptions
freemanzMrojo Oct 22, 2024
6cfeda5
Merge branch 'main' of https://github.com/vechain/vechain-sdk-js into…
freemanzMrojo Oct 22, 2024
129554f
feat: some more changes
freemanzMrojo Oct 22, 2024
e033966
feat: some more changes
freemanzMrojo Oct 22, 2024
c727a54
feat: solo tests not working
freemanzMrojo Oct 22, 2024
0334d16
feat: first tests working
freemanzMrojo Oct 22, 2024
4a2d74a
feat: more changes
freemanzMrojo Oct 22, 2024
8dcce93
feat: still delegation url to test
freemanzMrojo Oct 22, 2024
ad36cf2
feat: still delegation url to test
freemanzMrojo Oct 22, 2024
e348ea5
feat: still delegation url to test
freemanzMrojo Oct 22, 2024
0153438
feat: still delegation url to test
freemanzMrojo Oct 22, 2024
969cf55
feat: still delegation url to test
freemanzMrojo Oct 22, 2024
0b3e99b
feat: fixed delegated hash
freemanzMrojo Oct 23, 2024
4f5b430
feat: more tests
freemanzMrojo Oct 23, 2024
7ff51f6
feat: added testnet tests
freemanzMrojo Oct 23, 2024
10b98dd
Merge branch 'main' of https://github.com/vechain/vechain-sdk-js into…
freemanzMrojo Oct 23, 2024
cddbed5
feat: modified readme
freemanzMrojo Oct 23, 2024
6d06668
feat: modified readme
freemanzMrojo Oct 23, 2024
f6fde33
feat: modified readme
freemanzMrojo Oct 24, 2024
d8d82f9
Merge branch 'main' into feat/1413-aws-kms-delegator
freemanzMrojo Oct 24, 2024
1ef2d71
feat: modified readme
freemanzMrojo Oct 24, 2024
a35024c
Merge branch 'main' into feat/1413-aws-kms-delegator
fabiorigam Oct 28, 2024
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
3 changes: 2 additions & 1 deletion .gitleaksignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
# Exceptions for gitleaks to be placed here
465a9c6b265ec49015fd7ff641506905cb93811c:packages/aws-kms-adapter/tests/test-aws-credentials.json:generic-api-key:3
465a9c6b265ec49015fd7ff641506905cb93811c:packages/aws-kms-adapter/tests/test-aws-credentials.json:generic-api-key:12
2 changes: 1 addition & 1 deletion docker-compose.localstack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ services:
- CMD
- bash
- -c
- $$(awslocal kms list-keys | jq '.Keys | length | . == 1') || exit 1; # There is 1 key at the moment
- $$(awslocal kms list-keys | jq '.Keys | length | . == 2') || exit 1; # There are 2 keys at the moment
interval: 5s
timeout: 20s
start_period: 2s
Expand Down
14 changes: 10 additions & 4 deletions localstack/init/kms.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#!/bin/bash

CUSTOM_KEY_MATERIAL="f5KQzETF/SuV/iHWrW/l+pwXfhzW87TJapexPgnqoVg="
CUSTOM_ID="bffb20d8-35ca-4408-9d54-f775b929b38d"
CUSTOM_ORIGIN_KEY_MATERIAL="f5KQzETF/SuV/iHWrW/l+pwXfhzW87TJapexPgnqoVg="
CUSTOM_ORIGIN_ID="bffb20d8-35ca-4408-9d54-f775b929b38d"
CUSTOM_DELEGATOR_ID="3e47cac8-de37-4f50-b591-57f525c1b05c"

# The command succeeds but the key is not created with the custom key material (should be fixed once this is clarified: https://github.com/localstack/localstack/issues/11678)
# awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_key_material_\",\"TagValue\":\"$CUSTOM_KEY_MATERIAL\"},{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ID\"}]"
awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ID\"}]"
# awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_key_material_\",\"TagValue\":\"$CUSTOM_ORIGIN_KEY_MATERIAL\"},{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ORIGIN_ID\"}]"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this command commented?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is because of this issue localstack/localstack#11678 . Basically nowadays we cannot import a custom key into localstack, but once the issue is fixed we should be able to do it with this commented-out line.

The command itself does not break but it does not import anything.


# Origin key
awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_ORIGIN_ID\"}]"

# Delegator key
awslocal kms create-key --key-usage SIGN_VERIFY --key-spec ECC_SECG_P256K1 --tags "[{\"TagKey\":\"_custom_id_\",\"TagValue\":\"$CUSTOM_DELEGATOR_ID\"}]"
212 changes: 144 additions & 68 deletions packages/aws-kms-adapter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The AWS KMS Adapter for VeChain SDK provides a secure way to sign transactions u
- **Secure Key Management**: Use AWS KMS to securely manage and protect your private keys.
- **Transaction Signing**: Sign VeChain transactions using keys stored in AWS KMS.
- **Integration with VeChain SDK**: Seamlessly integrate with the VeChain SDK for blockchain interactions.
- **[WIP] Sign and send transactions using a delegator key**: You can specify the key ID of a delegator key to leverage this VeChain feature for signing and sending transactions.
- **Sign and send transactions using a delegator key**: You can specify the key ID of a delegator key to leverage this VeChain feature for signing and sending transactions.

## Installation

Expand All @@ -19,68 +19,61 @@ yarn add @vechain/sdk-aws-kms-adapter

## Test

To run all the tests, including the ones relying on a local instance of Thor Solo + LocalStack, please run:
To run all the tests, including the ones relying on a local instance of Thor Solo + LocalStack and Testnet, please run:

```bash
yarn test:solo
yarn test:integration
```

## Usage

To integrate this into your code, depending on how you plan to manage your AWS credentials, you can choose one of the following examples.

Within this repo, you can create a credentials file called `aws-credentials.json` with your custom credentials under the `tests` folder in case you want to give it a try before integrating with your project. A valid format would be as follows:
Within this repo, you can create a credentials file called `aws-credentials.json` with your custom credentials under the `tests` folder in case you want to give it a try before integrating with your project. A valid format would be as follows (it is an array in case you want to include a delegator key, assumed to be the second one):

```json
{
// AWS KMS keyId (mandatory)
"keyId": "00000000-0000-0000-0000-000000000000",
// AWS region (mandatory)
"region": "eu-west-1",
// AWS credentials (optional)
"credentials": {
// AWS access key id (mandatory if credentials)
"accessKeyId": "test",
// AWS secret access key (mandatory if credentials)
"secretAccessKey": "test",
// AWS session token if SSO is configured (optional)
"sessionToken": "test"
},
// AWS endpoint (optional, to be used locally along with LocalStack)
"endpoint": "http://localhost:4599"
}
[
{
// AWS KMS keyId (mandatory)
"keyId": "00000000-0000-0000-0000-000000000000",
// AWS region (mandatory)
"region": "eu-west-1",
// AWS credentials (optional)
"credentials": {
// AWS access key id (mandatory if credentials)
"accessKeyId": "test",
// AWS secret access key (mandatory if credentials)
"secretAccessKey": "test",
// AWS session token if SSO is configured (optional)
"sessionToken": "test"
},
// AWS endpoint (optional, to be used locally along with LocalStack)
"endpoint": "http://localhost:4599"
}
]
```

### IAM roles

This is the preferred way. If you integrate this library in an app deployed in AWS following with IAM roles, you can just do as follows:

```ts
import { KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import {
THOR_SOLO_URL,
ThorClient
} from '@vechain/sdk-network';
...

interface AwsClientParameters {
keyId: string;
region: string;
credentials?: {
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
};
endpoint?: string;
}

const awsClientParameters: KMSClientParameters = {
keyId: 'keyId',
region: 'region'
};
...

const thorClient = ThorClient.fromUrl(THOR_SOLO_URL);
const provider = new KMSVeChainProvider(
thorClient,
awsClientParameters.keyId,
awsClientParameters.region
awsClientParameters
);
const signer = new KMSVeChainSigner(provider);
// Signing typed data as per EIP712
Expand All @@ -96,33 +89,27 @@ import {
This way you can connect to your AWS account by using `accessKeyId`, `secretAccessKey` and `sessionToken` if SSO is enabled.

```ts
import { KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import {
signerUtils,
THOR_SOLO_URL,
ThorClient
} from '@vechain/sdk-network';
...

interface AwsClientParameters {
keyId: string;
region: string;
credentials?: {
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
};
endpoint?: string;
}

const awsClientParameters: KMSClientParameters = {
keyId: 'keyId',
region: 'region',
credentials: {
accessKeyId: 'accessKeyId',
secretAccessKey: 'secretAccessKey'
}
};
...

const thorClient = ThorClient.fromUrl(THOR_SOLO_URL);
const provider = new KMSVeChainProvider(
thorClient,
awsClientParameters.keyId,
awsClientParameters.region
awsClientParameters.credentials
awsClientParameters
);
const signer = new KMSVeChainSigner(provider);
// Signing and sending a transaction
Expand All @@ -139,34 +126,123 @@ import {
You can also leverage LocalStack so you can try the library locally. Sample values are included in the file `tests/test-aws-credentials.json`.

```ts
import { KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import {
THOR_SOLO_URL,
ThorClient
} from '@vechain/sdk-network';
...

interface AwsClientParameters {
keyId: string;
region: string;
credentials?: {
accessKeyId: string;
secretAccessKey: string;
sessionToken?: string;
};
endpoint?: string;
}

const awsClientParameters: KMSClientParameters = {
keyId: 'keyId',
region: 'region',
credentials: {
accessKeyId: 'accessKeyId',
secretAccessKey: 'secretAccessKey'
},
endpoint: 'localstackEndpoint'
};
...

const thorClient = ThorClient.fromUrl(THOR_SOLO_URL);
const provider = new KMSVeChainProvider(
thorClient,
awsClientParameters.keyId,
awsClientParameters.region
awsClientParameters.credentials
awsClientParameters
);
const signer = new KMSVeChainSigner(provider);
// Returns the address related to the KMS key
const address = await signer.getAddress();
```

### Delegation (provider)

You can also use delegation to sign your transactions. In this example the source of the delegation is a delegator which key is in KMS so requires a `KMSVeChainProvider`.

```ts
import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import {
THOR_SOLO_URL,
ThorClient
} from '@vechain/sdk-network';
...
const awsClientParameters: KMSClientParameters = {
keyId: 'keyId',
region: 'region',
credentials: {
accessKeyId: 'accessKeyId',
secretAccessKey: 'secretAccessKey'
},
endpoint: 'localstackEndpoint'
};

const delegatorAwsClientParameters: KMSClientParameters = {
// Same format as awsClientParameters, changing values so we can connect
// to something different to LocalStack if we want (see examples above)
}
...

const thorClient = ThorClient.fromUrl(THOR_SOLO_URL);
const provider = new KMSVeChainProvider(
thorClient,
awsClientParameters
);

// Signer with delegator enabled
const delegatorProvider = new KMSVeChainProvider(
thorClient,
delegatorAwsClientParameters
);
const signerWithDelegator = new KMSVeChainSigner(
provider,
{
provider: delegatorProvider
}
);

// Returns the address related to the origin KMS key
const address = await signerWithDelegator.getAddress();
// Returns the address related to the delegator KMS key
const address = await signerWithDelegator.getAddress(true);
```

### Delegation (url)

You can also use delegation to sign your transactions. In this example the source of the delegation is a URL that returns the signature (for instance, `https://sponsor-testnet.vechain.energy/by/705`, more details on how to get yours [here](https://learn.vechain.energy/vechain.energy/FeeDelegation/Setup/)).

```ts
import { type KMSClientParameters, KMSVeChainProvider, KMSVeChainSigner } from '@vechain/sdk-aws-kms-adapter';
import {
THOR_SOLO_URL,
ThorClient
} from '@vechain/sdk-network';
...
const awsClientParameters: KMSClientParameters = {
keyId: 'keyId',
region: 'region',
credentials: {
accessKeyId: 'accessKeyId',
secretAccessKey: 'secretAccessKey'
},
endpoint: 'localstackEndpoint'
};
...

const thorClient = ThorClient.fromUrl(THOR_SOLO_URL);

// Signer with delegator enabled
const provider = new KMSVeChainProvider(
thorClient,
awsClientParameters
);
const signerWithDelegator = new KMSVeChainSigner(
provider,
{
url: 'https://sponsor-testnet.vechain.energy/by/705'
}
);

// Returns the address related to the origin KMS key
const address = await signerWithDelegator.getAddress();

// See /tests folder for more examples. This time we wont get the address
// of the delegator since there is no provider
```
2 changes: 1 addition & 1 deletion packages/aws-kms-adapter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"stop-thor-solo": "echo 'Stopping thor solo node ...' && docker compose -f ../../docker-compose.thor.yml -f ../../docker-compose.localstack.yml --profile thor-solo down && echo 'Thor solo node and localstack stopped ...'",
"test": "docker compose -f ../../docker-compose.localstack.yml up -d && sleep 10 && yarn test:all; ret=$?; docker compose -f ../../docker-compose.localstack.yml down; exit $ret",
"test:all": "rm -rf ./coverage && jest --coverage --coverageDirectory=coverage --group=integration --group=unit",
"test:solo": "(yarn start-thor-solo && yarn test:all && yarn stop-thor-solo) || yarn stop-thor-solo",
"test:integration": "(yarn start-thor-solo && yarn test:all && yarn stop-thor-solo) || yarn stop-thor-solo",
"test:unit": "rm -rf ./coverageUnit && UNIT=true jest --coverage --coverageDirectory=coverageUnit --group=unit"
},
"dependencies": {
Expand Down
Loading