- Developer - update and build code and package unsigned code to S3
- Release Manager - reviews, signs and deploys code
- Install Amazon SAM CLI
- Install yq
- Install Docker Desktop for cross-compile support
Release Manager creates S3 bucket to host the code
# !!!Make sure you change the region name to the one you use!!!
export AWS_DEFAULT_REGION=ap-southeast-2
ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
BUCKET_NAME=secure-keygen-sam-$ACCOUNT_ID
aws s3 mb s3://$BUCKET_NAME
aws s3api put-bucket-versioning --bucket $BUCKET_NAME --versioning-configuration MFADelete=Disabled,Status=Enabled
Release Manager creates signing profile
aws signer put-signing-profile --platform-id "AWSLambda-SHA384-ECDSA" --profile-name Test1
Create developer user, record the credentials and create a new profile based on the credentials
cat <<EOT > s3access.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::$BUCKET_NAME/*"
]
}
]
}
EOT
aws iam create-user --user-name secure-keygen-dev
aws iam put-user-policy --user-name secure-keygen-dev --policy-name S3Access --policy-document file://s3access.json
aws iam create-access-key --user-name secure-keygen-dev
Open a new terminal and use the developer profile created previously.
# Developer build the packages
sam build --use-container
# Upload the package to S3
ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
BUCKET_NAME=secure-keygen-sam-$ACCOUNT_ID
export AWS_DEFAULT_REGION=ap-southeast-2 # !!!Make sure you change the region name to the one you use!!!
sam package --s3-bucket $BUCKET_NAME --output-template-file .aws-sam/build/template.yaml --region $AWS_DEFAULT_REGION
Developer should have deny access to perform code signing. Developer sends over template.yaml
to Release Manager
Release manager downloads and reviews the unsigned code. Developer also passes the generated CloudFormation template file i.e. ./.aws-sam/build/template.yaml
file to Release Manager.
CODE_S3_LOCATION=$(cat .aws-sam/build/template.yaml | yq '.Resources.ValidatorKeyGenFunction.Properties.CodeUri')
mkdir -p review
aws s3 cp $CODE_S3_LOCATION ./review/source.zip
To review the code, unzip the file:
cd ./review
unzip source.zip
After review, release manager signs the code and updates the stack with the signed code
SIGNING_PROFILE_ARN=$(aws signer get-signing-profile --profile-name Test1 --query profileVersionArn --output text)
sam deploy \
--region $AWS_DEFAULT_REGION \
--stack-name secure-keygen \
--template-file ./.aws-sam/build/template.yaml \
--parameter-overrides SigningProfileVersionArnParameter=$SIGNING_PROFILE_ARN \
--signing-profiles ValidatorKeyGenFunction=Test1 \
--confirm-changeset \
--capabilities CAPABILITY_IAM \
--no-disable-rollback
We need to invoke the Lambda function to generate the keys. Observe the payload structure to understand the parameters expected by the Lambda function
FUNCTION_ARN=$(aws cloudformation describe-stacks --stack-name secure-keygen --query "Stacks[0].Outputs[?OutputKey=='ValidatorKeyGenFunction'].OutputValue" --output text)
aws lambda invoke --function-name $FUNCTION_ARN --payload fileb://events/lambdaPayload.json output.json
Upon completion of the Lambda function execution, observe that there are new rows inserted into the DynamoDB table. You can find the DynamoDB table ARN by issuing the following command:
aws cloudformation describe-stacks --stack-name secure-keygen --query "Stacks[0].Outputs[?OutputKey=='ValidatorKeysTable'].OutputValue" --output text
Each DynamoDB table entry has the following field:
- web3signer_uuid - Used to assign the keys to Web3Signer instances. Each instance is assigned a UUID, and will query the table using this field. To assign the keys to a specific instance, modify the data in this field accordingly
- pubkey - The public key
- active - Applications such as Web3Signer can optionally use this field to determine whether to load the keys
- chain - Ethereum chain
- datetime - The date and time in which the key is generated
- deposit_json_b64 - The deposit JSON data in base64 encoding. Decode this data and upload it to Ethereum Staking Launchpad
- encrypted_key_password_mnemonic_b64 - KMS-encrypted JSON-formatted data structure consisting of:
keystore_b64
- Encrypted BLS12-381 keystore in base64 encodingpassword_b64
- randomly generated password to decrypt the keystore in base64 encodingmnemonic_b64
mnemonic from which the private key is derived from in base64 encoding
To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following:
aws cloudformation delete-stack --stack-name secure-keygen
Delete the developer user from IAM
aws iam delete-user --user-name secure-keygen-dev
Delete the Signer profile
PROFILE_VERSION=$(aws signer get-signing-profile --profile-name Test1 --query profileVersion --output text)
aws signer revoke-signing-profile --profile-name Test1 \
--profile-version $PROFILE_VERSION \
--reason "Unused" \
--effective-time $(date +%s)
Delete the deployment S3 bucket and its contents
ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
BUCKET_NAME=secure-keygen-sam-$ACCOUNT_ID
aws s3api delete-objects \
--bucket $BUCKET_NAME \
--delete "$(aws s3api list-object-versions \
--bucket $BUCKET_NAME | \
jq '{Objects: [.Versions[] | {Key:.Key, VersionId : .VersionId}], Quiet: false}')"
aws s3api delete-bucket --bucket $BUCKET_NAME
- Install Python 3.9
- Install Poetry
# Install dependencies
poetry install
# Activate virtual environment
source $(poetry env info --path)/bin/activate
If you modify the dependencies, export the requirements.txt
file
poetry export --without dev --without-hashes > secure_keygen/requirements.txt