使用 Puppet 配置云应用:全面指南
证书安全与分布式目录创建
为了确保云实例的安全性,为每个新的云实例创建一个 UUID 作为 Puppet 证书的通用名称是更安全的做法。首先,准备一个基础镜像,其中包含一个简单的
puppet.conf
文件,该文件仅包含
[main]
部分,且没有
certname
选项。然后,对引导脚本进行简单扩展:
#!/bin/bash
export PATH=/bin:/usr/bin
if ! grep -q ^certname /etc/puppet/puppet.conf ; then
CERT=`cat /proc/sys/kernel/random/uuid`
echo "certname = $CERT" >>/etc/puppet/puppet.conf
else
CERT=`puppet agent --configprint certname`
fi
DIR=`puppet agent --configprint certdir`
[ -f "${DIR}/${CERT}.pem" ] && exit 0
puppet agent --onetime --no-daemonize --waitforcert 300
这种无描述性的证书名称使得识别可能的恶意 CSR 变得困难。为了恢复一定的安全性,可以将 DNS 名称作为自定义属性添加到 CSR 中。
不建议为每个角色签署一个万能证书并在所有云代理之间共享,因为这不安全,并且 Puppet 内部对每个代理的证书名称唯一性有较深的依赖,例如 PuppetDB 就使用
$certname
。
分布式目录创建
如果云服务的设计能让每个实例通过负载均衡实现自我管理,可能可以跳过此部分。但在实际情况中,参与云服务的节点可能需要相互交互,例如配置消息队列、通过 SSH 向对等节点发出命令或实现自定义负载均衡等。
在这些场景下,所有实例需要形成可扩展的子服务网络,整个系统必须能够应对实例的任意加入和离开。这就要求 Puppet 维护每个实例配置的某些部分,包含其他节点的详细信息,Puppet 通过导出资源来支持这种分布式知识。
例如,导出的防火墙规则是导出资源的典型示例,它向相关节点分发以下信息:
- 最重要的信息几乎总是本地节点的 IP 地址。
- 导出资源还携带导出者的能力信息,如防火墙规则中会包含导出者愿意共享的一个或多个端口。
假设云使用基于 SSH 的 RPC 系统,可以通过以下方式构建云节点之间共享的资源:
define rcmd::command($runner, $user, $id) {
file {
"/etc/rcmd/${name}.d/${id}":
ensure => 'file',
content => "${user}@${runner}\n";
}
}
@@rcmd::command {
[ 'clear-cache', 'reload-config' ]:
runner => $ipaddress,
user => hiera('rcmd::user', 'rcmd'),
id => $clientcert,
}
每个节点必须自行管理可用目录,使用
file
类型的
purge
参数可以清理不再出现在导出资源数据库中的节点:
define rcmd::command_dir() {
include rcmd::base_dir
file {
"/etc/rcmd/${name}.d":
ensure => 'directory',
owner => 'root',
mode => 644,
recurse => true,
purge => true,
}
}
rcmd::command_dir { [ 'clear-cache', 'reload-config', … ]: }
# import peer nodes' configs
Rcmd::Command<<| |>>
# also use own exports
Rcmd::Command<| |>
# the class to make sure that /etc/rcmd exists
class rcmd::base_dir {
file { '/etc/rcmd': ensure => directory, ... }
}
为了建立 SSH 连接,需要使用预共享密钥。通过 Puppet 的
file
类型提供私钥,使用
ssh_authorized_key
资源授权公钥:
file {
'/root/.ssh/id_rsa.rcmd':
owner => 'root',
mode => '600',
source => 'puppet:///modules/rcmd/root/.ssh/id_rsa.rcmd',
}
ssh_authorized_key {
'rcmd-key':
ensure => 'present',
type => 'rsa',
user => hiera('rcmd::user'),
key => hiera('rcmd::public_key'),
}
通过在 Hiera 中更新新的公钥,可以轻松执行交错密钥轮换。
任意配置文件的组合
许多服务允许通过
conf.d
模式的目录进行配置,将目录中的所有文件连接起来形成完整的配置。但也有一些服务需要在单个文件中进行复杂配置,Puppet 原生工具管理这些文件时很难收集导出资源形成复合配置,典型的解决方案是使用
puppetlabs-concat
模块。
以构建 HAproxy 配置文件为例,使用
concat
模块可以将文件声明为多个文件部分的拼接:
define haproxy::config($ensure = 'present',
$globals = [ 'daemon' ],
$defaults = [ 'timeout connect 10s' ],
$use_http_mode = true) {
concat {
"/etc/haproxy/${name}.cfg":
ensure => $ensure;
}
Concat::Fragment { target => "/etc/haproxy/${name}.cfg" }
concat::fragment {
"haproxy-${name}-globals":
order => '10',
content => template('haproxy/cfg-global.erb');
"haproxy-${name}-defaults":
order => '20',
content => template('haproxy/cfg-defaults.erb');
"haproxy-${name}-frontend":
order => '30',
content => template('haproxy/cfg-frontend.erb');
"haproxy-${name}-backend-header":
order => '40',
content => "backend ${name}\n"
}
}
define haproxy::backend_server($instance, $address,
$port, $maxconn) {
$line = "server $name ${address}:$port maxconn $maxconn"
concat::fragment {
"haproxy-${instance}-backend-${name}":
target => "/etc/haproxy/${instance}.cfg",
order => '50',
content => " $line\n",
}
}
@@haproxy::backend_server {
$clientcert:
instance => 'my-balanced-service',
address => $ipaddress,
port => '3782',
maxconn => '24',
}
Haproxy::Backend_server<<| instance == 'my-balanced-service' |>>
这个设计模式适用于许多配置格式,可移植到大多数分布式软件解决方案中。
实例删除处理
导出资源会持久保存在 PuppetDB 中,当代理停用后,其记录通常仍会保留在数据库中,这对于动态云配置是不可取的。PuppetDB 可以停用记录,有两种方法可以实现:
- 手动停用:在 PuppetDB 服务器上(以 root 用户身份)使用
puppet node deactivate
命令,例如
puppet node deactivate 849b97f5-872e-4d31-a668-badf678c5b00
。
- 定义生存时间:在
/etc/puppet/puppetdb.conf
中设置
node-ttl = 60m
,如果导出信息在指定间隔内未定期更新,PuppetDB 将自动停用数据。
为了清理云配置,需要确保离开管理的资源从系统中实际删除。可以使用
file
资源的
purge
参数清理
conf.d
风格的目录,
concat
类型会自动清理消失的片段。对于其他原生资源,可以使用
resources
类型进行清理:
resources { "sshkey": purge => true }
但
resources
类型只能清理代理能轻松定位的资源,例如清理授权 SSH 密钥需要通过用户类型进行配置:
user {
'rcmd':
ensure => present,
uid => '2082',
purge_ssh_keys => true,
}
需要注意的是,清理操作仅适用于原生资源,对于定义类型的实例,需要针对其包装的资源进行清理。
自动扩展准备
云计算相对于传统数据中心运营的一个优势是能够最小化基础设施成本,可以根据负载情况通过自动扩展功能添加或删除实例。为了让 Puppet 在自动扩展的云中工作,需要解决以下两个关键问题。
证书管理
问题的关键在于让代理在没有操作员监督签名过程的情况下获取签名证书。将主节点的
autosign
选项设置为
true
可以实现自动签名,但这会带来安全风险。更安全的折衷方案是实现一个自动签名脚本,将
autosign
设置为文件路径:
autosign = /etc/puppet/autosign
脚本的功能是根据传入的 CSR 决定是否自动签名。为了让主节点验证请求是否来自授权代理,需要在请求中添加更多信息,例如使用 OID 嵌入任意信息,其中
1.3.6.1.4.1.34380.1.1.4
(短名称
pp_preshared_key
)可用于授权字符串。
在部署时为每个实例颁发预共享密钥(PSK),并将其添加到
csr_attributes.yaml
文件的
custom_attributes
哈希中:
custom_attributes:
pp_preshared_key: aiNDN#naCSaiun39nfASnfqwnfsacn!as93ASnfaX
extension_requests:
1.3.6.1.4.1.34380.1.2.42: appserver
为了防止欺骗,可以对密钥进行加盐哈希处理:
custom_attributes:
pp_preshared_key: __HASHED_PSK__
证书请求脚本负责计算哈希值:
#!/bin/bash
export PATH=/bin:/usr/bin
if ! grep -q ^certname /etc/puppet/puppet.conf ; then
CERT=`cat /proc/sys/kernel/random/uuid`
echo "certname = $CERT" >>/etc/puppet/puppet.conf
else
CERT=`puppet agent --configprint certname`
fi
DIR=`puppet agent --configprint certdir`
[ -f "${DIR}/${CERT}.pem" ] && exit 0
PSK=`cat /path/to/psk`
HASH=`echo "$CERT$PSK" | sha512sum - | cut -d\ -f1`
sed -i s/__HASHED_PSK__/$HASH/ /etc/puppet/csr_attributes.yaml
puppet agent --onetime --no-daemonize --waitforcert 10
rm /path/to/psk
自动签名脚本提取 CSR 属性并验证哈希值:
#!/bin/bash
CN=$1
PSK=`cat /path/to/psk`
EXPECT=`echo "$CN$PSK" | sha512sum - | cut -d\ -f1`
HASH=`openssl req -noout -text \
| grep '1\.3\.6\.1\.4\.1\.34380\.1\.1\.4' \
| cut -d: -f2 | tr -d ' '`
[[ "$HASH" = "$EXPECT" ]]
最终的等式测试结果决定是否签署证书。
限制往返时间
新导出的资源到达所有感兴趣的代理节点可能需要较长时间,默认运行间隔为半小时,在大型云中可能会增加这个间隔以减轻主节点压力,但这会导致配置细节分发的平均时间增加,影响自动扩展操作的效果。
可以创建一个构造,让 Puppet 以长间隔运行,但在检测到网络变化时快速响应。具体做法是使用一个专用节点,其清单非常简单,可以相对高频地编译。该节点应导入每个云实例导出的一个资源,如 SSH 主机密钥,资源的变化应触发整个网络的 Puppet 运行。清单如下:
exec { '/usr/local/sbin/trigger-puppet': refreshonly => true }
resources { 'sshkey': purge => true }
Sshkey<<| |>> ~> Exec['/usr/local/sbin/trigger-puppet']
Resources['sshkey'] ~> Exec['/usr/local/sbin/trigger-puppet']
其工作原理如下:
1.
exec
资源仅在收到信号时运行
trigger-puppet
脚本。
2. 从云中的所有对等节点导入 SSH 主机密钥,并使用
resources
类型清除过时的密钥。
3. 导入新密钥时,向
exec
资源发送事件。
4. 清除一个或多个密钥时,向
exec
资源发送信号。
可以使用自定义工具(如
rcmd
模块)或消息队列(如 MCollective)实现
trigger-puppet
脚本,触发所有对等节点的代理运行。例如,使用
rcmd
模块时,每个节点应注册自己以接收 Puppet 主节点的调用:
class puppet_remote_control::agent {
@@rcmd::command {
'trigger-puppet':
runner => $ipaddress,
user => hiera('rcmd::user', 'rcmd'),
id => $clientcert,
}
}
class puppet_remote_control::master {
Rcmd::Command<<| title == 'trigger-puppet' |>>
file {
'/usr/local/sbin/trigger-puppet':
ensure => 'file',
mode => '755',
source => 'puppet:///modules/puppet_remote_control/trigger-all-puppet-agents',
}
}
通过以上方法,可以有效地使用 Puppet 配置云应用,实现安全、高效的云环境管理。
使用 Puppet 配置云应用:全面指南
总结与实践建议
在前面的内容中,我们详细探讨了使用 Puppet 配置云应用的多个关键方面,包括证书安全、分布式目录创建、配置文件组合、实例删除处理以及自动扩展准备等。下面我们对这些内容进行总结,并给出一些实践建议。
关键要点总结
| 主题 | 要点 |
|---|---|
| 证书安全 | 为每个新云实例创建 UUID 作为证书通用名称,可添加 DNS 名称到 CSR 增加安全性,避免签署万能证书 |
| 分布式目录创建 |
通过导出资源实现节点间信息共享,使用
file
类型的
purge
参数清理目录,使用预共享密钥建立 SSH 连接
|
| 任意配置文件组合 |
对于复杂配置文件,使用
puppetlabs-concat
模块将文件声明为多个部分的拼接
|
| 实例删除处理 |
可手动停用或定义生存时间来处理 PuppetDB 中的停用记录,使用
resources
类型清理原生资源
|
| 自动扩展准备 | 使用自动签名脚本进行证书管理,添加更多信息到 CSR 验证请求,创建专用节点限制往返时间 |
实践建议
- 在实际应用中,优先考虑证书的安全性,避免使用不安全的自动签名设置。可以通过实现自动签名脚本,结合预共享密钥的哈希处理,有效防止恶意请求。
-
对于分布式目录的创建,合理设计导出资源,确保节点间信息的准确传递。同时,使用
purge参数可以保持配置的整洁,避免过期信息的干扰。 -
在处理任意配置文件时,充分发挥
puppetlabs-concat模块的优势,将复杂的配置拆分为多个部分,便于管理和维护。 - 对于实例删除,及时清理 PuppetDB 中的停用记录和系统中的无用资源,确保云环境的高效运行。
- 在自动扩展场景下,通过创建专用节点和相应的触发机制,减少配置更新的延迟,提高系统的响应速度。
流程图展示
下面是一个使用 Mermaid 绘制的流程图,展示了使用 Puppet 配置云应用的主要流程:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(证书安全配置):::process
B --> C(分布式目录创建):::process
C --> D(任意配置文件组合):::process
D --> E(实例删除处理):::process
E --> F(自动扩展准备):::process
F --> G{是否完成配置?}:::decision
G -->|是| H([结束]):::startend
G -->|否| B
常见问题及解决方案
在使用 Puppet 配置云应用的过程中,可能会遇到一些常见问题,下面为你列举并提供相应的解决方案。
证书签名问题
- 问题描述 :自动签名设置不安全,手动签名又过于繁琐。
-
解决方案
:使用自动签名脚本,结合预共享密钥的哈希处理,在保证安全性的同时实现自动化签名。具体步骤如下:
-
在
csr_attributes.yaml文件中添加预共享密钥的哈希值。 -
编写证书请求脚本,计算哈希值并替换
csr_attributes.yaml中的占位符。 - 编写自动签名脚本,提取 CSR 属性并验证哈希值。
-
在
配置文件更新延迟问题
- 问题描述 :新导出的资源到达所有代理节点时间过长,影响自动扩展操作。
-
解决方案
:创建专用节点,导入云实例导出的资源,当资源变化时触发整个网络的 Puppet 运行。具体步骤如下:
-
编写专用节点的清单,包含
exec资源和resources类型的清理操作。 -
配置
exec资源的触发条件,使其在资源变化时运行trigger-puppet脚本。 -
使用
rcmd模块或消息队列实现trigger-puppet脚本,触发所有对等节点的代理运行。
-
编写专用节点的清单,包含
实例删除后资源残留问题
- 问题描述 :代理停用后,其记录仍保留在 PuppetDB 中,系统中存在无用资源。
-
解决方案
:使用 PuppetDB 的停用功能,手动或自动停用记录。同时,使用
resources类型和file资源的purge参数清理系统中的无用资源。具体步骤如下:-
在 PuppetDB 服务器上使用
puppet node deactivate命令手动停用节点。 -
在
/etc/puppet/puppetdb.conf中设置node-ttl自动停用过期记录。 -
使用
resources类型清理原生资源,如resources { "sshkey": purge => true }。 -
使用
file资源的purge参数清理conf.d风格的目录。
-
在 PuppetDB 服务器上使用
未来趋势与展望
随着云计算技术的不断发展,Puppet 在云应用配置中的应用也将面临新的挑战和机遇。未来,我们可以预见以下几个趋势:
- 智能化配置管理 :借助人工智能和机器学习技术,实现自动化的配置优化和故障诊断,提高云应用的稳定性和性能。
- 多云环境支持 :随着企业采用多云战略,Puppet 需要更好地支持跨云平台的配置管理,确保不同云环境之间的一致性。
- 安全增强 :在日益复杂的网络环境下,加强证书管理和安全策略,防止恶意攻击和数据泄露。
- 集成与协作 :与其他 DevOps 工具和平台进行更紧密的集成,实现端到端的自动化流程,提高开发和运维效率。
通过不断关注这些趋势,并积极采用新的技术和方法,我们可以更好地利用 Puppet 配置云应用,为企业的数字化转型提供有力支持。
总之,使用 Puppet 配置云应用是一个复杂而又关键的过程,需要我们深入理解各个环节的技术细节,并结合实际需求进行合理的配置和优化。希望本文能够为你在云应用配置方面提供有益的参考和指导。
超级会员免费看
6

被折叠的 条评论
为什么被折叠?



