Synchronizing Configuration Management Objects

This guide describes how to synchronize configuration management objects from your orcharhino to orcharhino proxies.

Starting Point

Assume you have one orcharhino and a certain number of orcharhino proxies attached. You use orcharhino to do configuration management with one of the following tools:

The orcharhino abstraction makes them work in a very similar way. There is an assignable entity for each system: roles in Ansible, classes in Puppet, and states in Salt. Eventually, a host gets assigned a number of those entities - either directly or through higher levels like host groups.

In order to apply configuration to hosts, the required classes, roles, or states have to be available on either the orcharhino itself or one of the orcharhino proxies. For Ansible, this is set to the remote execution host for the given subnet. For Puppet and Salt, the master is chosen during host creation.

Example Scenario

A host my-host-1.example.com is situated in the subnet orcharhino-proxy-1, which is controlled by orcharhino-proxy-1.example.com. All required Ansible roles have to be installed under /usr/share/ansible/roles on orcharhino-proxy-1.example.com, similar to Puppet modules in /etc/puppetlabs/code/environments/production (if production is the chosen Puppet environment) and /srv/salt for Salt.

A second host my-host-2.example.com is attached to a subnet with direct access to the orcharhino. In that case, those files have to be present on the orcharhino itself.

A uniform configuration is required, that is the installed classes, roles, and states have to be the same on orcharhino and all attached orcharhino proxies. This guide covers an established method to do so using calls to the orcharhino API via the Hammer CLI.

Prerequisites

Content Synchronization

This document does not cover how you keep your configuration management up-to-date with upstream repositories. There are well-established techniques for each of them.

At ATIX, we prefer working with the following tools:

They all provide a well defined version of the respective classes, roles, and states in a given directory structure.

Prepare orcharhino User and Role

We need to access orcharhino using Hammer CLI and the orcharhino API.

Therefore, we need a user with the appropriate rights. For the calls presented, this is the minimum set of required filters applicable to your orcharhino user role:

  • Resource: Ansible role

    • import_ansible_roles

  • Resource: Environment

    • import_environments

    • view_environments

  • Resource: Puppet class

    • import_puppetclasses

  • Resource: Salt state

    • import_salt_modules

  • Resource: Smart proxy

    • view_smart_proxies

This user role looks as follows:

User Role

SSH Connection

The listings in this section assume that you are working from a machine with a working Hammer CLI configuration and can connect to your orcharhino proxies with enhanced privileges. Adjust if necessary.

Ensure you have a passwordless SSH connection from your orcharhino Server to your orcharhino Proxies. The user opening the SSH connection from the orcharhino Server (assume it is called cfgsync) needs to have read privileges on the relevant directories (/etc/puppetlabs/code/environments/, /usr/share/ansible/roles, and /srv/salt) and write privileges on the orcharhino Proxies.

Create a passwordless SSH key pair as user cfgsync and write the public key into the ~/.ssh/authorized_keys of the orcharhino proxies' target accounts. Ensure there are no firewalls blocking this connection.

Run the following commands on your orcharhino:

cfgsync_user=My_Config_Sync_User_Name
adduser -m ${cfgsync_user}
su ${cfgsync_user}
ssh-keygen -q -f ~/.ssh/id_rsa -N ""

Create an account on the orcharhino proxies:

cfgsync_user=My_Config_Sync_User_Name
public_key=<CONTENT of or:~/.ssh/id_rsa.pub>

adduser -m ${cfgsync_user}
su ${cfgsync_user}
mkdir -p ~/.ssh
cat >> ~/.ssh/authorized_keys << EOF
${public_key}
EOF
chmod -R 700 ~/.ssh

For a fine grained access control, file access control lists are a fitting solution. They are used to grant this single user access to the relevant directories.

cfgsync_user=My_Config_Sync_User_Name
or_proxies=($(hammer --csv --no-headers proxy list --search "not name=$(hostname)" --fields name))
directories=("/srv/salt" "/usr/share/ansible/roles" "/etc/puppetlabs/code/environments")
for or_proxy in ${or_proxies[@]}
do
  for directory in ${directories[@]}
  do
    echo "setting file access control lists on ${or_proxy} for ${directory}"
    ssh ${or_proxy} mkdir -p "${directory}"
    ssh ${or_proxy} setfacl -Rm u:${cfgsync_user}:rwx "${directory}"
    ssh ${or_proxy} setfacl -Rdm u:${cfgsync_user}:rwx "${directory}"
  done
done

Configure Hammer CLI

Obtaining data from orcharhino and managing available configuration management files is done using Hammer CLI which has to be configured in the directory of the previously created user.

Log in as that user and create the following configuration:

cfgsync_user=My_Config_Sync_User_Name
cfgsync_password=My_Config_Sync_Password
mkdir -p ~/.hammer/cli.modules.d
cat > ~/.hammer/cli.modules.d/foreman.yml << EOF
:foreman:
  :username: '${cfgsync_user}'
  :password: '${cfgsync_password}'
  :refresh_cache: false
  :request_timeout: 300
EOF

Test if it worked by querying your orcharhino proxies:

hammer --csv --no-headers proxy list

Synchronize Content

The actual synchronization is done using rsync:

or_proxies=($(hammer --csv --no-headers proxy list --search "not name=$(hostname)" --fields name))
directories=("/srv/salt" "/usr/share/ansible/roles" "/etc/puppetlabs/code/environments")
for or_proxy in ${or_proxies[@]}
do
  for directory in ${directories[@]}
  do
    echo "Syncing ${directory} to ${or_proxy}"
    rsync -rzu ${directory}/* "${or_proxy}":"${directory}/"
  done
done

This provides the content for all orcharhino proxies to act as Puppet or Salt Master or as a proxy for remote execution using Ansible roles. Note that for the actual ability to use these tools additional settings might be needed.

Importing Configuration Objects

orcharhino needs to be informed every time you install new Ansible roles, Puppet classes, and Salt States. This can be done through an API call or by using the Hammer CLI.

As the Hammer CLI was included in the previous code, we continue that way:

or_itself=$(hammer --csv --no-headers proxy list --search "name=$(hostname)" --fields id)
hammer ansible role import --proxy-id ${or_itself}
hammer salt-state import --smart-proxy-id ${or_itself}
hammer proxy import-classes --id ${or_itself}

Automation

It is now possible to create a recurring job, either directly by writing a script and adding it to the users crontab, or through an orcharhino task. In the latter case, navigate to Hosts > Job templates, click Run, and select Run Command - Ansible Default or Run Command - SSH Default.

Set the target to your domain and add the following script:

or_proxies=($(hammer --csv --no-headers proxy list --search "not name=$(hostname)" --fields name))
directories=("/srv/salt" "/usr/share/ansible/roles" "/etc/puppetlabs/code/environments")
for or_proxy in ${or_proxies[@]}
do
  for directory in ${directories[@]}
  do
    echo "Syncing ${directory} to ${or_proxy}"
    rsync -rzu ${directory}/* "${or_proxy}":"${directory}/"
  done
done

or_itself=$(hammer --csv --no-headers proxy list --search "name=$(hostname)" --fields id)
hammer ansible role import --proxy-id ${or_itself}
hammer salt-state import --smart-proxy-id ${or_itself}
hammer proxy import-classes --id ${or_itself}

In the management UI, choose to show the advanced fields and set the effective user to your prepared account. If you want to run the job periodically, set the job execution to recurringly.

Job Invocation

Final Remarks

It is also possible to perform all these steps under a user account with higher privileges. However, security considerations advise to restrict the rights to the absolute necessary minimum.

You can adjust the script to your needs, as you might not be using all of the mentioned configuration management tools or maybe do not want to import the discovered classes with each run. In that case, strip the rights of the technical account further and import your configuration management manually each time you update something.

This scenario assumes regularly updated configuration objects. You might, for instance, be using r10k to synchronize Puppet classes. Setting up your system as described would ensure that orcharhino is always aware of the newest classes and they are available on all the orcharhino proxies.