wiki:PuppetTweaks

Version 5 (modified by plazonic, 13 years ago) (diff)

--

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 facter tweaks webpage is required and it will 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"
                            }
                    }
            }