On February 8 2026 Amazon Web Services announced native support for
Nitro Enclaves inside
CodeBuild. This marks the first time a managed
CI/CD service can launch hardware‑isolated enclaves on‑the‑fly, giving teams a
practical way to protect API keys, TLS certificates, and other high‑value
secrets from the build environment itself. In this deep‑dive we’ll walk
through the architecture, required IAM policies, and a concrete example
that encrypts a Docker image’s ARG values inside an enclave before the
image is pushed to Amazon ECR.
Why Nitro Enclaves for CI/CD?
Traditional CodeBuild projects run in plain Amazon Linux containers that share the underlying EC2 host’s memory space. Even with IAM roles and Parameter Store, a compromised build script can read environment variables or temporary files and exfiltrate secrets. Nitro Enclaves provide memory‑isolated, attested execution environments that:
- Do not have any persistent storage or network interfaces.
- Communicate with the parent build container only through
vsockchannels. - Expose a cryptographic attestation document that can be verified by downstream services.
By off‑loading secret handling to an enclave, the build container can remain stateless and untrusted, dramatically reducing the attack surface.
High‑Level Architecture
The flow is simple:
- The CodeBuild runtime launches an
enclave‑launcherbinary. - The launcher creates a Nitro Enclave with a minimal Ubuntu 22.04 image that contains the
aws-nitro-enclaves-clitools. - The parent container sends a request over
vsockto the enclave, asking it to decrypt a ciphertext stored in AWS KMS. - The enclave returns the plaintext secret via the same channel; the parent process uses it for the build (e.g., Docker build‑arg, npm token, etc.).
- All secret material is discarded when the enclave terminates at the end of the job.
Preparing the Enclave Image
AWS supplies a base image called aws-nitro-enclaves-base, but most teams
prefer to bake their own minimal image that contains only the required
binaries (KMS SDK, OpenSSL, and any language‑specific tooling). Below is a
Dockerfile that builds an enclave image suitable for Java‑based builds:
FROM public.ecr.aws/nitro-enclaves/aws-nitro-enclaves-base:latest
# Install Java runtime & AWS SDK for KMS
RUN yum install -y java-17-openjdk \
&& curl -L https://repo.maven.apache.org/maven2/software/amazon/awssdk/kms/2.24.0/kms-2.24.0.jar -o /opt/kms.jar
# Add a small Go helper that reads from vsock and calls KMS Decrypt
COPY enclave-helper /opt/enclave-helper
RUN chmod +x /opt/enclave-helper
ENTRYPOINT ["/opt/enclave-helper"]
Build and push the enclave image to an ECR repository that the build project’s execution role can read:
aws ecr create-repository --repository-name ci-enclave-image
docker build -t ci-enclave-image .
docker tag ci-enclave-image:latest <account-id>.dkr.ecr.<region>.amazonaws.com/ci-enclave-image:latest
aws ecr get-login-password | docker login --username AWS --password-stdin <account-id>.dkr.ecr.<region>.amazonaws.com
docker push <account-id>.dkr.ecr.<region>.amazonaws.com/ci-enclave-image:latest
Configuring the CodeBuild Project
The new CodeBuild feature is enabled by adding an enclaveConfiguration
block to the buildspec.yml or via the console UI. Example
buildspec.yml:
version: 0.2
phases:
install:
runtime-versions:
java: corretto17
commands:
- echo Installing enclave launcher...
- yum install -y aws-nitro-enclaves-cli
pre_build:
commands:
- echo Starting Nitro Enclave…
- enclave-cli run \
--image <account-id>.dkr.ecr.<region>.amazonaws.com/ci-enclave-image:latest \
--cpu-count 2 \
--memory 512 \
--vsock-port 5000 \
--enclave-id $ENCLAVE_ID
- echo Requesting secret decryption…
- |
cat <<EOF > decrypt-request.json
{
"kmsKeyId": "arn:aws:kms:<region>:<account-id>:key/<key-id>",
"ciphertextBlob": "$(aws ssm get-parameter --name /ci/build-token --with-decryption --query Parameter.Value --output text)"
}
EOF
- ENCLAVE_SECRET=$(enclave-cli vsock-send --enclave-id $ENCLAVE_ID \
--port 5000 --payload file://decrypt-request.json)
build:
commands:
- echo Building Docker image…
- docker build --build-arg BUILD_TOKEN=$ENCLAVE_SECRET -t my-app:latest .
post_build:
commands:
- echo Pushing image to ECR…
- $(aws ecr get-login-password | docker login --username AWS --password-stdin <account-id>.dkr.ecr.<region>.amazonaws.com)
- docker tag my-app:latest <account-id>.dkr.ecr.<region>.amazonaws.com/my-app:latest
- docker push <account-id>.dkr.ecr.<region>.amazonaws.com/my-app:latest
artifacts:
files: '**/*'
Note the use of vsock-send to exchange JSON with the enclave.
The enclave binary validates the request, calls KMS Decrypt,
and returns the plaintext. Because the secret never appears in the
build container’s environment, a compromised step cannot leak it.
IAM and KMS Permissions
Two policies are required:
- CodeBuild execution role – must be able to
sts:AssumeRoleon the enclave‑launcher service and read the ECR image:
{ "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage" ], "Resource": "*" } - KMS key policy – grants the enclave’s isolated
principal (identified by the enclave’s attestation document) permission
to
Decrypt. The policy uses theaws:PrincipalTag/Enclavecondition, which is automatically injected by the enclave runtime:{ "Sid": "AllowEnclaveDecrypt", "Effect": "Allow", "Principal": {"AWS": "*"}, "Action": "kms:Decrypt", "Resource": "*", "Condition": { "StringEquals": { "aws:PrincipalTag/Enclave": "true" } } }
Testing and Attestation Verification
After the first successful run, you should verify the enclave’s attestation document to ensure it originated from the expected AMI and code hash. The CLI provides a helper:
enclave-cli attest --enclave-id $ENCLAVE_ID --output json | jq .verificationResult
A true result confirms the enclave has not been tampered with.
Integrate this check into a pre‑build step; if verification fails, abort the
pipeline to avoid leaking secrets.
Best Practices and Gotchas
- Keep enclave images minimal. Smaller attack surface and faster start‑up.
- Never write decrypted secrets to disk. Pass them directly to the next process via environment variables or command‑line arguments that are cleared afterward.
- Limit enclave lifetime. The enclave terminates automatically when the CodeBuild job ends, but you can also invoke
enclave-cli stopearly if an error occurs. - Monitor
vsocktraffic. CloudWatch Logs for the build container should capture the enclave’s stdout/stderr; watch for unexpected errors that may indicate SDK version mismatches. - Cost awareness. Each enclave consumes a dedicated Nitro hypervisor slice (≈ $0.012 per GB‑hour). For short‑lived builds the cost is negligible, but factor it into large‑scale pipelines.
"Treat the enclave as a hardware‑rooted vault that lives only for the duration of a build step – no more, no less."
Conclusion
By embedding Nitro Enclaves directly into CodeBuild, AWS gives DevOps
engineers a concrete path to hardware‑backed secret isolation without
leaving the managed CI/CD ecosystem. The pattern described here—creating
a minimal enclave image, invoking it via vsock, and using KMS
for decryption—can be reused across languages and frameworks, from Docker
builds to serverless function packaging. As supply‑chain attacks grow more
sophisticated, moving secrets out of the build container’s memory and into
a tamper‑evident enclave is a pragmatic defense that scales with the
modern CI/CD workflow.