GCTT|通过Docker和Go实现https访问标题图片

GCTT|通过Docker和Go实现https访问


最近一直在构建很多 Webhook,通常我需要通过 HTTPS 协议为应用程序提供服务。快速实现这一目标的一种常见方法是使用 Let's Encrypt,但设置起来可能有点繁琐。我希望能够将这个过程完全自动化,包括证书更新。我一直在使用 docker 来构建我的应用程序,并且希望保持构建过程和容器镜像尽可能轻量级。最后,我想将整个过程作为应用程序代码,这样我可以轻松地进行动态更改和重新部署。此外,不依赖运维 /shell 脚本,我的应用程序可移植并轻松部署到许多不同的环境。

幸运的是,使用Go acme/autocert包可以实现所有这些功能。ACME表示自动证书管理环境,是一种低成本和自动化 TLS 证书生成和验证的协议。

Let's Encrypt 是利用 ACME向任何要求认证域的人提供免费的域名证书认证。验证的一种方法是应用程序从 Let's Encrypt(通过安全连接)请求秘钥令牌,然后 Let's Encrypt 将对正在验证的域名发出HTTP 请求。如果应用程序可以将秘钥令牌提供给 Let's Encrypt,则验证该域名具有对域的控制权,并且 Let's Encrypt 将签署证书以在域上使用。

Let's get cooking

let's_get_cooking首先你需要有一个域名。只要能将应用程序部署到该域所托管的服务上,任何域 /子域都可以。您可以拥有多个域,例如,您可以在同一个应用程序中托管和验证 chat.example.com和www.example.com。对于此示例,我将在kappa.serv.brendanr.net 上托管我的应用程序。理想情况下,您的应用程序不会进行负载平衡 - 虽然可以在负载平衡域上实现 ACME 验证,但它更复杂。

接下来,你需要一个可以部署应用的服务器。确保配置 DNS服务器以将域名指向该服务器。

最后,您需要使用上文提到的 acme/autocert 包来请求和响应 ACME 请求。Krzysztof Kowalczyk 提供了一个很好的示例,您可以阅读它,但我将向您展示一个为更简单的版本以便更好地解释它是如何工作的。

应用代码1funcmain(){
2mux:=http.NewServeMux()
3mux.HandleFunc('/',func(whttp.ResponseWriter,r*http.Request){
4w.Write([]byte('Helloworld'))
5})
6
7certManager:=autocert.Manager{
8Prompt:autocert.AcceptTOS,
9Cache:autocert.DirCache('cert-cache'),
10//Putyourdomainhere:
11HostPolicy:autocert.HostWhitelist('kappa.serv.brendanr.net'),
12}
13
14server:= http.Server{
15Addr:':443',
16Handler:mux,
17TLSConfig: tls.Config{
18GetCertificate:certManager.GetCertificate,
19},
20}
21
22Gohttp.ListenAndServe(':80',certManager.HTTPHandler(nil))
23server.ListenAndServeTLS('','')
24}
逐步分解
1mux:=http.NewServeMux()
2mux.HandleFunc('/',func(whttp.ResponseWriter,r*http.Request){
3w.Write([]byte('Helloworld'))
4})

在这里,我们设置首页请求处理程序。一旦你开始着手去做 , 你应该以同样的方式为你的应用程序去注册处理函数。

1certManager:=autocert.Manager{
2Prompt:autocert.AcceptTOS,
3Cache:autocert.DirCache('cert-cache'),
4HostPolicy:autocert.HostWhitelist('kappa.serv.brendanr.net'),
5}

上述代码为 ACME 相关配置信息。Prompt: autocert.AcceptTOS 字段意味着您接受了 Let's Encrypt 的服务条款。Cache字段指定 autocert 包是否缓存以及缓存证书的方式。Let's Encrypt 存在请求速率 限制,限制了您申请证书的频率,因此将证书存储在后续可以检索的地方非常重要。这里我们指定证书存储在 cert-cache 目录中。最后,HostPolicy 字段允许我们将期望申请证书的域名加入白名单。如果没有该设置,攻击者可能会耗尽所分配的速率限额,并可能会阻止您生成所需的证书,因此配置该字段很重要。

1server:= http.Server{
2Addr:':443',
3Handler:mux,
4TLSConfig: tls.Config{
5GetCertificate:certManager.GetCertificate,
6},
7}
8
9gohttp.ListenAndServe(':80',certManager.HTTPHandler(nil))
10server.ListenAndServeTLS('','')

最后,我们配置并启动 HTTP 和 HTTPS 服务。HTTPS服务将使用我们之前编写的处理程序进行响应。在响应HTTPS请求时,会自动获取HTTPS 证书(来自缓存或 Let's Encrypt)。HTTP服务专门用于允许 Let's Encrypt 对我前面提到的秘钥令牌发出请求。也可以将HTTP服务重定向到 HTTPS -- 请查看之前的示例。

构建和部署您的应用程序,并向其发出 https 请求!虽然应用程序第一次使用 Let's Encrypt 进行 ACME质询流程请求时会有几秒耗时,但您的应用程序仍将使用安全可靠的 HTTPS 页面进行响应。

You promised me Docker

在容器化这个应用程序前,你需要避免几个问题。以下是完整的Dockerfile。我正在使用的这个 Dockerfile 是基于 Pierre Prinetti Go 1.11 Web service Dockerfile 的修改版本。

1#设置构建镜像的Go版本参数
2#默认版本Go1.11
3ARGGO_VERSION=1.11
4
5#第一步:构建可执行程序。
6FROMGolang:${GO_VERSION}-alpineASbuilder
7
8#获取 Git 需要的依赖项。
9RUNapkadd--no-cacheca-certificatesGit
10
11#设置除$GOPATH 以外的工作目录来确保对模块的支持。
12WORKDIR/src
13
14#首先获取依赖包;它们在每次构建过程中变化不大,因此将会缓存以加速下一次构建。
15RUNGomoddownload
16
17#从上下文导入代码
18COPY././
19
20#将可执行程序构建为`/app`,将构建标记为静态链接。
21RUNCGO_ENABLED=0Gobuild\
22-installsuffix'static'\
23-o/app.
24
25#最后一步:运行容器
26FROMscratchASfinal
27
28#从第一阶段导入已编译的可执行文件。
29COPY--from=builder/app/app
30#导入根ca证书(需要Let'sEncrypt)
31COPY--from=builder/etc/ssl/certs/ca-certificates.crt/etc/ssl/certs/
32
33 #应用程序提供 443 和 80服务端口。
34EXPOSE443
35EXPOSE80
36
37 #将证书缓存目录挂载至本地磁盘,这样在部署新版本时仍然存在。
38VOLUME['/cert-cache']
39
40#运行编译的二进制文件。
41ENTRYPOINT['/app']

Dockerfile分两个阶段,构建和最终阶段。这使我们能够发送极小的最终镜像 - 我们甚至可以使用scratch(空的分层)作为基础。上面的代码和 Dockerfile 最终构建了一个只有 7 MB的镜像!

注意事项:

您必须在最终镜像上安装 ca-certificates,即使您的应用程序未进行 TLS 连接也是如此。这是因为您的应用程序将对 Let's Encrypt 发起的所有请求都是基于 HTTPS,因此您需要根证书。

即使您不打算通过 HTTP 提供任何服务,也必须开放 80 端口。这是因为 Let's Encrypt 需要能够向我们的应用程序发出 HTTP 请求。

您应该将缓存目录缓存至本地磁盘,即便在部署过程中也会缓存证书。如果你不这样做,你可能会超出 Let's Encrypt 速率限制。

总结一下

我希望这篇文章可以帮助您在设置下一个 Web 服务时减少一些时间和困惑,或者至少让您有兴趣再写一些 Go。

完整的代码可查看

https://github.com/bmon/go-web-base

最初发表在

brendanr.net。

via: https://medium.com/weareservian/automagical-https-with-docker-and-go-4953fdaf83d2

作者:Brendan Roy
译者:liulizhi
校对:polaris1119

最新回复 (0)
    • 小鱼在线
      2
          喵
返回