📜 ⬆️ ⬇️

Automation of management of Let's Encrypt SSL certificates using DNS-01 challenge and AWS

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.


Create zip file


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.


Creating an IAM Role


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 .


Creating a lambda function that runs acme-dns-route53


Hooray! Now you can add our AWS function using the aws lambda create-function command. Lambda must be configured using the following environment variables:



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" } 

Creating a CloudWatch timer that triggers the function 2 times a day


The last step is to configure cron, which calls our function twice a day:



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