Open kkazala opened 1 year ago
I'm a little rusty in my openssl command line skills, but in your above example wouldn't cert.pem
be the file you want to pass along to the credential rather than the key file?
Thank you for looking into it :) The cert.pem (public key) is uploaded to Service Principal’s certificates, the private key (key.pem) should be referenced in AZURE_CLIENT_CERTIFICATE_PATH https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet#service-principal-with-certificate :)
From: Jeff Fisher @.> Sent: Monday, August 14, 2023 7:26:32 PM To: Azure/azure-sdk-for-js @.> Cc: Kinga @.>; Author @.> Subject: Re: [Azure/azure-sdk-for-js] DefaultAzureCredential using Service principal with certificate (Issue #26806)
I'm a little rusty in my openssl command line skills, but in your above example wouldn't cert.pem be the file you want to pass along to the credential rather than the key file?
— Reply to this email directly, view it on GitHubhttps://github.com/Azure/azure-sdk-for-js/issues/26806#issuecomment-1677762754, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AFLD3H7IUQEOKCLAYP2NB7DXVJNURANCNFSM6AAAAAA3PSNUM4. You are receiving this because you authored the thread.Message ID: @.***>
@xirzec It seems I finally made it work. 💪 Let me share my findings.
By specifying AZURE_CLIENT_CERTIFICATE_PATH
we use the following DefaultAzureCredential
-> EnvironmentCredential
-> ClientCertificateCredential
-> MsalClientCertificate
MsalClientCertificate
in the init
method is:
thumbprint
based on the AZURE_CLIENT_CERTIFICATE_PATH
private key
, also based on the AZURE_CLIENT_CERTIFICATE_PATH
The certificate under AZURE_CLIENT_CERTIFICATE_PATH
must contain both: certificate and private key.
Depending on whether the password (AZURE_CLIENT_CERTIFICATE_PASSWORD
) is used, it must be either decrypted (no password) or encoded (password).
For example, the following commands:
md temp
cd temp
openssl req `
-x509 `
-days 365 `
-newkey rsa:2048 `
-keyout keytmp.pem `
-out cert.pem `
-subj '/CN=AuthTestWithPassword/C=CH/ST=Zurich/L=Zurich' `
-passout pass:HereIsMySuperPass
... generate:
cert.pem
- the certificate. This must be uploaded to "Certificates and Secrets" of the Service Principalkeytmp.pem
- encrypted private key with the following contents: -----BEGIN ENCRYPTED PRIVATE KEY----- ... -----END ENCRYPTED PRIVATE KEY-----
`DefaultAzureCredential
cert.pem
to "Certificates and Secrets" of the Service PrincipalBOTH.pem
file and copy the contents of both, the cert.pem
and keytmp.pem
files. It should look sth like that:
-----BEGIN CERTIFICATE-----
MIIDfTCCAmWgAwIBAgIUKoqrm/mWZ2EoC/a60vBoAXxoEMEwDQYJKoZIhvcNAQEL
...
tjs1jav+97FKR1lLnyGS90e2LjtTjLzqy1O5k8T1+6sv
-----END CERTIFICATE-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIZ6SyJiacCZwCAggA
...
UaTp6QTCR5NvDEb3iPNbQw==
-----END ENCRYPTED PRIVATE KEY-----
Either set the env variables using PS, or in the root of your project create .env.cert
file with the following content:
TenantName= "{tenant-name}"
AZURE_CLIENT_ID= "{client-id}"
AZURE_TENANT_ID= "{tenant-id}"
AZURE_CLIENT_CERTIFICATE_PATH= "./temp/BOTH.pem"
AZURE_CLIENT_CERTIFICATE_PASSWORD= "HereIsMySuperPass"
AZURE_CLOUD_INSTANCE= "https://login.microsoftonline.com/"
GRAPH_API_ENDPOINT= "https://graph.microsoft.com/"
import dotenv from "dotenv"
import { AccessToken, DefaultAzureCredential } from "@azure/identity";
dotenv.config({ path: "./.env.cert"})
const credential = new DefaultAzureCredential()
const resultGraph: AccessToken = await credential.getToken("https://graph.microsoft.com/.default")
const resultSPO: AccessToken = await credential.getToken(`https://${process.env.TenantName}.sharepoint.com/.default`)
console.log("Auth Graph: ", resultGraph.token.slice(0, 10) + "...")
console.log("Auth SPO: ", resultSPO.token.slice(0, 10) + "...")
You should now see the first 10 digits of the token printed out in the console:
Auth Graph: eyJ0eXAiOi...
Auth SPO: eyJ0eXAiOi...
@xirzec I understand that it's difficult to keep the documentation up to date, but perhaps the team could update it some time soon? =)
PEM
certificate must contain BOTH: the certificate and the private key @azure/identity
only supports PEM certificates that are not password protected." is no longer true (See: ClientSecretCredential and ClientCertificateCredential)jsonwebtoken
version 9 introduces several security fixes, for example RSA key size must be
2048bits or greater
. This wasn't my problem in this case but I think it's worth to mention*.pfx
certificate, but I think we have to use PEM
Or maybe you want to change the implementation of the MsalClientCertificate
and add configuration that accepts thumbprint (we can take it from "Certificates & secrets" and private key?
I'm not closing it yet because it would be absolutely fantastic if the documentation was updated. But please feel free to close it if you want to =)
@kkazala Thanks for the feedback! I'll update the documentation! :)
Describe the bug The msalClientCertificate.parseCertificate incorrectly validates the PEM private key file.
The certificatePattern requires
/(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/g
but the private key file has-----BEGIN PRIVATE KEY----- [...] -----END PRIVATE KEY-----
The comment correctly states that
To Reproduce Steps to reproduce the behavior:
key.pem
. The file has-----BEGIN PRIVATE KEY----- [...] -----END PRIVATE KEY-----
contentAZURE_CLIENT_ID
,AZURE_TENANT_ID
,AZURE_CLIENT_CERTIFICATE_PATH
,AZURE_CLIENT_CERTIFICATE_PASSWORD
: path tokey.pem
Expected behavior Authentication using Service principal with certificate should work correctly.
Additional context I'm not sure if fixing the regex will fix the problem, but it certainly looks like this might be it =)