Archive for November, 2018

import boto3
ec2 = boto3.resource('ec2',region_name='eu-west-1')
def lambda_handler(event, context):
     for vol in ec2.volumes.all():
      if vol.state=='available':
        for tag in vol.tags:
         if tag in vol.tags or tag==None:
           print "VolumeID:"+ vol.id, "Volume Name:"+tag['Value'] + " AWS Region:Ireland"

 

 

Advertisements

This Python boto3 script will get notification if instances are stopped for more than 30 days

import json
import boto3
import re
import smtplib
import datetime
import time
from datetime import datetime
from datetime import date
from dateutil.relativedelta
import relativedeltainstance_ids = []
instance_names = []
stopped_reasons = []
output=[]
transition_timestamps=[]
ses = boto3.client('ses')
def send_mail(email_from, email_to, subject, body):
smtp_address = 'smtp.office365.com'
provider_username = 'sender@example.com'
provider_password = 'Pass'
smtpserver = smtplib.SMTP(smtp_address, 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo() # extra characters to permit edit
smtpserver.login(provider_username, provider_password)
header = 'To: ' + email_to + '\n' + 'From: ' + email_from + '\n' + 'Subject: ' + subject + '\n'
msg = header + '\n ' + body + ' \n\n'
smtpserver.sendmail(provider_username, email_to, msg)
smtpserver.quit()
def lambda_handler(event, context):
 client = boto3.client('ec2',region_name='eu-west-2')
 reservations = client.describe_instances().get('Reservations', [])
 for reservation in reservations:
    for instance in reservation['Instances']:
      tags = {}
      for tag in instance['Tags']:
            tags[tag['Key']] = tag['Value']
            if tag['Key'] == 'Name':
                name=tag['Value']
    if instance['State']['Name'] == 'stopped':
       instance_ids.append(instance['InstanceId'])
       instance_names.append(name)
       stopped_reason = instance['StateTransitionReason']
       stopped_reasons.append(stopped_reason)
       transition_timestamp = datetime.strptime(instance['StateTransitionReason'][16:39], '%Y-%m-%d %H:%M:%S %Z')
       transition_timestamps.append(str(transition_timestamp))
       days=(datetime.now() - transition_timestamp).days
       if days > 30:
          a = "InstanceID:" + instance['InstanceId'] + "," + ' Instance Name:' +name + "," + " Shutdown Time: "+str(transition_timestamp)
          output.append(a)
body= "\n\n".join(output)
if body:
emailbody = "The following instances are stopped for more than 30 days in London region\n\n\n\n" +body + "\n\n\n If instances are not needed anymore please terminate it or start it otherwise"
send_mail('sender@example.com', 'recipient@example.com', 'Notification of stopped instances', emailbody)

It’s presumed Chocolatey server will be installed on D drive,it’s presumed Chocolatey server has no internet access.

Choco installation files are obtained in following way:

On any windows machine with internet access following has been done:

  • installed chocolatey
  • after chocolatey has been installed following command has been executed:
    choco install chocolatey.server
  • all required files are downloaded to C:\tools folder

Capture.PNG

Copy tools folder somewhere to Ansible server, Ansible playbook will copy  it to D drive on Windows server.

Folder structure:

|—————–winplaybook/choco.yml   chocoserver/tools/

|—————group_vars/

|             | ————–features/features.yml

|————–windows/vars_win.yml   vaul_win.yml

features.yml contains list of IIS features and IIS users

---
features:
- Web-Server
- Web-Asp-Net45
- Web-AppInit 

users:

- IIS_IUSRS
- IUSR
- IIS APPPOOL\ChocolateyServer

chocoserver/tools contains chocolatey server installation (copied from windows machine with internet access)

Chocolatey API key is in vars_win.yml (unencrypted-point to vault_win.yml) and vault_win.yml (encrypted)

vars_win.yml:

api_key: '{{ vault_api_key }}'

vault_win.yml:

vault_api_key: myapi

Playbook will copy Chocolatey server files to D drive, installs IIS server and features,removes default IIS web site, creates Chocolatey application pool, sets ACL permissions on D:\tools\chocolatey.server and D:\tools\chocolatey.server\App_Data,creates Chocolatey IIS site and changes default API key

– name: install choco server
hosts: dc2
vars_files:
– group_vars/windows/vars_win.yml
– group_vars/features/features.yml
gather_facts: yes
tasks:
– name: Copy Chocolatey server to D drive
win_copy:
src: /root/win_playbooks/choco_server/
dest: D:\
– name: Ensure IIS is installed
win_feature:
name: Web-Server
state: present
include_management_tools: True
– name: Ensure IIS Web-Server and ASP.NET are installed
win_feature:
name: ‘{{ item }}’
state: present
with_items: ‘{{ features }}’
– name: Ensure Default Web Site is not present
win_iis_website:
name: “Default Web Site”
state: absent
#- name: Chocolatey.server package is installed
# win_chocolatey:
# name: “chocolatey.server”
# state: present
– name: Configure AppPool for Chocolatey.server
win_iis_webapppool:
name: ChocolateyServer
state: started
attributes:
enable32BitAppOnWin64: true
managedRuntimeVersion: v4.0
managedPipelineMode: Integrated
startMode: AlwaysRunning
autoStart: true
– name: Grant read permissions to D:\tools\chocolatey.server
win_acl:
user: ‘{{ item }}’
path: D:\tools\chocolatey.server
rights: Read
state: present
type: allow
inherit: ContainerInherit, ObjectInherit
progagation: InheritOnly
with_items: ‘{{ users }}’
– name: Grant IIS APPPOOL\ modify permissions to D:\tools\chocolatey.server\App_Data
win_acl:
user: ‘{{ item }}’
path: D:\tools\chocolatey.server
rights: Modify
state: present
type: allow
inherit: ContainerInherit, ObjectInherit
progagation: InheritOnly
with_items: ‘{{ users }}’
– name: Create Chocolatey IIS site
win_iis_website:
name: “chocolatey”
state: started
port: 80
#ip: 127.0.0.1
application_pool: “ChocolateyServer”
physical_path: D:\tools\chocolatey.server
parameters: logfile.directory:c:\ChocolateyServer\logs
register: website
– name: Change default API key
win_lineinfile:
path: D:\tools\chocolatey.server\web.config
regexp: ‘<add key=”apiKey” value=”chocolateyrocks” />’
line:’         <add key=”apiKey” value=”{{ api_key }}”/>’
state: present

PuppetDB is open source storage service for Puppet nodes

Installation

In this example postgresql 11 is installed

rpm -Uvh https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/pgdg-centos11-11-2.noarch.rpm
yum install postgresql11-server postgresql11-contrib

Initialize postgresql

/usr/pgsql-11/bin/postgresql-11-setup initdb

Start PostrgeSQL service

systemctl enable postgresql-11.service
systemctl start postgresql-11.service

Switch to postgress user, create user puppetdb and puppetdb database

sudo -iu postgres
createuser -DRSP puppetdb
createdb -E UTF8 -O puppetdb puppetdb
psql puppetdb -c 'create extension pg_trgm'

Edit  /var/lib/pgsql/11/data/pg_hba.conf

Untitled.png

Install puppetdb

rpm -Uvh https://yum.puppetlabs.com/puppet5/puppet5-release-el-7.noarch.rpm
yum install puppetdb

Edit /etc/puppetlabs/puppetdb/conf.d/database.ini, specify puppetdb username/password

[database]
classname = org.postgresql.Driver
subprotocol = postgresql

# The database address, i.e. //HOST:PORT/DATABASE_NAME
subname = //localhost:5432/puppetdb

# Connect as a specific user
username = puppetdb

# Use a specific password
password = puppetdb

Edit /etc/puppetlabs/puppetdb/conf.d/jetty.ini

Uncomment host = 0.0.0.0

Edit /etc/sysconfig/puppetdb and re-map memory needed for puppetdb

JAVA_ARGS="-Xmx192m

Start puppetdb

systemctl start puppetdb && systemctl enable puppetdb

Setting Puppet server

make sure puppetb DNS name is resolveable (/etc/hosts)

Edit  /etc/puppetlabs/puppet/puppet.conf,add following lines

[master]
storeconfigs = true
storeconfigs_backend = puppetdb

Create /etc/puppetlabs/puppet/puppetdb.conf

[main]
server_urls = https://puppetdb.example.com:8081/

Create /etc/puppetlabs/puppet/routes.yaml

---
master:
facts:
terminus: puppetdb
cache: yaml

install puppetdb-termini and restart puppet server

yum install puppetdb-termini
systemctl restart puppetserver

On puppet node run puppet -t

Login to puppetdb and verify data from node are transfered to puppetdb

psql -h localhost puppetdb puppetdb
puppetdb=>\x
puppetdb=>select * from catalogs;

Untitled.png

Unlike other tasks, this one requires runas (become) permissions. So, we need to specify become statement in playbook, and to add following directives in group_vars folder (see this guide how to create it.

add 4 “ansible_become” lines as per example

---
ansible_user: Administrator
ansible_password: Pass
ansible_connection: winrm
ansible_port: 5986
ansible_winrm_server_cert_validation: ignore
ansible_become: yes
ansible_become_user: Administrator
ansible_become_pass: Passw
ansible_become_method: runas
Both are same account,it’s local admin account promoted to Domain Administrator after creating AD Domain, the reason why we need to add those 4 lines is because renaming AD joined machines required Active Directory credentials, those 4 “ansible_become” lines instruct Ansible to use domain administrator credentials instead of local administrator.
- name: Change computer name
  hosts: dc2
  tasks:
   - name: Change host name
     become: yes
     win_hostname:
       name: server2
     register: name_changed
   - name: reboot server after hostname changes
     win_reboot:
       msg: "Computer name changed,rebooting...."
       pre_reboot_delay: 15
     when: name_changed.changed

 

In this example Page file will be moved to D drive, in order for Ansible to “track changes” file C:\Pagefile.log will be created after Page file is moved and server will be restarted afterwards.

In this example page file is set to automatic (InitialSize = 0; MaximumSize = 0), we can set custom Initial/Maximum size (in MB).

- name: Moving page file to another drive
  hosts: winserver
  gather_facts: yes
  tasks:
   - name: "Move Page File to D Drive"
     win_shell: |
       $a=Get-WmiObject -Query "select * from Win32_PageFileSetting"
       if ($a.Name -like 'C:\pagefile.sys') {
       $CurrentPageFile = Get-WmiObject -Query "select * from Win32_PageFileSetting where name='c:\\pagefile.sys'"
       $CurrentPageFile.delete()
       Set-WMIInstance -Class Win32_PageFileSetting -Arguments @{name="d:\pagefile.sys";InitialSize = 0; MaximumSize = 0}
       } write-output "Done" | out-file C:\Pagefile.log -Append
     args:
      creates: C:\Pagefile.log
     register: page
   - name: reboot server
     win_reboot:
       msg: "Page file moved,rebooting..."
       pre_reboot_delay: 15
     when: page.changed

Puppet Load Balancing

Posted: November 22, 2018 in Linux, puppet

1.PNG

Puppetmaster is Load Balancer,SSL termination happens there, Puppet client communicates only with puppetmaster, and puppetmaster sends requests to puppetservers1/2

 Settings puppetmaster,puppetservers 1 and 2

rpm -Uvh https://yum.puppetlabs.com/puppet5/puppet5-release-el-7.noarch.rpm yum -y install puppetserver

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

source ~/.bash_profile

edit /etc/puppetlabs/puppetserver/conf.d/webserver.conf.This will configure puppetservers to listen on port 8141 for TLS encrypted traffic and port 18140 for unencrypted traffic.

webserver: {
access-log-config: /etc/puppetlabs/puppetserver/request-logging.xml
client-auth: want
ssl-host: 0.0.0.0
ssl-port: 8141
host: 0.0.0.0
port: 18140
}

On all machines run netstat -nltp to make sure ports 18140/8141 are opened

2

Edit /etc/puppetlabs/puppet/puppet.conf

[main]
certname=puppetmaster.example.com
[master]
dns_alt_names = puppet,puppetmaster,puppetserver

Settings on puppetserver 1 and 2

When a Puppet agent connects to a Puppet master, the communication is authenticated with SSL certificates.On these backend servers we need to configure them to access certificate information passed in SSL certificates headers. Setting allow-header-cert-info to ‘true’ puts Puppet Server in vulnerable state. Ensure puppeservers1/1 are not reachable by an untrusted network.With allow-header-cert-info set to ‘true’, authorization code will use only the client HTTP header values—not an SSL-layer client certificate—to determine the client subject name, authentication status, and trusted facts.

On Puppetmaster1/2 edit /etc/puppetlabs/puppetserver/conf.d/auth.conf  and add following line at the beginning of file:allow-header-cert-info: true

authorization: {

version: 1

 allow-header-cert-info: true

 rules: [

{

…………………………..

Create SSL Certificate on puppetmaster (Load Balancer)

Initialize CA certificate

puppet cert list -a

Create certificate request
puppet certificate generate --dns-alt-names puppet,puppetmaster,puppetserver puppetmaster.example.com --ca-location local

Issue certificate

puppet cert sign puppetmaster.example.com --allow-dns-alt-names
puppet certificate find puppetmaster.example.com --ca-location local

On Puppetserver1/2 remove contents of /etc/puppetlabs/puppet/ssl folder

Now, from Puppetmaster copy content of /etc/puppetlabs/puppet/ssl/ to the same location of puppetserver1/2

cd /etc/puppetlabs/puppet/ssl
scp -r * root@172.23.124.228:/etc/puppetlabs/puppet/ssl/
scp -r * root@172.23.124.230:/etc/puppetlabs/puppet/ssl/

Once certificates are copied, on puppetserver1/2 execute puppet cert list -a

all copied certificates should be recognized by both puppet backend servers.

On puppetmaster (Load Balancer) install apache and mod_ssl

yum install httpd mod_ssl

Create /etc/httpd/conf.d/puppetlb.conf

Listen 8140

ServerName puppetmaster.example.com

SSLEngine on
SSLProtocol -ALL +TLSv1 +TLSv1.1 +TLSv1.2
SSLCipherSuite ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:-LOW:-SSLv2:-EXP

SSLCertificateFile /etc/puppetlabs/puppet/ssl/certs/puppetmaster.example.com.pem
SSLCertificateKeyFile /etc/puppetlabs/puppet/ssl/private_keys/puppetmaster.example.com.pem
SSLCertificateChainFile /etc/puppetlabs/puppet/ssl/ca/ca_crt.pem
SSLCACertificateFile /etc/puppetlabs/puppet/ssl/ca/ca_crt.pem

SSLCARevocationFile /etc/puppetlabs/puppet/ssl/ca/ca_crl.pem
SSLVerifyClient optional
SSLVerifyDepth 1
SSLOptions +StdEnvVars +ExportCertData

RequestHeader unset X-Forwarded-For
RequestHeader set X-SSL-Subject %{SSL_CLIENT_S_DN}e
RequestHeader set X-Client-DN %{SSL_CLIENT_S_DN}e
RequestHeader set X-Client-Verify %{SSL_CLIENT_VERIFY}e

ProxyPassMatch ^/(puppet-ca/v[123]/.*)$ balancer://puppetca/$1
ProxyPass / balancer://puppetworker/
ProxyPassReverse / balancer://puppetworker

BalancerMember http://172.23.124.237:18140
BalancerMember http://172.23.124.228:18140
BalancerMember http://172.23.124.230:18140

This configuration creates an Apache VirtualHost that will listen for connections on port 8140 and redirect traffic to one of the three puppetserver instances.Communication between the puppetserver machine and the puppetser1/2 will be unencrypted.

To redirect all certificate related traffic to a specific machine, the following ProxyPassMatch directive can be used:
ProxyPassMatch ^/([^/]+/certificate.*)$ balancer://puppetca/$1

On puppetserver start httpd and puppet

systemctl start httpd && systemctl enable httpd && systemctl start puppetserver && systemctl enable puppetserver

On backend puppetserver1/2 start puppeserver service

systemctl start puppetserver && systemctl enable puppetserver

Now on puppet node run puppet agent -t, sign certificate and puppet agent should work fine.