这篇文章介绍了使用Let's Encrypt作为自动证书颁发机构(它提供维护良好的API)来设置自动SSL证书创建和更新所需的步骤。
acme-dns-route53
是一种工具,可通过带有Route53的 DNS-01质询和AWS的Amazon Certificate Manager从Let's Encrypt获得SSL证书。 acme-dns-route53
还具有内置功能,可以在AWS Lambda中使用此工具,这就是我们要做的。
这篇文章分为4个部分:
- 建立一个独立的,可部署的zip文件
- 为lambda函数创建一个IAM角色,使其具有执行所需的权限
- 创建一个执行
acme-dns-route53
的lambda函数 - 创建每天两次触发lambda函数的CloudWatch计时器
注意:开始之前,请确保已安装GoLang 1.9+和AWS CLI。
构建一个独立的,可部署的zip文件
acme-dns-route53
用acme-dns-route53
编写,支持版本不少于1.9。 我们需要创建一个独立的,可部署的zip文件,其中包含acme-dns-route53
工具的可执行文件。
第一步是使用go install
命令从acme-dns-route53
工具的远程GitHub存储库中构建可执行文件:
$ env GOOS=linux GOARCH=amd64 go install github.com/begmaroman/acme-dns-route53
该可执行文件将安装在$GOPATH/bin
目录中。 重要提示:作为此命令的一部分,我们使用env在命令持续时间内临时设置两个环境变量( GOOS=linux
和GOARCH=amd64
)。 这些指令指示Go编译器创建适用于Linux OS和amd64架构的可执行文件-当我们将其部署到AWS时,它将在运行该可执行文件。
AWS要求我们将lambda函数上传到一个zip文件中,因此让我们制作一个acme-dns-route53.zip
zip文件,其中包含我们刚刚创建的可执行文件:
$ zip -j ~/acme-dns-route53.zip $GOPATH/bin/acme-dns-route53
请注意,可执行文件必须位于zip文件的根目录中-而不是zip文件中的文件夹中。 为了确保这一点,我在上面的片段中使用了-j
标志来填充目录名。
现在可以部署该zip文件,但是它仍然需要运行权限。
为lambda函数创建一个IAM角色,使其具有执行所需的权限
我们需要设置一个IAM角色,该角色定义lambda函数在运行时将具有的权限。
现在,让我们设置一个lambda-acme-dns-route53-executor
角色,并将AWSLambdaBasicExecutionRole
托管策略附加到该角色。 这将为我们的lambda函数提供运行和登录到AWS CloudWatch服务所需的基本权限。
首先,我们必须创建一个信任策略JSON文件。 这实际上将指示AWS允许lambda服务承担lambda-acme-dns-route53-executor
角色:
$ touch ~/lambda-acme-dns-route53-executor-policy.json
创建的JSON文件的内容应为以下内容:
{ "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/*" ] } ] }
然后使用aws iam create-role
命令使用此信任策略创建角色:
$ aws iam create-role --role-name lambda-acme-dns-route53-executor \ --assume-role-policy-document ~/lambda-acme-dns-route53-executor-policy.json
记下返回的ARN(Amazon资源名称)-下一步将需要它。
现在,已经创建了lambda-acme-dns-route53-executor
角色,我们需要指定该角色具有的权限。 最简单的方法是使用aws iam attach-role-policy
命令,传入AWSLambdaBasicExecutionRole
权限策略的ARN, AWSLambdaBasicExecutionRole
所示:
$ aws iam attach-role-policy --role-name lambda-acme-dns-route53-executor \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
注意:您可以在此处找到其他可能有用的权限策略列表。
创建一个执行acme-dns-route53的lambda函数
现在,我们准备将lambda函数实际部署到AWS,我们可以使用aws lambda create-function
命令来完成。 lambda函数需要配置以下选项:
- 值为
1
AWS_LAMBDA
环境变量,用于调整在Lambda内部函数中使用的工具。 DOMAINS
是环境变量,包含要为其颁发证书的域的逗号分隔列表。LETSENCRYPT_EMAIL
是环境变量,其中包含“让我们加密到期电子邮件”。NOTIFICATION_TOPIC
是包含SNS通知主题ARN的环境变量。STAGING
是环境变量,使用暂存“加密环境”时必须包含1
值,而对于生产环境则必须包含0 1
值。RENEW_BEFORE
是定义过期前必须更新证书的期限的天数。1024
MB是内存限制(可以根据需要更改)。- 最大超时时间为
900
秒(15分钟)。 acme-dns-route53
是lambda函数的处理程序名称。fileb://~/acme-dns-route53.zip
是上面创建的.zip文件。
继续尝试部署它:
$ 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" }
创建每天触发一次lambda函数的CloudWatch计时器
最后一步是为该功能创建每日触发器。 为此,我们可以:
- 使用所需的
schedule_expression
(何时运行)创建CloudWatch规则。 - 创建一个指定lambda函数的ARN的规则目标(应该运行的目标)。
- 授予CloudWatch规则权限以调用lambda函数。
我在下面为其粘贴了Terraform配置,但是从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}" }
现在您也可以100%自动执行TLS证书续订!