Andrea Veri's Blog Me, myself and I

A few useful Puppet snippets

As per Wikipedia:

Puppet is a tool for managing the configuration of Unix-like systems, declaratively. The developer provides puppet templates for describing parts of the system, and, when these templates are deployed, the runtime puts the managed systems into the declared state.

Puppet consists of a custom declarative language to describe system configuration, distributed using the client-server paradigm (using XML-RPC protocol), and a library to realize the configuration. The resource abstraction layer enables administrators to describe the configuration in high-level terms, such as users, services and packages.

I’ve been playing with the aforementioned tool lately both on my home network and within the Fedora’s Infrastructure team and I thought some of the work I did might be useful for anyone out there being stuck with a Puppet’s manifest or an ERB template.

Snippet #1: Make sure the user ‘foo’ is always created with its own home directory, password, shell, and full name.

class users {
    users::add { "foo":
        username        => 'foo',
        comment         => 'Foo's Full Name',
        shell           => '/bin/bash',
        password_hash   => 'pwd_hash_as_you_can_see_in_/etc/shadow'
    }

define users::add($username, $comment, $shell, $password_hash) {
    user { $username:
        ensure => 'present',
        home   => "/home/${username}",
        comment => $comment,
        shell  => $shell,
        managehome => 'true',
        password => $password_hash,
    }
  }
}

Snippet #2: Make sure the user ‘foo’ gets added into /etc/sudoers.

class sudoers {

file { "/etc/sudoers":
      owner   => "root",
      group   => "root",
      mode    => "440",
     }
}

augeas { "addfootosudoers":
  context => "/files/etc/sudoers",
  changes => [
    "set spec[user = 'foo']/user foo",
    "set spec[user = 'foo']/host_group/host ALL",
    "set spec[user = 'foo']/host_group/command ALL",
    "set spec[user = 'foo']/host_group/command/runas_user ALL",
  ],
}

Snippet #3: Make sure that openssh-server is: installed, running on Port 222 and accepting RSA authentications only.

class openssh-server {

  package { "openssh-server": 
      ensure => "installed",
  }

    service { "ssh":
        ensure    => running,
        hasstatus => true,
        require   => Package["openssh-server"],
    }

augeas { "sshd_config":
  context => "/files/etc/ssh/sshd_config",
    changes => [
    "set PermitRootLogin no",
    "set RSAAuthentication yes",
    "set PubkeyAuthentication yes",
    "set AuthorizedKeysFile	%h/.ssh/authorized_keys",
    "set PasswordAuthentication no",
    "set Port 222",
  ],
 }
}

Snippet #4: Don’t apply a specific IPTABLES rule if an host is tagged as ‘staging’ in the relevant node file.

On templates/iptables.erb:

# Allow unlimited traffic on eth0
-A INPUT -i eth0 -j ACCEPT
-A OUTPUT -o eth0 -j ACCEPT

# Allow unlimited traffic from trusted IP addresses
-A INPUT -s 192.168.1.1/24 -j ACCEPT

<% if environment == "production" %>

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

<% unless defined?(staging).nil? %>
-A INPUT -s X.X.X.X -j REJECT --reject-with icmp-host-prohibited
<% end -%>

<% end -%>

On the manifest file:

class iptables {
    package { iptables:
        ensure => installed;
    }

    service { "iptables":
        ensure    => running,
        hasstatus => true,
        require   => Package["iptables"],
    }

    file { "/etc/sysconfig/iptables":
        owner   => "root",
        group   => "root",
        mode    => 644,
        content => template("iptables/iptables.erb"),
        notify  => Service["iptables"],
    }
}

That’s all for now!