Chapter 25. Using Ansible to manage IdM service vaults: storing and retrieving secrets

This section shows how an administrator can use the ansible-freeipa vault module to securely store a service secret in a centralized location. The vault used in the example is asymmetric, which means that to use it, the administrator needs to perform the following steps:

  1. Generate a private key using, for example, the openssl utility.
  2. Generate a public key based on the private key.

The service secret is encrypted with the public key when an administrator archives it into the vault. Afterwards, a service instance hosted on a specific machine in the domain retrieves the secret using the private key. Only the service and the administrator are allowed to access the secret.

If the secret is compromised, the administrator can replace it in the service vault and then redistribute it to those individual service instances that have not been compromised.

Prerequisites

This section includes these procedures:

In the procedures:

  • admin is the administrator who manages the service password.
  • private-key-to-an-externally-signed-certificate.pem is the file containing the service secret, in this case a private key to an externally signed certificate. Do not confuse this private key with the private key used to retrieve the secret from the vault.
  • secret_vault is the vault created to store the service secret.
  • HTTP/webserver1.idm.example.com is the service that is the owner of the vault.
  • HTTP/webserver2.idm.example.com and HTTP/webserver3.idm.example.com are the vault member services.
  • service-public.pem is the service public key used to encrypt the password stored in password_vault.
  • service-private.pem is the service private key used to decrypt the password stored in secret_vault.

25.1. Ensuring the presence of an asymmetric service vault in IdM using Ansible

Follow this procedure to use an Ansible playbook to create a service vault container with one or more private vaults to securely store sensitive information. In the example used in the procedure below, the administrator creates an asymmetric vault named secret_vault. This ensures that the vault members have to authenticate using a private key to retrieve the secret in the vault. The vault members will be able to retrieve the file from any IdM client.

Prerequisites

  • You have configured your Ansible control node to meet the following requirements:

    • You are using Ansible version 2.14 or later.
    • You have installed the ansible-freeipa package on the Ansible controller.
    • The example assumes that in the ~/MyPlaybooks/ directory, you have created an Ansible inventory file with the fully-qualified domain name (FQDN) of the IdM server.
    • The example assumes that the secret.yml Ansible vault stores your ipaadmin_password.
  • The target node, that is the node on which the ansible-freeipa module is executed, is part of the IdM domain as an IdM client, server or replica.
  • You know the IdM administrator password.

Procedure

  1. Navigate to the /usr/share/doc/ansible-freeipa/playbooks/vault directory:

    $ cd /usr/share/doc/ansible-freeipa/playbooks/vault
  2. Obtain the public key of the service instance. For example, using the openssl utility:

    1. Generate the service-private.pem private key.

      $ openssl genrsa -out service-private.pem 2048
      Generating RSA private key, 2048 bit long modulus
      .+++
      ...........................................+++
      e is 65537 (0x10001)
    2. Generate the service-public.pem public key based on the private key.

      $ openssl rsa -in service-private.pem -out service-public.pem -pubout
      writing RSA key
  3. Optional: Create an inventory file if it does not exist, for example inventory.file:

    $ touch inventory.file
  4. Open your inventory file and define the IdM server that you want to configure in the [ipaserver] section. For example, to instruct Ansible to configure server.idm.example.com, enter:

    [ipaserver]
    server.idm.example.com
  5. Make a copy of the ensure-asymmetric-vault-is-present.yml Ansible playbook file. For example:

    $ cp ensure-asymmetric-vault-is-present.yml ensure-asymmetric-service-vault-is-present-copy.yml
  6. Open the ensure-asymmetric-vault-is-present-copy.yml file for editing.
  7. Add a task that copies the service-public.pem public key from the Ansible controller to the server.idm.example.com server.
  8. Modify the rest of the file by setting the following variables in the ipavault task section:

    • Set the ipaadmin_password variable to the IdM administrator password.
    • Define the name of the vault using the name variable, for example secret_vault.
    • Set the vault_type variable to asymmetric.
    • Set the service variable to the principal of the service that owns the vault, for example HTTP/webserver1.idm.example.com.
    • Set the public_key_file to the location of your public key.

      This is the modified Ansible playbook file for the current example:

    ---
    - name: Tests
      hosts: ipaserver
      gather_facts: false
      vars_files:
      - /home/user_name/MyPlaybooks/secret.yml
      tasks:
      - name: Copy public key to ipaserver.
        copy:
          src: /path/to/service-public.pem
          dest: /usr/share/doc/ansible-freeipa/playbooks/vault/service-public.pem
          mode: 0600
      - name: Add data to vault, from a LOCAL file.
        ipavault:
          ipaadmin_password: "{{ ipaadmin_password }}"
          name: secret_vault
          vault_type: asymmetric
          service: HTTP/webserver1.idm.example.com
          public_key_file: /usr/share/doc/ansible-freeipa/playbooks/vault/service-public.pem
  9. Save the file.
  10. Run the playbook:

    $ ansible-playbook --vault-password-file=password_file -v -i inventory.file ensure-asymmetric-service-vault-is-present-copy.yml

25.2. Adding member services to an asymmetric vault using Ansible

Follow this procedure to use an Ansible playbook to add member services to a service vault so that they can all retrieve the secret stored in the vault. In the example used in the procedure below, the IdM administrator adds the HTTP/webserver2.idm.example.com and HTTP/webserver3.idm.example.com service principals to the secret_vault vault that is owned by HTTP/webserver1.idm.example.com.

Prerequisites

  • You have configured your Ansible control node to meet the following requirements:

    • You are using Ansible version 2.14 or later.
    • You have installed the ansible-freeipa package on the Ansible controller.
    • The example assumes that in the ~/MyPlaybooks/ directory, you have created an Ansible inventory file with the fully-qualified domain name (FQDN) of the IdM server.
    • The example assumes that the secret.yml Ansible vault stores your ipaadmin_password.
  • The target node, that is the node on which the ansible-freeipa module is executed, is part of the IdM domain as an IdM client, server or replica.
  • You know the IdM administrator password.
  • You have created an asymmetric vault to store the service secret.

Procedure

  1. Navigate to the /usr/share/doc/ansible-freeipa/playbooks/vault directory:

    $ cd /usr/share/doc/ansible-freeipa/playbooks/vault
  2. Optional: Create an inventory file if it does not exist, for example inventory.file:

    $ touch inventory.file
  3. Open your inventory file and define the IdM server that you want to configure in the [ipaserver] section. For example, to instruct Ansible to configure server.idm.example.com, enter:

    [ipaserver]
    server.idm.example.com
  4. Make a copy of the data-archive-in-asymmetric-vault.yml Ansible playbook file. For example:

    $ cp data-archive-in-asymmetric-vault.yml add-services-to-an-asymmetric-vault.yml
  5. Open the data-archive-in-asymmetric-vault-copy.yml file for editing.
  6. Modify the file by setting the following variables in the ipavault task section:

    • Set the ipaadmin_password variable to the IdM administrator password.
    • Set the name variable to the name of the vault, for example secret_vault.
    • Set the service variable to the service owner of the vault, for example HTTP/webserver1.idm.example.com.
    • Define the services that you want to have access to the vault secret using the services variable.
    • Set the action variable to member.

      This the modified Ansible playbook file for the current example:

    ---
    - name: Tests
      hosts: ipaserver
      gather_facts: false
    
      vars_files:
      - /home/user_name/MyPlaybooks/secret.yml
      tasks:
      - ipavault:
          ipaadmin_password: "{{ ipaadmin_password }}"
          name: secret_vault
          service: HTTP/webserver1.idm.example.com
          services:
          - HTTP/webserver2.idm.example.com
          - HTTP/webserver3.idm.example.com
          action: member
  7. Save the file.
  8. Run the playbook:

    $ ansible-playbook --vault-password-file=password_file -v -i inventory.file add-services-to-an-asymmetric-vault.yml

25.3. Storing an IdM service secret in an asymmetric vault using Ansible

Follow this procedure to use an Ansible playbook to store a secret in a service vault so that it can be later retrieved by the service. In the example used in the procedure below, the administrator stores a PEM file with the secret in an asymmetric vault named secret_vault. This ensures that the service will have to authenticate using a private key to retrieve the secret from the vault. The vault members will be able to retrieve the file from any IdM client.

Prerequisites

  • You have configured your Ansible control node to meet the following requirements:

    • You are using Ansible version 2.14 or later.
    • You have installed the ansible-freeipa package on the Ansible controller.
    • The example assumes that in the ~/MyPlaybooks/ directory, you have created an Ansible inventory file with the fully-qualified domain name (FQDN) of the IdM server.
    • The example assumes that the secret.yml Ansible vault stores your ipaadmin_password.
  • The target node, that is the node on which the ansible-freeipa module is executed, is part of the IdM domain as an IdM client, server or replica.
  • You know the IdM administrator password.
  • You have created an asymmetric vault to store the service secret.
  • The secret is stored locally on the Ansible controller, for example in the /usr/share/doc/ansible-freeipa/playbooks/vault/private-key-to-an-externally-signed-certificate.pem file.

Procedure

  1. Navigate to the /usr/share/doc/ansible-freeipa/playbooks/vault directory:

    $ cd /usr/share/doc/ansible-freeipa/playbooks/vault
  2. Optional: Create an inventory file if it does not exist, for example inventory.file:

    $ touch inventory.file
  3. Open your inventory file and define the IdM server that you want to configure in the [ipaserver] section. For example, to instruct Ansible to configure server.idm.example.com, enter:

    [ipaserver]
    server.idm.example.com
  4. Make a copy of the data-archive-in-asymmetric-vault.yml Ansible playbook file. For example:

    $ cp data-archive-in-asymmetric-vault.yml data-archive-in-asymmetric-vault-copy.yml
  5. Open the data-archive-in-asymmetric-vault-copy.yml file for editing.
  6. Modify the file by setting the following variables in the ipavault task section:

    • Set the ipaadmin_password variable to the IdM administrator password.
    • Set the name variable to the name of the vault, for example secret_vault.
    • Set the service variable to the service owner of the vault, for example HTTP/webserver1.idm.example.com.
    • Set the in variable to "{{ lookup('file', 'private-key-to-an-externally-signed-certificate.pem') | b64encode }}". This ensures that Ansible retrieves the file with the private key from the working directory on the Ansible controller rather than from the IdM server.
    • Set the action variable to member.

      This the modified Ansible playbook file for the current example:

    ---
    - name: Tests
      hosts: ipaserver
      gather_facts: false
    
      vars_files:
      - /home/user_name/MyPlaybooks/secret.yml
      tasks:
      - ipavault:
          ipaadmin_password: "{{ ipaadmin_password }}"
          name: secret_vault
          service: HTTP/webserver1.idm.example.com
          in: "{{ lookup('file', 'private-key-to-an-externally-signed-certificate.pem') | b64encode }}"
          action: member
  7. Save the file.
  8. Run the playbook:

    $ ansible-playbook --vault-password-file=password_file -v -i inventory.file data-archive-in-asymmetric-vault-copy.yml

25.4. Retrieving a service secret for an IdM service using Ansible

Follow this procedure to use an Ansible playbook to retrieve a secret from a service vault on behalf of the service. In the example used in the procedure below, running the playbook retrieves a PEM file with the secret from an asymmetric vault named secret_vault, and stores it in the specified location on all the hosts listed in the Ansible inventory file as ipaservers.

The services authenticate to IdM using keytabs, and they authenticate to the vault using a private key. You can retrieve the file on behalf of the service from any IdM client on which ansible-freeipa is installed.

Prerequisites

  • You have configured your Ansible control node to meet the following requirements:

    • You are using Ansible version 2.14 or later.
    • You have installed the ansible-freeipa package on the Ansible controller.
    • The example assumes that in the ~/MyPlaybooks/ directory, you have created an Ansible inventory file with the fully-qualified domain name (FQDN) of the IdM server.
    • The example assumes that the secret.yml Ansible vault stores your ipaadmin_password.
  • The target node, that is the node on which the ansible-freeipa module is executed, is part of the IdM domain as an IdM client, server or replica.
  • You know the IdM administrator password.
  • You have created an asymmetric vault to store the service secret.
  • You have archived the secret in the vault.
  • You have stored the private key used to retrieve the service vault secret in the location specified by the private_key_file variable on the Ansible controller.

Procedure

  1. Navigate to the /usr/share/doc/ansible-freeipa/playbooks/vault directory:

    $ cd /usr/share/doc/ansible-freeipa/playbooks/vault
  2. Optional: Create an inventory file if it does not exist, for example inventory.file:

    $ touch inventory.file
  3. Open your inventory file and define the following hosts:

    • Define your IdM server in the [ipaserver] section.
    • Define the hosts onto which you want to retrieve the secret in the [webservers] section. For example, to instruct Ansible to retrieve the secret to webserver1.idm.example.com, webserver2.idm.example.com, and webserver3.idm.example.com, enter:
    [ipaserver]
    server.idm.example.com
    
    [webservers]
    webserver1.idm.example.com
    webserver2.idm.example.com
    webserver3.idm.example.com
  4. Make a copy of the retrieve-data-asymmetric-vault.yml Ansible playbook file. For example:

    $ cp retrieve-data-asymmetric-vault.yml retrieve-data-asymmetric-vault-copy.yml
  5. Open the retrieve-data-asymmetric-vault-copy.yml file for editing.
  6. Modify the file by setting the following variables in the ipavault task section:

    • Set the ipaadmin_password variable to your IdM administrator password.
    • Set the name variable to the name of the vault, for example secret_vault.
    • Set the service variable to the service owner of the vault, for example HTTP/webserver1.idm.example.com.
    • Set the private_key_file variable to the location of the private key used to retrieve the service vault secret.
    • Set the out variable to the location on the IdM server where you want to retrieve the private-key-to-an-externally-signed-certificate.pem secret, for example the current working directory.
    • Set the action variable to member.

      This the modified Ansible playbook file for the current example:

    ---
    - name: Retrieve data from vault
      hosts: ipaserver
      become: no
      gather_facts: false
    
      vars_files:
      - /home/user_name/MyPlaybooks/secret.yml
      tasks:
      - name: Retrieve data from the service vault
        ipavault:
          ipaadmin_password: "{{ ipaadmin_password }}"
          name: secret_vault
          service: HTTP/webserver1.idm.example.com
          vault_type: asymmetric
          private_key: "{{ lookup('file', 'service-private.pem') | b64encode }}"
          out: private-key-to-an-externally-signed-certificate.pem
          state: retrieved
  7. Add a section to the playbook that retrieves the data file from the IdM server to the Ansible controller:

    ---
    - name: Retrieve data from vault
      hosts: ipaserver
      become: no
      gather_facts: false
      tasks:
    [...]
      - name: Retrieve data file
        fetch:
          src: private-key-to-an-externally-signed-certificate.pem
          dest: ./
          flat: yes
          mode: 0600
  8. Add a section to the playbook that transfers the retrieved private-key-to-an-externally-signed-certificate.pem file from the Ansible controller on to the webservers listed in the webservers section of the inventory file:

    ---
    - name: Send data file to webservers
      become: no
      gather_facts: no
      hosts: webservers
      tasks:
      - name: Send data to webservers
        copy:
          src: private-key-to-an-externally-signed-certificate.pem
          dest: /etc/pki/tls/private/httpd.key
          mode: 0444
  9. Save the file.
  10. Run the playbook:

    $ ansible-playbook --vault-password-file=password_file -v -i inventory.file retrieve-data-asymmetric-vault-copy.yml

25.5. Changing an IdM service vault secret when compromised using Ansible

Follow this procedure to reuse an Ansible playbook to change the secret stored in a service vault when a service instance has been compromised. The scenario in the following example assumes that on webserver3.idm.example.com, the retrieved secret has been compromised, but not the key to the asymmetric vault storing the secret. In the example, the administrator reuses the Ansible playbooks used when storing a secret in an asymmetric vault and retrieving a secret from the asymmetric vault onto IdM hosts. At the start of the procedure, the IdM administrator stores a new PEM file with a new secret in the asymmetric vault, adapts the inventory file so as not to retrieve the new secret on to the compromised web server, webserver3.idm.example.com, and then re-runs the two procedures.

Prerequisites

  • You have configured your Ansible control node to meet the following requirements:

    • You are using Ansible version 2.14 or later.
    • You have installed the ansible-freeipa package on the Ansible controller.
    • The example assumes that in the ~/MyPlaybooks/ directory, you have created an Ansible inventory file with the fully-qualified domain name (FQDN) of the IdM server.
    • The example assumes that the secret.yml Ansible vault stores your ipaadmin_password.
  • The target node, that is the node on which the ansible-freeipa module is executed, is part of the IdM domain as an IdM client, server or replica.
  • You know the IdM administrator password.
  • You have created an asymmetric vault to store the service secret.
  • You have generated a new httpd key for the web services running on IdM hosts to replace the compromised old key.
  • The new httpd key is stored locally on the Ansible controller, for example in the /usr/share/doc/ansible-freeipa/playbooks/vault/private-key-to-an-externally-signed-certificate.pem file.

Procedure

  1. Navigate to the /usr/share/doc/ansible-freeipa/playbooks/vault directory:

    $ cd /usr/share/doc/ansible-freeipa/playbooks/vault
  2. Open your inventory file and make sure that the following hosts are defined correctly:

    • The IdM server in the [ipaserver] section.
    • The hosts onto which you want to retrieve the secret in the [webservers] section. For example, to instruct Ansible to retrieve the secret to webserver1.idm.example.com and webserver2.idm.example.com, enter:

      [ipaserver]
      server.idm.example.com
      
      [webservers]
      webserver1.idm.example.com
      webserver2.idm.example.com
    Important

    Make sure that the list does not contain the compromised webserver, in the current example webserver3.idm.example.com.

  3. Open the data-archive-in-asymmetric-vault-copy.yml file for editing.
  4. Modify the file by setting the following variables in the ipavault task section:

    • Set the ipaadmin_password variable to the IdM administrator password.
    • Set the name variable to the name of the vault, for example secret_vault.
    • Set the service variable to the service owner of the vault, for example HTTP/webserver.idm.example.com.
    • Set the in variable to "{{ lookup('file', 'new-private-key-to-an-externally-signed-certificate.pem') | b64encode }}". This ensures that Ansible retrieves the file with the private key from the working directory on the Ansible controller rather than from the IdM server.
    • Set the action variable to member.

      This the modified Ansible playbook file for the current example:

    ---
    - name: Tests
      hosts: ipaserver
      gather_facts: false
    
      vars_files:
      - /home/user_name/MyPlaybooks/secret.yml
      tasks:
      - ipavault:
          ipaadmin_password: "{{ ipaadmin_password }}"
          name: secret_vault
          service: HTTP/webserver.idm.example.com
          in: "{{ lookup('file', 'new-private-key-to-an-externally-signed-certificate.pem') | b64encode }}"
          action: member
  5. Save the file.
  6. Run the playbook:

    $ ansible-playbook --vault-password-file=password_file -v -i inventory.file data-archive-in-asymmetric-vault-copy.yml
  7. Open the retrieve-data-asymmetric-vault-copy.yml file for editing.
  8. Modify the file by setting the following variables in the ipavault task section:

    • Set the ipaadmin_password variable to your IdM administrator password.
    • Set the name variable to the name of the vault, for example secret_vault.
    • Set the service variable to the service owner of the vault, for example HTTP/webserver1.idm.example.com.
    • Set the private_key_file variable to the location of the private key used to retrieve the service vault secret.
    • Set the out variable to the location on the IdM server where you want to retrieve the new-private-key-to-an-externally-signed-certificate.pem secret, for example the current working directory.
    • Set the action variable to member.

      This the modified Ansible playbook file for the current example:

    ---
    - name: Retrieve data from vault
      hosts: ipaserver
      become: no
      gather_facts: false
    
      vars_files:
      - /home/user_name/MyPlaybooks/secret.yml
      tasks:
      - name: Retrieve data from the service vault
        ipavault:
          ipaadmin_password: "{{ ipaadmin_password }}"
          name: secret_vault
          service: HTTP/webserver1.idm.example.com
          vault_type: asymmetric
          private_key: "{{ lookup('file', 'service-private.pem') | b64encode }}"
          out: new-private-key-to-an-externally-signed-certificate.pem
          state: retrieved
  9. Add a section to the playbook that retrieves the data file from the IdM server to the Ansible controller:

    ---
    - name: Retrieve data from vault
      hosts: ipaserver
      become: true
      gather_facts: false
      tasks:
    [...]
      - name: Retrieve data file
        fetch:
          src: new-private-key-to-an-externally-signed-certificate.pem
          dest: ./
          flat: yes
          mode: 0600
  10. Add a section to the playbook that transfers the retrieved new-private-key-to-an-externally-signed-certificate.pem file from the Ansible controller on to the webservers listed in the webservers section of the inventory file:

    ---
    - name: Send data file to webservers
      become: true
      gather_facts: no
      hosts: webservers
      tasks:
      - name: Send data to webservers
        copy:
          src: new-private-key-to-an-externally-signed-certificate.pem
          dest: /etc/pki/tls/private/httpd.key
          mode: 0444
  11. Save the file.
  12. Run the playbook:

    $ ansible-playbook --vault-password-file=password_file -v -i inventory.file retrieve-data-asymmetric-vault-copy.yml

25.6. Additional resources

  • See the README-vault.md Markdown file in the /usr/share/doc/ansible-freeipa/ directory.
  • See the sample playbooks in the /usr/share/doc/ansible-freeipa/playbooks/vault/ directory.