VCF 3.9 – automate managing certificates for Cloud Foundation components using Ansible.

In VCF 3.9 we can manage certificates for all Cloud Foundation components, including configuring a certificate authority, generating and downloading CSRs, and installing them.
In this post i will show you how to configure Microsoft certificate authority and create and install certificates for the following components:
- Platform Services Controllers
- vCenter Server
- NSX Manager
- SDDC Managee
- vRealize Log Insight
- vRealize Operations
And of course we will use Ansible. Because there is no any module that could be used so we need to use API.
NOTE!!! Because it’s not possible to create and install certificates for all components simultaneously (some VCF limitation) we need to do that one by on using predefined list (with_items).
My vars looks like that:
# vars
vcfRestApiUrlCa: https://sddcManager_FQDN/v1/certificate-authorities
vcfRestApiUrlCheckCa: https://sddcManager_FQDN/v1/certificate-authorities/Microsoft
vcfRestApiUrlCsrs: https://sddcManager_FQDN/v1/domains/MGMT/csrs
vcfRestApiUrlCert: https://sddcManager_FQDN/v1/domains/MGMT/certificates
vcfRestApiUrlTaskStatus: https://sddcManager_FQDN/v1/tasks
vcfRestApiUrlFetchCertificates: https://sddcManager_FQDN/v1/domains/MGMT/resource-certificates
issuingCA: https://issuingCA_FQDN
#credentials
vcfUser: admin
vcfPassword: s0mEpAsSw0rD
# VCF components ("One among: ESXI, SDDC_MANAGER, VCENTER, PSC, NSX_MANAGER, NSX_CONTROLLER, NSX_EDGE, NSXT_MANAGER, NSXT_CONTROLLER, NSXT_EDGE, VRLI, VROPS, LCM_REPO, VRA, VRSLCM, DEPOT_USER, VXRAIL_MANAGER, AD, BACKUP")
vcfResources:
resources:
- fqdn: vcs01_FQDN
type: VCENTER
- fqdn: psc01_FQDN
type: PSC
- fqdn: psc02_FQDN
type: PSC
- fqdn: vrli_FQDN
type: VRLI
- fqdn: lcm_FQDN
type: VRSLCM
- fqdn: nsx_FQDN
type: NSX_MANAGER
- fqdn: sddcManager_FQDN
type: SDDC_MANAGER
- fqdn: vrops_FQDN
type: VROPS
#VCF services that need to be restarted
vcfServices:
- commonsvcs
- lcm
- domainmanager
- operationsmanager
- sddc-manager-ui-app
- solutionsmanager
Playbook:
#playbook
- name: VCF - certificates management
hosts: sddcMnager
gather_facts: false
become: yes
tasks:
- name: "Running role: vcfCerts "
include_role:
name: manageVcfCertificates
And tasks: I created two tasks: createCerts.yml and restartVcfServices.yml
As I mentioned at the very beginning of this post, we will create and install certificates for all VCF components (defined in vars as ‘vcfResources’), so we need to use loop (with_items) in main.yml:
#main.yml
- name: Create and install cert for all VCF components
include_tasks: createCerts.yml
with_items:
- "{{ vcfResources.resources }}"
- name: Restart VCF services
include_tasks: restartVcfServices.yml
And tasks:
#createCerts.yml
- name: Check if Certificate Authority is configured.
uri:
url: "{{ vcfRestApiUrlCa }}"
method: GET
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
force_basic_auth: yes
return_content: yes
status_code:
- 200
register: checkCa
delegate_to: localhost
- name: Certificate Authority configuration status
debug:
msg: "Microsoft Certificate Authority is not configured"
when: (checkCa.json.elements | length == 0)
If CA is not yet configured, we can do that in that way:
- name: Create a certificate authority if not exists
uri:
url: "{{ vcfRestApiUrlCa }}"
method: PUT
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
headers:
Content-Type: "application/json"
force_basic_auth: yes
return_content: yes
body_format: json
status_code:
- 200
body:
microsoftCertificateAuthoritySpec:
secret: "{{ vcfPassword }}"
serverUrl: "https://{{ issuingCA }}/certsrv"
templateName: webserver
username: "{{ temporaryCredentials.windowsUsername }}@{{ activeDirectory.domainName }}"
register: createCa
delegate_to: localhost
when: (checkCa.json.elements | length == 0)
- name : Certificate Authority configuration status
debug:
msg: "Microsoft Certificate Authority https://issuingCA_FQDN/certsrv configured"
when: (checkCa.json.elements | length > 0)


So now let’s create CSR first:
- name: "Generate CSR for {{ item.fqdn }}"
uri:
url: "{{ vcfRestApiUrlCsrs }}"
method: PUT
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
headers:
Content-Type: "application/json"
force_basic_auth: yes
return_content: yes
body_format: json
status_code:
- 200
- 202
body:
csrGenerationSpec:
country: PL
keyAlgorithm: RSA
keySize: '2048'
locality: PL
organization: vconfig
organizationUnit: vconfig
state: PL
resources:
- fqdn: "{{ item.fqdn }}"
type: "{{ item.type }}"
register: generateCsr
delegate_to: localhost
- name : "Get CSR creation task ID for {{ item.fqdn }}"
debug:
msg: "CSR task ID: {{generateCsr.json.id}}"
when: generateCsr.status==202
- name: "Waiting for CSR creation - {{ item.fqdn }}"
uri:
url: "{{ vcfRestApiUrlTaskStatus }}/{{generateCsr.json.id}}"
method: GET
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
headers:
Content-Type: "application/json"
force_basic_auth: yes
return_content: yes
body_format: json
status_code:
- 200
# - "{{ vcfResources.resources }}"
register: CsrTaskStatus
# when: csrValidationStatus.json.status=='SUCCESSFUL'
delegate_to: localhost
until: (CsrTaskStatus.json.status == 'SUCCESSFUL')
delay: 2
retries: 100
- name : "CSR creation status - {{ item.fqdn }}"
debug:
msg: "CSR for {{ item.fqdn }} created"
when: CsrTaskStatus.json.status=='SUCCESSFUL'


When CSR is ready we can generate certificate:
- name: "Generate certificate for {{ item.fqdn }}"
uri:
url: "{{ vcfRestApiUrlCert }}"
method: PUT
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
headers:
Content-Type: "application/json"
force_basic_auth: yes
return_content: yes
body_format: json
status_code:
- 200
- 202
body:
caType: Microsoft
resources:
- fqdn: "{{ item.fqdn }}"
type: "{{ item.type }}"
# with_items:
# - "{{ vcfResources.resources }}"
register: generateCert
# when: csrValidationStatus.json.status=='SUCCESSFUL'
delegate_to: localhost
- name: "Waiting for certificate creation - {{ item.fqdn }}"
uri:
url: "{{ vcfRestApiUrlTaskStatus }}/{{generateCert.json.id}}"
method: GET
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
headers:
Content-Type: "application/json"
force_basic_auth: yes
return_content: yes
body_format: json
status_code:
- 200
register: CertTaskStatus
delegate_to: localhost
until: (CertTaskStatus.json.status == 'SUCCESSFUL')
delay: 10
retries: 100
- name : "Certificate creation status - {{ item.fqdn }}"
debug:
msg: "Certificate for {{ item.fqdn }} created"
when: CertTaskStatus.json.status == 'SUCCESSFUL'



Certificate generated successfully so we let’s install it.
- name: "Install certificate for {{ item.fqdn }}"
uri:
url: "{{ vcfRestApiUrlCert }}"
method: PATCH
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
headers:
Content-Type: "application/json"
force_basic_auth: yes
return_content: yes
body_format: json
status_code:
- 200
- 202
body:
operationType: INSTALL
resources:
- fqdn: "{{ item.fqdn }}"
type: "{{ item.type }}"
# with_items:
# - "{{ vcfResources.resources }}"
register: installCert
when: CertTaskStatus.json.status == 'SUCCESSFUL'
delegate_to: localhost
- name: "Waiting for certificate installation - {{ item.fqdn }}"
uri:
url: "{{ vcfRestApiUrlTaskStatus }}/{{installCert.json.id}}"
method: GET
user: "{{ vcfUser }}"
password: "{{ vcfPassword }}"
validate_certs: no
headers:
Content-Type: "application/json"
force_basic_auth: yes
return_content: yes
body_format: json
status_code:
- 202
- 200
register: CertInstallationTaskStatus
delegate_to: localhost
until: (CertInstallationTaskStatus.json.status == 'SUCCESSFUL')
delay: 120
retries: 100

- name : Certificate installation status - {{ item.fqdn }}"
debug:
msg: "Certificate for {{ item.fqdn }} installed"
when: CertInstallationTaskStatus.json.status == 'SUCCESSFUL'
And as you can see certificate for vRSLCM is installed. You can try to get to https://vRSLCM_FQDN and check if is installed correctly.

When all certificates are finally installed, the last step is to restart all SDDC Manager services after root certificate chain to the SDDC Manager keystore adding. Services are defined as ‘vcfServices’ in vars.
And the task looks like that:
- name: Restart SDDC Manager services after root certificate chain to the SDDC Manager keystore adding.
service:
name: "{{ item }}"
state: restarted
with_items: "{{ vcfServices }}"
become: yes
become_method: sudo
become_user: root
That’s it. If you have any idea how to do that in much easier way i’ll be more than welcome to read about that.
Cheers!!