To derive the most value from Enclaver, your application’s sensitive data should be encrypted using a key stored in AWS Key Management Service (KMS) to be decrypted only within an enclave. To ensure the data can only be decrypted from within an enclave running a specific image hash, a KMS key policy can constrain the Decrypt operation to requests with given PCR values (hashes). See Using cryptographic attestation with AWS KMS for details.
The PCR values are included in an attestation document, signed by AWS. An application running inside an enclave can retrieve such a document and attach it to the KMS requests.
However it is a cumbersome process to be done directly by the application. The Enclaver includes a KMS proxy that makes this process transparent.
By configuring the application to connect to the KMS proxy running on localhost
, all outgoing KMS requests that support it (e.g. Decrypt) will have the attestation documents attached to them.
Enable the KMS proxy in your enclaver.yaml
as follows:
kms_proxy:
listen_port: 9999
egress:
allow:
- 169.254.169.254
- kms.*.amazonaws.com
When the enclave starts up, Enclaver will define a AWS_KMS_ENDPOINT=http://127.0.0.1:9999
environment variable. The value can be passed into the AWS SDK to override the default endpoint.
The exact details are language specfiic. See below for examples of the most popular languages.
WARNING: Do not expose the KMS proxy port (9999 in this example) in the ingress
section. Doing so will expose the KMS proxy outside the enclave, allowing untrusted code to decrypt the data.
The following examples show how to pass the environment variable to the AWS SDK in the most idiomatic way per programming language.
import os, boto3
kms = boto3.client('kms', endpoint_url=os.environ['AWS_KMS_ENDPOINT'])
resp = kms.decrypt(CiphertextBlob=b'...ciphertext...')
plaintext = resp['Plaintext']
require "base64"
require 'aws-sdk'
client = Aws::KMS::Client.new(
endpoint: ENV["AWS_KMS_ENDPOINT"]
)
resp = client.decrypt({
ciphertext_blob: ciphertext
})
plaintext = resp.plaintext
Node AWS SDK does not automatically honor http_proxy
and no_proxy
environment variables and require a global-agent
module to inject HTTP proxy support.
import { KMSClient, DecryptCommand } from "@aws-sdk/client-kms";
import { bootstrap } from 'global-agent';
bootstrap();
global.GLOBAL_AGENT.HTTP_PROXY = process.env.http_proxy;
global.GLOBAL_AGENT.NO_PROXY = process.env.no_proxy;
const kms = new KMSClient({
endpoint: process.env.AWS_KMS_ENDPOINT
});
const decrypt = const response = await kms.send(new DecryptCommand({
CiphertextBlob: ciphertext
}));
var plaintext = response.Plaintext);
endpoint := os.Getenv("AWS_KMS_ENDPOINT")
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
return aws.Endpoint{
PartitionID: "aws",
URL: endpoint,
SigningRegion: region,
}, nil
})
cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolverWithOptions(customResolver))
client := kms.NewFromConfig(cfg)
resp, err := client.Decrypt(context.TODO(), &kms.DecryptInput{
CiphertextBlob: []byte(ciphertext),
})
plaintext = resp.Plaintext
For a sample Python application using the KMS proxy, checkout the Running a Python App guide.