- Newest
- Most votes
- Most comments
You can make this work with inline Lambda code by installing the package at runtime to /tmp and deferring the import. The /tmp directory in Lambda provides 512MB (or up to 10GB if configured) of ephemeral storage, and you can use pip to install packages there during cold starts.
The Pattern: Runtime pip install with deferred import
import json import subprocess import sys import cfnresponse def install_packages(): """Install cryptography to /tmp on cold start.""" subprocess.check_call([ sys.executable, '-m', 'pip', 'install', 'cryptography', '--target', '/tmp/pip_packages', '--quiet', '--no-cache-dir' ]) sys.path.insert(0, '/tmp/pip_packages') # Install on cold start (outside handler) install_packages() # NOW import cryptography (after install) from cryptography import x509 from cryptography.x509.oid import NameOID from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa import datetime def handler(event, context): try: if event['RequestType'] == 'Delete': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return # Generate CA private key ca_key = rsa.generate_private_key( public_exponent=65537, key_size=2048 ) # Generate CA certificate ca_name = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, "My Custom CA"), x509.NameAttribute(NameOID.ORGANIZATION_NAME, "MyOrg"), ]) ca_cert = ( x509.CertificateBuilder() .subject_name(ca_name) .issuer_name(ca_name) .public_key(ca_key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(datetime.datetime.utcnow()) .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=3650)) .add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True) .sign(ca_key, hashes.SHA256()) ) # Serialize to PEM ca_key_pem = ca_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() ).decode('utf-8') ca_cert_pem = ca_cert.public_bytes( serialization.Encoding.PEM ).decode('utf-8') cfnresponse.send(event, context, cfnresponse.SUCCESS, { 'CACertificatePem': ca_cert_pem, 'CAPrivateKeyPem': ca_key_pem }) except Exception as e: print(f"Error: {str(e)}") cfnresponse.send(event, context, cfnresponse.FAILED, { 'Error': str(e) })
Important considerations:
-
Cold start penalty: The
pip installadds 5-15 seconds to cold starts. Set your Lambda timeout to at least 120 seconds (custom resources allow up to 3600s). -
Memory: Set memory to at least 512MB — the
cryptographylibrary compilation and loading is memory-intensive. -
Idempotency: The install runs on every cold start but is fast on warm invocations since the module is already in
sys.path. You can add a check:if not os.path.exists('/tmp/pip_packages/cryptography'). -
Network access: The Lambda needs internet access (NAT Gateway or public subnet) OR a VPC endpoint for PyPI. If your Lambda is in a VPC without internet, this won't work — use a Lambda Layer instead.
-
Pinning versions: For production, pin the version:
'cryptography==42.0.0'to avoid unexpected breaking changes.
References:
answered 2 months ago
The short answer is: no, not with ZipFile inline Lambda code alone.
The cryptography package contains compiled native extensions (_rust, OpenSSL bindings, C/Rust components). AWS Lambda inline code only supports pure Python standard library modules already included in the runtime.
Because of that:
from cryptography import x509
fails with:
Runtime.ImportModuleError: No module named 'cryptography'
Why this happens
When you use:
Code: ZipFile: | ...
CloudFormation creates a tiny deployment package containing only your inline source code.
There is:
- no
pip install - no dependency resolution
- no compiled wheel support
- no vendored libraries
So only built-in runtime modules work.
Your realistic options
| Option | Works with ZipFile | Portable | Recommended |
|---|---|---|---|
| Pure stdlib only | ✅ | ✅ | ❌ (no X.509 support) |
| Inline + custom minimal crypto implementation | Technically | Very hard | ❌ |
Lambda Layer with cryptography | ❌ | Moderate | ✅ |
| Prebuilt deployment ZIP | ❌ | Moderate | ✅ |
| Container image Lambda | ❌ | Lower | ✅ Best long-term |
| Custom resource calling external service | ✅ | Depends | Sometimes |
Important technical detail
Python's standard library does not provide full X.509 certificate generation APIs.
So even though modules like:
import ssl import hashlib
exist, they cannot generate ACM PCA-compatible certificates or CSRs.
You specifically need libraries like:
cryptographypyOpenSSL
which require native binaries.
Best Practice (AWS perspective)
For certificate generation in Lambda, AWS best practice is usually:
Option 1 — Lambda Layer
Build the dependency on Amazon Linux compatible environment:
pip install cryptography -t python/ zip -r layer.zip python
Attach as a Lambda Layer.
Pros:
- reusable
- clean separation
- smaller templates
- production standard
Cons:
- additional artifact
Option 2 — Container Image Lambda (Recommended for crypto-heavy workloads)
Example:
FROM public.ecr.aws/lambda/python:3.12 COPY requirements.txt . RUN pip install -r requirements.txt COPY app.py . CMD ["app.handler"]
Pros:
- deterministic builds
- native libs work reliably
- easiest long-term maintenance
- ideal for PKI tooling
Cons:
- no longer fully inline/self-contained
If portability is your real goal
A better architectural approach is usually:
CloudFormation ↓ Custom Resource ↓ Dedicated certificate Lambda/service
instead of embedding PKI logic directly into the template.
Reason:
X.509 generation is operationally complex:
- entropy requirements
- OpenSSL compatibility
- wheel architecture issues
- runtime ABI compatibility
- future Python runtime changes
Trying to force this into ZipFile inline code becomes fragile very quickly.
One possible workaround (not ideal)
You could invoke AWS services directly instead of generating certificates locally.
For example:
- ACM PCA
IssueCertificate - AWS Private CA APIs
- external CA endpoint
But if you truly need:
- RSA keypair generation
- CSR creation
- self-signed certs
- Client VPN cert chains
then you still need a crypto library somewhere.
Conclusion
cryptography cannot be used directly inside CloudFormation inline Lambda (ZipFile) because inline Lambdas cannot bundle compiled dependencies.
For X.509 operations on Lambda, the practical choices are:
- Lambda Layer
- Deployment package ZIP
- Container image Lambda (best overall)
There is no supported way to make cryptography magically available inside pure inline Python Lambda code.
answered 2 months ago
Relevant content
asked 4 years ago
