Monday, 24 October 2016

Quickstart: Installing and configuring puppet

For the puppet master we will need a VM with at least 8GB of RAM, 80GB of disk and 2 vCPU.

The topology will comprise of two nodes - MASTERNODE (The puppet server) and the CLIENTNODE (the puppet client).

Let's firstly install the offical Puppet repository:

cd /tmp
wget https://apt.puppetlabs.com/puppetlabs-release-pc1-jessie.deb
dpkg -i puppetlabs-release-pc1-jessie.deb
apt-get update
apt-get install puppetmaster

or for RHEL 7 / CentOS 7:

cd /tmp
curl -o https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm puppetlabs-release-pc1-el-7.noarch.rpm
rpm -i puppetlabs-release-pc1-el-7.noarch.rpm
yum install puppetmaster-passenger

We should then set our DNS name for the puppet server:

sed -i '/main/a dns_alt_names="puppet.healix.com"' /etc/puppet/puppet.conf

and start the puppet master:

sudo service puppetmaster start

we should then install our client:

cd /tmp
wget https://apt.puppetlabs.com/puppetlabs-release-pc1-jessie.deb
dpkg -i puppetlabs-release-pc1-jessie.deb
apt-get update
apt-get install puppet

or on RHEL based systems:

yum install puppet

sed -i '/main/a server = "puppet.healix.com"' /etc/puppetlabs/puppet/puppet.conf

and restart the puppet client:

systemctl restart puppet

Set path details:

export PATH=/opt/puppetlabs/bin:$PATH

The puppet server (master) utilizes PKI to ensure authenticity between itself and the client - so we must firstly generate a certifcate signing request from the client:

puppet agent --enable
puppet agent -t

At this point I got an an error:

Error: Could not request certificate: Error 400 on SERVER: The environment must be purely alphanumeric, not 'puppet-ca'
Exiting; failed to retrieve certificate and waitforcert is disabled

This turned out due to a version mismatch between the puppet client and server.

Note: The Puppet server version must always be >= than that of the puppet client - I actually ended up removing the official puppet repo from the client and using the EPEL repo instead.

So again ebnsure the server is set in our puppet client configuration (which is in a different location):

sed -i '/main/a server = "puppet.healix.com"' /etc/puppet/puppet.conf

systemctl restart puppet

and then attempt to enable puppet and generate our certificate:

puppet agent --enable
puppet agent -t

At this point I got the following error:

Exiting; no certificate found and waitforcert is disabled.

This is because the generated certifcate has not yet been approved by the puppet master!

In order to approve the certificate - on the puppet master issue:

puppet cert list

and then sign it by issueing:

puppet cert sign hostname.domain.com

We can then view the signed certifcate with:

puppet cert list -all

Now head back to the client and attempt to initailize the puppet agent again:

puppet agent -t

We should (if everything goes to plan) see something like:

Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppetmaster.yourdomain.com
Info: Applying configuration version '1234567890'
Info: Creating state file /var/lib/puppet/state/state.yaml
Notice: Finished catalog run in 0.02 seconds

We want to install few modules firstly:

puppet module install ghoneycutt/ssh
puppet module install jfryman/nginx

We will extend our modules:

nano /etc/puppet/modules/firewall/manifests/ssh.pp

ssh::permit_root_login
  permit_root_login => 'no',
 
Now lets create our manifest:

cd /etc/puppet/manifests

vi site.pp

import "/etc/puppet/modules/firewall/manifests/*.pp"

node default {

  package { tcpdump: ensure => installed; }
  package { nano: ensure => installed; }
  package { wget: ensure => installed; }
  package { firewalld: ensure => absent; }
 
  service { 'firewalld':
    ensure     => stopped,
    enable     => false,
    hasstatus  => true,
  }
 
  service { 'iptables':
    ensure     => started,
    enable     => true,
    hasstatus  => true,
  }
 
  resources { "firewall":
    purge   => true
  }

  Firewall {
    before  => Class['fw::post'],
    require => Class['fw::pre'],
  }

  class { ['fw::pre', 'fw::post']: }
 
  include common
  include ssh
 
}

We have two sets of rules - one of which will be applied first:

nano /etc/puppet/modules/firewall/manifests/pre.pp

class fw::pre {
 
  Firewall {
    require => undef,
  }

  # basic in/out
  firewall { "000 accept all icmp":
    chain    => 'INPUT',
    proto    => 'icmp',
    action   => 'accept',
  }

  firewall { '001 accept all to lo interface':
    chain    => 'INPUT',
    proto    => 'all',
    iniface  => 'lo',
    action   => 'accept',
  }

  firewall { '006 Allow inbound SSH':
    dport     => 22,
    proto    => tcp,
    action   => accept,
  }

  firewall { '003 accept related established rules':
    chain    => 'INPUT',
    proto    => 'all',
    state    => ['RELATED', 'ESTABLISHED'],
    action   => 'accept',
  }

  firewall { '004 accept related established rules':
    chain    => 'OUTPUT',
    proto    => 'all',
    state    => ['RELATED', 'ESTABLISHED'],
    action   => 'accept',
  }

  firewall { '005 allow all outgoing traffic':
    chain    => 'OUTPUT',
    state    => ['NEW','RELATED','ESTABLISHED'],
    proto    => 'all',
    action   => 'accept',
  }
 
}

and afterwards:

nano /etc/puppet/modules/firewall/manifests/post.pp

class fw::post {
 
  firewall { '900 log dropped input chain':
    chain      => 'INPUT',
    jump       => 'LOG',
    log_level  => '6',
    log_prefix => '[IPTABLES INPUT] dropped ',
    proto      => 'all',
    before     => undef,
  }

  firewall { '900 log dropped forward chain':
    chain      => 'FORWARD',
    jump       => 'LOG',
    log_level  => '6',
    log_prefix => '[IPTABLES FORWARD] dropped ',
    proto      => 'all',
    before     => undef,
  }

  firewall { '900 log dropped output chain':
    chain      => 'OUTPUT',
    jump       => 'LOG',
    log_level  => '6',
    log_prefix => '[IPTABLES OUTPUT] dropped ',
    proto      => 'all',
    before     => undef,
  }

  firewall { "910 deny all other input requests":
    chain      => 'INPUT',
    action     => 'drop',
    proto      => 'all',
    before     => undef,
  }

  firewall { "910 deny all other forward requests":
    chain      => 'FORWARD',
    action     => 'drop',
    proto      => 'all',
    before     => undef,
  }

  firewall { "910 deny all other output requests":
    chain      => 'OUTPUT',
    action     => 'drop',
    proto      => 'all',
    before     => undef,
  }

}

 
We should also validate the file as follows:

sudo puppet parser validate site.pp
 
The puppet client (by default) will poll every 30 minutes - we can change this by defining:

runinterval=900

Where 900 is == number of seconds. (This should be appended to the 'main' section in puppet.conf

We can also test the config by issuing:

puppet agent --test

We should see something like:

Info: Retrieving pluginfacts
Info: Retrieving plugin
...
Notice: /Stage[main]/Main/Node[default]/Package[tcpdump]/ensure: created
Notice: /Stage[main]/Main/Node[default]/Package[nano]/ensure: created
Notice: Finished catalog run in 6.88 seconds

Now we want to define some host-specific configuration - lets say our host runs a bespoke application running on tcp/8000:

node 'webserver.yourdomain.com' {
  firewall { '006 Allow inbound SSH':
  dport     => 22,
  proto    => tcp,
  action   => accept,
}
 
Finally run a test again to ensure the firewall rule has been executed:

puppet agent --test

iptables -L

0 comments:

Post a Comment