在CentOS 6上使用Hiera设置Puppet Server
开源Puppet是基于模型的声明式配置管理解决方案,使我们能够使用Puppet语言定义测试环境基础设施的状态。
换句话说,Puppet是一个配置管理系统。
Hiera是用于配置数据的键/值查找工具,旨在使Puppet更好,并允许我们设置特定于节点的数据而无需重复自己。
安装
添加Puppet存储库:
# rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm
安装Puppet服务器(Puppet 3.8版将Hiera安装为依赖项):
# yum install -y puppet-server
配置:Puppet主服务器
打开“ /etc/puppet/puppet.conf”进行编辑和配置,如下所示:
[main]
# The Puppet log directory
logdir = /var/log/puppet
# Where Puppet PID files are kept
rundir = /var/run/puppet
# Where SSL certificates are kept
ssldir = $vardir/ssl
server = puppet.igi.local
pluginsync = true
parser = future
# Merge recursively; in the event of a conflict,
# allow higher priority values to win
merge_behaviour = deeper
# Environment variable that is used by Hiera
environmet = prod
[agent]
# The file in which puppetd stores a list of the classes
# associated with the retrieved configuration
classfile = $vardir/classes.txt
# Where puppetd caches the local configuration
localconfig = $vardir/localconfig
[master]
# The comma-separated list of alternative DNS names to use for the local host.
# When the node generates a CSR for itself, these are added to the request as
# the desired subjectAltName in the certificate
dns_alt_names = puppet,puppet.igi.local
always_cache_features = true
# If set to false, never autosign even if an autosign.conf file is written
autosign = true
完成后,启动puppetmaster服务:
# /etc/init.d/puppetmaster start
允许服务在启动时启动:
# chkconfig puppetmaster on
Puppet master现在已启动并正在运行,但没有任何用处。
安装:Puppet模块
我们将使用以下Puppet模块:
# puppet module install puppetlabs-firewall ;\ puppet module install puppetlabs-ntp ;\ puppet module install erwbgy-limits ;\ puppet module install thias-sysctl ;\ puppet module install spiette-selinux ;\ puppet module install Aethylred-postfix ;\ puppet module install puppetlabs-apache ;\ puppet module install puppetlabs-mysql
配置:防火墙模块
创建一个自定义防火墙模块:
# mkdir -p /etc/puppet/modules/lsn_firewall/manifests
放置一些基本的元数据,以便在运行Puppet模块列表时可以看到它:
# cat << EOL > /etc/puppet/modules/lsn_firewall/metadata.json
{
"name": "lsn_firewall",
"version": "1.0.0",
"author": "www.theitroad.com",
"summary": "Manages iptables firewall",
"license": "",
"source": "",
"project_page": "",
"issues_url": "",
"operatingsystem_support": [],
"requirements": [],
"dependencies": []
}
EOL
创建lsn_firewall :: pre和lsn_firewall :: post类
由于该部分主要基于PuppetForge文章而进行,因此无需多做解释:https://forge.puppetlabs.com/puppetlabs/firewall
我们的方法将采用白名单设置,因此我们可以定义所需的规则,而忽略所有其他规则,而不是删除所有其他规则。
防火墙规则的运行顺序为:
- lsn_firewall :: pre中的规则,
- 代码中定义的规则('lsn_firewall/manifests/init.pp'),
- 规则lsn_firewall :: post。
前置和后置类中的规则相当通用:允许新的传入SSH连接,允许所有相关/已建立的流量,记录并拒绝其他所有内容。
# cat << EOL > /etc/puppet/modules/lsn_firewall/manifests/pre.pp
class lsn_firewall::pre {
Firewall {
require => undef,
}
# Default firewall rules
firewall { '000 accept all icmp':
proto => 'icmp',
action => 'accept',
}->
firewall { '001 accept all lo interface':
proto => 'all',
iniface => 'lo',
action => 'accept',
}->
firewall { '002 Allow ssh traffic':
dport => [ 22 ],
proto => 'tcp',
state => ['NEW'],
action => 'accept',
}
}
EOL
# cat << EOL >/etc/puppet/modules/lsn_firewall/manifests/post.pp
class lsn_firewall::post {
firewall { '997 accept related/established':
proto => 'all',
state => ['RELATED', 'ESTABLISHED'],
action => 'accept',
}->
firewall { '998 Log sessions':
jump => 'LOG',
log_level => '4',
log_prefix => 'iptables_input ',
}->
firewall { '999 drop all':
proto => 'all',
action => 'drop',
before => undef,
}
}
EOL
从上面可以看到,规则允许基本的联网并确保不关闭现有连接。
创建防火墙规则
我们将为以下服务创建防火墙规则:
- Puppet主控(TCP 8140)
- HTTP/S(TCP 80,443)
- MySQL(TCP 3306)
- DNS(TCP 53,UDP 53)
- DHCP(UDP 67)
- NTP(UDP 123)
- SMTP(TCP 25)
可以根据需要添加更多服务。
大多数规则将仅限于内部10.0.0.0/8网络。
# cat << EOL > /etc/puppet/modules/lsn_firewall/manifests/init.pp
class fw_puppet {
firewall { '004 Allow puppet traffic':
dport => [ 8140 ],
source => '10.0.0.0/8',
proto => tcp,
action => accept,
}
}
class fw_http {
firewall { '005 Allow http/s traffic':
dport => [ 80, 443 ],
source => '10.0.0.0/8',
proto => tcp,
action => accept,
}
}
class fw_mysql {
firewall { '006 Allow MySQL traffic':
dport => [ 3306 ],
source => '10.0.0.0/8',
proto => tcp,
action => accept
}
}
class fw_dns {
firewall { '007 Allow BIND traffic TCP':
dport => [ 53 ],
source => '10.0.0.0/8',
proto => tcp,
action => accept
}
firewall { '008 Allow BIND traffic UDP':
dport => [ 53 ],
source => '10.0.0.0/8',
proto => udp,
action => accept
}
}
class fw_dhcp {
firewall { '009 Allow DHCP traffic':
dport => [ 67 ],
proto => udp,
action => accept
}
}
class fw_ntp {
firewall { '010 Allow NTP traffic':
dport => [ 123 ],
source => '10.0.0.0/8',
proto => udp,
action => accept
}
}
class fw_smtp {
firewall { '011 Allow SMTP traffic':
dport => [ 25 ],
source => '10.0.0.0/8',
proto => tcp,
action => accept
}
}
EOL
现在,我们要设置一个元类型来清除不受管理的防火墙资源,然后为所有防火墙规则设置默认参数。
这应该确保前置和后置类以正确的顺序运行。
我们还必须声明lsn_firewall :: pre和lsn_firewall :: post类以满足相关性。
最后一行是使用hiera_include函数将类分配给节点的方法(本文稍后将使用)。
# cat << EOL > /etc/puppet/manifests/site.pp
# Clear any existing IPv4 rules and make sure that only
# rules defined in Puppet exist on the machine
resources { "firewall":
purge => true
}
# Ensure that the pre and post classes are run in the correct
# order to avoid locking us out of our box during the first
# Puppet run
Firewall {
before => Class['lsn_firewall::post'],
require => Class['lsn_firewall::pre'],
}
# Declare the pre and post classes to satisfy dependencies
class { ['lsn_firewall::pre', 'lsn_firewall::post']: }
# Assign classes to nodes using the hiera_include function
hiera_include('classes')
EOL
配置:希拉
层次结构和树结构
本文假设读者(至少)知道什么是希拉以及它应该如何工作。
我们将使用Hiera数据目录为'/etc/puppet/hieradata'的json后端。
层次结构如下:
- fqdn-来自事实,
- server_role-来自配置文件('/etc/puppet/server_role'),请参见下文,
- 环境-来自“ /etc/puppet/puppet.conf”文件。
我们将在'/etc/puppet/hieradata /'下使用以下树结构(按优先级从低到低的顺序排列):
- common.json-适用于所有节点,但可以被其他任何配置覆盖,
- env/envname.json-环境名称,例如“ prod”,
- server_role/role.json-服务器角色,例如“ puppetmaster”,“ mysql”等,
- node/fqdn.json-特定的节点配置(实际上并没有使用,除非节点需要某些特定的配置,而上述所有配置都无法使用)。
其中许多是由变量或者事实(因素)定义的。
每当从Puppet触发Hiera查找时,Hiera都会收到Puppet当前可用的所有变量的副本,包括顶级范围变量和局部变量。
我们可以使用facter加载并检查Puppet特定的事实:
# facter -p
创建一个新的server_role事实:
# cat << EOL > /etc/puppet/modules/stdlib/lib/facter/server_role.rb
Facter.add("server_role") do
setcode do
Facter::Util::Resolution.exec("cat /etc/puppet/server_role")
end
end
EOL
server_role事实将从“/etc/puppet/server_role”(需要创建此文件)中收集。
设定档
创建一个Hiera配置文件:
# cat << EOL > /etc/puppet/hiera.yaml
--
:merge_behaviour: deeper
:logger: console
:backends:
- json
:json:
:datadir: /etc/puppet/hieradata
:hierarchy:
- "node/%{::fqdn}"
- "server_role/%{::server_role}"
- "env/%{::environment}"
- common
EOL
创建一个符号链接:
# ln -sf /etc/puppet/hiera.yaml /etc/hiera.yaml
创建一个hieradata文件夹结构:
# mkdir -p /etc/puppet/hieradata/{node,server_role,env}
定义Puppet主服务器的服务器角色:
# echo "puppetmaster" > /etc/puppet/server_role
为环境创建hiera数据源文件:
# touch /etc/puppet/hieradata/env/{prod.json,dev.json}
为服务器角色创建hiera数据源文件:
# touch /etc/puppet/hieradata/server_role/{default.json,puppetmaster.json,mysql.json}
在此示例中,我们只有三个服务器角色,一个用于Puppet主服务器的puppetmaster角色,一个用于配置MySQL服务器的mysql服务器角色,以及一个用于其他所有服务器的默认服务器角色。
我们将以在产品中启用SELinux但在开发人员中将其设置为允许的方式配置环境。
配置还包括一些用于信息公开的Apache内容。
配置环境:
# cat << EOL > /etc/puppet/hieradata/env/prod.json
{
"classes": [
"selinux"
],
"selinux::mode": "enforcing",
"apache::server_signature": "Off",
"apache::trace_enable": "Off",
"apache::server_tokens": "Prod"
}
EOL
# cat << EOL > /etc/puppet/hieradata/env/dev.json
{
"classes": [
"selinux"
],
"selinux::mode": "permissive",
"apache::server_signature": "On",
"apache::trace_enable": "On",
"apache::server_tokens": "Full"
}
EOL
现在,我们可以为puppetmaster服务器角色创建一个Hiera配置。
该配置将执行以下操作:
- 配置防火墙以允许以下服务的传入流量:
- Puppet,HTTP/S,DNS,DHCP,NTP,SMTP,
- 配置NTP服务器。
创建文件:
# cat << EOL > /etc/puppet/hieradata/server_role/puppetmaster.json
{
"classes": [
"fw_puppet",
"fw_http",
"fw_dns",
"fw_dhcp",
"fw_ntp",
"fw_smtp",
"ntp"
],
"ntp::enable": true,
"ntp::servers": [
"0.uk.pool.ntp.org iburst",
"1.uk.pool.ntp.org iburst",
"2.uk.pool.ntp.org iburst",
"3.uk.pool.ntp.org iburst"
],
"ntp::servers": [
"0.uk.pool.ntp.org",
"1.uk.pool.ntp.org",
"2.uk.pool.ntp.org",
"3.uk.pool.ntp.org"
],
"ntp::interfaces": [ "0.0.0.0" ],
"ntp::restrict": [
"-4 default kod nomodify notrap nopeer noquery",
"-6 default kod nomodify notrap nopeer noquery",
"127.0.0.1",
"-6 ::1",
"10.0.0.0 mask 255.0.0.0 nomodify notrap nopeer"
]
}
EOL
我们还将为mysql服务器角色创建一个Hiera配置,该配置将执行以下操作:
- 配置防火墙以允许传入的MySQL通信,
- 配置Postfix中继,
- 配置自定义Linux安全限制,
- 使用合理的参数配置MySQL服务器。
创建文件:
# cat << EOL > /etc/puppet/hieradata/server_role/mysql.json
{
"classes": [
"fw_mysql",
"postfix",
"mysql::server"
],
"postfix::relayhost": "smtp.igi.local",
"postfix::inet_interfaces": "localhost",
"limits": {
"mysql": {
"nproc": {
"soft": "4096"
},
"nofile": {
"soft": "4096"
}
}
},
"mysql::server::create_root_user": "true",
"mysql::server::root_password": "passwd",
"mysql::server::create_root_my_cnf": "true",
"mysql::server::remove_default_accounts": "false",
"mysql::server::restart": "true",
"mysql::server::override_options": {
"mysqld": {
"bind-address": "0.0.0.0",
"datadir": "/var/lib/mysql",
"socket": "/var/lib/mysql/mysql.sock",
"symbolic-links": "0",
"max_allowed_packet": "16M",
"max_heap_table_size": "256M",
"max_connections": "100",
"wait_timeout": "60",
"open_files_limit": "4096",
"general_log_file": "/var/log/mysql/mysql.log",
"general_log": "0",
"server_id": "1",
"expire_logs_days": "7",
"max_binlog_size": "1G",
"query_cache_type": "1",
"query_cache_limit": "16M",
"thread_cache_size": "8",
"key_buffer_size": "64M",
"innodb_buffer_pool_size": "32M",
"innodb_additional_mem_pool_size": "32M",
"innodb_log_buffer_size": "10M",
"tmp_table_size": "256M",
"query_cache_size": "64M",
"read_buffer_size": "1M",
"read_rnd_buffer_size": "256K",
"sort_buffer_size": "2M",
"join_buffer_size": "1M",
"thread_stack": "256K",
"binlog_cache_size": "32K",
"innodb_file_per_table": "1",
"innodb_flush_method": "fsync",
"innodb_flush_log_at_trx_commit": "1",
"innodb_log_file_size": "32M",
"innodb_lock_wait_timeout": "100",
"innodb_data_file_path": "ibdata1:16M:autoextend:max:2048M"
},
"client": {
"socket": "/var/lib/mysql/mysql.sock"
},
"mysqld_safe": {
"socket": "/var/lib/mysql/mysql.sock"
},
"mysqldump": {
"max_allowed_packet": "16M"
}
}
}
EOL
默认服务器角色具有仅配置的后缀中继:
# cat << EOL > /etc/puppet/hieradata/server_role/default.json
{
"classes": [
"postfix"
],
"postfix::relayhost": "smtp.igi.local",
"postfix::inet_interfaces": "localhost"
}
EOL
最后一点是创建一个Hiera通用数据源文件。
当Hiera找不到层次结构中其他位置的给定键的匹配项时,此文件将提供我们要使用的任何默认值。
默认配置将包括以下内容:
- 防火墙,
- NTP,
- Postfix中继,
- Linux安全限制
- sysctl内核参数。
创建文件:
# cat << EOL > /etc/puppet/hieradata/common.json
{
"classes": [
"firewall",
"ntp",
"limits",
"sysctl::base"
],
"apache::serveradmin": "Hyman@theitroad",
"apache::server_signature": "Off",
"apache::trace_enable": "Off",
"apache::server_tokens": "Prod",
"ntp::package_ensure": "present",
"ntp::service_enable": true,
"ntp::service_ensure": "running",
"ntp::servers": [ "ntp.igi.local" ],
"ntp::iburst_enable": true,
"ntp::interfaces": [ "127.0.0.1" ],
"ntp::restrict": [
"default ignore",
"-6 default ignore",
"127.0.0.1",
"-6 ::1"
],
"limits": {
"*": {
"nofile": {
"soft": "2048",
"hard": "65536"
},
"nproc": {
"soft": "2048",
"hard": "16384"
},
"locks": {
"soft": "2048",
"hard": "2048"
},
"stack": {
"soft": "10240",
"hard": "32768"
},
"fsize": {
"soft": " 33554432",
"hard": "67108864"
},
"memlock": {
"soft": "64",
"hard": "64"
},
"core": {
"hard": "0"
}
},
"root": {
"nofile": {
"soft": "2048",
"hard": "65536"
},
"nproc": {
"soft": "2048",
"hard": "16384"
},
"stack": {
"soft": "10240",
"hard": "32768"
},
"fsize": {
"soft": "33554432"
}
}
},
"sysctl::base::values": {
"fs.suid_dumpable": { "value": "0" },
"vm.swappiness": { "value": "0" },
"kernel.panic": { "value": "10" },
"kernel.sysrq": { "value": "0" },
"kernel.core_uses_pid": { "value": "1" },
"kernel.dmesg_restrict": { "value": "1" },
"kernel.kptr_restrict": { "value": "1" },
"kernel.msgmnb": { "value": "65536" },
"kernel.msgmax": { "value": "65536" },
"kernel.shmmax": { "value": "1073741824" },
"kernel.shmall": { "value": "262144" },
"kernel.exec-shield": { "value": "1" },
"kernel.randomize_va_space": { "value": "2" },
"kernel.pid_max": { "value": "32768" },
"net.core.wmem_max": { "value": "12582912" },
"net.core.rmem_max": { "value": "12582912" },
"net.core.netdev_max_backlog": { "value": "5000" },
"net.ipv4.ip_forward": { "value": "0" },
"net.ipv4.tcp_syncookies": { "value": "1" },
"net.ipv4.tcp_rmem": { "value": "4096 87380 16777216" },
"net.ipv4.tcp_wmem": { "value": "4096 65536 16777216" },
"net.ipv4.tcp_window_scaling": { "value": "1" },
"net.ipv4.tcp_sack": { "value": "1" },
"net.ipv4.tcp_timestamps": { "value": "1" },
"net.ipv4.tcp_no_metrics_save": { "value": "1" },
"net.ipv4.conf.all.accept_source_route": { "value": "0"},
"net.ipv4.conf.default.accept_source_route": { "value": "0" },
"net.ipv4.conf.all.send_redirects": { "value": "0" },
"net.ipv4.conf.all.accept_redirects": { "value": "0" },
"net.ipv4.conf.all.secure_redirects": { "value": "0" },
"net.ipv4.conf.default.send_redirects": { "value": "0" },
"net.ipv4.conf.default.accept_redirects": { "value": "0" },
"net.ipv4.conf.default.secure_redirects": { "value": "0" },
"net.ipv4.conf.all.rp_filter": { "value": "1" },
"net.ipv4.conf.default.rp_filter": { "value": "1" },
"net.ipv4.conf.all.log_martians ": { "value": "1" },
"net.ipv4.conf.default.log_martians": { "value": "1" },
"net.ipv4.icmp_echo_ignore_broadcasts": { "value": "1" },
"net.ipv4.icmp_ignore_bogus_error_messages": { "value": "1" },
"net.ipv4.icmp_ignore_bogus_error_responses": { "value": "1" },
"net.bridge.bridge-nf-call-iptables": { "value": "0" },
"net.bridge.bridge-nf-call-arptables": { "value": "0" },
"net.ipv6.conf.all.rp_filter": { "value": "1" },
"net.ipv6.conf.all.accept_ra": { "value": "0" },
"net.ipv6.conf.default.accept_ra": { "value": "0" },
"net.ipv6.conf.all.accept_redirects": { "value": "0" },
"net.ipv6.conf.default.accept_redirects": { "value": "0" }
}
}
EOL
检查Puppet模块列表:
# puppet module list
现在该手动触发在puppetmaster上运行的Puppet客户端了:
# puppet agent -t
现在,我们应该看到我们的主节点已连接:
# puppet cert list -all

