I found that after uploading the certificate to Fortinet, I needed to update the SSL VPN configuration so that the Fortinet appliance was using the latest generated LetsEncrypt certificate. After that, I needed to update the SSO configuration to use the same newly-generated SSL certificate.
Because I wasn't able to find Ansible modules to do that in the `fortinet.fortios collection` collection (someone feel free to correct me if these do exist), I ended up writing a playbook that utilised the Fortinet HTTP API directly.
I will be writing a blog post about this on our website sometime within the next week or two. In the interim, see the entire playbook below:
--- - hosts: all gather_facts: no vars: cert_fc: /path/to/fullchain.pem cert_pk: /path/to/privkey.pem cert_fn: /path/to/subdomain.example.com.pem tasks: - block: - name: Create temporary directory ansible.builtin.tempfile: state: directory suffix: ansible_pb register: temp_dir - name: Copy Full Chain and Private Key to Temp Folder ansible.builtin.copy: src: "{{item}}" dest: "{{ temp_dir.path }}" remote_src: yes loop: - "{{cert_fc}}" - "{{cert_pk}}" - name: Assemble into a cert file ansible.builtin.assemble: src: "{{ temp_dir.path }}" dest: "{{ cert_fn }}" register: cert no_log: true - name: Convert file to PEM to PKCS12 ansible.builtin.command: openssl pkcs12 -export -in {{cert_fc}} -inkey {{cert_pk}} -out {{temp_dir.path}}/domain.pfx -password pass:Example1234 register: cert_pkcs12 when: cert.changed == true no_log: true - name: Read certificate into Base64 ansible.builtin.slurp: src: "{{temp_dir.path}}/domain.pfx" register: cert_b64 when: cert.changed == true no_log: true - name: Upload SSL certificate to Fortinet ansible.builtin.uri: url: "https://192.168.1.1/api/v2/monitor/vpn-certificate/local/import?access_token={{ Fortinet_APIKey }}" method: POST body_format: json body: type: pkcs12 certname: subdomain.example.com password: Example1234 scope: global file_content: "{{cert_b64.content}}" validate_certs: false when: cert.changed == true delegate_to: localhost no_log: true - name: Change VPN certificate to newly uploaded cert ansible.builtin.uri: url: "https://192.168.1.1/api/v2/cmdb/vpn.ssl/settings?access_token={{ Fortinet_APIKey }}" method: PUT body: servercert: q_origin_key: "subdomain.example.com" validate_certs: false body_format: json when: cert.changed == true delegate_to: localhost no_log: true - name: Change SSO certificate to newly uploaded cert ansible.builtin.uri: url: "https://192.168.1.1/api/v2/cmdb/user/saml/fac-sslvpn?access_token={{ Fortinet_APIKey }}" method: PUT body: cert: "subdomain.example.com" body_format: json validate_certs: false when: cert.changed == true delegate_to: localhost no_log: true rescue: - name: Failed to combine cert set_stats: data: ErrorCode: 166f54e4-d9b7-41b6-9fbc-d56420933f0 - meta: end_play always: - name: Remove Temporary Directory ansible.builtin.file: path: "{{ temp_dir.path }}" state: absent when: temp_dir.path is defined
* Use at your own risk.