Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implements AWS Nitro Enclave-based confidential computing environments with cryptographic attestation, KMS policy integration using PCR-based condition keys, and secure vsock communication channels. The practitioner builds enclave images, configures attestation-aware KMS policies, validates attestation documents against the AWS Nitro PKI root of trust, and establishes isolated computation pipelines for processing sensitive data such as PII, cryptographic keys, and healthcare records. Activates for requests involving Nitro Enclave setup, enclave attestation validation, confidential computing on AWS, or KMS enclave policy configuration.
.claude/skills/implementing-aws-nitro-enclave-security/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | — | — |
| case-11 | ✗→✓ | ▲ Improved | — | — |
| case-03 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-02 | ✗→✓ | ▲ Improved | — | — |
Do not use when the workload does not handle sensitive data that requires hardware-level isolation, when the instance type does not support Nitro Enclaves (requires Nitro-based instances with at least 4 vCPUs), or when latency constraints make the vsock communication overhead unacceptable.
nitro-cli toolset installed on the parent EC2 instance (Amazon Linux 2 or AL2023)aws-nitro-enclaves-sdk-c or Python aws-encryption-sdk for enclave-side KMS operations/etc/nitro_enclaves/allocator.yamlSet up the parent EC2 instance to support enclave launches:
bash sudo amazon-linux-extras install aws-nitro-enclaves-cli sudo yum install aws-nitro-enclaves-cli-devel -y sudo systemctl enable --now nitro-enclaves-allocator.service sudo systemctl enable --now docker sudo usermod -aG ne ec2-user sudo usermod -aG docker ec2-user
/etc/nitro_enclaves/allocator.yaml to reserve resources for the enclave. The enclave requires dedicated memory that is carved from the parent instance:yaml --- memory_mib: 4096 cpu_count: 2 Restart the allocator: sudo systemctl restart nitro-enclaves-allocator.service
nitro-cli describe-enclaves to confirm the CLI can communicate with the Nitro hypervisor. An empty JSON array [] indicates no enclaves are running and the setup is correct.Package the sensitive workload into a signed enclave image:
dockerfile FROM amazonlinux:2
RUN yum install -y python3 python3-pip && \ pip3 install boto3 cbor2 cryptography requests
COPY enclave_app.py /app/enclave_app.py
WORKDIR /app CMD "python3", "enclave_app.py"]
bash docker build -t enclave-app:latest . nitro-cli build-enclave \ --docker-uri enclave-app:latest \ --output-file enclave-app.eif The output contains three critical PCR values:
Record these values; they are used in KMS key policies for attestation-based access control.
bash openssl ecparam -name secp384r1 -genkey -noout -out enclave_key.pem openssl req -new -key enclave_key.pem -sha384 \ -nodes -subj "/CN=Enclave Signer" -out enclave_csr.pem openssl x509 -req -days 365 -in enclave_csr.pem \ -signkey enclave_key.pem -sha384 -out enclave_cert.pem
nitro-cli build-enclave \ --docker-uri enclave-app:latest \ --output-file enclave-app.eif \ --private-key enclave_key.pem \ --signing-certificate enclave_cert.pem PCR8 (the signing certificate hash) enables KMS policies that trust any image signed by a specific certificate, allowing image updates without changing the policy.
Create a KMS key policy that restricts decryption to a verified enclave:
json { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowEnclaveDecrypt", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111122223333:role/EnclaveParentRole" }, "Action": [ "kms:Decrypt", "kms:GenerateDataKey" ], "Resource": "*", "Condition": { "StringEqualsIgnoreCase": { "kms:RecipientAttestation:ImageSha384": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210" } } } ] }
json { "Condition": { "StringEqualsIgnoreCase": { "kms:RecipientAttestation:PCR8": "ab3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890abcdef" } } }
json { "Condition": { "StringEqualsIgnoreCase": { "kms:RecipientAttestation:PCR0": "<pcr0-hex>", "kms:RecipientAttestation:PCR1": "<pcr1-hex>" } } }
kms:Decrypt permission, but the KMS key policy condition ensures the actual decryption only succeeds when the request originates from a valid enclave with the correct attestation document attached.Establish the parent-to-enclave communication channel:
3, and the enclave CID is assigned at launch.python import socket import json import boto3
VSOCK_CID = 3 # Parent CID VSOCK_PORT = 5000
def start_proxy(): sock = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) sock.bind((VSOCK_CID, VSOCK_PORT)) sock.listen(5)
kms_client = boto3.client('kms', region_name='us-east-1')
while True: conn, addr = sock.accept() data = conn.recv(65536) request = json.loads(data.decode())
if request'action'] == 'decrypt': response = kms_client.decrypt( CiphertextBlob=bytes.fromhex(request'ciphertext']), Recipient={ 'KeyEncryptionAlgorithm': 'RSAES_OAEP_SHA_256', 'AttestationDocument': bytes.fromhex(request'attestation_doc']) } ) conn.sendall(json.dumps({ 'ciphertext_for_recipient': response'CiphertextForRecipient'].hex() }).encode()) conn.close()
/dev/nsm, attaches it to KMS decrypt requests, and receives data encrypted to the enclave's ephemeral public key:python import socket import json from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.primitives import hashes, serialization
PARENT_CID = 3 VSOCK_PORT = 5000
def get_attestation_document(public_key_der): """Request attestation document from NSM device.""" # Uses the aws-nitro-enclaves-nsm-api # NSM provides: module_id, digest (SHA384), timestamp, PCRs, # certificate (from Nitro PKI), cabundle, public_key, user_data, nonce import nsm_util nsm_fd = nsm_util.nsm_lib_init() attestation_doc = nsm_util.nsm_get_attestation_doc( nsm_fd, public_key=public_key_der, user_data=None, nonce=None ) return attestation_doc
def decrypt_via_parent(ciphertext_hex): """Send decrypt request through vsock to parent proxy.""" private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048 ) public_key_der = private_key.public_key().public_bytes( serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo )
attestation_doc = get_attestation_document(public_key_der)
sock = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) sock.connect((PARENT_CID, VSOCK_PORT)) sock.sendall(json.dumps({ 'action': 'decrypt', 'ciphertext': ciphertext_hex, 'attestation_doc': attestation_doc.hex() }).encode())
response = json.loads(sock.recv(65536).decode()) sock.close()
# KMS encrypted the plaintext to the enclave's public key # Only the enclave's private key can decrypt it ciphertext_for_recipient = bytes.fromhex( response'ciphertext_for_recipient'] ) plaintext = private_key.decrypt( ciphertext_for_recipient, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) return plaintext
Verify attestation documents from enclaves to establish trust:
module_id: Identifier for the NSM moduledigest: Hashing algorithm (SHA-384)timestamp: Unix epoch milliseconds when the document was createdpcrs: Map of PCR index to measurement value (PCR0-PCR15)certificate: The NSM's x509 certificate, signed by the Nitro PKIcabundle: Certificate chain from the NSM certificate to the AWS Nitro root CApublic_key: The enclave's ephemeral public key (provided at attestation request time)user_data: Optional application-defined data (up to 512 bytes)nonce: Optional nonce for freshness verificationhttps://aws-nitro-enclaves.amazonaws.com/AWS_NitroEnclaves_Root-G1.zip)aws.nitro-enclaves CNpython import cbor2 from cose import CoseMessage from cryptography import x509 from cryptography.x509.oid import NameOID
def validate_attestation(attestation_bytes, expected_pcrs, expected_nonce=None): cose_msg = CoseMessage.decode(attestation_bytes) payload = cbor2.loads(cose_msg.payload)
# Verify certificate chain cert = x509.load_der_x509_certificate(payload'certificate']) cabundle = x509.load_der_x509_certificate(c) for c in payload'cabundle']]
# Check root CA is AWS Nitro root = cabundle-1] cn = root.subject.get_attributes_for_oid(NameOID.COMMON_NAME)0].value assert cn == 'aws.nitro-enclaves', f'Unexpected root CA: {cn}'
# Verify PCR measurements pcrs = payload'pcrs'] for idx, expected_value in expected_pcrs.items(): actual = pcrs.get(idx, b'').hex() assert actual == expected_value, f'PCR{idx} mismatch: {actual}'
# Verify nonce freshness if expected_nonce: assert payload.get('nonce') == expected_nonce, 'Nonce mismatch'
return payload
Run the enclave and implement operational monitoring:
bash nitro-cli run-enclave \ --eif-path enclave-app.eif \ --cpu-count 2 \ --memory 4096 \ --enclave-cid 16 \ --debug-mode Note: --debug-mode enables the enclave console for development. Remove it in production as it allows reading enclave output, which breaks the isolation guarantee.
bash nitro-cli describe-enclaves Expected output includes "State": "RUNNING", the assigned EnclaveCID, memory, CPU count, and enclave flags.
bash nitro-cli console --enclave-id <enclave-id>
bash nitro-cli terminate-enclave --enclave-id <enclave-id>
python # Parent-side health check over vsock def check_enclave_health(enclave_cid, port=5001): try: sock = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM) sock.settimeout(5) sock.connect((enclave_cid, port)) sock.sendall(b'HEALTH_CHECK') response = sock.recv(1024) sock.close() return response == b'OK' except (socket.timeout, ConnectionRefusedError): return False
| Term | Definition | |------|------------| | Nitro Enclave | An isolated virtual machine created by the Nitro Hypervisor on a Nitro-based EC2 instance with no persistent storage, no network access, and no interactive access, even from the parent instance's root user | | Attestation Document | A CBOR-encoded, COSE-signed document generated by the Nitro Security Module containing PCR measurements, a certificate chain to the AWS Nitro root CA, and optional user-provided data | | PCR (Platform Configuration Register) | SHA-384 hash measurements that uniquely identify an enclave's image (PCR0), kernel/bootstrap (PCR1), application (PCR2), IAM role (PCR4), instance ID (PCR3), and signing certificate (PCR8) | | Vsock | A virtual socket providing the sole communication channel between a parent EC2 instance and its enclave, using CID (Context Identifier) and port addressing | | EIF (Enclave Image File) | The packaged enclave image built by nitro-cli from a Docker image, containing the kernel, ramdisk, and application, producing PCR measurements at build time | | Nitro Security Module (NSM) | A custom Linux device (/dev/nsm) inside the enclave that provides attestation document generation and hardware random number generation | | COSE_Sign1 | CBOR Object Signing and Encryption single-signer structure used to sign the attestation document with the NSM's private key | | kms:RecipientAttestation | AWS KMS condition key prefix that enables key policies to enforce that decrypt/generate operations only succeed when a valid attestation document with matching PCR values is presented |
Decrypt and GenerateDataKey operations that include Recipient parameters, enabling auditing of enclave-originated cryptographic operationsContext: A healthcare SaaS company processes patient records containing PHI. Regulations require that the decryption and tokenization of PHI never occurs on an instance accessible to operators. The company deploys a Nitro Enclave that receives encrypted patient records, decrypts them inside the enclave using KMS with attestation, tokenizes the PII fields, and returns only the tokenized records through the vsock.
Approach:
kmstool-enclave-cli binary, and a vsock server that accepts encrypted recordsnitro-cli build-enclave and record PCR0, PCR1, PCR2 from the build outputkms:RecipientAttestation:ImageSha384 condition matching PCR0, allowing only this specific enclave build to decrypt patient recordskms:Decrypt on the key, but the KMS condition ensures decryption only succeeds inside the attested enclave{ssn: "tok_a8f3...", dob: "tok_b2e1...", name: "tok_c9d4..."}Decrypt calls with RecipientAttestation parameters, confirming all decryption occurs within the enclave boundaryPitfalls:
allocator.yaml, causing the enclave to fail at launch with an opaque "resource not available" error## Nitro Enclave Security Assessment
**Enclave Image**: enclave-tokenizer.eif
**Build Date**: 2026-03-19T14:30:00Z
**Instance Type**: m5.2xlarge
**Allocated Resources**: 2 vCPUs, 4096 MiB memory
### PCR Measurements
| PCR | Value | Bound in KMS Policy |
|-----|-------|---------------------|
| PCR0 (Image) | a1b2c3d4e5f6... | Yes |
| PCR1 (Kernel) | f6e5d4c3b2a1... | Yes |
| PCR2 (Application) | 1a2b3c4d5e6f... | No |
| PCR8 (Signing Cert) | 9f8e7d6c5b4a... | Yes (production) |
### KMS Key Policy Verification
- Key ARN: arn:aws:kms:us-east-1:111122223333:key/mrk-abc123
- Attestation condition: kms:RecipientAttestation:ImageSha384 = PCR0
- Signing cert condition: kms:RecipientAttestation:PCR8 = <cert-hash>
- Parent role: arn:aws:iam::111122223333:role/EnclaveParentRole
- Direct decrypt from parent: BLOCKED (attestation required)
- Decrypt from verified enclave: ALLOWED
### Security Posture
- [PASS] Debug mode disabled in production launch command
- [PASS] Vsock is the only communication channel (no network interface)
- [PASS] Attestation document nonce verification implemented
- [PASS] Certificate chain validates to AWS Nitro root CA
- [WARN] PCR0 used in policy; consider PCR8 for deployment flexibility
- [FAIL] Health check endpoint does not verify enclave attestation freshness| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.