Forum Discussion
Stefan_Engel
Jun 01, 2021Cirrus
Extract content of Certificate key file with REST or Ansible
Hi Community, I'm working on an automation for renewing Certificates on multiple BIG-IP's using Ansible. As not all available Ansible F5 modules provide what is required, I'm currently using a m...
Jul 08, 2021
Exporting key material is not supported as far as I know. Using the CLI is the only option I am aware of.
Only a CSR can be exported.
Creating a CSR:
- name: create string of subject alternative names when defined in inventory
set_fact:
san_list: "{{ san_list | default([]) + ['DNS:%s' | format(item.name)] }}"
with_items: "{{ hostvars[inventory_hostname].certificates.server[0].subject_alternative_names | selectattr('name', 'defined') | list }}"
when: hostvars[inventory_hostname].certificates.server[0].subject_alternative_names is defined
- name: add signing request name and properties to data structure
set_fact:
csr_data: "{{ {
'csr_consumer': 'ltm',
'csr_prefix': 'cert',
'csr_suffix': device_info[inventory_hostname].ansible_host_time,
'csr_name': hostvars[inventory_hostname].certificates.server[0].name,
'csr_cn': hostvars[inventory_hostname].certificates.server[0].subject.common_name,
'csr_san': san_list | default(['DNS:%s' | format(hostvars[inventory_hostname].certificates.server[0].name)]) | join(','),
'csr_country': hostvars[inventory_hostname].certificates.server[0].subject.location_country | default('US'),
'csr_state': hostvars[inventory_hostname].certificates.server[0].subject.location_state | default(''),
'csr_city': hostvars[inventory_hostname].certificates.server[0].subject.location_city | default(''),
'csr_organization': hostvars[inventory_hostname].certificates.server[0].subject.organization_name | default(''),
} }}"
- name: create certificate signing request on load balancer
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/tm/sys/crypto/csr
method: POST
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body_format: json
body:
'name': "{{ csr_data.csr_prefix + '_' + csr_data.csr_name + '_' + csr_data.csr_suffix }}"
'key': "{{ csr_data.csr_prefix + '_' + csr_data.csr_name + '_' + csr_data.csr_suffix }}"
'common-name': "{{ csr_data.csr_cn }}"
'subject-alternative-name': "{{ csr_data.csr_san }}"
'country': "{{ csr_data.csr_country }}"
'state': "{{ csr_data.csr_state }}"
'city': "{{ csr_data.csr_city }}"
'organization': "{{ csr_data.csr_organization }}"
'consumer': "{{ csr_data.csr_consumer }}"
register: result
until: result.status == 200
retries: 40
delay: 5
when: csr_data is defined
Exporting a CSR:
- name: add certificate signing request name to data structure
set_fact:
csr_data: "{{ {
'csr_prefix': 'cert',
'csr_suffix': device_info[inventory_hostname].ansible_host_time,
'csr_name': hostvars[inventory_hostname].certificates.server[0].name,
'csr_file_extension': 'csr'
} }}"
- name: debug data
debug:
msg: "{{ csr_data }}"
- name: export certificate signing request
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/tm/util/bash
method: POST
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body_format: json
body:
command: run
utilCmdArgs: "-c 'tmsh list sys crypto csr {{ csr_data.csr_prefix + '_' + csr_data.csr_name + '_' + csr_data.csr_suffix }} | sed -re \'/-----/,/-----/!d\''"
register: csr_result
- name: debug data
debug:
msg: "{{ csr_result.json.commandResult }}"
- name: save certificate signing request to local file and replace encoded new line characters
copy:
content: "{{ csr_result.json.commandResult | regex_replace('\\n', '\n') }}"
dest: "{{ '~/ssl/server/csr/%s.%s' | format(csr_data.csr_prefix + '_' + csr_data.csr_name + '_' + csr_data.csr_suffix, csr_data.csr_file_extension) }}"
force: yes
Uploading all key material:
- name: register cert file properties
stat:
path: "{{ crt_file_path }}"
register: crt_properties
when: crt_file_path is defined
- name: set certificate file size information
set_fact:
crt_file_size: "{{ crt_properties.stat.size }}"
when: crt_properties is defined
- name: register key file properties
stat:
path: "{{ key_file_path }}"
register: key_properties
when: key_file_path is defined
- name: set key file size information
set_fact:
key_file_size: "{{ key_properties.stat.size }}"
when: key_properties is defined
- name: register chain file properties
stat:
path: "{{ chain_file_path }}"
register: chain_properties
when: chain_file_path is defined
- name: set chain file size information
set_fact:
chain_file_size: "{{ chain_properties.stat.size }}"
when: chain_properties is defined
- name: copy certificate to temp directory
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/shared/file-transfer/uploads/{{ crt_file_name }}
method: POST
headers:
Content-Range: "0-{{ crt_file_size | int - 2 }}/{{ crt_file_size }}"
Content-Type: "application/octet-stream"
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body: "{{ lookup('file', crt_file_path) }}"
- name: copy key to temp directory
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/shared/file-transfer/uploads/{{ key_file_name }}
method: POST
headers:
Content-Range: "0-{{ key_file_size | int - 2 }}/{{ key_file_size }}"
Content-Type: "application/octet-stream"
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body: "{{ lookup('file', key_file_path) }}"
- name: copy chain to temp directory
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/shared/file-transfer/uploads/{{ chain_file_name }}
method: POST
headers:
Content-Range: "0-{{ chain_file_size | int - 2 }}/{{ chain_file_size }}"
Content-Type: "application/octet-stream"
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body: "{{ lookup('file', chain_file_path) }}"
- name: copy certificate to TMOS filestore (TMOS v14+)
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/tm/sys/crypto/cert
method: POST
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body_format: json
body:
command: install
name: "{{ '%s_%s_%s' | format(crt_prefix,crt_name,crt_suffix) }}"
from-local-file: "/var/config/rest/downloads/tmp/{{ '%s_%s_%s.%s' | format(crt_prefix,crt_name,crt_suffix,crt_file_extension) }}"
- name: copy key to TMOS filestore (TMOS v14+)
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/tm/sys/crypto/key
method: POST
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body_format: json
body:
command: install
name: "{{ '%s_%s_%s' | format(crt_prefix,crt_name,crt_suffix) }}"
from-local-file: "/var/config/rest/downloads/tmp/{{ '%s_%s_%s.%s' | format(crt_prefix,crt_name,crt_suffix,key_file_extension) }}"
- name: copy chain to TMOS filestore (TMOS v14+)
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/tm/sys/crypto/cert
method: POST
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body_format: json
body:
command: install
name: "{{ '%s_%s_%s' | format(chain_prefix,crt_name,crt_suffix) }}"
from-local-file: "/var/config/rest/downloads/tmp/{{ '%s_%s_%s.%s' | format(chain_prefix,crt_name,crt_suffix,crt_file_extension) }}"
- name: specifiy name of profile (TMOS v14+ does not use the file extension)
set_fact:
profile: "{{ '%s_%s_%s' | format(profile_prefix,crt_name,profile_suffix) }}"
- name: lookup current cert, key and chain assignments in client-ssl profile
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/tm/ltm/profile/client-ssl/{{ profile }}?$select=cert,key,chain
method: GET
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
register: lookup_result
- name: modify existing client-ssl persistence
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/tm/ltm/profile/client-ssl/{{ profile }}
method: PATCH
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
body_format: json
body:
cert: "{{ '%s_%s_%s' | format(crt_prefix,crt_name,crt_suffix) }}"
key: "{{ '%s_%s_%s' | format(crt_prefix,crt_name,crt_suffix) }}"
chain: "{{ '%s_%s_%s' | format(chain_prefix,crt_name,crt_suffix) }}"
If you are exporting the key material anyway, why not creating the key pair and CSR outside the F5? (see next reply, please)
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects