自动管理Mesosphere Marathon上运行的应用程序的Let's Encrypt证书
项目描述
自动为ACME证书Marathon应用程序marathon-lb
工作原理
部署marathon-acme的一个主要要求是:必须在marathon-acme和所有marathon-lb实例之间有共享持久存储。这将用于存储证书。
marathon-acme监视Marathon以检测应用程序定义的更改。
它收集所有应用程序上MARATHON_ACME_{n}_DOMAIN标签的值。这将形成要获取证书的域名集。
它使用配置的ACME证书颁发机构为任何新的域名生成、验证和存储证书。
它通过marathon-lb HTTP API告诉marathon-lb重新加载。
它每天为即将到期的证书颁发新的证书。
marathon-acme是用Python编写的,使用了Twisted。证书颁发功能得益于txacme库。
大多数人可能最有可能使用的ACME提供商是Let’s Encrypt。在使用Let’s Encrypt与marathon-acme之前,请确保您了解他们的速率限制。
以下展示了整个证书颁发工作流程
用法
marathon-acme可作为Python包在PyPI上安装。然而,大多数用户可能会选择使用来自Docker Hub的Docker镜像。
> $ docker run --rm praekeltfoundation/marathon-acme --help usage: marathon-acme [-h] [-a ACME] [-e EMAIL] [-m MARATHON[,MARATHON,...]] [-l LB[,LB,...]] [-g GROUP] [--allow-multiple-certs] [--listen LISTEN] [--sse-timeout SSE_TIMEOUT] [--log-level {debug,info,warn,error,critical}] storage-dir Automatically manage ACME certificates for Marathon apps positional arguments: storage-dir Path to directory for storing certificates optional arguments: -h, --help show this help message and exit -a ACME, --acme ACME The address for the ACME Directory Resource (default: https://acme-v01.api.letsencrypt.org/directory) -e EMAIL, --email EMAIL An email address to register with the ACME service (optional) -m MARATHON[,MARATHON,...], --marathon MARATHON[,MARATHON,...] The addresses for the Marathon HTTP API (default: http://marathon.mesos:8080) -l LB[,LB,...], --lb LB[,LB,...] The addresses for the marathon-lb HTTP API (default: http://marathon-lb.marathon.mesos:9090) -g GROUP, --group GROUP The marathon-lb group to issue certificates for (default: external) --allow-multiple-certs Allow multiple certificates for a single app port. This allows multiple domains for an app, but is not recommended. --listen LISTEN The address for the port to listen on (default: :8000) --sse-timeout SSE_TIMEOUT Amount of time in seconds to wait for some event data to be received from Marathon. Set to 0 to disable. (default: 60) --log-level {debug,info,warn,error,critical} The minimum severity level to log messages at (default: info) --version show program's version number and exit
marathon-acme应用定义
marathon-acme应作为Marathon应用部署。
{
"id": "/marathon-acme",
"cpus": 0.01,
"mem": 128.0,
"args": [
"--email", "letsencrypt@example.com",
"--marathon", "http://marathon1:8080,http://marathon2:8080,http://marathon3:8080",
"--lb", "http://lb1:9090,http://lb2:9090",
"/var/lib/marathon-acme"
],
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "marathon-acme.example.com",
"HAPROXY_0_BACKEND_WEIGHT": "1",
"HAPROXY_0_PATH": "/.well-known/acme-challenge/",
"HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH": " acl host_{cleanedUpHostname} hdr(host) -i {hostname}\n acl path_{backend} path_beg {path}\n redirect prefix http://{hostname} code 302 if !host_{cleanedUpHostname} path_{backend}\n use_backend {backend} if host_{cleanedUpHostname} path_{backend}\n"
},
"container": {
"type": "DOCKER",
"docker": {
"image": "praekeltfoundation/marathon-acme",
"network": "BRIDGE",
"portMappings": [
{ "containerPort": 8000, "hostPort": 0 }
],
"parameters": [
{
"value": "my-volume-driver",
"key": "volume-driver"
},
{
"value": "marathon-acme-certs:/var/lib/marathon-acme",
"key": "volume"
}
],
}
}
}
上述内容在不同部署中应大多相同。卷参数将取决于您的特定网络存储解决方案。
HAPROXY标签
"labels": {
"HAPROXY_GROUP": "external",
"HAPROXY_0_VHOST": "marathon-acme.example.com",
"HAPROXY_0_BACKEND_WEIGHT": "1",
"HAPROXY_0_PATH": "/.well-known/acme-challenge/",
"HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH": " acl host_{cleanedUpHostname} hdr(host) -i {hostname}\n acl path_{backend} path_beg {path}\n redirect prefix http://{hostname} code 302 if !host_{cleanedUpHostname} path_{backend}\n use_backend {backend} if host_{cleanedUpHostname} path_{backend}\n"
}
为了将所有以/.well-known/acme-challenge/开头的HTTP请求转发到marathon-acme以服务ACME HTTP挑战响应,需要几个特殊的marathon-lb标签。
HAPROXY_GROUP
external
marathon-lb实例被分配一个组。只有具有与其组匹配的HAPROXY_GROUP标签的Marathon应用才会通过该实例进行路由。“external”是面向公众的负载均衡器的常用名称。
HAPROXY_0_VHOST
marathon-acme.example.com
marathon-acme需要一个自己的域名来响应ACME挑战请求。此域名必须解析到您的marathon-lb实例。
HAPROXY_0_BACKEND_WEIGHT
1
我们希望这个规则在HAProxy的配置文件中位于其他规则之前,以便在为其他Marathon应用进行(通常基于域名的)路由之前将请求路由到marathon-acme。默认权重是0,因此将其设置为1,以便该规则优先。
HAPROXY_0_PATH
/.well-known/acme-challenge/
这是ACME验证挑战的HTTP路径的开始。
HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH
acl host_{cleanedUpHostname} hdr(host) -i {hostname} acl path_{backend} path_beg {path} redirect prefix http://{hostname} code 302 if !host_{cleanedUpHostname} path_{backend} use_backend {backend} if host_{cleanedUpHostname} path_{backend}
这变得复杂了……可以使用标签按应用编辑用于生成HAProxy的模板。这是必要的,因为默认情况下,marathon-lb将首先根据域名进行路由,但我们不想这样做。您可以在此处看到标准模板。
在此,我们添加了一个额外的redirect规则。该规则将所有匹配ACME挑战路径的请求重定向到marathon-acme,但不会将已指向marathon-acme的请求重定向。Let’s Encrypt服务器将遵循重定向。
HAPROXY HTTPS标签
虽然通常不需要,但marathon-acme可以在HTTPS上服务ACME挑战请求。在这种情况下,需要为marathon-acme颁发证书,并且需要修改HTTP重定向标签。
"labels": {
...,
"MARATHON_ACME_0_DOMAIN": "marathon-acme.example.com",
"HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH": " acl host_{cleanedUpHostname} hdr(host) -i {hostname}\n acl path_{backend} path_beg {path}\n redirect prefix https://{hostname} code 302 if path_{backend}\n"
}
请注意,使用marathon-acme的HAPROXY_0_REDIRECT_TO_HTTPS标签将破坏一切。由于marathon-lb模板的方式,该标签对我们来说很难使用。
MARATHON_ACME_0_DOMAIN
marathon-acme.example.com
在此,我们为marathon-acme设置获取证书。
HAPROXY_0_HTTP_FRONTEND_ACL_WITH_PATH
acl host_{cleanedUpHostname} hdr(host) -i {hostname} acl path_{backend} path_beg {path} redirect prefix https://{hostname} code 302 if path_{backend}
我们将所有域名(包括 marathon-acme 的)对 ACME 挑战路径的请求重定向到 HTTPS 地址(https://{hostname})。现在可以删除 use_backend 指令,因为后端永远不会通过 HTTP 使用,因为所有请求都进行了重定向。
注意,此标签只能在 marathon-acme 获取其自身域的第一个证书之后设置。换句话说,首先设置 MARATHON_ACME_0_DOMAIN,并确保它已经生效,然后再设置此标签。
Docker 镜像
Docker Hub(https://hub.docker.com/r/praekeltfoundation/marathon-acme/)上提供了 Docker 镜像。有两种不同的 Docker 镜像流可供使用
:latest/:<version>:跟踪 PyPI 上 marathon-acme 的最新发布版本。这些 Dockerfile 在 praekeltfoundation/docker-marathon-acme 仓库中。
:develop:跟踪此仓库的 develop 分支,并使用此仓库中的 Dockerfile 构建。
有关 Docker 镜像的更多详细信息,请参阅 praekeltfoundation/docker-marathon-acme 仓库。
卷和端口
marathon-acme 容器默认将 /var/lib/marathon-acme 目录用于存储证书和 ACME 客户端私钥。这是容器内部应该挂载为共享卷的路径。
容器还默认在所有接口上监听端口 8000。
您可以通过向 Docker 容器提供参数来覆盖这些值。
证书文件
marathon-acme 创建以下目录/文件结构
/var/lib/marathon-acme/
client.key:ACME 客户端私钥
default.pem:为 HAProxy 备用的自签名通配符证书
certs/
www.example.com.pem:针对域签发的 ACME 证书
unmanaged-certs/:未管理证书的目录
在创建 unmanaged-certs/ 目录后,marathon-acme 对其不做任何操作。如果 HAProxy 的证书配置中的任何路径不存在,则会失败,因此将未管理的证书放置在标准位置可以减少设置摩擦。
marathon-lb 配置
为了能够触发 HAProxy 重新加载,marathon-acme 需要 marathon-lb 1.4.0 或更高版本。
如前所述,marathon-lb 必须与 marathon-acme 共享持久存储。BYONS:自携网络存储。
marathon-lb 所需的唯一真实配置是将 marathon-acme 的证书存储目录路径添加为证书来源。HAProxy 支持从目录加载证书。您应将 marathon-lb 的 --ssl-certs CLI 选项设置为证书目录路径以及备用证书(如果 HAProxy 在提供的路径中找不到任何证书,则无法启动)。
--ssl-certs <storage-dir>/certs,<storage-dir>/default.pem
应用配置
marathon-acme 使用单个类似 marathon-lb 的标签将域名分配给应用程序端口:MARATHON_ACME_{n}_DOMAIN,其中 {n} 是端口号索引。标签的值是一组以逗号和/或空格分隔的域名,尽管默认情况下只考虑第一个域名。
目前,marathon-acme 只能针对单个域名颁发证书。这意味着对于配置了多个域名的应用程序,需要颁发多个证书。
增加了一个限制,将应用程序限制为单个域名。可以通过传递 --allow-multiple-certs 命令行选项来移除此限制,尽管这不建议使用,因为这使得可以为单个应用程序颁发大量证书,可能会耗尽 Let’s Encrypt 的速率限制。
应用程序或其端口必须与在启动时配置 marathon-acme 的同一 HAPROXY_GROUP 。
我们决定不重复使用 HAPROXY_{n}_VHOST 标签,以限制颁发的证书所针对的域名数量。
限制
用于 ACME 证书管理的库 txacme,目前其功能相当有限。最大的两个限制是
目前还没有 Subject Alternative Name (SAN) 支持 (#37)。每个证书将对应于确切的一个域名。这个限制使得更容易达到 Let’s Encrypt 的速率限制。
没有支持从 txacme 的证书存储中 删除 证书 (#77)。一旦 marathon-acme 为应用程序颁发了一个证书,它将尝试无限期地续订该证书,除非手动从证书存储中删除。
有关问题的更完整列表,请参阅此存储库的问题页面。
故障排除
挑战 ping 端点
一个常见问题是 marathon-lb 配置错误,ACME 挑战请求无法到达 marathon-acme。您可以使用挑战 ping 端点测试挑战请求路由到 marathon-acme。
应该能够从 marathon-lb 服务的所有域名访问 /.well-known/acme-challenge/ping 路径。
> $ curl cake-service.example.com/.well-known/acme-challenge/ping {"message": "pong"} > $ curl soda-service.example.com/.well-known/acme-challenge/ping {"message": "pong"}
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源分布
构建分布
marathon-acme-0.6.1.tar.gz 的哈希
算法 | 哈希摘要 | |
---|---|---|
SHA256 | c001e77101a0f63b16ee5e36cbf8d628e6dc3c35281d38dd5f9c264a6d901bc3 |
|
MD5 | b5457854dedc36cc7e6bff3e7c6cfd4f |
|
BLAKE2b-256 | 82a0c37cbb0810245ffbf03fc052daa1cddb97994b86ee9ed962b49cdaa031fe |
marathon_acme-0.6.1-py2.py3-none-any.whl 的哈希
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 01d7d74e22931206436ef2ad0147e1b8eed3ff8177b7f9db48e17f4cdf34ef0c |
|
MD5 | 0a7d9691b1a772922529653f863c858b |
|
BLAKE2b-256 | 7154d9f1dd09c691a69a1956e752f31e93965375fbfa23634e721d5def4d10df |