在CentOS 6上使用Hiera设置Puppet Server

时间:2020-03-21 11:47:09  来源:igfitidea点击:

开源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