Using saslauthd with PAM for Percona MongoDB

March 2nd, 2021 No comments

I recently had reason to authenticate users in MongoDB against an Active Directory source. In Mongo Community Edition, this isn’t enabled/possible. Upgrading to Mongo Enterprise is required for those features. Our team made the switch to Percona’s Distribution of Mongo to take advantage of the In Memory backend otherwise only available in Mongo Enterprise. There is some documentation around using saslauthd as an authentication proxy directly to LDAP, however we already have these Linux hosts joined to our Active Directory domain. We wanted to take advantage of the existing realmd/sssd connection to authenticate AD users. What we ended up with was a combination of a couple of places as I searched the web and wanted to pull it all together here. Here are a few of the posts that helped point me in the right direction:


We’re running CentOS 7 and Percona Mongo 4.4. Here’s the settings I made to allow us to use SASL with our existing PAM configuration:

# Install SASL
sudo yum -y install cyrus-sasl cyrus-sasl-plain
# /etc/sasl2/mongodb.conf
pwcheck_method: saslauthd
saslauthd_path: /var/run/saslauthd/mux
log_level: 5
mech_list: plain
# /etc/pam.d/mongodb
auth       include	password-auth
account    include	password-auth

And finally in the Mongo configuration, we need to enable Authentication as well as allow the PLAIN mechanism in addition to the SCRAM-SHA-1 used for internal Mongo auth.

# /etc/mongod.conf
    mode: requireTLS
  authorization: enabled
  authenticationMechanisms: PLAIN,SCRAM-SHA-1

That’s pretty much it. Initially, a local administrator account will need to be created – for example:

mongo --tls --tlsAllowInvalidHostnames --authenticationDatabase admin 
> use admin
switched to db admin
> db.createUser({user: "dba", pwd: passwordPrompt(), roles: ['root']});
Enter password:
Successfully added user: { "user" : "dba", "roles" : [ "root" ] }

Disconnect and reconnect using authentication and then add users to the $external authentication database:

mongo --tls --authenticationDatabase admin --host -u dba
> use MyDatabase
switched to db MyDatabase
> db.getSiblingDB("$external").createUser({user: "myadaccount",  roles: [ {role: 'dbAdmin', db: "MyDatabase" }] });
Successfully added user: {
	"user" : "myadaccount",
	"roles" : [
			"role" : "dbAdmin",
			"db" : "MyDatabase"

Hopefully this helps someone else in the future!

IE 11 and CloudForms Certificate Issues

May 16th, 2016 No comments

We were receiving an error when using IE 11 against a CloudForms appliance: “Error: Name is required”. It appears to be due to IE’s handling of Self-Signed certificates.

Since we’re using IPA as the authentication source for CloudForms, I figured we’d just use that to generate certs for the appliance and then we can trust the CA from IPA. Here’s a gist of the shell script I whipped up to do that. It should be run from the CF Appliance that’s already joined to the IPA realm.

Packaging VMware VDDK 6.0.x RPM for CloudForms

April 27th, 2016 No comments


Here’s a SPEC file I came up with to package the VMware VDDK as an RPM for CloudForms/ManageIQ appliances. VDDK 5.x came with an install script, but 6.x does not. It’s probably better packaged as an RPM anyway. This is based off of the instructions available at (for paying Red Hat customers).

The latest versions will be available at


This is packaged as a nosrc.rpm since VMware-vix-disklib can’t be distributed. To build, run the following:

yum install rpmdevtools

Download the VMware-vix-disklib-6.0.2-3566099.x86_64.tar.gz to ~/rpmbuild/SOURCES
Download the vmware-vix-disklib.spec to ~/rpmbuild/SPECS

rpmbuild -ba ~/rpmbuild/SPECS/vmware-vix-disklib.spec

SPEC file

Name:           vmware-vix-disklib
Version:        6.0.2
Release:        1%{?dist}
Summary:        The Virtual Disk Development Kit (VDDK) is a collection of C libraries, code samples, utilities, and documentation to help you create or access VMware virtual disk storage.
License:        Proprietary
Source0:        VMware-vix-disklib-6.0.2-3566099.x86_64.tar.gz
NoSource:	0
BuildRequires:  coreutils
The Virtual Disk Development Kit (VDDK) is a collection of C libraries, code samples, utilities, and documentation to help you create or access VMware virtual disk storage. The kit includes:
* The Virtual Disk and Disk Mount libraries, sets of C function calls to manipulate virtual disk files. C++ code samples that you can build with either Visual Studio or the GNU C compiler
* Documentation about the VDDK libraries and the command-line utilities
* The Disk Mount utility to access files and file systems in offline virtual disks on Windows or Linux guest virtual machines
* The Virtual Disk Manager utility to manipulate offline virtual disk on Windows or Linux (clone, create, relocate, rename, grow, shrink, or defragment)
%setup -n %{name}-distrib
%__mkdir_p %{buildroot}/usr/lib/vmware-vix-disklib
%__cp -r bin64 include lib64 %{buildroot}/usr/lib/%{name}
%__ln_s /usr/lib/vmware-vix-disklib/lib64/ %{buildroot}/usr/lib/
%__ln_s /usr/lib/vmware-vix-disklib/lib64/ %{buildroot}/usr/lib/
%doc doc/*
* Wed Apr 27 2016 Matt Hyclak <> 6.0.2-1
Initial Build

Delaying VM Deletion during Retirement in CFME 5.4

September 29th, 2015 No comments

At $DAYJOB we would like to be able to “un-retire” a VM, especially in those cases where a customer retires it and “didn’t know that’s what it would do” or similar. To meet these requirements, I’ve introduced a delay in processing the full retirement by overriding the default pre_retirement.rb method. Here’s the gist of things:

# Description: This method powers-off the VM on the provider and waits for Retirement Delay to pass before continuing
require 'miq_dev_util'
@logger =$evm, 'pre_retirement')
vm = $evm.root['vm']
customer_id = $evm.instantiate('/Configuration/Methods/get_customer_identifier')['return_value']
retirement_delay = $evm.instantiate("/Infrastructure/VM/Retirement/Configuration/RetirementDelay/#{customer_id}")['retirement_delay'].gsub(' ', '.')
#TODO: Figure out a way to ensure retirement_delay is valid
@logger.log('info', "Found Customer #{customer_id} with retirement delay #{retirement_delay}")
# Power off the VM
unless vm.nil? || vm.attributes['power_state'] == 'off'
  ems = vm.ext_management_system
  @logger.log('info', "Powering Off VM <#{}> in provider <#{ems.try(:name)}>")
# If we don't have a delay, continue on
if retirement_delay.nil?
  @logger.log('info', "No retirement delay requested. Continuing with the process")
# Otherwise process the delay
  if vm.retirement_state == 'retiring'
    @logger.log('info', "Delaying #{retirement_delay} before finishing retirement for #{}")
    # The VM isn't really retired here, but for display purposes lets see what happens
    # The retirement date isn't set, so that may be a way to differentiate if we need to
    vm['retired'] = true # Because exposing the retired= method is too hard?
    vm.retirement_state = 'delaying'
    $evm.root['ae_result']         = 'retry'
    $evm.root['ae_retry_interval'] = "#{retirement_delay}"
  elsif vm.retirement_state == 'delaying'
    @logger.log('info', "Retirement delay reached. Continuing with the process.")
    vm['retired'] = false # Have to set this back so finish_retirement doesn't bomb later.
    vm.retirement_state = 'retiring'

Some items of note:

  1. I’m using the miq_dev_util module written by my colleague that provides a couple of nice utility functions. In this case I’m only using the logging, so swapping that out would be no big deal.
  2. The VM gets “retired” very early on so that the VM shows up with an ‘R’ for an icon and it is obvious it’s been retired – even though it hasn’t been deleted. During this time, the Retirement Status is set to “Delaying”.
  3. We take advantage of the retry capabilities of the state machine to perform the delay for us.
  4. customer_identifier is something internal to us. You can use whatever key you like to search for the appropriate instance of RetirementDelay. Eventually, retirement_delay should contain a ruby-valid time statement, such as ’60.minutes’ or ‘7.days’

Hope you find this useful!

Deploying ESXi with Satellite 6

June 11th, 2015 2 comments

Deploy the files to the Satellite server

  • Download the latest ISO from VMware (e.g. VMware-ESXi-5.5U2-RollupISO2.iso).
  • Transfer to the satellite server
  • Run some code
# mount -o loop VMware-ESXi-5.5U2-RollupISO2.iso /mnt
# mkdir /var/lib/tftpboot/boot/esxi55u2
# cd /mnt
# cp -a * /var/lib/tftpboot/boot/esxi55u2
# cd /var/lib/tftpboot/boot/esxi55u2
# sed -i 's#/#/boot/esxi55u2/#g' boot.cfg
# cd ..
# restorecon -R esxi55u2

Create the Operating System inside Satellite

Hosts -> Operating Systems

  • Click New Operating System
    • Operating System
      • Name: ESXi
      • Major version: 5
      • Minor version: 5
      • Description: ESXi 5.5U2
      • OS Family: Red Hat
      • Arch: x86_64
    • Partition Table
      • Kickstart Default
    • Installation Media
      • Any Mirror – Can create a esxi mirror if desired.

Hosts -> Provisioning Templates

  • Click New Template
    • Provisioning Template
      • Name: ESXi OCP PXELinux
        SERIAL 0 115200n8
        DEFAULT esxi5.serial
        PROMPT 0
        MENU TITLE PXE Boot
        LABEL esxi5.serial
             MENU LABEL ^4) ESXi55_Serial
             KERNEL boot/esxi55u2/mboot.c32
             APPEND -c boot/esxi55u2/boot.cfg text com1_Port=0x3f8 gdbPort=none logPort=none tty2Port=com1 ks=<%=foreman_url("provision")%>; ignoreHeadless="True"
        LABEL hddboot
        LOCALBOOT 0x80
        MENU LABEL ^Boot from local disk
    • Type: PXELinux
    • Association:
    • ESXi 5.5
  • Click New Template
    • Provisioning Template
      • Name: ESXi OCP Kickstart
        install --firstdisk --overwritevmfs
        rootpw --iscrypted <%= root_pass %>
        network --bootproto=dhcp
        %post --interpreter=busybox --ignorefailure=true
        # Add temporary DNS resolution so the foreman call works
        echo "nameserver <%= @host.subnet.dns_primary %>" >> /etc/resolv.conf
        echo "nameserver <%= @host.subnet.dns_secondary %>" >> /etc/resolv.conf
        wget -O /dev/null <%= foreman_url %>
        echo "Done with Foreman call"
        esxcfg-advcfg -k none gdbPort
        esxcfg-advcfg -k none logPort
        esxcfg-advcfg -k com1 tty2Port
        #script to set first boot options
        %firstboot --interpreter=busybox
        # enable VHV (Virtual Hardware Virtualization to run nested 64bit Guests + Hyper-V VM)
        grep -i "vhv.enable" /etc/vmware/config || echo "vhv.enable = \"TRUE\"" >> /etc/vmware/config
        # enable & start remote ESXi Shell (SSH)
        vim-cmd hostsvc/enable_ssh
        vim-cmd hostsvc/start_ssh
        # enable & start ESXi Shell (TSM)
        vim-cmd hostsvc/enable_esx_shell
        vim-cmd hostsvc/start_esx_shell
        # supress ESXi Shell shell warning
        esxcli system settings advanced set -o /UserVars/SuppressShellWarning -i 1
        # ESXi Shell interactive idle time logout
        esxcli system settings advanced set -o /UserVars/ESXiShellInteractiveTimeOut -i 3600
        # Disable IPv6 for VMkernel interfaces
        esxcli system module parameters set -m tcpip3 -p ipv6=0
        # enable firewall
        esxcli network firewall set --default-action false --enabled yes
        # services to enable by default
        FIREWALL_SERVICES="syslog sshClient ntpClient updateManager httpClient netdump"
        esxcli network firewall ruleset set --ruleset-id ${SERVICE} --enabled yes
        # enter maintenance mode
        esxcli system maintenanceMode set -e true
        # Needed for configuration changes that could not be performed in esxcli
        esxcfg-advcfg -k none gdbPort
        esxcfg-advcfg -k none logPort
        esxcfg-advcfg -k com1 tty2Port
        esxcli system shutdown reboot -d 60 -r "rebooting after host configurations"
      • Type: provision
      • Association:
        • ESXi 5.5

Hosts -> Operating Systems

  • Select ESXi 5.5
    • Templates
      • provision: ESXi OCP Kickstart
      • PXELinux: ESXi OCP PXELinux



Pasteboard (clipboard) utilities in OSX

May 20th, 2015 No comments

I came across the pbcopy and pbpaste utilities today. It was handy, so I thought I’d post something mostly so I don’t forget. With file redirection, it becomes handy for things like pasting your public key into a website like github.

pbcopy < ~/.ssh/
Categories: System Administration Tags: ,

CloudForms VMware Tools Upgrade method

May 14th, 2015 No comments

I wrote a method a while back to allow me to upgrade VMware tools from within the CloudForms interface. I thought I would share it. I usually create a VM button to call the method, but it could probably be used elsewhere with some tweaking.

For the button, create it with System/Process/Request, Message create and Request upgrade_vmware_tools.

Screen Shot 2015-05-14 at 10.31.33 AM

Next, create an instance under /System/Process/Request called upgrade_vmware_tools that has a relationship field pointing to the location of your method. In my case, I chose /Infrastructure/VM/Operations/Methods/upgrade_vmware_tools

Screen Shot 2015-05-14 at 10.32.56 AM

Finally, you can create your instance and method.

Screen Shot 2015-05-14 at 10.33.32 AM

Here’s the code for what I wrote:

# CFME Automate Method: upgrade_vmware_tools
# Inputs: $evm.root['vm']
  # Method for logging
  def log(level, message)
    @method = 'upgrade_vmware_tools'
    $evm.log(level, "#{@method} - #{message}")
  def dump_attributes(my_object, my_object_name)
    $evm.log(:info, "Begin #{my_object_name}.attributes")
    my_object.attributes.sort.each { |k, v| $evm.log(:info, "#{my_object_name} Attribute - #{k}: #{v}")}
    $evm.log(:info, "End #{my_object_name}.attributes")
    $evm.log(:info, "")
  def dump_associations(my_object, my_object_name)
    $evm.log(:info, "Begin #{my_object_name}.associations")
    my_object.associations.sort.each { |a| $evm.log(:info, "#{my_object_name} Association - #{a}")}
    $evm.log(:info, "End #{my_object_name}.associations")
    $evm.log(:info, "")
  def dump_virtual_columns(my_object, my_object_name)
    $evm.log(:info, "Begin #{my_object_name}.virtual_columns")
    my_object.virtual_column_names.sort.each { |vcn| $evm.log(:info, "#{my_object_name} Virtual Column - #{vcn}")}
    $evm.log(:info, "End #{my_object_name}.virtual_columns")
    $evm.log(:info, "")
  log(:info, "CFME Automate Method Started")
  # Log information 
  #dump_attributes($evm.root, "$evm.root")
  #dump_associations($evm.root['vm'], "vm")
  #dump_virtual_columns($evm.root, "$evm.root")
  def find_vm(dc, name)
    vm = {}
    dc.datastoreFolder.childEntity.collect do |datastore|
      vm[:instance] = datastore.vm.find { |x| == name }
      if vm[:instance]
        vm[:datastore] =
  def upg_tools(vm)
    if vm[:instance][:guest][:guestFamily] == 'windowsGuest'
      instopts = '/s /v "/qn REBOOT=ReallySuppress"'
      instopts = nil
    $evm.log(:info, "Upgrading VMware Tools on #{vm[:instance][:name]}")
    upgtask = vm[:instance].UpgradeTools_Task(:installerOptions =&gt; instopts).wait_for_completion
  require 'rbvmomi'
  VIM = RbVmomi::VIM
  rvm  = $evm.root['vm']
  ems = rvm.ext_management_system()
  credentials = { :host =&gt; ems['hostname'], :user =&gt; ems.authentication_userid(), :password =&gt; ems.authentication_password(), :insecure =&gt; true }
  vim = VIM.connect credentials
  dc = vim.serviceInstance.find_datacenter
  vm = find_vm(dc,
  rc = upg_tools(vm)
  # Exit method
  log(:info, "CFME Automate Method Ended")
  exit MIQ_OK
  # Ruby rescue 
rescue =&gt; err
  log(:error, "[#{err}]\n#{err.backtrace.join("\n")}")
  exit MIQ_ABORT

Using the CloudForms SOAP API for daily provision reports

May 7th, 2015 No comments

For several reasons, we are currently unable to integrate directly from CloudForms to our CMDB. The current workaround is to send a CSV with the pertinent information to the group responsible for creating CIs in the CMDB. We implemented this originally as part of the Automation workflow – but after talking with this group, they indicated that the volume of individual CSV files would be overwhelming.

Read more…

Drum practice setup

April 24th, 2015 No comments

I’ve been using the Akai Professional EIE Pro 24-bit Electromusic Interface Expander
to interface with my PC for over a year now. I’ve used it to record into Reaper, but my primary use is for practicing my drums without the computer at all.

My current setup is 4 mics into the Akai (kick, snare, 2 overheads). I take the output of that and run it into an Behringer Xenyx 802. I also run my phone into the Xenyx for music playback. My Shure SE215-CL In Ears are then mixed between the music and the Akai, allowing me to control the mix of my own playing with the music.

It’s great for practicing new songs, controls the volume blasting my ears and has overall been a great solution for me.

Quick Script to join content hosts to Satellite 6

April 23rd, 2015 No comments

I wrote this for $DAYJOB to move machines registered with RHN or CentOS machines not registered to anything over to our Satellite 6 server.

I presume you have created activation keys titled organization-${DISTRO}${MAJ_REL}-development for all combinations of DISTRO (rhel, centos) and MAJ_REL (6, 7).

# Prepare to register with Satellite
# Make sure lsb_release is installed  
rpm -q redhat-lsb-core 2>&1 >/dev/null
if [ $? -ne 0 ]; then
  yum -y install redhat-lsb-core
# Which version are we running
RELEASE=`lsb_release -r -s`
# Are we on CentOS or RHEL?
if [ -f /etc/centos-release ]; then
  # Get the copr release of RHSM for CentOS
  if [ ! -f /etc/yum.repos.d/dgoodwin-subscription-manager.repo ]; then
    wget -O /etc/yum.repos.d/dgoodwin-subscription-manager.repo${MAJ_REL}/dgoodwin-subscription-manager-epel-${MAJ_REL}.repo
# Install the certificates - will pull in subscription-manager
yum -y install
# Install additional useful packages
yum -y install katello-agent
/sbin/service goferd start
# Register with Satellite
subscription-manager register --org="Example" --activationkey="example-${DISTRO}${MAJ_REL}-development"