This pattern represents an example implementation of outbound communication from an AWS Nitro enclave with an Amazon Relational Database Service (Amazon RDS) database.
Deploying the solution with the AWS CDK The AWS CDK is an open-source framework for defining and provisioning cloud application resources. It uses common programming languages such as JavaScript, C#, and Python. The AWS CDK command line interface (CLI) allows you to interact with CDK applications. It provides features like synthesizing AWS CloudFormation templates, confirming the security changes, and deploying applications.
This section shows how to prepare the environment for running CDK and the sample code. For this walkthrough, you must have the following prerequisites:
An AWS account.
- An IAM user with administrator access
- Configured AWS credentials
- Installed Node.js, Python 3, and pip. To install the example application:
When working with Python, it’s good practice to use venv to
create project-specific virtual environments. The use of venv
also reflects AWS CDK standard behavior. You can find
out more in the
workshop Activating the virtualenv.
-
Install the CDK and test the CDK CLI:
npm install -g aws-cdk && cdk --version
-
Download the code from the GitHub repo and switch in the new directory:
git clone --single-branch --branch feature/rds_integration https://github.com/aws-samples/aws-nitro-enclave-blockchain-wallet.git && cd aws-nitro-enclave-blockchain-wallet
-
Install the dependencies using the Python package manager:
pip install -r requirements.txt
-
Specify the AWS region and account for your deployment:
export CDK_DEPLOY_REGION=us-east-1 export CDK_DEPLOY_ACCOUNT=$(aws sts get-caller-identity | jq -r '.Account') export CDK_APPLICATION_TYPE=rds_integration export CDK_PREFIX=dev
You can set the
CDK_PREFIX
variable as per your preference. -
Trigger the
kmstool_enclave_cli
build:./scripts/build_kmstool_enclave_cli.sh
-
Trigger the
viproxy
build:./scripts/build_vsock_proxy.sh
-
Deploy the example code with the CDK CLI:
cdk deploy ${CDK_PREFIX}NitroRdsIntegration
-
The deployment will print out the
devNitroWalletEth.RDSendpoint
parameter. Copy the valuedevnitrowallet[...]us-east-1.rds.amazonaws.com
and insert it at therds_endpoint_address
placeholder variable in thenitro_wallet/nitro_rds_integration_stack.py
file. -
Re-deploy the enclave via:
cdk deploy ${CDK_PREFIX}NitroRdsIntegration
-
Get EC2 instance ids by providing the
devNitroWalletEth.ASGGroupName
from thecdk deploy
output to the script:
./scripts/get_asg_instances.sh <asg group name>
- Pick one of the two instance ids and connect to it via AWS System Manager Session Manager (SSM):
aws ssm start-session --target <EC2 instance id> --region ${CDK_DEPLOY_REGION}
Note: If Session Manager plugin is not installed, you can install it by following this guide.
- Change to
ec2-user
and attach to the enclave debug output:
sudo su ec2-user
nitro-cli console --enclave-name signing_server
You should see a similar output like this:
viproxy: 2024/03/19 13:08:00 viproxy.go:98: Accepted incoming connection from 127.0.0.1:43970.
viproxy: 2024/03/19 13:08:00 viproxy.go:108: Dispatched forwarders for 127.0.0.1:5432 <-> vm(3):8001.
(1, 'master_key', 'Super important key')
(2, 'secondary_key', 'Less important key')
(3, 'backup_key', 'Somehow important key')
viproxy: 2024/03/19 13:08:00 viproxy.go:136: Closed connection tuple for 127.0.0.1:43970 <-> vm(3):8001.
This tells you that the enclave was able to create a new database schema, inject 3 records and execute a select all.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable decrypt from enclave",
"Effect": "Allow",
"Principal": {
"AWS": <devNitroWalletEth.EC2InstanceRoleARN>
},
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringEqualsIgnoreCase": {
"kms:RecipientAttestation:ImageSha384": <PCR0_VALUE_FROM_EIF_BUILD>
}
}
},
{
"Sid": "Enable encrypt from lambda",
"Effect": "Allow",
"Principal": {
"AWS": <devNitroWalletEth.LambdaExecutionRoleARN>
},
"Action": "kms:Encrypt",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": <KMS_ADMINISTRATOR_ROLE_ARN>
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion",
"kms:GenerateDataKey",
"kms:TagResource",
"kms:UntagResource"
],
"Resource": "*"
}
]
}
To leverage the provided generate_key_policy.sh
script, a CDK output file needs to be provided.
This file can be created by running the following command:
cdk deploy devNitroWalletEth -O output.json
After the output.json
file has been created, the following command can be used to create the KMS key policy:
./script/generate_key_policy.sh ./output.json
If the debug mode has been turned on by appending --debug-mode
to the enclaves start sequence, the enclaves PCR0 value
in the AWS KMS key policy needs to be updated
to 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
,
otherwise AWS KMS will return error code 400
.
Use the command below to create a temporary Ethereum private key.
openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout > key
cat key | grep priv -A 3 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^00//'
Use the following command to calculate the corresponding public address for your temporary Ethereum key created in the previous step. keccak-256sum binary needs to be made available to execute the calculation step successfully.
cat key | grep pub -A 5 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^04//' > pub
echo "0x$(cat pub | keccak-256sum -x -l | tr -d ' -' | tail -c 41)"
Please be aware that the calculated public address does not comply with the valid mixed-case checksum encoding standard for Ethereum addresses specified in EIP-55.
Replace the Ethereum key placeholder in the JSON request below and use the request to encrypt and store the Ethereum key
via the Lambda test
console:
{
"operation": "set_key",
"eth_key": <ethereum_key_placeholder>
}
Use the request below to sign an Ethereum EIP-1559 transaction with the saved Ethereum key using the Labda test
console:
{
"operation": "sign_transaction",
"transaction_payload": {
"value": 0.01,
"to": "0xa5D3241A1591061F2a4bB69CA0215F66520E67cf",
"nonce": 0,
"type": 2,
"chainId": 4,
"gas": 100000,
"maxFeePerGas": 100000000000,
"maxPriorityFeePerGas": 3000000000
}
}
Once you have completed the deployment and tested the application, clean up the environment to avoid incurring extra cost. This command removes all resources in this stack provisioned by the CDK:
cdk destroy
See CONTRIBUTING for more information.
This library is licensed under the MIT-0 License. See the LICENSE file.