= Puppet Tweaks = == selinux httpd module == Using puppet server with passenger will require some selinux hacks since puppet will effectively be running as apache. Here is what we have so far... {{{ policy_module(httpd-puppet,1.0.0) require { type httpd_t; type puppet_var_lib_t; type puppet_var_run_t; type puppet_log_t; type puppet_port_t; type lib_t; type httpd_tmp_t; type port_t; } allow httpd_t puppet_var_lib_t:dir rw_dir_perms; allow httpd_t puppet_var_lib_t:file manage_file_perms; allow httpd_t puppet_var_run_t:dir {search getattr}; allow httpd_t puppet_log_t:dir rw_dir_perms; allow httpd_t puppet_log_t:file rw_file_perms; allow httpd_t puppet_log_t:file create_file_perms; allow httpd_t puppet_log_t:file setattr; allow httpd_t puppet_port_t:tcp_socket name_bind; allow httpd_t lib_t:file execute_no_trans; allow httpd_t httpd_tmp_t:sock_file rw_sock_file_perms; allow httpd_t httpd_tmp_t:sock_file {create unlink setattr}; allow httpd_t self:capability { fowner fsetid sys_ptrace }; allow httpd_t port_t:udp_socket name_bind; }}} Install selinux-policy to get /usr/share/selinux/devel directory, make a file in that directory called httpd-puppet.te Then make the module {{{ [root@server devel]# make httpd-puppet.pp Compiling targeted httpd-puppet module /usr/bin/checkmodule: loading policy configuration from tmp/httpd-puppet.tmp /usr/bin/checkmodule: policy configuration loaded /usr/bin/checkmodule: writing binary representation (version 10) to tmp/httpd-puppet.mod Creating targeted httpd-puppet.pp policy package rm tmp/httpd-puppet.mod tmp/httpd-puppet.mod.fc [root@server devel]# }}} == Some helper modules for work with text files == What follows are some helper functions for working with text files. If native puppet resource type or augeas lens exists for the file type you want to manage please use that instead of these hacks. {{{ # Josko Plazonic 20110314 # should be self explanatory define append_if_no_such_line($file, $line, $refreshonly = 'false') { exec { "/bin/echo '$line' >> '$file'": unless => "/bin/grep -Fxqe '$line' '$file'", path => "/bin", refreshonly => $refreshonly } } # can only be used for files where the parameter already exists and will change it define change_present_param_custom($file, $param, $value, $refreshonly = 'false', $separator = '=', $matchfor="") { if $matchfor == "" { $realmatchfor="$param$separator$value" } else { $realmatchfor = $matchfor } exec { "/usr/bin/perl -pi -e 's|^$param$separator.*|$param$separator$value|g' '$file'": unless => "/bin/grep -Fxqe '$realmatchfor' '$file'", path => "/bin:/usr/bin", refreshonly => $refreshonly } } # similar to above but if the param is not there it will add it define change_param_custom($file, $param, $value, $refreshonly = 'false', $separator = '=', $matchfor="") { if $matchfor == "" { $realmatchfor="$param$separator$value" } else { $realmatchfor = $matchfor } exec { "/bin/grep -q '^$param$separator.*' '$file' && /usr/bin/perl -pi -e 's|^$param$separator.*|$param$separator$value|g' '$file' || echo '$param$separator$value' >> '$file' ": unless => "/bin/grep -Fxqe '$realmatchfor' '$file'", path => "/bin:/usr/bin", refreshonly => $refreshonly } } # delete a line from a text file define remove_line($file, $line, $refreshonly = 'false') { exec { "/usr/bin/perl -pi -e 's|^$line\$\\\\n||' '$file'": onlyif => "/bin/grep -Fxqe '$line' '$file'", path => "/bin", refreshonly => $refreshonly } } }}} Examples: {{{ # add a path to use for environment modules append_if_no_such_line { "usr_local_modules": file => "/usr/share/Modules/init/.modulespath", line => "/usr/local/share/Modules/modulefiles", require => Package["environment-modules"], } # change to who mdadm sends emails change_present_param_custom { mdadmReport: file => "/etc/mdadm.conf", param => "MAILADDR", value => 'reportreceiver@mydomain.com', separator => " ", notify => Service["mdmonitor"], require => Package["mdadm"] } }}} == Kernel version monitoring recipes == These sample recipes should help you with ensuring your puppet clients run the latest version of kernel and with associated cleanup and security lock down. The idea is the following: * either via yum nightly update or with a puppet recipe ensure latest kernel(s) are installed. E.g. in emergencies (say a critical local kernel vulnerability that you want installed on next puppet client run) you could easily do {{{ package { "kernel-2.6.32-71.18.2.el6.x86_64": ensure => "installed" } }}} * kernel version fact from [wiki:FacterTweaks facter tweaks webpage] allows access to info on currently running client kernel ($kernelrelease), newest installed kernel ($kernelnewest) and oldest installed kernel ($kerneloldest). * example optional security lock down - disallow remote ssh: {{{ # Josko Plazonic 20110314 case $kernelnewest { "",$kernelrelease: { # either puppet does not have (yet) kernel version facts or we are currently # running the latest kernel so allow ssh from our usual open networks $sshallowwks = "192.168.1.1/255.255.255.0" } default: { # if we are arriving here it is because $kernelnewest != $kernelrelease so we list # trusted hosts we always allow remote logins from $sshallowwks = "127.0.0.1, 192.168.1.250, 192.168.1.251" } } # Now set it in hosts.allow, it would be better to use augeas but # no available lens for hosts.allow/deny forces us to use the below change_param_custom { "set_ssh_hosts_allow": file => "/etc/hosts.allow", param => "sshd", separator => ": ", value => "$sshallowwks" } } }}} * remove older kernels: {{{ # Josko Plazonic 20110314 case $kerneloldest { "",$kernelrelease: { # do nothing, we either do not have the kernel version facts # or we are running oldest kernel } default: { package { "kernel-$kerneloldest": ensure => "absent" } } } }}} * reboot - this one is tricky and you will have to tweak it for your environment carefully. I give an example used on Linux workstation where by using $cmdtocheck_users command - ps and a long long egrep - we exclude processes that are safe to ignore when rebooting (like ssh-agent, ntp daemon and so on) but anything left over (say firefox, or matlab or ...) will prevent reboot: {{{ # Josko Plazonic 20110314 case $kernelnewest { "",$kernelrelease: { # do nothing, either kernel version facts missing or we are current } default: { # here we go, current kernel not matching running kernel # the following line excludes processes we do not care about, anything left over will prevent reboot $cmdtocheck_users = "/bin/ps -auxw | /bin/egrep -v '^(USER|root|postfix|rpc|rpcuser|68|dbus|ntp|rtkit|gdm) | (ssh-agent|-bash|/usr/bin/pulseaudio|/usr/libexec/pulse/gconf-helper|/usr/bin/gnome-keyring-daemon|gnome-session|sshd:|dbus-launch|/bin/dbus-daemon|/usr/bin/seahorse-agent|/usr/libexec/gconfd-2|/usr/libexec/gnome-settings-daemon|seahorse-daemon|metacity|gnome-panel|nautilus|/usr/libexec/bonobo-activation-server|bluetooth-applet|abrt-applet|/usr/share/system-config-printer/applet.py|/usr/libexec/gvfs.*|/usr/libexec/.*notification-daemon|/usr/libexec/wnck-applet|gnome-power-manager|/usr/libexec/trashapplet|/usr/libexec/polkit-gnome-authentication-agent-1|gnome-volume-control-applet|krb5-auth-dialog|/usr/sbin/restorecond|/usr/libexec/im-settings-daemon|gnome-screensaver|/usr/bin/gnote|/usr/libexec/clock-applet|/usr/libexec/notification-area-applet|/usr/libexec/gdm-user-switch-applet|/usr/libexec/gconf-im-settings-daemon|gnome-terminal|gnome-pty-helper|bash|/usr/libexec/gam_server|/opt/google/talkplugin/GoogleTalkPlugin|/usr/libexec/evolution-data-server-2.28|gnome-help)( |$)'" # Reboot and send an email about it (tweak to your preferences) if safe to do exec { "ps -auxw | mail -s Auto_rebooting_$hostname root && /sbin/reboot": path => [ "/sbin", "/bin", "/usr/sbin", "/usr/bin" ], cwd => "/root", # the following line will prevent reboot if yum is running or if $cmdtocheck_users finds processes not excluded with above unless => [ "/usr/bin/pgrep yum >/dev/null", "$cmdtocheck_users > /dev/null" ] } # this rule is entirely optional, just reminds root that some machines continue running with old kernels and lists reasons why exec { "$cmdtocheck_users | mail -s Cannot_reboot_on_$hostname root": path => [ "/sbin", "/bin", "/usr/sbin", "/usr/bin" ], cwd => "/root", onlyif => "$cmdtocheck_users > /dev/null" } } } }}}