我想通过 Puppet 设置和配置 Apache,并使用以下方式申请 SSL 证书acme_tiny.py。除了第一次启动之外,我的 Puppet 类和资源在大多数情况下都可以用于 Web 服务器和 acme-tiny 工作。
不幸的是,acme_tiny 需要一个正在运行的 Web 服务器,该服务器直到 acme_tiny 资源成功完成后才会启动。我想象流程应该是这样的:
安装 Apache -> 启动 Apache -> 配置 HTTP vhost -> 重新加载 Apache -> 运行 acme_tiny -> 配置 HTTPS vhost -> 重新加载 Apache
问题是资源“apache2 reload”在 Puppet 中只能存在一次,如果我在两者之间排序 acme_tiny 资源,就会出现依赖循环。此外,每次创建新的 vhost 时,资源也由 puppetlabs/apache 模块管理,但只在最后应用。目前,流程如下:
安装 Apache -> 启动 Apache -> 配置 HTTP vhost -> 运行 acme_tiny(失败)-> 配置 HTTPS vhost(由于依赖项失败而跳过)-> 配置其他所有内容 -> 重新加载 Apache(由于依赖项失败而跳过)
如果我在第一次运行后手动启动 Apache2,一切都会正常:证书已检索,HTTPS vhost 已创建,Web 服务器已重新加载。不幸的是,如果没有手动干预,它就无法工作。
我的 acme-tiny 资源如下所示:
exec { "${url}.crt":
command => "acme_tiny.py --quiet --account-key ./${url}_account.key --csr ./${url}.csr --acme-dir /home/web/${url}/www > ${url}.crt",
path => [ '/usr/bin', '/usr/local/bin' ],
cwd => $profile::apache::params::ssl_dir,
require => File['acme_tiny.py'],
subscribe => File["${profile::apache::params::ssl_dir}/${url}.csr"],
notify => Service['apache2'],
}
有人知道如何修复这个问题吗?理想情况下,所有操作都应该在一次 Puppet 运行中完成,次优选择是如果需要第二次 Puppet 运行而无需人工干预。本质上,如果 acme_tiny 失败,只有 HTTPS vhost 的配置应该会失败,而不会重新加载 Apache。
答案1
我设法通过一些肮脏的手段做到了这一点,但至少它有效。
我看到 Puppet 安装软件包后,Apache 已经在默认 Debian 设置中运行,但 Puppet 重新配置了它(并apache reload
在最后发出)。幸运的是,Web 服务器已经响应全部通过提供静态文件来提供请求。
然后我将 acme_tiny 资源分成两部分:设置和更新:对于设置,Puppet 首先创建文件夹/var/www/html/.well-known/acme-challenge
,然后执行以下 exec:
# Request a new certificate if the crt file does not yet exist
exec { "${url}.crt initial":
command => "acme_tiny.py --quiet --account-key ./${url}_account.key --csr ./${url}.csr --acme-dir /var/www/html/.well-known/acme-challenge > ${url}.crt",
creates => "${profile::apache::params::ssl_dir}/${url}.crt",
path => [ '/usr/bin', '/usr/local/bin' ],
cwd => $profile::apache::params::ssl_dir,
require => [ File['acme_tiny.py'], File['/var/www/html/.well-known/acme-challenge'] ],
subscribe => File["${profile::apache::params::ssl_dir}/${url}.csr"],
notify => Service['apache2'],
}
如果证书已经存在(因此存在参数creates
),则不会执行此资源。
在每次后续运行时,将执行更新执行程序:
exec { "${url}.crt renewal":
command => "acme_tiny.py --quiet --account-key ./${url}_account.key --csr ./${url}.csr --acme-dir /home/web/${url}/www > ${url}.crt",
unless => ["openssl x509 -checkend 2592000 -noout -in ${url}.crt",
"test ! -f ${url}.crt" ],
path => [ '/usr/bin', '/usr/local/bin' ],
cwd => $profile::apache::params::ssl_dir,
require => File['acme_tiny.py'],
subscribe => File["${profile::apache::params::ssl_dir}/${url}.csr"],
notify => Service['apache2'],
}
仅当现有证书有效期少于一个月时,此 exec 才会执行和如果证书已经存在。
这应该使 execs 互相排斥,以便在一次 Puppet 运行中只执行一个 exec。
仍有一些设置需要进行(即使在初始设置之后也必须创建一个默认的 vhost,例如,如果您想在已经运行的 Web 服务器中配置第二个 vhost),但我目前它运行得很好。
这并不能解决 Puppet 的问题(因为它目前依赖于 Apache 的一个“功能”),但实际上我非常怀疑 Puppet 是否可以做到这一点:Puppet 的一个核心功能是每个资源只能应用一次。