vCloud SAML authentication – Automation

Cant say that I did everything by my self in this post, I had a great great help from my college and friend Kasper Hansen. Also gotten a great help from the vExpert community, especially Tom Fojta.

In my last post I found out how to setup vCloud SAML against AzureAD. Now we are gonna look on how to automate each tenant to use the same AzureAD. In these days everybody have either a Microsoft og AzureAD account, so this way its easy to invite them as guest users and this way have controlled access but also ensure that vCloud users have MFA enabled.

We use VRO for the creation of vCloud tenants, in this flow we are now going to introduce a new workflow that will do following. Although the workflow is just a restcall to trigger an event in Azure Automation.

  • Create AzureAD Groups for admin and viewer
  • Post federation metadata to vCloud tenant
  • Post federation groups to vCloud tenant

Enable SAML

Fojta have some very good articles on his blog on the basic setup of SAML to different IDP systems. I also did a piece on it where Azure where the IDP provider.

Because we want to have all organisations linked to the same SAML app in Azure we need to have the same SAML certificate on all organisations. You can only do this with the API, but what the documentation did not say was that the certificate needs to be trusted by the keystore, the java keystore of the cells.

Create a self-signed certificate and make vCloud trust it

These commands will help you create a certificate and a private key in the needed pkcs8 format and certificate in the x509 format.

### Create the self-signed private key and certificate
jr@mbp:~ jr$ openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout selfsigned.key.pem -out selfsigned-x509.crt

### Convert the private key to pkcs8 format
jr@mbp:~ jr$ openssl pkcs8 -topk8 -inform PEM -outform PEM -in 
selfsigned.key.pem -out selfsigned-pkcs8.key -nocrypt

When you have done the new self-signed certificate you need to import it to each and one of your cells. After import you will need to restart the cells. One of the errors I did here way that I tried to import a .pem where the private key and certificate where combines, that won’t work. Only import the certificate.

/opt/vmware/vcloud-director/jre/bin/keytool --import -trustcacerts -keystore /opt/vmware/vcloud-director/jre/lib/security/cacerts -alias saml -file selfsigned-x508.crt

Publish federation settings to API

We where having a lot of trial and error in this step, because that vCloud did not trust the certificate. Each time a put where done to the API the log complained. /opt/vmware/vcloud-director/logs/vcloud-container-debug.log it showed “Failed to generate keystore | requestId=<id>,request=PUT.”

Following is a example done in PowerShell, insert your self-signed certificate where it says —–END/BEGIN CERTIFICATE—–

### XML with federation metadata for AzureAD saml app
$xmlBody = 
@'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OrgFederationSettings xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:common="http://schemas.dmtf.org/wbem/wscim/1/common" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1" xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5" xmlns:ns9="http://www.vmware.com/vcloud/versions" href="https://<VCD_URI>/api/admin/org/7688ff82-77e8-4f70-a4b6-b1767ab110d1/settings/federation" type="application/vnd.vmware.admin.organizationFederationSettings+xml">
<SAMLMetadata>
    ...
</SAMLMetadata>
    <Enabled>true</Enabled>
    <SamlSPEntityId>test</SamlSPEntityId>
    <SamlAttributeMapping>
    	<EmailAttributeName>EmailAddress</EmailAttributeName>
    	<UserNameAttributeName>UserName</UserNameAttributeName>
    	<FirstNameAttributeName>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname</FirstNameAttributeName>
    	<SurnameAttributeName>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname</SurnameAttributeName>
    	<FullNameAttributeName>FullName</FullNameAttributeName>
    	<GroupAttributeName>Groups</GroupAttributeName>
    	<RoleAttributeName>Role</RoleAttributeName>
    </SamlAttributeMapping>
    <SamlSPKeyAndCertificateChain>
         <Key>-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----</Key>
        <CertificateChain>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----</CertificateChain>
     </SamlSPKeyAndCertificateChain>
</OrgFederationSettings>
'@

Invoke-RestMethod -Uri "https://<VCD_URI>/api/admin/org/$orgId/settings/federation" -Method Put  -Headers @{'x-vcloud-authorization'= $vCDAuthorizationToken ; Accept = 'application/*+xml;version=31.0'; "Content-type"  =  "application/*+xml;version=31.0"} -Body ([System.Text.Encoding]::UTF8.GetBytes(($xmlBody)))

Publish SAML groups to API

Now that the SAML metadata/certificate is uploaded and in place we need to add groups to tenant. You can read more about what groups/users should be imported in my other SAML blog post.

Each tenant have its own role ids, so when doing automation with group import we need to query the vCloud API and get the role ids. There is a specific query API to get data. When using a system account we need to specify a “VCLOUD-TENANT-CONTEXT” in the header of the request. This we we can query a tenant context from a system account.

 ### Retrieve roles from tenant
[xml]$xml = Invoke-RestMethod  -UseBasicParsing -Uri 'https://<VCD_URI>/api/query?type=role&page=1&pageSize=20&links=true'  -Method get  -Headers @{'x-vcloud-authorization'= $vCDAuthorizationToken ; Accept = 'application/*+xml;version=31.0'; "Content-type"  =  "application/*+xml;version=31.0";  "X-VMWARE-VCLOUD-TENANT-CONTEXT" = "$orgId"}'

### Find the real is for x
$RoleHref = ($xml.QueryResultRecords.RoleRecord | where {$_.Name -eq "$role"}).href

After we got the role id we can now send up the group together with the role id and this was be able to authenticate based on a SAML group from AzureAD.

### Define XML with role and groupid
$xmlBody =
@'
<Group xmlns="http://www.vmware.com/vcloud/v1.5"
    xmlns:ns9="http://www.vmware.com/vcloud/versions" name="{1}"
    type="application/vnd.vmware.admin.group+xml">
    <ProviderType>SAML</ProviderType>
    <Role href="{0}" type="application/vnd.vmware.admin.role+xml"/>
</Group>
'@ -f $RoleHref , $GroupId
 
### Post xml to vcd 
Invoke-RestMethod -UseBasicParsing -Uri "https://<VCD_URI>/api/admin/org/$orgId/groups"  -Method Post  -Headers @{'x-vcloud-authorization'= $vCDAuthorizationToken ; Accept = 'application/*+xml;version=31.0'; "Content-type"  =  "application/*+xml;version=31.0"} -Body ([System.Text.Encoding]::UTF8.GetBytes(($xmlBody)))

Conclusion

Now we have all the pieces for making automation where we can enable a tenant for SAML authentication and afterwards import f.eks. a viewer and admin group. External users will then be invited to the AzureAD, imported into the right group and now they have access to the their tenant. We can help the organisation secure the access to their virtual datacenter with MFA and they will have single sign-on with there own user that originates from their own AzureAD or Microsoft account.

A service library will be made where users can be invited to the tenant organisation. So that when one user have been invited that user will be able to invite its colleagues.

Jesper Ramsgaard