Your IP: Unknown · Your Status: ProtectedUnprotectedUnknown

Skip to main content

How we manage passwords using Ansible

Ansible is the core of our quick deployment infrastructure (which I’ve detailed here), meaning that we use it to run thousands of servers and automated processes. All of that infrastructure also needs password management, but at our scale, Ansible Vault doesn’t quite fulfill our needs. I’d like to share our solution for group password and permission management on Ansible.

How we manage passwords using Ansible

The problem with Ansible Vault is that it has poor support for group work and doesn’t have convenient user, permission and value management options. We always try to keep our infrastructure 100% IaC (Infrastructure as Code), so splitting passwords or adding manual actions wasn’t really an option for us.

We’ve grown fond of Team Password Manager (TPM) over time, but it was its integration functionality that made it the perfect fit for our solution. We were able to integrate TPM to Ansible, solving our group work, permission, and password organization issues. This also took password management off of DevOP’s hands by using encrypted vault files that solve merge requests and search problems in GitLab.

Here are the key changes we made to ensure that our many admins and developers could work securely and conveniently:

  • We moved all passwords and sensitive information from Ansible Vault and GitLab Variables to TPM;
  • We reworked all application configuration files to the jinja format;

These changes helped us fully separate the server configuration and application development processes. It also made the deployment process fully automated and developer-controlled.

Here are a few examples of how we use the TPM ansible module in group_vars and deployment playbooks.

Group_vars YAML example

elasticsearch_users:
  - { user: "writer", password: "{{ {'id':1517,'auth':'auth:deploy'} | nordsec.team_password_manager.get_password }}", roles: [ "writeonly" ] }
  - { user: "reader", password: "{{ {'id':1518,'auth':'auth:deploy'} | nordsec.team_password_manager.get_password }}", roles: [ "readonly" ] }

Playbook example

How to pull different values for different environments.

- name: Set tpm passwords
  set_fact:
    site_map_ids:
      production:
        projects:
          - 930
          - 963
        passwords:
          - 16383
      staging:
        projects:
          - 947
          - 1163
        passwords:
        - 16382

Preparing get request config:

- name: Prepare tpm config
  set_fact:
    tpm_config:
      auth: "auth:deploy"
      get_passwords_from_projects: "{{ site_map_ids[deploy_environment]['projects']|default([]) }}"
      get_passwords: "{{ site_map_ids[deploy_environment]['passwords']|default([]) }}"

The warmup process:

- name: Get passwords from TPM (warmup)
  tpm_module: "{{ tpm_config | combine({'update_cache': True}) }}"
  connection: local
  run_once: True
  when: inventory_hostname == ansible_play_hosts_all[0]

Getting all values from the cache:

- name: Get passwords from TPM
  tpm_module: "{{ tpm_config }}"
  connection: local
  register: tpm_pass_list

Results with variable names with can be used in application configurations and can easily be replaced.

"msg": {
        "changed": false,
        "failed": false,
        "tpm": {
            "IDENTITY_EMAIL_PARAM_AES_KEY": "xxxxxxxxxx",
            "AUTH_API_CLIENT_ID": "xxxxxxxxxx",
            "AUTH_API_CLIENT_SECRET": "xxxxxxxxxx",
...
            "RABBITMQ_API_PASSWORD": "xxxxxxxxxx"
        }
    }
}

You’ll have to complete the implementation based on your own specific needs and technical capabilities, but these are some of the building blocks that were essential for our implementation (you can find it all on GitHub). Now, all of our admin and dev teams across all of our infrastructure enjoy easy and dependable password management.