Graph API正在从AzureAD中的企业应用程序中删除证书



当我从Powershell脚本中调用graphAPI时,它首先从Azure AD中的企业应用程序服务主体中删除所有keyCredentials(证书(,然后上传我的自定义证书。如何保留当前安装在应用程序上的证书,并在非活动状态下上传新证书?

这是尸体。


{
"keyCredentials": [
{
"customKeyIdentifier":
"endDateTime": 
"keyId": 
"startDateTime":
"type": "X509CertAndPassword",
"usage": "Sign",
"key":
"displayName": 
},
{
"customKeyIdentifier": 
"endDateTime": 
"keyId": 
"startDateTime": 
"type": "AsymmetricX509Cert",
"usage": "Verify",
"key": 
"displayName": 
}
],
"passwordCredentials": [
{
"customKeyIdentifier": 
"keyId": 
"endDateTime": 
"startDateTime": 
"secretText": 
}
]
}'

每个密钥都有一个值,我只是为了隐私而删除它们。

这是对graphAPI 的调用

$response = Invoke-RestMethod -Method Patch -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/{AppID}" -Headers $global:Header -Body $certBody

所有信息都是正确的,因为它正确上传了自定义证书。我只想把其他证书放在一边。

经过一些研究和与Microsoft的讨论,使用此方法并保留证书的方法是使用对https://graph.microsoft.com/v1.0/servicePrincipals/{id}的常规GET调用来查询服务主体的密钥凭据。然后,使用GET调用的CURRENT密钥凭据和new密钥凭据创建一个新的JSON负载。然后,您可以使用相同的URI和该负载进行PATCH调用,它将成功更新服务主体证书,而不删除当前证书。

需要注意的几件事:

  1. ;customKeyIdentifier";字段有一个字符限制,由于建议使用指纹的哈希,我尝试了SHA256,但它创建的哈希太长,所以我使用了SHA1。由于这不那么安全,只要在限制范围内,另一个随机生成就可以工作,尽管GUID不起作用,我怀疑这是破折号的字符类型问题。我还没有做足够的测试来找到限制,尽管我的标识符是40个字符,而且它是成功的。

  2. 对于私钥,您可以在Powershell中使用以下命令来获得正确的解码私钥。这是我找到这个命令的地方。(这是我发现唯一有用的方法,因为OpenSSL似乎没有输出Azure正在寻找的正确私钥(

    $fileContentBytes = get-content '<PATH_TO_PFX_FILE>' -asbytestream
    $privKey = [system.convert]::tobase64string($fileContentBytes)
    

这是一个成功的JSON负载示例,其中包含现有证书和新证书。密码凭据部分应包含新证书的密码短语以及私钥的keyID。此特定服务主体具有两个当前证书。

请注意,虽然当前证书只有一个";AsymmetricX509Cert";对于该类型;AsymmetricX509Cert";以及";X509证书和密码";分别使用公钥和私钥。

{
"keyCredentials": [
{
"customKeyIdentifier": "<HASH_OF_THUMBPRINT>",
"displayName": "<CN>",
"endDateTime": "<EXPIRY_DATE>",
"key": null <EXISTING_CERT>,
"keyId": "<GUID>",
"startDateTime": "<START_DATE>",
"type": "AsymmetricX509Cert",
"usage": "Verify"
},
{
"customKeyIdentifier": "<HASH_OF_THUMBPRINT>",
"displayName": "<CN>",
"endDateTime": "<EXPIRY_DATE>",
"key": null <EXISTING_CERT>,
"keyId": "<GUID>",
"startDateTime": "<START_DATE>",
"type": "AsymmetricX509Cert",
"usage": "Sign"
},
{
"customKeyIdentifier": "<HASH_OF_THUMBPRINT>",
"displayName": "<CN>",
"endDateTime": "<EXPIRY_DATE>",
"key": null <EXISTING_CERT>,
"keyId": "<GUID>",
"startDateTime": "<START_DATE>",
"type": "AsymmetricX509Cert",
"usage": "Verify"
},
{
"customKeyIdentifier": "<HASH_OF_THUMBPRINT>",
"displayName": "<CN>",
"endDateTime": "<EXPIRY_DATE>",
"key": null <EXISTING_CERT>,
"keyId": "<GUID>",
"startDateTime": "<START_DATE>",
"type": "AsymmetricX509Cert",
"usage": "Sign"
},
{
"customKeyIdentifier": "<HASH_OF_THUMBPRINT>",
"endDateTime": "<EXPIRY_DATE>",
"type": "X509CertandPassword",
"key": "<NEWCERT-PrivateKey>",
"displayName": "<CN>",
"startDateTime": "<START_DATE>",
"keyId": "<GUID>",
"usage": "Sign"
},
{
"customKeyIdentifier": "<HASH_OF_THUMBPRINT>",
"endDateTime": "<EXPIRY_DATE>",
"type": "AsymmetricX509Cert",
"key": "<NEWCERT-PublicKey>",
"displayName": "<CN>",
"startDateTime": "<START_DATE>",
"keyId": "<GUID>",
"usage": "Verify"
}
],
"passwordCredentials": [
{
"endDateTime": "<EXPIRY_DATE>",
"secretText": "<PASSPHRASE_FOR_NEW_CERT>",
"startDateTime": "<START_DATE>",
"keyId": "<KEY_ID_OF_PRIVATE_KEY>",
"customKeyIdentifier": "<HASH_OF_THUMBPRINT_OF_NEW_CERT>"
}
]
}

使用addKey而不是Update方法添加额外的keyCredentials:

POST /servicePrincipals/{id}/addKeyPATCH /servicePrincipals/{id}

但要注意:

没有任何现有有效证书(即:尚未添加任何证书,或所有证书都已过期(的ServicePrincipals将无法使用此服务操作。更新servicePrincipal可以用来执行更新。

最新更新