上下文:要实现完整的“基础结构即代码”,我想对以下过程进行编码:使用certbot
请求SSL证书,使用DNS TXT
记录验证域,将证书上传到Amazon Certificate Manager(ACM),最后将证书ACM ARN附加到我的Cloudfront发行版中。所有这些都应通过无服务器框架完成。
我看到了2个可能的选项可以使这项工作。
选项1:使用异步javascript文件变量
即在serverless.yml
中,我将定义以下条目:
custom:
domains:
prod: tommedema.tk
ssl:
prod:
dnsTxtRoot: ${{file(scripts/request-cert.js):cert.dnsTxtRoot}}
dnsTxtWww: ${{file(scripts/request-cert.js):cert.dnsTxtWww}}
certArn: ${{file(scripts/request-cert.js):cert.certArn}}
然后资源将在何处使用这些变量,如下所示:
- Type: TXT
Name: _acme-challenge.www.${{self:custom.domains.${{self:provider.stage}}, ''}}
TTL: '86400'
ResourceRecords:
- ${{self:custom.ssl.${{self:provider.stage}}.dnsTxtWww}}
scripts/request-cert.js
如下所示:module.exports.cert = () => {
console.log('running async logic')
// TODO: run certbot, get DNS records, upload to ACM
return Promise.resolve({
dnsTxtRoot: '"LnaKMkgqlIkXXXXXXXX-7PkKvqb_wqwVnC4q0"',
dnsTxtWww: '"c43VS-XXXXXXXXXWVBRPCXXcA"',
certArn: 'arn:aws:acm:us-east-1:XXXX95:certificate/XXXXXX'
})
}
这里的问题是,似乎无法将参数发送到
request-cert.js
,或者此脚本无法知道serverless
或options
插件参数(因为它不是插件,而是没有上下文的简单脚本) )。这意味着脚本无法知道部署所针对的阶段和领域等,因此缺少用于请求证书的必要变量。因此,选项1似乎是不可能的。
选项2:创建插件
当然,我可以创建一个插件,该插件将具有所有必需的变量,因为它可以访问
serverless
和options
对象。现在的问题是,我将不得不访问serverless.yml
中插件的输出,到目前为止,我还没有看到如何做到这一点。即我希望能够做这样的事情:custom:
domains:
prod: tommedema.tk
ssl:
prod:
dnsTxtRoot: ${{myPlugin:cert.dnsTxtRoot}}
dnsTxtWww: ${{myPlugin:cert.dnsTxtWww}}
certArn: ${{myPlugin:cert.certArn}}
但这似乎是不可能的。那正确吗?
如果这也是不可能的,我如何实现我的目的,以编程方式(即遵循基础结构作为代码原则)使用自定义SSL证书部署服务,而无需任何手动步骤?即
向certbot请求证书
从certbot接收DNS txt记录以进行验证
将DNS txt记录附加到route53记录集
部署DNS记录并验证证书
从certbot下载证书并将其上传到ACM
收到ACM颁发的ARN证书
从cloudformation模板内部的cloudfront分发中引用证书ARN
重新部署附有证书ARN的证书
最佳答案
您可以在部署时执行此操作,但是证书会过期,因此最好使它重复出现。
遇到此问题时,我创建了一个Lambda来向上插入SSL证书并进行安装。 (它需要很长的超时时间,但这很好-它不需要经常运行)。它需要的密钥可以作为安全的环境变量给出。
然后,我使用serverless-warmup-plugin
设置每日触发器,以检查证书是否应更新。该插件也可配置为预热部署中的相关lambda,这使我可以在每次部署中检查是否存在过期或丢失的SSL证书。
也许您可以做类似的事情。