Ansible Amenities is a series of semi-regularly published posts documenting different uses of Ansible in the spirit of Hubert Klein Ikkinks Groovy Goodness.

Gitlab can do a whole host of different things for you. From building and testing to releasing and managing your software projects. We manage the SSH keys deployed to our engineering services through it as well. In this article we’re going to build a quick module for Ansible to fetch public SSH Key data from Gitlab to supply to our servers.

Gitlab API with Python

A module for Gitlab in Ansible is just a bit of Python written to interact with the API.

Interacting with the Gitlab API requires you to create an AccessToken. Make sure your account has created a valid Personal Access Token.

Using the Access Token we can log into Gitlab:

import gitlab

gitlab_url = "https://gitlab.example.org"
gitlab_token = "abcd"

gl = gitlab.Gitlab(gitlab_url, gitlab_token, per_page=100)

Retrieving Keys from Gitlab needs the username of the user to create:

user = "username"

gl_user = gl.users.list(search=user)[0] # We assume a single user matches the name we're looking for

Depending on your setup, your users may have multiple keys old and knew registered in Gitlab. Make sure you take the latest keys:

keys_data = gl_user.keys.list()

sanitized_keys_data = []
for k in keys_data:
    if k.last_used_at is not None:
        sanitized_keys_data.append(k)

ordered_keys_data = sorted(sanitized_keys_data, key=lambda key: key.last_used_at);
key = list(reversed(ordered_keys_data))[0].key

key now holds the public key bits of the SSH Key used by the user.

Ansible Module

With all the above learned, we can write our Ansible module:

class GitlabUserKeysInfo:
    def __init__(self, module):
        self.module = module
        self.gitlab_url = module.params.get("gitlab_url")
        self.gitlab_token = module.params.get("gitlab_token")
        self.user = module.params.get("user")
        self.gl = gitlab.Gitlab(self.gitlab_url, self.gitlab_token, per_page=100)

    def lookupUser(self):
        """
        - Finds the Username in Gitlab
        - Look up his SSH Keys
        - Grab last Used key
        - Respond with the username and key public data
        """
        user_data = self.gl.users.list(search=self.user)[0]
        keys_data = user_data.keys.list()

        sanitized_keys_data = []
        for k in keys_data:
            if k.last_used_at is not None:
                sanitized_keys_data.append(k)

        ordered_keys_data = sorted(sanitized_keys_data, key=lambda key: key.last_used_at);

        key = list(reversed(ordered_keys_data))[0].key

        user = {
            "name": user_data.username,
            "ssh_key": key
        }
        return user

def main():
    module = AnsibleModule(
        argument_spec=dict(
            gitlab_url=dict(type='str'),
            gitlab_token=dict(type='str', no_log=True),
            user=dict(type='str')
        )
    )

    gitlabUserKeysInfo = GitlabUserKeysInfo(module)
    result = dict()
    result = gitlabUserKeysInfo.lookupUser()
    module.exit_json(**result)

if __name__ == '__main__':
    main()

Placed in your Ansible modules directory, you can use it like this:

- name: "Get Keys for the user 'developer'"
  gitlab_group_members_info:
    gitlab_url: "https://gitlab.example.org"
    gitlab_token: "T0KEN"
    user: "developer"
  register: "gitlab_user_key"
... 
- name: Add key to users ~/.ssh/authorized_keys
  ansible.posix.authorized_key:
    user: developer
    state: present
    key: ""