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, 2021As mentioned before, I prefer creating the private/public key pair outside the BIG-IP and finally upload the signed certificate and chain to the BIG-IP device(s).
Here is how I create the key material and CSR (and sign it locally for testing purposes):
- hosts: localhost
  gather_facts: yes
  
  tasks:
  
  - name: retrieve system time information (YYYYMMDD_HHMMSS)
    set_fact:
      ansible_clock_information: "{{ '%s%s%s_%s%s%s' | format(ansible_date_time.year, ansible_date_time.month, ansible_date_time.day, ansible_date_time.hour, ansible_date_time.minute, ansible_date_time.second) }}"
    delegate_to: localhost
    
  - name: debug ansible_clock_information
    debug:
      msg: "{{ ansible_clock_information }}"
      
  - name: include variables file (required for local CA access)
    no_log: true
    include_vars: sample_credentials.yml
    
  - name: include certificate variables file and suppress logging
    include_vars: 
      file: "{{ certificate_data }}"
      name: certificate_config
      
  - name: debug variables
    debug:
      msg: "{{ certificate_config.server_certificate }}"
      
  - 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: "{{ certificate_config.server_certificate.subject_alternative_names | selectattr('name', 'defined') | list }}"
    when: certificate_config.server_certificate.subject_alternative_names is defined
    
  - name: debug string of subject alternative names
    debug:
      msg: "{{ san_list }}"
      
  - name: add signing request name and properties to data structure
    set_fact:
      csr_data: "{{ {
          'csr_type': certificate_config.server_certificate.key_type,
          'csr_length': certificate_config.server_certificate.key_length,
          'csr_prefix': 'cert',
          'csr_suffix': ansible_clock_information,
          'csr_name': certificate_config.server_certificate.name,
          'csr_cn': certificate_config.server_certificate.subject.common_name,
          'csr_san': san_list | default(['DNS:%s' | format(certificate_config.server_certificate.name)]) | join(','),
          'csr_country': certificate_config.server_certificate.subject.location_country | default('US'),
          'csr_state': server_certificate.subject.location_state | default(''),
          'csr_city': certificate_config.server_certificate.subject.location_city | default(''),
          'csr_organization': certificate_config.server_certificate.subject.organization_name | default(''),
        } }}"
        
  - name: debug data
    debug: 
      msg: "{{ csr_data }}"
      
  - name: assemble key material file name
    set_fact:
      key_file_name: "{{ csr_data.csr_prefix + '_' + csr_data.csr_name + '_' + csr_data.csr_suffix }}"
      
  - name: assemble certificate subject
    set_fact:
      certificate_subject: "{{ '/C=' + csr_data.csr_country + '/ST=' + csr_data.csr_state + '/L=' + csr_data.csr_city + '/O=' +csr_data.csr_organization + '/CN=' + csr_data.csr_cn }}"
      
  - name: generate a new private/public key pair
    command: openssl gen{{ csr_data.csr_type | lower }} -out ~/ssl/server/material/{{ key_file_name }}.key  {{ csr_data.csr_length }}
    
  - name: generate temporary config files with subject alternative names
    copy:
      dest: "~/ssl/server/tmp/{{ key_file_name }}.cnf"
      content: |
        [SAN]
        subjectAltName={{ csr_data.csr_san }}
        [ req ]
        distinguished_name  = req_distinguished_name
        [ req_distinguished_name ]
        
  - name: generate CSRs
    command: openssl req -new -sha256 -reqexts SAN -key ~/ssl/server/material/{{ key_file_name }}.key -out ~/ssl/server/material/{{ key_file_name }}.csr  -subj '{{ certificate_subject }}' -config ~/ssl/server/tmp/{{ key_file_name }}.cnf
    
  - name: generate key/csr information
    set_fact:
      key_csr_info:
        reference: "{{ csr_data.csr_name }}"
        timestamp: "{{ csr_data.csr_suffix }}"
        new_key: "{{ key_file_name + '.key' }}"
        new_csr: "{{ key_file_name + '.csr' }}"
        
  - name: save timestamp information to local file
    copy:
      content: "{{ key_csr_info | to_nice_yaml }}"
      dest: "{{ '~/ssl/server/material/cert_%s.info' | format(csr_data.csr_name) }}"
      force: yes
      
  - name: print file locations
    debug:
      msg: 
      - "{{ 'new private key created: ~/ssl/server/material/' + key_file_name + '.key' }}"
      - "{{ 'new signing req created: ~/ssl/server/material/' + key_file_name + '.csr' }}"
      - "{{ 'new key/csr information: ~/ssl/server/material/cert_%s.info' | format(csr_data.csr_name) }}"
      
  - name: sign certificate with local CA
    command: openssl ca -notext -md sha256 -days 730 -batch -passin pass:{{ intermediate_ca_credentials.secret }} -out ~/ssl/server/material/{{ key_file_name }}.crt -config ~/ssl/intermediate/openssl.cnf -extensions server_cert -in ~/ssl/server/material/{{ key_file_name }}.csr
    
  - name: save intermediate CA chain (src is referencing the locally saved chain of intermediate CAs)
    copy:
      src: "~/ssl/intermediate/crt/intermediate-ca.crt"
      dest: "{{ '~/ssl/server/material/chain_' + csr_data.csr_name + '_' + csr_data.csr_suffix + '.crt' }}"
      
  - name: print file locations
    debug:
      msg: 
      - "{{ 'new signed cert created: ~/ssl/server/material/' + key_file_name + '.csr' }}"
      - "{{ 'new intermediate saved: ~/ssl/server/material/chain_' + csr_data.csr_name + '_' + csr_data.csr_suffix + '.crt' }}"Cheers, Stephan
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