Forum Discussion
Stefan_Engel
Cirrus
Jun 01, 2021Extract 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...
StephanManthey
Nacreous
Jul 08, 2021Exporting 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 definedExporting 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: yesUploading 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