AAD Azure Azure DevOps

Azure DevOps – use certificate for Azure Service Connection SPN

Updates

If you want to do this with GUI options continue reading this post.

CLI version

If you want to automate the deployment via script, please check the CLI version repo

To create Azure Service Connection for ARM with certificate you need to include PEM certificate with Bag attributes.

Issue

When you create RSA key pair BAG attributes are omitted, as BAG attributes are typically only included if the key pair was of type PKCS#12

Solution

include BAG attributes when creating the PEM file for Azure Devops Service Connection

Why should you use certificate credential over password credential? (From Azure Secure DevOps Kit)

Rationale: Password/shared secret credentials can be easily shared and hence can be easily compromised. Certificate credentials offer better security.

Description Azure Active Directory applications, which used in pipeline, must use certificate based authentication.

Error messages you may counter with adding SPN with cert

You encounter this if you have not uploaded the correct Public Key for the App registration _[Reason - The key was not found., Thumbprint of key used by client
Failed to obtain the Json Web Token(JWT) using service principal client ID. Exception message: Cannot find the requested object.
Failed to obtain the Json Web Token(JWT) using service principal client ID. Exception message: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

GUI setup

Correct type certificate

I’ve created an previous example which creates the correct type certificate, but you could do similar version with following commands (change the subj to match something you use)

  • I didn’t found handy command to include the BAG attributes without first going through ”pkcs12” pass-trough, as it appends the BAG attributes for the file.
openssl genrsa -out private1.pem 2048
openssl req -new -x509 -key private1.pem -out public1.pem -days 720 -subj "/C=FI/CN=spnforaad.localdom/OU=IT Department/"
openssl pkcs12 -inkey private1.pem -in public1.pem -export -out pack.pfx -passout "pass:mypass"
openssl pkcs12 -in pack.pfx -passin "pass:mypass"  -out "PemWithBagAttributes.pem" -nodes

Upload the public key to Azure AD

You can follow previous guide I’ve written here. If you used openssl commands above, use the public key ”public1.pem” in upload dialog for Azure AD app

jsa2/aadClientCredWithCert: Azure AD Client Credentials with Certificate code examples (github.com)

It’s recommended to test the token retrieval locally before proceeding to next phase

Expected response (audience will obviously be difference)

Create service connection (GUI)

Before doing the service connection you need to assign the SPN to appropriate subscription and role.

Paste contents of ” PemWithBagAttributes.pem” to certificate selection

Create service connection (AZ CLI with powershell)

 az devops login --org  https://dev.azure.com/yourOrganization

 az devops service-endpoint azurerm create `
--azure-rm-service-principal-certificate-path C:\git\aadClientCredWithCert\PemWithBagAttributes.pem  `
--azure-rm-tenant-id "46d2c4e6-a732-4fb4-b9f8-374af03f3f58"  `
--azure-rm-subscription-id "MYGUIDID" `
--azure-rm-service-principal-id "010ef950-c02b-47d8-87a1-cbc6de2145b9" `
--name "CertConnection" `
--azure-rm-subscription-name "MySub" `
--project "MyProject"

Alternative options

Create an Azure Resource Manager service connection using automated security

  • This option unfortunately uses the password credential option by default

Managed identity

  • The SPN can also be Managed Identity, but last time I checked it required the agent to be on a VM.

Connect to Microsoft Azure – Azure Pipelines | Microsoft Docs

11 comments on “Azure DevOps – use certificate for Azure Service Connection SPN

  1. It’s a comprehensive post to learn why certificate-based authentication is better while creating a new Azure service connection. Thank you!

    Tykkää

  2. Thank you so much, you really saved my day.

    Would you mind sharing where did you find the information that states such private-key format is required?

    Tykkää

    • Sorry for reply delay and thx!. I think I was able to piece together the solution by following some disparate threads on ms tech forum, and stackOverflow, unless there was any clear guidance… to be honest I don’t remember, and if there was something clear I always try to credit op

      Tykkää

  3. Thank you for your detailed explanation especially on points like using certificate credential over password credentials & using legit public key.

    Tykkää

  4. Thank you for the post, you are a life-saver!

    Just want to point out that with Azure DevOps service (as of 2021-12-02), the only thing required to in the ”certificate” field appears to be the ”Bag Attributes” headers:

    Bag Attributes
    —–BEGIN CERTIFICATE—–
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

    AAAAAAAAAAAAAAAAAAAAAAAA
    —–END CERTIFICATE—–
    Bag Attributes
    —–BEGIN PRIVATE KEY—–
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

    AAAAAAAAAAAAAAAAAAAAAAAA
    —–END PRIVATE KEY—–

    Tykkää

    • Upon further inspection… it turns out that the ”Bag attributes” headers are not necessary as long as the private key is in PKCS#8 format (instead of PKCS#1 in our case). You can tell them apart by the header and footer:

      PKCS#8 (GOOD)
      —–BEGIN PRIVATE KEY—–

      —–END PRIVATE KEY—–

      PKCS#1 (NOT GOOD for Azure DevOps service connection)
      —–BEGIN RSA PRIVATE KEY—–

      —–END RSA PRIVATE KEY—–

      Tykkää

      • Thx for the insight- What do you mean, by not good? Unnecessary I might understand, vs using PKCS8. I shall test this, and update the blog at some point if it turns out to be correct. Nonetheless from security perspective there is no difference, just different attributes for a workflow which delivers the keys to service connection

        Tykkää

      • Hi Joosua,

        By ”not good”, I meant that when using the PKCS#1 encoded private key (instead of the same private key encoded in PKCS#8), the ”Edit service connection” dialog in Azure DevOps would give the following error message on ”Verify”:

        Failed to obtain the Json Web Token(JWT) using service principal client ID. Exception message: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

        (I think we can all agree it’s not the best error message…)

        Tykkää

    • Thx for the insights! And glad to have helped

      Tykkää

Jätä kommentti