Part 2.1: Deploying Let’s Encrypt Certificates to an ASA Using Ansible with AWX/AAP

Introduction

Continuing from Part 2 of our series, this tutorial will guide you through Let’s Encrypt certificates using AWX/Ansible Automation Platform to an ASA firewall. There will be a new playbook to apply the certificate to the ASA, but running the playbook will be the same as in Part 2 of our series. You will also have to make sure you have a few Prerequisites setup a head of time.

Important Note:

This blog post will not rehash specifics on:
  • Creating projects in AWX.
  • Creating templates.
  • Creating and using custom credentials.
  • Adding surveys to templates.
  • Detailed steps on how to run projects in AWX.
  • Creating and using the cert-store repository on Git.
For comprehensive details on these topics, please refer to Part 2 of our series.


Storing Playbooks and Vault Files in a Secure Git Repository

Before you start, ensure that both your playbooks and the Ansible Vault file are stored in a secure Git repository. For this example, we’ll use GitLab, but the principles apply to any Git hosting service.

1. Set Up Your Git Repository or Clone my repository:

  • Create a Private Repository: Make sure your repository is private to ensure sensitive data is not exposed publicly. This repository should be hosted locally for security purposes.
  • Set up a collections folder and requirements.yml file: Begin by creating a collections folder in your project directory, and then add a requirements.yml file to specify the necessary modules.
# requirements.yml
collections:
  - name: cisco.asa
  • Install the Collections: This setup ensures that AWX or Ansible Automation Platform (AAP) installs the specified modules automatically.

  • Add Playbooks and Vault Files: Store your vars.yml (vault file) and playbooks in this repository.

2. Ensure Repository Security:

  • Use Strong Access Controls: Limit access to the repository to only those who need it.
  • Use SSH or Token-Based Authentication: For secure interactions with your Git repository, prefer SSH keys or personal access tokens over password-based authentication.

3. Creating Custom Credentials

  • We need to create a few custom credentials:

    1. GitLab credentials for the cert-store repository:

      • Input Configuration:
      ---
      fields:
        - id: gitlab_username
          type: string
          label: GitLab username
          secret: false
        - id: gitlab_password
          type: string
          label: GitLab password
          secret: true
        - id: gitlab_project
          type: string
          label: GitLab project
          secret: false
      required:
        - gitlab_username
        - gitlab_password
      
      • Injector configuration:
      ---
      extra_vars:
        gitlab_project: '{{ gitlab_project }}'
        gitlab_password: '{{ gitlab_password }}'
        gitlab_username: '{{ gitlab_username }}'
      
    2. Certificate URL & Password:

      • Input Configuration:
      ---
      fields:
        - id: cert_url
          type: string
          label: url
        - id: cert_password
          type: string
          label: cert_password
          secret: true
      required:
        - cert_url
        - cert_password
      
      • Injector configuration:
      ---
      extra_vars:
        Cert_PW: '{{ cert_password }}'
        Cert_URL: '{{ cert_url }}'
      
    3. ASA Credentails:

      • Add ASA credentials using machine type credentials template.
  • NOTE: All of these credentials can also be stored in an Ansible Vault file.

4. Create a Inventory for your ASA

For the first time in this series, we will also need an inventory file specifically for the ASA device.

NOTE:
I am using NetBox as my source of truth (SOT) to build this inventory, but you can also build your inventory manually:

4.1. Adding the ASA Host in AWX/Ansible Automation Platform (AAP)

Here’s how you can create an inventory and add the ASA host in AWX or Ansible Automation Platform (AAP):

Step 1: Create a New Inventory

  • In the left-hand menu, click on Inventories.
  • Click Add and select Inventory.
  • Fill in the details:
    • Name: Inventory
    • Organization: Choose the relevant organization.
  • Click Save.

Step 2: Add a Host to the Inventory

  • After saving the inventory, click on the Hosts tab within your new inventory.
  • Click Add to create a new host.
  • Fill in the details:
    • Name: asa_firewall (or any name you prefer).
    • Description: Cisco ASA.
    • Variables: Add the following host variables in the YAML format:
      ansible_connection: network_cli
      ansible_host: x.x.x..x
      ansible_network_os: cisco.asa.asa
      device_roles:
        - firewall
      device_types:
        - asa
      platforms:
        - cisco-asa
      primary_ip4: x.x.x.x
      
  • Click Save.

Step 4: Grouping Hosts (Optional)

  • If you want to organize your inventory into groups, navigate to the Groups tab in your inventory and click Add.
  • Create a new group, such as firewalls, and assign the ASA host to this group for better organization.

Step 5: Verify Inventory Configuration

  • Once your host and variables are saved, you can go to the Hosts tab to verify that the ASA host is correctly added with the appropriate variables.

For comprehensive details on these topics, please refer to Part 2 for creating custom credentials and How to Use NetBox as an Inventory in Ansible.

Creating a Vault File for Secure Variables

Enhance the security of your sensitive data by using Ansible Vault to protect variables like passwords and certificate URLs. This step is optional if custom credentials were already created in previous steps.

1. Create a Vault File:

To create a new vault file, use:

ansible-vault create vars.yml

In the editor that opens, input your sensitive variables:

# vars.yml
---
Cert_URL: "vpn.example.com"
Cert_PW: "mysecurepassword"

Save and exit. This file is now encrypted.

2. Edit the Vault File:

To modify the vault file later, use:

ansible-vault edit vars.yml

3. Use the Vault File in Your Playbook:

  • add your vault password to AWX/AAP
  • When executing the playbook from AWX/AAP, ensure the vault file is referenced in the playbook.
  • vars_files:
    - vars.yml
    

Ansible Playbook Breakdown for AWX/AAP

This playbook is designed to be executed from AWX/AAP, utilizing its features to automate certificate deployment to Cisco ASA firewalls.

1. Set Variables and Hosts

We define variables, including file locations and certificate details, and manage these securely through the vault file.

    ---
    #------------------------------------------------------------------------------
    #---- Ansible Playbook to Deploy Certificates to Cisco ASA using AWX/AAP
    #---- Hosts: ASA firewalls
    #------------------------------------------------------------------------------
    - name: Cert Management on ASA
      hosts: 
        - asa_firewall
      become: true
      become_method: enable
      gather_facts: false
      vars_files:
        - vars.yml
      vars:
        #------------------------------------------------------------------------------
        #---- files_loc: Directory where certificates and keys will be stored.
        #---- vpn_cert: The certificate URL. pulled from custom credentials
        #---- p12_password: Password for the PKCS#12 certificate. pullled from custom credentials
        #---- trustpoint_name: Trustpoint name for ASA. pulled from custom credentials
        #------------------------------------------------------------------------------
        files_loc: ~/cert-store
        vpn_cert: "{{ Cert_URL }}"
        p12_password: "{{ Cert_PW }}"
        trustpoint_name: "RAVPN"
  • vars_files: Includes the vault file, referenced in AWX/AAP.
  • files_loc: Location where certificates are stored locally
  • vpn_cert, p12_password, trustpoint_name: Pulled from custom credentials

2. Clone the Git Repository

The playbook clones the Git repository containing the certificates. This task runs only once and on the control node.

    #------------------------------------------------------------------------------
    #---- Clone the Git repository containing certificates
    #------------------------------------------------------------------------------
  - name: Clone the git repo with current certificates
    shell: |
      git config --global user.email "ansible_certadmin@donotreply.com"
      git config --global user.name "Ansible certificate agent"
      git clone "https://{{ gitlab_username | urlencode }}:{{ gitlab_password | urlencode }}@gitlab.com/{{ gitlab_username | urlencode }}.git" {{files_loc}}       
    delegate_to: localhost
    run_once: true
  • delegate_to: Runs the Git clone command on the control node.
  • run_once: Ensures the task executes only once.

3. Convert the Certificate to PKCS#12 Format

Convert the certificate to PKCS#12 format for compatibility with ASA.

    #------------------------------------------------------------------------------
    #---- Convert certificate to PKCS#12 format
    #------------------------------------------------------------------------------
  - name: Convert certificate to PKCS#12 format
    community.crypto.openssl_pkcs12:
      action: export
      path: "{{ files_loc }}/{{ vpn_cert }}/{{ vpn_cert }}.p12"
      privatekey_path: "{{ files_loc }}/{{ vpn_cert }}/{{ vpn_cert }}.key"
      certificate_path: "{{ files_loc }}/{{ vpn_cert }}/{{ vpn_cert }}.crt"
      friendly_name: "{{ vpn_cert }}"
      passphrase: "{{ p12_password }}"
    delegate_to: localhost
  • community.crypto.openssl_pkcs12: Converts the certificate into PKCS#12 format.

4. Read and Encode the PKCS#12 Certificate

Read and base64-encode the PKCS#12 file for import into ASA.

    #------------------------------------------------------------------------------
    #---- Encode the PKCS#12 certificate in base64
    #------------------------------------------------------------------------------
  - name: Get Certificate
    set_fact:
      cert: >
        {{ (lookup('file', '{{ files_loc }}/{{ vpn_cert }}/{{ vpn_cert }}.p12') | b64encode | regex_replace('(.{1,64})', '\1|')).split('|') | select('string') | reject('match', '^$') | list + ['quit'] }}        
    tags: [ cert ]
  • set_fact: Encodes the certificate and prepares it for ASA import.

5. Import the Certificate into ASA

Import the PKCS#12 certificate into ASA using the defined trustpoint.

    #------------------------------------------------------------------------------
    #---- Import the certificate to ASA using the defined trustpoint
    #------------------------------------------------------------------------------
  - name: Import PKCS12 using trustpoint
    asa_config:
      replace: block
      parents: "crypto ca import {{ trustpoint_name }} pkcs12 {{ p12_password }} nointeractive"
      lines: "{{ cert }}"
    notify:
      - Assign the Trustpoint to the SSL Interface
  • asa_config: Handles the configuration of ASA to import the certificate.

6. Assign Trustpoint to SSL Interface

Assign the imported certificate to the SSL interface on ASA.

  handlers:
    #------------------------------------------------------------------------------
    #---- Assign the trustpoint to the ASA SSL interface and save configuration
    #------------------------------------------------------------------------------
  - name: Assign the Trustpoint to the SSL Interface
    cisco.asa.asa_config:
      save: true
      lines:
        - "ssl trust-point {{ trustpoint_name }} outside"
    register: assign_trustpoint
  • save: Ensures the configuration changes are saved.
  • ssl trust-point: Binds the trustpoint to the ‘outside’ interface.

Running the Playbook from AWX/AAP

To execute this playbook in AWX/AAP:

  1. Create a New Project:

    • Define a new project in AWX/AAP that points to the GitLab repository containing your playbooks.
  2. Create a New Job Template:

    • Create a job template in AWX/AAP. Specify the inventory containing your ASA hosts.
    • In the ‘Variables’ section, include the vault file reference:
      vars_files:
        - vars.yml
      
    • Configure other necessary parameters for the job template.
  3. Execute the Job:

    • Launch the job template from the AWX/AAP interface. The playbook will run and handle the entire certificate deployment process.

Conclusion

In this post, we outlined how to deploy Let’s Encrypt certificates to Cisco ASA firewalls using Ansible within an AWX/AAP environment. By securely managing sensitive data with Ansible Vault and leveraging AWX/AAP’s automation features, you can efficiently handle certificate management. For additional tasks and configurations, refer to Part 2 of this series.

Next Steps

  • Part 2.2: Deploying Let’s Encrypt certificates to F5 Big-IP LTM’s using Ansible.
  • Part 3: Scheduling Auto-Renewal workflows and automating the deployment of certificates to Firewalls and F5’s.
  • Part 4: ServiceNow Integration.
  • BONUS: Using ThousandEyes with Event-Driven Ansible to renew Certs before they expire.

Stay tuned for the next part of the series, where we will cover advanced automation techniques for certificate deployment to F5’s.