Published: 27-01-2017 | Author: Remy van Elst | Text only version of this article

This guide shows you how to access group variables for a group the current host is not a member of. In Ansible you can access other host variables using hostvars['hostname'] but not group variables. The way described here is workable, but do I consider it a dirty hack. So why did I need this? I have a setup where ssl is offloaded by haproxy servers, but the virtual hosts and ssl configuration are defined in Apache servers. The loadbalancers and appservers are two different hostgroups, the ssl settings are in the appserver group_vars, which the hosts in the loadbalancer group need to access. The best way to do this is change the haproxy playbooks and configuration and define the certificates there, but in this specific case that wasn't a workable solution. Editing two yaml files (one for the appservers and one for the loadbalancers) was not an option in this situation.

If you like this article, consider sponsoring me by trying out a Digital Ocean VPS. With this link you'll get $100 credit for 60 days). (referral link)

This is applicable for other scenario's as well. In templates this can be worked around by looping over all the groups, then over all the hosts in the specific group, then if the host is the first in the loop, go over all the hostvars for that host and then access the group var you want. This stackoverflow post goes over that. In my case I needed to access it in a playbook, the looping construction woudln't work there.

The inventory

In the inventory file I created a new group. This group has the two other groups, appservers and loadbalancers in them and nothing else. Like so:

[appserver] app1.cluster app2.cluster [loadbalancer] lb1.cluster lb2.cluster [ssl:children] loadbalancer appserver

The shortnames expand to specifc SSH configuration. The ssl hostgroup effectively includes the following hosts:

app1

app2

lb1

lb2

However, we do need to modify the playbook that modifies the vhosts to only place the certificates on the loadbalancers, and do nothing with the certificates on the appservers. The playbook should still do it's normal thing, configuring the vhosts, on the appservers, but not on the loadbalancers.

The documentation has more information on hostgroups based on other groups.

The playbook

The playbook ( deploy-vhosts.yml ) first was this:

--- - hosts: appserver roles: - apache-vhost

After changing the hostgroup we need to add the specific role that deploys the certificates. We also put a when in place to make sure the two roles only run on the hosts where they should and not the other hosts:

--- - hosts: ssl roles: - {role: apache-vhost, when: "'appserver' in group_names" } - {role: sslcerts, when: "'loadbalancer' in group_names " }

The group vars

The group vars for the appservers contain the following information to configure the virtual hosts:

--- apache_vhost: example.cluster.nl: name: example.cluster.nl docroot: /home/example-cluster/domains/example.cluster.nl/public-html/ webuser: example-cluster ssl_name: example.cluster.nl serveraliases: - www.example.cluster.nl example2.cluster.nl: name: example2.cluster.nl docroot: /home/example2-cluster/domains/example2.cluster.nl/public-html/ webuser: example2-cluster ssl_name: example2.cluster.nl serveraliases: - www.example2.cluster.nl

The problem is that, when the deploy vhosts playbook in run on the loadbalancers, they cannot access these variables since they are not in the same group.

The role

The role sslcerts has one task file and one handler ( restart haproxy ). It makes sure the folder for the certificates exists and it places the certificate files there. There are extra when statements to make sure it only runs on the loadbalancers.

- name: create ssl folder file: path: /etc/ssl/cluster/ state: directory owner: root group: root when: "'loadbalancer' in group_names" tags: ssl - name: place certificates copy: src: files/ssl/{{ item.value.ssl_name }}.pem dest: /etc/ssl/cluster/{{ item.value.ssl_name }}.pem with_dict: '{{ apache_vhost }}' when: "'loadbalancer' in group_names" notify: restart haproxy tags: ssl

The crux

Even after configuring the special playbook that runs on all the hosts, the loadbalancers still cannot access the group variables from the appservers. The dirty hack part is that we symlink the group vars from the appserver folder to the loadbalancer folder:

ln -s /home/deploy/ansible/group_vars/appserver/apache-vhost.yml /home/deploy/ansible/group_vars/loadbalancer/apache-vhost-symlink.yml

Now, the loadbalancers have the group variable apache_vhost as well, and when the file in the appserver folder is changed, the loadbalancer file is as well because it's a symlink.

haproxy

haproxy in this case has one frontend where all traffic comes into, the appservers handle the different virtual hosts:

frontend https-in mode http bind 1.2.3.4:443 ssl crt /etc/ssl/cluster/ no-sslv3 acl secure dst_port eq 443 rsprep ^Set-Cookie:\ (.*) Set-Cookie:\ \1;\ Secure if secure rspadd Strict-Transport-Security:\ max-age=31536000 if secure option httplog option forwardfor option http-server-close option httpclose reqadd X-Forwarded-Proto:\ https default_backend appserver

haproxy handles sni transparantly based on the requested hostname, if it finds the certificate in the folder /etc/ssl/cluster/ . The files there are a concatenation of the public key, the private key and if needed the certificate chain.

Conclusion

In this case it might be better to change the haproxy playbook to handle this, or to change the group_vars to all . However, this environment has certain constraints set, so this 'suboptimal' workaround works.

Tags: ansible