echo "

Ansible check if machines can connect to a port on a server

I had to test if all hosts were able to connect to a certain port on a certain server. Ansible was the perfect tool, but since not all machines have nc or nmap installed I had to make a workaround using Python. I will be checking if TCP port nagios.company.com:5666 is open.

the script, nagios.py (will be copied and executed on the remote host by ansible). This only works for TCP, changing SOCK_STREAM to SOCK_DGRAM will always return 0.

#!/usr/bin/python
import socket;
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex(('nagios.company.com',5666))
if result == 0:
   print "OK"
else:
   print "Not OK"

the playbook, nagios.yml

- name: Nagios connectivity test
  hosts: all
  tasks:
    - name: script
      script: /tmp/nagios.py
      register: nagios
    - debug: msg="{{ nagios.stdout }}"

the run command to filter the hosts that can't connect

ansible-playbook /tmp/nagios.yml | grep -B1 Not\ OK

Swap clean up script

Today I had a machine that had no swap space left which in return triggered a monitoring alert. Since the pressure was already gone but the swap wasn't cleared fast enough I searched and found this script as a nice solution.

clearswap.sh

#!/bin/bash

free_data="$(free)"
mem_data="$(echo "$free_data" | grep 'Mem:')"
free_mem="$(echo "$mem_data" | awk '{print $4}')"
buffers="$(echo "$mem_data" | awk '{print $6}')"
cache="$(echo "$mem_data" | awk '{print $7}')"
total_free=$((free_mem + buffers + cache))
used_swap="$(echo "$free_data" | grep 'Swap:' | awk '{print $3}')"

echo -e "Free memory:\t$total_free kB ($((total_free / 1024)) MB)\nUsed swap:\t$used_swap kB ($((used_swap / 1024)) MB)"
if [[ $used_swap -eq 0 ]]; then
    echo "Congratulations! No swap is in use."
elif [[ $used_swap -lt $total_free ]]; then
    echo "Freeing swap..."
    sudo swapoff -a
    sudo swapon -a
else
    echo "Not enough free memory. Exiting."
    exit 1
fi

 Thx Scott Severance for the script

Setting a Grub password using Ansible (update)

After an upgrade from RedHat the template for the password is changed and uses a variable that OpenScap doesn't read. This makes that our test fails. On top of that the test checks for the use of common administrator account names like root, admin or administrator. This update solves the issue and from now we use a user instead of root for Grub2.

Today I had to update and verify that we have an entry password for Grub on all machines. We needed to do this to comply with the Certified Cloud Service Provider's OpenScap benchmark.

This only prevents a person with physical access to boot in single user mode! The machine can still be booted without the need of a password.

RHEL6 machines all use legacy boot where on RHEL7 we also make a difference between EFI and non-EFI machines. 

 

First generate the hashes (on a RHEL6 and on a RHEL7 node)

RHEL6

grub-crypt --sha-512

RHEL7

grub2-mkpasswd-pbkdf2

And to finish... Here are the Ansible lines:

playbook lines:

#GRUB
- name: "grub v1 | add password"
  lineinfile: dest=/etc/grub.conf regexp='^password ' state=present line='password --encrypted {{ grub_password_v1_passwd }}' insertafter='^timeout'
  when: rhel6
  tags: grub-password

- stat: path=/sys/firmware/efi/efivars/
  register: grub_efi
  when: rhel7
  tags: grub-password

- name: remove unwanted grub.cfg on EFI systems
  file:
    state: absent
    path: /boot/grub2/grub.cfg
  when: rhel7 and grub_efi.stat.exists == True
  tags: grub-password

- name: Install user template to make sure grub2-mkconfig doesn't mess up the config
  template:
    src: 01_users.j2
    dest: /etc/grub.d/01_users
    owner: root
    group: root
    mode: '0700'
  notify:
     - grub2-mkconfig EFI
     - grub2-mkconfig MBR
  when: rhel7
  tags: grub-password

- name: "grub v2 EFI | add password"
  lineinfile: dest=/etc/grub2-efi.cfg regexp="^password_pbkdf2 {{ grub_user }} " state=present insertafter=EOF line='password_pbkdf2 {{ grub_user }} {{ grub_password_v2_passwd }}'
  when: rhel7 and grub_efi.stat.exists == True
  tags: grub-password

- name: "grub v2 MBR | add password"
  lineinfile: dest=/etc/grub2.cfg regexp="^password_pbkdf2 {{ grub_user }} " state=present insertafter=EOF line='password_pbkdf2 {{ grub_user }} {{ grub_password_v2_passwd }}'
  when: rhel7 and grub_efi.stat.exists == False

vars:

grub_password_v1_passwd: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
grub_password_v2_passwd: grub.pbkdf2.sha512.10000.xxxxxxxxxxxxxxxxxxx
grub_user: loginuser

 Handlers:

- name: grub2-mkconfig EFI
  command: grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
  when: grub_efi.stat.exists == True

- name: grub2-mkconfig MBR
  command: grub2-mkconfig -o /boot/grub2/grub.cfg
  when: grub_efi.stat.exists == False

01_users.j2:

#!/bin/sh -e

cat << "EOF"
set superusers="{{ grub_user }}"
export superusers
password_pbkdf2 {{ grub_user }} {{ grub_password_v2_passwd }}
EOF

Confluence Collaborative Editing

"This page is taking longer to load than usual. Give it a few moments, then try refreshing. Still having issues? Contact your Confluence admin" 

This is what I got after upgrading Confluence to a version above 6 (6.3.3 in my case), this is an issue caused by a too old version of httpd/apache as a reverse proxy and since we don't need the collaborative editing function we needed to find out how to disable it to get our system going again.

 

I know there is a python script for the rest API and you can use to web GUI and so on, but if you tried those you prabably already found out you can't kill the damn Synchrony process or get it disabled no matter how hard you try...

 

The easy solution is to go to Manage add-ons -> Select the view for the system add-ons -> And disable these 2:

 

Synchrony Interop Bootstrap Plugin

Confluence Collaborative Editor Plugin

 

And restart confluence to make sure it is permanent.

Attaching a USB device to KVM that reconnects frequently

I was trying to flash a new firmware to my BT headset (Sena SMH5-FM) and found out that the device reconnects several times during the flash process. Since KVM forces the use of BUS and ID rather than VendorID:DeviceID and the ID increments by one every reconnect this never works more than one time. To work around this I made a solution using UDEV to force a connect/reconnect of the device in KVM everytime it is being connected/disconnected to/from the host.

 

First find out the name of your KVM machine, you can try this command to get only the name portion

ps -ef | grep kvm |sed -n -e 's/^.*\(-name \)/\1/p'| cut -f2 -d" "

Mine is called win2k12r2, albeit a Win10

Stop the VM and create the following file (if you already tried to flash and you have a device like mine that also changes the DeviceID a couple of times make more entries) -> replace Sena with a portion of the name or brand of your device (see output lsusb)

grep -B3 Sena /var/log/syslog | sed -n -e 's/^.*\(idProduct\)/\1/p' | sort | uniq

I got this as a result (I suppose they just change it twice and that the logic is xxxx becomes yxxx and one time they use a generic ffff)

idProduct=4d65
idProduct=cd65
idProduct=ffff

The VendorID is always the same and for Sena it is 092b

 

Next I created a USB device xml for everyone of them under

/etc/libvirt/qemu/hostdev-092b:ffff.xml

<hostdev mode='subsystem' type='usb'>
<source>
<vendor id='0x092b'/>
<product id='0xffff'/>
</source>
</hostdev>

and a UDEV rule to connect and disconnect them

/etc/udev/rules.d/10-local.rules

ACTION=="add", ATTRS{idVendor}=="092b", ATTRS{idProduct}=="ffff", RUN+="/usr/bin/virsh attach-device win2k12r2 /etc/libvirt/qemu/hostdev-092b:ffff.xml"
ACTION=="remove", ATTRS{idVendor}=="092b", ATTRS{idProduct}=="ffff", RUN+="/usr/bin/virsh detach-device win2k12r2 /etc/libvirt/qemu/hostdev-092b:ffff.xml"
ACTION=="add", ATTRS{idVendor}=="092b", ATTRS{idProduct}=="cd65", RUN+="/usr/bin/virsh attach-device win2k12r2 /etc/libvirt/qemu/hostdev-092b:cd65.xml"
ACTION=="remove", ATTRS{idVendor}=="092b", ATTRS{idProduct}=="cd65", RUN+="/usr/bin/virsh detach-device win2k12r2 /etc/libvirt/qemu/hostdev-092b:cd65.xml"
ACTION=="add", ATTRS{idVendor}=="092b", ATTRS{idProduct}=="4d65", RUN+="/usr/bin/virsh attach-device win2k12r2 /etc/libvirt/qemu/hostdev-092b:4d65.xml"
ACTION=="remove", ATTRS{idVendor}=="092b", ATTRS{idProduct}=="4d65", RUN+="/usr/bin/virsh detach-device win2k12r2 /etc/libvirt/qemu/hostdev-092b:4d65.xml"

 

After this you can start your VM and try to flash your device, if it still fails check again to see if there are no extra DeviceID's in the syslog

Configuring F5 and Apache for security headers

We started to implement security headers in all our public web services. This article has some examples of how I implemented them in F5 and/or Apache.

 

For HTTP Strict Transport Security (HSTS) I used an iRule. (current max-age is 181 days)

when RULE_INIT {
set static::max_age 15638400
}
when HTTP_RESPONSE {
  #HSTS
  HTTP::header insert Strict-Transport-Security "max-age=$static::max_age; includeSubDomains"
}

If you don't have an F5 you can implement the HSTS header in apache as well like this:

Header append Strict-Transport-Security "max-age=63072000; includeSubdomains;"

The other Security Headers are in Apache if possible.

RequestHeader set X-Forwarded-Proto "https"

Header append X-Frame-Options SAMEORIGIN
Header append X-XSS-Protection "1; mode=block"
Header append X-Content-Type-Options nosniff
Header append Content-Security-Policy "frame-ancestors 'self' https://*.cloudfront.net https://*.googleapis.com https://fonts.gstatic.com https://*.youtube.com https://www.googleadservices.com https://googleads.g.doubleclick.net https://s.ytimg.com https://www.google.com https://www.google.be https://usage.trackjs.com https://i.ytimg.com"
Header append x-webkit-csp "frame-ancestors 'self' https://*.cloudfront.net https://*.googleapis.com https://fonts.gstatic.com https://*.youtube.com https://www.googleadservices.com https://googleads.g.doubleclick.net https://s.ytimg.com https://www.google.com https://www.google.be https://usage.trackjs.com https://i.ytimg.com"
Header append X-Content-Security-Policy "frame-ancestors 'self' https://*.cloudfront.net https://*.googleapis.com https://fonts.gstatic.com https://*.youtube.com https://www.googleadservices.com https://googleads.g.doubleclick.net https://s.ytimg.com https://www.google.com https://www.google.be https://usage.trackjs.com https://i.ytimg.com"
Header append Referrer-Policy "strict-origin-when-cross-origin"

Or for Java based applications we also use an iRule:

when HTTP_REQUEST { 
HTTP::header insert X-Forwarded-Proto "https"
}
when HTTP_RESPONSE {
#X-XSS-Protection
HTTP::header insert X-XSS-Protection "1; mode=block"
#X-Frame-Options
HTTP::header insert X-Frame-Options "SAMEORIGIN"
#X-Content-Type-Options
HTTP::header insert X-Content-Type-Options "nosniff"
#CSP
HTTP::header insert Content-Security-Policy "frame-ancestors 'self'"
#CSP for IE
HTTP::header insert X-Content-Security-Policy "frame-ancestors 'self'"
#CSP
HTTP::header insert x-webkit-csp "frame-ancestors 'self'"
#referrere policy
HTTP::header insert Referrer-Policy "strict-origin-when-cross-origin"
}

Some info about Security Headers:

And to verify your Security Headers you can use this online tool

And the blog of the guy who made the test. He seems well informed and his blog has a lot of useful information and examples

And of course to verify that this site got an A rating!

Home ← Older posts