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:
- 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.
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:
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 }}'
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 }}'
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.
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:
Create a New Project:
- Define a new project in AWX/AAP that points to the GitLab repository containing your playbooks.
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.
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.