The post describes steps for automating the management of SSL certificates from Let's Encrypt CA using DNS-01 challenge and AWS .
acme-dns-route53 is a tool that will allow us to implement this feature. He is able to work with SSL certificates from Let's Encrypt, save them in Amazon Certificate Manager, use the Route53 API to implement the DNS-01 challenge, and, finally, push notifications in SNS. In acme-dns-route53 , there is also built-in functionality for use inside AWS Lambda, and this is what we need.
This article is divided into 4 sections:
Note: you must install GoLang 1.9+ and AWS CLI before you start.
acme-dns-route53 is written in GoLang and supports version 1.9 or later.
We need to create a zip file with the acme-dns-route53
inside. To do this, you need to install acme-dns-route53
from the GitHub repository using the go install
command:
$ env GOOS=linux GOARCH=amd64 go install github.com/begmaroman/acme-dns-route53
The binary is installed in the $GOPATH/bin
directory. Please note that during the installation we specified two environments: GOOS=linux
and GOARCH=amd64
. They make it clear to the Go compiler about the need to create a binary suitable for Linux OS and amd64 architecture - this is what runs in AWS.
AWS first deploys our program in a zip file, so let's create an acme-dns-route53.zip
archive that will contain the newly installed binary:
$ zip -j ~/acme-dns-route53.zip $GOPATH/bin/acme-dns-route53
Note: the binary should be at the root of the zip file. For this we use the -j
flag.
Now our zip-nick is ready for deployment, it remains only to create a role with the necessary rights.
We need to play an IAM role with the rights that our lambda requires during its execution.
Let's call this policy lambda-acme-dns-route53-executor
and immediately give it the basic role of AWSLambdaBasicExecutionRole
. This will allow our lambda to start and write logs to the AWS CloudWatch service.
To begin, create a JSON file that describes our rights. This, in essence, will allow lambda services to use the lambda-acme-dns-route53-executor
role:
$ touch ~/lambda-acme-dns-route53-executor-policy.json
The contents of our file are as follows:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup" ], "Resource": "arn:aws:logs:<AWS_REGION>:<AWS_ACCOUNT_ID>:*" }, { "Effect": "Allow", "Action": [ "logs:PutLogEvents", "logs:CreateLogStream" ], "Resource": "arn:aws:logs:<AWS_REGION>:<AWS_ACCOUNT_ID>:log-group:/aws/lambda/acme-dns-route53:*" }, { "Sid": "", "Effect": "Allow", "Action": [ "route53:ListHostedZones", "cloudwatch:PutMetricData", "acm:ImportCertificate", "acm:ListCertificates" ], "Resource": "*" }, { "Sid": "", "Effect": "Allow", "Action": [ "sns:Publish", "route53:GetChange", "route53:ChangeResourceRecordSets", "acm:ImportCertificate", "acm:DescribeCertificate" ], "Resource": [ "arn:aws:sns:<AWS_REGION>:<AWS_ACCOUNT_ID>:<TOPIC_NAME>", "arn:aws:route53:::hostedzone/*", "arn:aws:route53:::change/*", "arn:aws:acm:<AWS_REGION>:<AWS_ACCOUNT_ID>:certificate/*" ] } ] }
Now run the aws iam create-role
command to create the role:
$ aws iam create-role --role-name lambda-acme-dns-route53-executor \ --assume-role-policy-document ~/lambda-acme-dns-route53-executor-policy.json
Note: remember the policy ARN (Amazon Resource Name) - we will need it in the next steps.
The lambda-acme-dns-route53-executor
role is created, now we need to specify permissions for it. The easiest way to do this is to use the aws iam attach-role-policy
command, passing the policy ARN AWSLambdaBasicExecutionRole
as follows:
$ aws iam attach-role-policy --role-name lambda-acme-dns-route53-executor \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Note: a list with other policies can be found here .
Hooray! Now you can add our AWS function using the aws lambda create-function
command. Lambda must be configured using the following environment variables:
AWS_LAMBDA
- makes it clear to acme-dns-route53 that execution takes place inside AWS Lambda.DOMAINS
- comma separated list of domains.LETSENCRYPT_EMAIL
- contains Let's Encrypt Email .NOTIFICATION_TOPIC
is the name of the SNS Notification Topic (optional).STAGING
- if set to 1
, the staging environment is used.RENEW_BEFORE
— The number of days defining the period until the expiration of the period during which the certificate should be renewed.1024
MB - memory limit, can be changed.900
secs (15 min) - timeout.acme-dns-route53
is the name of our binary, which is in the archive.fileb://~/acme-dns-route53.zip
- the path to the archive that we created.Now deploy:
$ aws lambda create-function \ --function-name acme-dns-route53 \ --runtime go1.x \ --role arn:aws:iam::<AWS_ACCOUNT_ID>:role/lambda-acme-dns-route53-executor \ --environment Variables="{AWS_LAMBDA=1,DOMAINS=\"example1.com,example2.com\",LETSENCRYPT_EMAIL=begmaroman@gmail.com,STAGING=0,NOTIFICATION_TOPIC=acme-dns-route53-obtained,RENEW_BEFORE=7}" \ --memory-size 1024 \ --timeout 900 \ --handler acme-dns-route53 \ --zip-file fileb://~/acme-dns-route53.zip { "FunctionName": "acme-dns-route53", "LastModified": "2019-05-03T19:07:09.325+0000", "RevisionId": "e3fadec9-2180-4bff-bb9a-999b1b71a558", "MemorySize": 1024, "Environment": { "Variables": { "DOMAINS": "example1.com,example2.com", "STAGING": "1", "LETSENCRYPT_EMAIL": "your@email.com", "NOTIFICATION_TOPIC": "acme-dns-route53-obtained", "RENEW_BEFORE": "7", "AWS_LAMBDA": "1" } }, "Version": "$LATEST", "Role": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/lambda-acme-dns-route53-executor", "Timeout": 900, "Runtime": "go1.x", "TracingConfig": { "Mode": "PassThrough" }, "CodeSha256": "+2KgE5mh5LGaOsni36pdmPP9O35wgZ6TbddspyaIXXw=", "Description": "", "CodeSize": 8456317, "FunctionArn": "arn:aws:lambda:us-east-1:<AWS_ACCOUNT_ID>:function:acme-dns-route53", "Handler": "acme-dns-route53" }
The last step is to configure cron, which calls our function twice a day:
schedule_expression
.Below I attached my Terraform config, but in fact it is done very simply using the AWS console or the AWS CLI.
# Cloudwatch event rule that runs acme-dns-route53 lambda every 12 hours resource "aws_cloudwatch_event_rule" "acme_dns_route53_sheduler" { name = "acme-dns-route53-issuer-scheduler" schedule_expression = "cron(0 */12 * * ? *)" } # Specify the lambda function to run resource "aws_cloudwatch_event_target" "acme_dns_route53_sheduler_target" { rule = "${aws_cloudwatch_event_rule.acme_dns_route53_sheduler.name}" arn = "${aws_lambda_function.acme_dns_route53.arn}" } # Give CloudWatch permission to invoke the function resource "aws_lambda_permission" "permission" { action = "lambda:InvokeFunction" function_name = "${aws_lambda_function.acme_dns_route53.function_name}" principal = "events.amazonaws.com" source_arn = "${aws_cloudwatch_event_rule.acme_dns_route53_sheduler.arn}" }
Now you are configured to automatically create and update SSL certificates.
Source: https://habr.com/ru/post/451848/
All Articles