上下文:要实现完整的“基础结构即代码”,我想对以下过程进行编码:使用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,或者此脚本无法知道serverlessoptions插件参数(因为它不是插件,而是没有上下文的简单脚本) )。这意味着脚本无法知道部署所针对的阶段和领域等,因此缺少用于请求证书的必要变量。

因此,选项1似乎是不可能的。

选项2:创建插件

当然,我可以创建一个插件,该插件将具有所有必需的变量,因为它可以访问serverlessoptions对象。现在的问题是,我将不得不访问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证书。

也许您可以做类似的事情。

08-25 21:50