Skip to main content

Raymii.org Logo (IEC resistor symbol)logo

Quis custodiet ipsos custodes?
Home | About | All pages | RSS Feed | Gopher

Ansible: access group vars for groups the current host is not a member of

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


Table of Contents


ansible logo

This guide shows you how to access group variables for a group the current hostis not a member of. In Ansible you can access other host variables usinghostvars['hostname'] but not group variables. The way described here isworkable, but do I consider it a dirty hack. So why did I need this? I have asetup where ssl is offloaded by haproxy servers, but the virtual hosts and sslconfiguration are defined in Apache servers. The loadbalancers and appserversare 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 dothis is change the haproxy playbooks and configuration and define thecertificates 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 OceanVPS. 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 workedaround by looping over all the groups, then over all the hosts in the specificgroup, then if the host is the first in the loop, go over all the hostvars forthat host and then access the group var you want. This stackoverflow postgoes over that. In my case I needed to access it in a playbook, the loopingconstruction woudln't work there.

The inventory

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

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

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

However, we do need to modify the playbook that modifies the vhosts to onlyplace the certificates on the loadbalancers, and do nothing with thecertificates 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 thecertificates. We also put a when in place to make sure the two roles only runon 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 configurethe 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 theloadbalancers, they cannot access these variables since they are not in the samegroup.

The role

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

- 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, theloadbalancers still cannot access the group variables from the appservers. Thedirty hack part is that we symlink the group vars from the appserver folder tothe 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 whenthe file in the appserver folder is changed, the loadbalancer file is aswell because it's a symlink.

haproxy

haproxy in this case has one frontend where all traffic comes into, theappservers 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 findsthe certificate in the folder /etc/ssl/cluster/. The files there are aconcatenation of the public key, the private key and if needed the certificatechain.

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 certainconstraints set, so this 'suboptimal' workaround works.

Tags: ansible, client-side-ssl, haproxy, loadbalancer, ssl, tutorials