A python script that gets to renew your SSL certificates from AWS Lambda via DNS challenge using Let's Encrypt services. It stores your keys and certificates in a S3 bucket. If the keys don't exists, it generates them and re-uses them later (useful for public key pinning).
All in all, the script talks to Let's Encrypt and Amazon Route53 (for the DNS challenge), Amazon S3 and Amazon IAM (to store your certificates) and Amazon Elastic Load Balancing. And optionally, Amazon KMS can be used to encrypt your data in your S3 bucket.
The configuration file is based on YAML. It should be easy to understand by reviewing the provided configuration. Nonetheless, here is a short explanation of each configuration directive
directory
: The Let's Encrypt directory endpoint to use to request the certificate issuance. This is useful when you need to switch between staging and production. Possible values are:
https://acme-v01.api.letsencrypt.org/directory
for productionhttps://acme-staging.api.letsencrypt.org/directory
for development and tests
info
: The information to be used when the script is registering your account for the first time. You should provide a valid email or the registration may fail.
info:
- mailto:myemail@example.com
domains
: a list of domain information.
name
: The host name for which you want your certificate to be issued for.r53_zone
: the Route53 hosted zone name which contains the DNS entry forname
.countryName
: This parameter is used forcountryName
in the Certificate Signing Request (CSR).elb
: Name of your Elastic Load Balancer.elb_port
: ELB listening port. If left unspecified, the default is 443 (HTTPS).elb_region
: the region is which your ELB has been deployed in. Default is the Lambda local region.kmsKeyArn
: Your KMS key arn to encrypt the Let's Encrypt account key and your certificate private keys. You may also useAES256
for AWS managed at rest encryption. Default isAES256
.reuse_key
: The Lambda function will try to reuse the same private key to generate the new CSR. This is useful if you ever want to use Public Key Pinning (Mobile App development) and yet want to renew your certificates every X months
This project relies on third party projects that requires some files to be compiled. Since AWS Lambda runs on Amazon Linux 64 bit (ref), it's important that you have such instance running to prepare your Lambda function. Note that nany other distribution may not be compatible with Lambda functions.
$> yum install libcffi-devel libffi-devel libyaml-devel gcc openssl-devel git
$> virtualenv .env
$> source .env/bin/activate
$> pip install -r requirements.txt
$> mv .env/lib/python2.7/site-packages/* .
$> mv .env/lib64/python2.7/site-packages/* .
$> mv .env/src/acme/acme/acme* .
$> rm -rf .env
$> zip -r letslambda.zip .
Once this is done, all you have to do is to upload your lambda function to a S3 bucket.
$> aws s3 cp letslambda.zip s3://bucket/
Alternatively, you may use the Amazon Management Console to upload your package from the comfort of your web browser.
And finally, let Amazon CloudFormation do the heavy job of deploying your Lambda function.
$> aws cloudformation create-stack --stack-name letslambda --template-body file://letslambda.json --parameters ParameterKey=Bucket,ParameterValue=bucket --capabilities CAPABILITY_IAM
As a possible alternative, you may use the CloudFormation Management Console to deploy your Lambda function. Though, you should ensure that you deploy the IAM resources included in the template.
As part of the deployment process, the CloudFormation template will create 4 IAM managed policies and one Lambda execution role. Each managed policy has been crafted so you can access your resources securely. The Lambda execution role defines the privilege level for the Lambda function.
LetsLambdaManagedPolicy
This policy is core to the Lambda function and how it interacts with CloudWatch logs, Amazon IAM, Amazon Elastic Load Balancing and Route53.LetsLambdaKmsKeyManagedPolicy
Through this policy, the Lambda function can encrypt and read encrypted private keys.LetsLambdaS3WriteManagedPolicy
Allow the Lambda function to write into the user defined S3 bucket.LetsLambdaS3ReadManagedPolicy
This policy is used to access any objects in the S3 bucket. Encrypted objects such as private keys will remain inaccessible untilLetsLambdaKmsKeyManagedPolicy
is used in conjunction with this policy.
Having access to private keys is sensitive by definition. You should ensure that your private keys do not leak outside in any way.
To retrieve more easily your private keys from an EC2 instance, you should create/update an EC2 role and add both LetsLambdaKmsKeyManagedPolicy
and LetsLambdaS3ReadManagedPolicy
. This will allow your the EC2 instances running under the corresponding role/managed policies to access the private keys without any hard coded credentials.