Using AWS KMS to Encrypt a Secret
In the previous section, you created an AWS KMS key in AWS KMS. In this section, you will use this key to encrypt some data.
You should run the commands in this section from an account/role with kms:Encrypt permission
on that AWS KMS key.
|
Overview
The Anjuna Nitro Runtime tools provide the ability to automatically configure enclaves with secrets encrypted by a KMS key.
When building the Enclave Image File (EIF), the Anjuna Nitro Runtime can optionally take a configuration file that contains various information on how to set up the enclave when it starts. One of the configuration items in that file is the location of the encrypted data in an S3 bucket. When the enclave starts, the Anjuna Nitro Runtime performs the following steps:
-
Read the location of the encrypted file from the configuration file
-
Download the encrypted file from AWS S3
-
Prepare an attestation document
-
Submit a request to KMS to decrypt the file (which includes submitting the attestation document)
-
Store the secrets in environment variables or files which are accessible to applications running in the enclave
In this example, you will learn how to expose secrets to the application running in the Nitro Enclave through environment variables.
The first step is to encrypt some data using a KMS key, and store the encrypted file in an S3 bucket. On the next page, you will build an enclave that can automatically download this file, and decrypt it using AWS KMS.
Prerequisites
This section assumes that a few AWS objects have been created, and permissions to access them are granted to the current user:
-
an AWS KMS key
-
a Nitro-capable EC2 instance associated with a IAM role that has access to KMS
-
an S3 bucket for storing KMS-encrypted files
The following AWS objects must reside in the same AWS region:
|
If the requirements above are met, declare the following environment variables (the example commands shown on this page will use those environment variables):
$ export AWS_REGION=<your-region>
$ export KMS_KEY_ID=<your-kms-key>
$ export AWS_S3_BUCKET=<your-s3-bucket>
For example:
$ export AWS_REGION=us-east-2
$ export KMS_KEY_ID=arn:aws:kms:us-east-2:111122223333:alias/nitro-kms-key
$ export AWS_S3_BUCKET=anjuna-encrypted-data
The For example:
|
Verification
Before using the AWS objects mentioned above, check that they are valid by running the following
commands (this assumes that you have the AWS CLI tools installed in this host and that you have
defined the proper environment variables AWS_REGION
, KMS_KEY_ID
, and AWS_S3_BUCKET
):
Validate the IAM Role
Run the following command (replacing the string <iam-role-for-instance>
with the IAM role you want
to use for your Nitro-capable EC2 instance):
$ aws iam get-role --role-name <iam-role-for-instance> | jq .
The command should produce an output similar to this:
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
},
"MaxSessionDuration": 3600,
"RoleId": "AROAYDZEBCMBGI7I65HWP",
"CreateDate": "2021-04-20T06:33:56Z",
"RoleName": "<iam-role-for-instance>",
"Path": "/",
"RoleLastUsed": {
"Region": "<your-region>",
"LastUsedDate": "2021-04-21T08:03:51Z"
},
"Arn": "arn:aws:iam::account:role/<iam-role-for-instance>"
}
}
Validate the AWS KMS Key
Enter the following command to get some information on the AWS KMS key:
$ aws kms describe-key --key-id ${KMS_KEY_ID} | jq .
If the command succeeds, ensure that the region for this key (in the Arn
field) matches the value
you selected for the variable AWS_REGION
.
Once you have verified that the key is valid, inspect the policy associated with the key to make sure that the permissions are set up correctly.
Run the following command to inspect the policy associated with the KMS key:
$ KMS_KEY_ARN=$(aws kms describe-key --key-id ${KMS_KEY_ID} | jq -r .KeyMetadata.Arn)
$ aws kms get-key-policy --key-id ${KMS_KEY_ARN} --policy-name default | jq -r .Policy | jq .
Inspect the output of the command above, and make sure the policies are correct.
-
As the owner of the key, you should have permission to manage the KMS key (change the policies associated with this KMS key) and encrypt data using the KMS key. One of the entries in the JSON policy attached to the key should look like this:
{
"Sid": "Allow admin and encryption for the user that created the key, but not decryption",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<account>:user/<your-username>"
},
"Action": [
"kms:Update*",
"kms:UntagResource",
"kms:TagResource",
"kms:ScheduleKeyDeletion",
"kms:Revoke*",
"kms:ReEncrypt*",
"kms:Put*",
"kms:List*",
"kms:Get*",
"kms:GenerateDataKey*",
"kms:Encrypt",
"kms:Enable*",
"kms:Disable*",
"kms:DescribeKey",
"kms:Describe*",
"kms:Delete*",
"kms:Create*",
"kms:CancelKeyDeletion"
],
"Resource": "*"
}
-
The IAM role attached to the Nitro-capable EC2 instance can be used to authenticate to KMS and decrypt data when a Nitro Enclave presents a valid attestation document. One of the entries in the JSON policy attached to the key should look like this (in this example, the policy uses the
PCR0
value, but any combination of the enclave measurements can be used):
{
"Sid": "Enable decrypt for Nitro Enclaves running on EC2 instance associated with the proper role",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<account>:<iam-role-for-instance>/<>"
},
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringEqualsIgnoreCase": {
"kms:RecipientAttestation:PCR0": ""
}
}
}
Since you have not yet built the Nitro Enclave (EIF), the enclave measurements are not known
yet, and the value for PCR0 can be left empty. You will use the actual values of the enclave
measurements will be used in the next page.
|
Validate the AWS S3 bucket
Run this command to ensure that the AWS S3 bucket you specified is valid:
$ aws s3 ls --summarize ${AWS_S3_BUCKET}
If the command succeeds, verify that the policy attached to the bucket has GetObject
(i.e. READ
)
permission granted to the IAM role attached to the Nitro-capable EC2 instance.
$ aws s3api get-bucket-policy --bucket ${AWS_S3_BUCKET} | jq -r .Policy | jq .
The output of the command should look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Allow nitro instance role the ability to retrieve the bucket objects",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<account>:role/<iam-role-for-instance>"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<your-s3-bucket>/*"
}
]
}
Create Secret File
Create a file named secret-data.yaml
with list of environment variables and files that should be
made available to the application running in the Nitro Enclave.
The following example provides two environment variables
(INITDB_ROOT_USERNAME
and INITDB_ROOT_PASSWORD
) and a configuration file:
version: 1.6
environment:
- INITDB_ROOT_USERNAME=anjuna
- INITDB_ROOT_PASSWORD=0mMZMU01NChE095yZ7
files:
- path: "/etc/my-application-startup.conf"
mode: 0644
content: |
# This is an example of configuration file.
# It could be anything, including TLS certificates
Hello world!
You can specify as many environment variables as you want in this file. |
The Anjuna Nitro Runtime will not create the directories for the file entries. Make sure the directory exists as part of the Docker container specification. In the example above, the enclave startup would fail if you specified a path like
|
Encrypt the data
Make sure you have the following information available before running the command:
|
Run the following command (assuming you have defined the variables with the values for AWS_REGION
,
KMS_KEY_ID
and AWS_S3_BUCKET
):
$ anjuna-nitro-encrypt \
--cmk $KMS_KEY_ID \
--bucket-name $AWS_S3_BUCKET \
--bucket-key kms-encrypted-data.bin \
--config secret-data.yaml
If the command succeeds, a new file will be created in the specified S3 bucket, encrypted by the specified AWS KMS key. Furthermore, only enclaves that match the condition specified in the AWS KMS key policy will be allowed to decrypt this file.
The next step is to build an enclave, measure it, and update the policy attached to your AWS KMS key to authorize this enclave to decrypt the data.
Most of the steps listed in this section were to verify the AWS S3 objects were created
and set up properly. The actual encryption of the secrets is as simple as calling the
anjuna-nitro-encrypt command-line tool.
|