-
Notifications
You must be signed in to change notification settings - Fork 300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create a SSO SAML Signing Certificate #823
Comments
It is possible to create the certificate, but apparently, the activation has to be done manually or using Azure CLI. My code so far: data "azuread_client_config" "current" {}
resource "random_uuid" "oauth2_permission_scope" {
keepers = {
domain_name = var.saml_identifier_uri
}
}
resource "random_uuid" "app_role_user" {
keepers = {
domain_name = var.saml_identifier_uri
}
}
resource "random_uuid" "app_role_msiam_access" {
keepers = {
domain_name = var.saml_identifier_uri
}
}
resource "azuread_application" "this" {
display_name = var.display_name
owners = [data.azuread_client_config.current.object_id]
identifier_uris = [var.saml_identifier_uri]
api {
oauth2_permission_scope {
id = random_uuid.oauth2_permission_scope.id
admin_consent_description = "Allow the application to access ${var.display_name} on behalf of the signed-in user."
admin_consent_display_name = "Access ${var.display_name}"
user_consent_description = "Allow the application to access ${var.display_name} on behalf of the signed-in user."
user_consent_display_name = "Access ${var.display_name}"
enabled = true
type = "User"
value = "user_impersonation"
}
}
app_role {
allowed_member_types = ["User"]
description = "User"
display_name = "User"
id = random_uuid.app_role_user.id
}
app_role {
allowed_member_types = ["User"]
description = "msiam_access"
display_name = "msiam_access"
id = random_uuid.app_role_msiam_access.id
}
optional_claims {
saml2_token {
essential = true
name = "email"
additional_properties = ["sam_account_name"]
}
}
web {
homepage_url = "https://${var.app_fqdn}"
logout_url = "https://${var.app_fqdn}"
redirect_uris = [
"https://${var.app_fqdn}/saml/acs"
]
implicit_grant {
access_token_issuance_enabled = false
id_token_issuance_enabled = true
}
}
}
resource "azuread_service_principal" "this" {
application_id = azuread_application.this.application_id
app_role_assignment_required = false
owners = [data.azuread_client_config.current.object_id]
feature_tags {
enterprise = true
gallery = true
custom_single_sign_on = true
}
preferred_single_sign_on_mode = "saml"
notification_email_addresses = var.notification_emails
}
resource "tls_private_key" "this" {
algorithm = "RSA"
rsa_bits = 2048
}
resource "tls_self_signed_cert" "this" {
allowed_uses = ["client_auth", "server_auth"]
key_algorithm = "RSA"
private_key_pem = tls_private_key.this.private_key_pem
validity_period_hours = 4321
subject {
common_name = azuread_application.this.display_name
organization = var.organisation_name
}
}
resource "azuread_service_principal_certificate" "this" {
service_principal_id = azuread_service_principal.this.id
type = "AsymmetricX509Cert"
value = tls_self_signed_cert.this.cert_pem
end_date_relative = "4320h"
}
resource "null_resource" "manual_certificate_approve" {
provisioner "local-exec" {
command = "echo '\n\n-= Please activate the SSO certificate THEN RUN `touch /tmp/ididit`; I WILL WAIT HERE =-\n\n'; while ! test -f /tmp/ididit; do sleep 1; done"
}
depends_on = [azuread_service_principal_certificate.this]
}
resource "azuread_claims_mapping_policy" "this" {
definition = [
jsonencode(
{
ClaimsMappingPolicy = {
ClaimsSchema = [
{
ID = "employeeid"
JwtClaimType = "name"
SamlClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
Source = "user"
},
{
ID = "mail"
JwtClaimType = "mail"
SamlClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
Source = "user"
},
{
ID = "groups"
JwtClaimType = "groups"
SamlClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/groups"
source = "user"
}
]
IncludeBasicClaimSet = "true"
Version = 1
}
}
),
]
display_name = "${var.display_name}_cmp"
}
resource "azuread_service_principal_claims_mapping_policy_assignment" "this" {
claims_mapping_policy_id = azuread_claims_mapping_policy.this.id
service_principal_id = azuread_service_principal.this.id
}
data "azuread_service_principal" "this" {
object_id = azuread_service_principal.this.id
}
data "http" "idp_metadata" {
url = data.azuread_service_principal.this.saml_metadata_url
request_headers = {
Accept = "application/xml"
}
depends_on = [
azuread_service_principal.this,
azuread_service_principal_certificate.this
]
}
|
I tried the certificate from the computer and generated with tls_self_signed_cert. It really needs to be activated manually on the SSO page. But it does not show up in "Federation Metadata". If you manually import the PFX certificate, it is displayed in "Federation Metadata". I tried @rajish code. The certificate did not show up in "Federation Metadata" |
Regarding the metadata link, there's a workaround that conforms the Azure Graph documentation: data "http" "idp_metadata" {
url = "https://login.microsoftonline.com/${data.azuread_client_config.current.tenant_id}/federationmetadata/2007-06/federationmetadata.xml?appid=${azuread_application.this.application_id}"
request_headers = {
Accept = "application/xml"
}
depends_on = [
azuread_service_principal.this,
azuread_service_principal_certificate.this
]
} But the certificate activation is a pain for two reasons, see the commented out code: resource "null_resource" "manual_certificate_approve" {
provisioner "local-exec" {
command = "echo '\n\n-= Please activate the SSO certificate THEN RUN `touch /tmp/ididit`; I WILL WAIT HERE =-\n\n'; while ! test -f /tmp/ididit; do sleep 1; done"
# TODO no thumbprint here
# command = "az ad sp update --id ${azuread_application.this.application_id} --set preferredTokenSigningKeyThumbprint=${tls_self_signed_cert.this.thumbprint}"
}
depends_on = [azuread_service_principal_certificate.this]
}
|
@rajish, not sure if this is a recent change from Microsoft but when I call this endpoint, and point to an existing service principal I've created with Terraform (that doesn't have a cert) it generates a certificate and activates it. Not sure if this is new or just the way my app registration and service principal are configured? the script I used to call the endpoint https://gist.github.com/brodster2/16dfc11cdb55e4a84e3903dfab9f4bf4 |
I'm actually having exactly the same issue, did you ever find a resolution? Basically if I provide my own cert via a |
Using the snippet from @rajish I was able to activate a token by using
|
Hey @vschum which az cli version did you run the exec command on? Doesn't seem to work on
|
Worked for me with the following version.
|
That is strange, I've downgraded az cli to 2.38.0 and I'm still getting a empty list response when trying to update preferredTokenSigningKeyThumbprint.
|
@vschum I tried your solution and still the cert needed to be activated manually ,, does anyone have another solution maybe? |
i'm also getting the following error when using the above code.
|
This is working for me. Be interested to see if others are able to use it too.
|
This sort of worked for me. While it seems to have activated my cert according to the Azure Portal, the cert is still not configured completely it seems. I receive the error "AADSTS500031: Cannot find signing certificate configured." when trying to test SSO, and the metadata does not contain the cert. |
I compared what is created by the UI and what is created by the
|
Wow, great find John. Anyone with the skill to add the 2nd API call to the resource creation? |
I wonder if it is enough to make |
Bit of a novice on how this stuff all sits together but i'm assuming you would need to issue the API call twice upon resource creation? Once for the "verify", another for "sign"? |
I've had a bit of poke into this - the existing resource provider for certificates is available here - The last update to this was on Nov 12, 2021, but the underlying client it uses to controls resource was only updated to have addTokenSigningCertificate and set the thumbprint (although Im not sure setting the thumbprint is required - i think this might be done automatically by the aforementioned API call and this is somewhat validate by @brodster2) in February. See below for the commit. -> manicminer/hamilton@221ac23 The existing resource provider uses a more involved method of making direct calls to the key endpoint (which addTokenSigningCertificate effectively wraps) and then doesn't set the thumbprint. The two approaches are actually outlined in step 4 of the below of the documentation It should be enough to modify the resource creation routine to use addTokenSigningCertificate instead - the existing routines to may not need to change - e.g. deletion would still involve needing to look the key up by the key ID. @manicminer I can look into prepping a PR to fix this if you would like? I'm currently fixing this in a private provider and once I've 100% confirmed this fixes behavior I can look into preparing an appropriate change? EDIT: This is effectively covered by the following issues & draft pull request |
hey hey 👋 thanks for your input, @cruikshj I followed your steps and I got the same result, my metadata file doesn't contain the certificate. What is the status of this issue? |
This adds a new resource called `service_principal_token_signing_certificate` that is used to manage the whole lifecycle of token signing certificates used for SAML authentication. This resource makes use of the `AddTokenSigningCertificate` function that was added to hamilton previously here: manicminer/hamilton#158 MS Graphs Docs: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-addtokensigningcertificate?view=graph-rest-1.0&tabs=http As documented in the docs above, when the `AddTokenSigningCertificate` function is invoked, 3 individual objects are created... - Verify `keyCredential` (Public Cert) - Sign `keyCredential` (Private Key) - `passwordCredential` (Private Key Password) When the object is returned, it includes the thumbprint, the public key pem value, and a `keyId`. However, we found an odd behavior that the `keyId` that is returned is actually for the Sign `keyCredential`. Since the Verify certificate is the one that we acutally care about, we used the `customKeyIdentifier`, which is the same for all 3 values, to get the Verify `keyId`, which we then use in building the resource ID. We additionally had to "calculate" the thumbprint value from the actual value of the Verify cert, as this value is not returned from the API, except after initial creation in the Create step. We did this by getting pem value of the Verify cert by adding the `$select=keyCredential` odata query to the GET of the service principal. By combining this value with the PEM header/footer, we can calculate the SHA-1 fingerprint, which matches up to the appropriate thumbprint. Finally, to delete the certificate, we have to PATCH the service principal with all 3 objects mentioned previously removed. To gather this, we used the `customKeyIdentifier` value in a loop. Closes hashicorp#732 And part of hashicorp#823
This adds a new resource called `service_principal_token_signing_certificate` that is used to manage the whole lifecycle of token signing certificates used for SAML authentication. This resource makes use of the `AddTokenSigningCertificate` function that was added to hamilton previously here: manicminer/hamilton#158 MS Graphs Docs: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-addtokensigningcertificate?view=graph-rest-1.0&tabs=http As documented in the docs above, when the `AddTokenSigningCertificate` function is invoked, 3 individual objects are created... - Verify `keyCredential` (Public Cert) - Sign `keyCredential` (Private Key) - `passwordCredential` (Private Key Password) When the object is returned, it includes the thumbprint, the public key pem value, and a `keyId`. However, we found an odd behavior that the `keyId` that is returned is actually for the Sign `keyCredential`. Since the Verify certificate is the one that we acutally care about, we used the `customKeyIdentifier`, which is the same for all 3 values, to get the Verify `keyId`, which we then use in building the resource ID. We additionally had to "calculate" the thumbprint value from the actual value of the Verify cert, as this value is not returned from the API, except after initial creation in the Create step. We did this by getting pem value of the Verify cert by adding the `$select=keyCredential` odata query to the GET of the service principal. By combining this value with the PEM header/footer, we can calculate the SHA-1 fingerprint, which matches up to the appropriate thumbprint. Finally, to delete the certificate, we have to PATCH the service principal with all 3 objects mentioned previously removed. To gather this, we used the `customKeyIdentifier` value in a loop. Closes hashicorp#732 And part of hashicorp#823
This adds a new resource called `service_principal_token_signing_certificate` that is used to manage the whole lifecycle of token signing certificates used for SAML authentication. This resource makes use of the `AddTokenSigningCertificate` function that was added to hamilton previously here: manicminer/hamilton#158 MS Graphs Docs: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-addtokensigningcertificate?view=graph-rest-1.0&tabs=http As documented in the docs above, when the `AddTokenSigningCertificate` function is invoked, 3 individual objects are created... - Verify `keyCredential` (Public Cert) - Sign `keyCredential` (Private Key) - `passwordCredential` (Private Key Password) When the object is returned, it includes the thumbprint, the public key pem value, and a `keyId`. However, we found an odd behavior that the `keyId` that is returned is actually for the Sign `keyCredential`. Since the Verify certificate is the one that we acutally care about, we used the `customKeyIdentifier`, which is the same for all 3 values, to get the Verify `keyId`, which we then use in building the resource ID. We additionally had to "calculate" the thumbprint value from the actual value of the Verify cert, as this value is not returned from the API, except after initial creation in the Create step. We did this by getting pem value of the Verify cert by adding the `$select=keyCredential` odata query to the GET of the service principal. By combining this value with the PEM header/footer, we can calculate the SHA-1 fingerprint, which matches up to the appropriate thumbprint. Finally, to delete the certificate, we have to PATCH the service principal with all 3 objects mentioned previously removed. To gather this, we used the `customKeyIdentifier` value in a loop. Closes hashicorp#732 And part of hashicorp#823
This adds a new resource called `service_principal_token_signing_certificate` that is used to manage the whole lifecycle of token signing certificates used for SAML authentication. This resource makes use of the `AddTokenSigningCertificate` function that was added to hamilton previously here: manicminer/hamilton#158 MS Graphs Docs: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-addtokensigningcertificate?view=graph-rest-1.0&tabs=http As documented in the docs above, when the `AddTokenSigningCertificate` function is invoked, 3 individual objects are created... - Verify `keyCredential` (Public Cert) - Sign `keyCredential` (Private Key) - `passwordCredential` (Private Key Password) When the object is returned, it includes the thumbprint, the public key pem value, and a `keyId`. However, we found an odd behavior that the `keyId` that is returned is actually for the Sign `keyCredential`. Since the Verify certificate is the one that we acutally care about, we used the `customKeyIdentifier`, which is the same for all 3 values, to get the Verify `keyId`, which we then use in building the resource ID. We additionally had to "calculate" the thumbprint value from the actual value of the Verify cert, as this value is not returned from the API, except after initial creation in the Create step. We did this by getting pem value of the Verify cert by adding the `$select=keyCredential` odata query to the GET of the service principal. By combining this value with the PEM header/footer, we can calculate the SHA-1 fingerprint, which matches up to the appropriate thumbprint. Finally, to delete the certificate, we have to PATCH the service principal with all 3 objects mentioned previously removed. To gather this, we used the `customKeyIdentifier` value in a loop. Closes hashicorp#732 And part of hashicorp#823
This adds a new resource called `service_principal_token_signing_certificate` that is used to manage the whole lifecycle of token signing certificates used for SAML authentication. This resource makes use of the `AddTokenSigningCertificate` function that was added to hamilton previously here: manicminer/hamilton#158 MS Graphs Docs: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-addtokensigningcertificate?view=graph-rest-1.0&tabs=http As documented in the docs above, when the `AddTokenSigningCertificate` function is invoked, 3 individual objects are created... - Verify `keyCredential` (Public Cert) - Sign `keyCredential` (Private Key) - `passwordCredential` (Private Key Password) When the object is returned, it includes the thumbprint, the public key pem value, and a `keyId`. However, we found an odd behavior that the `keyId` that is returned is actually for the Sign `keyCredential`. Since the Verify certificate is the one that we acutally care about, we used the `customKeyIdentifier`, which is the same for all 3 values, to get the Verify `keyId`, which we then use in building the resource ID. We additionally had to "calculate" the thumbprint value from the actual value of the Verify cert, as this value is not returned from the API, except after initial creation in the Create step. We did this by getting pem value of the Verify cert by adding the `$select=keyCredential` odata query to the GET of the service principal. By combining this value with the PEM header/footer, we can calculate the SHA-1 fingerprint, which matches up to the appropriate thumbprint. Finally, to delete the certificate, we have to PATCH the service principal with all 3 objects mentioned previously removed. To gather this, we used the `customKeyIdentifier` value in a loop. Closes hashicorp#732 And part of hashicorp#823
This adds a new resource called `service_principal_token_signing_certificate` that is used to manage the whole lifecycle of token signing certificates used for SAML authentication. This resource makes use of the `AddTokenSigningCertificate` function that was added to hamilton previously here: manicminer/hamilton#158 MS Graphs Docs: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-addtokensigningcertificate?view=graph-rest-1.0&tabs=http As documented in the docs above, when the `AddTokenSigningCertificate` function is invoked, 3 individual objects are created... - Verify `keyCredential` (Public Cert) - Sign `keyCredential` (Private Key) - `passwordCredential` (Private Key Password) When the object is returned, it includes the thumbprint, the public key pem value, and a `keyId`. However, we found an odd behavior that the `keyId` that is returned is actually for the Sign `keyCredential`. Since the Verify certificate is the one that we acutally care about, we used the `customKeyIdentifier`, which is the same for all 3 values, to get the Verify `keyId`, which we then use in building the resource ID. We additionally had to "calculate" the thumbprint value from the actual value of the Verify cert, as this value is not returned from the API, except after initial creation in the Create step. We did this by getting pem value of the Verify cert by adding the `$select=keyCredential` odata query to the GET of the service principal. By combining this value with the PEM header/footer, we can calculate the SHA-1 fingerprint, which matches up to the appropriate thumbprint. Finally, to delete the certificate, we have to PATCH the service principal with all 3 objects mentioned previously removed. To gather this, we used the `customKeyIdentifier` value in a loop. Closes hashicorp#732 And part of hashicorp#823
Tested and approved ! No need of https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/service_principal_certificate anymore |
Thanks for your work @tagur87, we've started this week creating an AD App for SAML singing and we needed this. We've done this for including the rotation, in case it is useful for someone else: resource "time_rotating" "saml-certificate" {
rotation_years = 3
}
resource "azuread_service_principal_token_signing_certificate" "saml-certificate" {
service_principal_id = azuread_service_principal.app.id
display_name = "CN=${var.app_name} SSO Certificate"
end_date = time_rotating.saml-certificate.rotation_rfc3339
provisioner "local-exec" {
command = <<-SHELL
az ad sp update \
--id ${self.service_principal_id} \
--set preferredTokenSigningKeyThumbprint=${self.thumbprint}
SHELL
}
} |
I have been using the Has anyone been successful with this? Thanks |
any updates on this issue? We are facing the same problem. Thx. |
@ojc97 were you able to address this? |
Hello, I was able to address this via the tokenIssuancePolicies: resource "azuread_service_principal_token_signing_certificate" "saml_signing_cert" {
for_each = { for app in local.apps_map : app.app_name => app if app.type == "saml" }
service_principal_id = azuread_service_principal.sp[each.key].id
display_name = "CN=${each.value.app_name} SSO Certificate"
end_date = time_rotating.saml_certificate.rotation_rfc3339
provisioner "local-exec" {
command = <<EOT
az rest --method GET --uri https://graph.microsoft.com/v1.0/servicePrincipals/${azuread_service_principal.sp[each.key].object_id}/tokenIssuancePolicies \
| jq -r '.value[0].id' > ./tmp/${each.key}_policy.txt
EOT
}
provisioner "local-exec" {
command = <<EOT
az rest --method PATCH --uri https://graph.microsoft.com/v1.0/policies/tokenIssuancePolicies/$(cat ./tmp/${each.key}_policy.txt) \
--headers 'Content-Type=application/json' \
--body '{
"definition": [
"{\n \"TokenIssuancePolicy\": {\n \"Version\": 1,\n \"SigningAlgorithm\": \"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\",\n \"TokenResponseSigningPolicy\": \"ResponseAndToken\",\n \"SamlTokenVersion\": \"2.0\"\n }\n}"
]
}'
EOT
}
}
but the easiest way is actually to create the App resource using the template ID for the non-gallery apps, this will set the policy correctly automatically. |
For me an issue remains as this is not updating: preferredTokenSigningKeyEndDateTime. Has anyone succeeded in that? Thanks |
Community Note
Description
I would like to open a new feature request to enable creation of a SSO Signing Certificate. This functionality currently exists via the API, but seems to be missing in the terraform provider.
API Reference
Azure AD service principle certificate only provides importing a certificate. This request would be for creating a SSO certificate.
New or Affected Resource(s)
References
The text was updated successfully, but these errors were encountered: