Open MarkDordoy opened 5 years ago
@MarkDordoy Were you able to make any progress on this? Looking to do the same.
Hi @MarkDordoy, the configuration you posted is the full extent to which you can currently configure a service principal with the provider. We are presently limited in different ways by SDK and API support, however we are planning to migrate to the Microsoft Graph API which will enable wider capabilities for us.
If anyone subscribed to this issue is able to look over the API documentation for AAD Graph and MS Graph, specifically for service principals, to help determine what aspects are supported by both APIs, that would be super helpful and appreciated.
AAD Graph link: https://docs.microsoft.com/en-gb/previous-versions/azure/ad/graph/api/entity-and-complex-type-reference#serviceprincipal-entity MS Graph Link: https://docs.microsoft.com/en-us/graph/api/resources/serviceprincipal?view=graph-rest-beta
@manicminer would it be possible for me to call the graph API based on the current setup of this provider?
Ive successfully got this working using a powershell script to go and enable SSO post terraform run. I'd be happy to extend this provider (well try to) to also make that call based on a new tf parameter in the Service principal resource, but i'm not even sure if i can why it is using the Active Directory graph.
@MarkDordoy currently no, but we're working on it and when we have an implementation for MS Graph we'll ping all waiting issues. If you have any working PS or other implementations please feel free to post them here as it may help for context when it gets implemented.
@manicminer and @manicminer Here is my Terraform module for SAML with "Grant Admin Consent" workflow as well as adding the SAML attributes. Please note I have two GitHub Issues open with the Graph Dev team for the missing API functions:
az-cli missing parameter SAML Identifier missing on Service Principal via API create
resource "azuread_application" "this" {
//https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-single-sign-on-non-gallery-applications
name = var.app_name
identifier_uris = [var.identifier_uri]
reply_urls = var.reply_url
available_to_other_tenants = false
oauth2_allow_implicit_flow = true
type = var.app_type
group_membership_claims = var.group_claims
owners = var.owners
required_resource_access {
//https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/grant-admin-consent
resource_app_id = "00000003-0000-0000-c000-000000000000"
resource_access {
id = "5f8c59db-677d-491f-a6b8-5f174b11ec1d"
type = "Scope"
}
resource_access {
id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
type = "Scope"
}
}
app_role {
allowed_member_types = [
"User"
]
description = "User"
display_name = "User"
is_enabled = true
}
app_role {
allowed_member_types = [
"User"
]
description = "msiam_access"
display_name = "msiam_access"
is_enabled = true
}
// We need to wait because Azure Graph API returns a 200 before its call-able #eventualconsistancy...
provisioner "local-exec" {
command = "sleep 20"
}
//https://github.com/Azure/azure-cli/issues/7579
//Add metadata URL
// provisioner "local-exec" {
// command = "az ad app update --id ${self.application_id} --set samlMetadataUrl=${var.saml_metadata_url}"
// }
// We need to wait because Azure Graph API returns a 200 before its call-able #eventualconsistancy...
// provisioner "local-exec" {
// command = "sleep 5"
// }
//https://github.com/Azure/azure-cli/issues/12946
//https://github.com/Azure/azure-cli/issues/11534
//https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims
//Optional Claims for tokens
provisioner "local-exec" {
command = "az rest --method PATCH --uri 'https://graph.microsoft.com/v1.0/applications/${self.object_id}' --body '{\"optionalClaims\": {\"saml2Token\": [{\"name\": \"groups\", \"additionalProperties\": [\"sam_account_name\"]}]}}'"
}
}
resource "azuread_service_principal" "this" {
//https://github.com/Azure/azure-cli/issues/9250
application_id = azuread_application.this.application_id
tags = [
"WindowsAzureActiveDirectoryIntegratedApp",
"WindowsAzureActiveDirectoryCustomSingleSignOnApplication",
"WindowsAzureActiveDirectoryGalleryApplicationNonPrimaryV1"
]
// We need to wait because Azure Graph API returns a 200 before its call-able #eventualconsistancy...
provisioner "local-exec" {
command = "sleep 20"
}
provisioner "local-exec" {
command = "az ad sp update --id ${azuread_application.this.application_id} --set preferredSingleSignOnMode='saml'"
}
depends_on = [
azuread_application.this
]
}
resource "null_resource" "grant_admin_constent" {
count = var.admin_consent ? 1 : 0
// https://docs.microsoft.com/en-us/cli/azure/ad/app/permission?view=azure-cli-latest#code-try-3
provisioner "local-exec" {
command = "sleep 20"
}
provisioner "local-exec" {
command = "az ad app permission admin-consent --id ${azuread_application.this.application_id}"
}
depends_on = [
azuread_service_principal.this
]
}
data "http" "idp_metadata" {
url = var.idp_metadata_url
}
resource "vault_generic_secret" "vault-azure-sso-component" {
path = "sites/${var.vault_site_name}/components/azure-sso"
data_json = <<EOF
{
"application_id": "${azuread_application.this.application_id}",
"description": "This key is managed by terrafom, do not change/add/remove any values, see terraform module: azure-sso-app",
"identifier_uri": "${var.identifier_uri}"
}
EOF
// "idp_metadata_file": "${data.http.idp_metadata.body}"
depends_on = [
azuread_application.this
]
}
@nickadams675 Thanks for the post, I did consider using the local-exec but you dont get state stored with these calls.
@manicminer Do you have any timeline as to when we can expect the provider to be switched to the Microsoft Graph?
@MarkDordoy It's something we're actively working on, but we don't have a timeline at this stage
@MarkDordoy can you post the script you're using with ms graph api?
@nickadams675 i saw both yoru issues got close to be rerouted, did you come up with a solution?
The script i used to get me around this issue while this provider gets updated to the AzureAD Graph was the following (I cannot post all the solution but happy to share the functions i wrote to get this part working)
First i created a class for the Graph API Auth:
Class GraphAPIToken {
[ValidateNotNullOrEmpty()]
[string]$Grant_Type
[ValidateNotNullOrEmpty()]
[string]$Scope
[ValidateNotNullOrEmpty()]
[string]$Client_Id
[ValidateNotNullOrEmpty()]
[string]$Client_Secret
[ValidateNotNullOrEmpty()]
[string]$Tenant_Id
[ValidateNotNullOrEmpty()]
[datetime]$Token_Expiry
[ValidateNotNullOrEmpty()]
[string]$Token
GraphAPIToken ([string]$grant_Type, [string]$scope, [string]$client_Id, [string]$client_secret, [string]$tenantId) {
$this.Client_Id = $client_Id
$this.Client_Secret = $client_secret
$this.Scope = $scope
$this.Grant_Type = $grant_Type
$this.Tenant_Id = $tenantId
$this.RequestToken()
}
[void]RequestToken() {
try {
$ReqTokenBody = @{
Grant_Type = $this.grant_Type
Scope = $this.scope
client_Id = $this.Client_Id
Client_Secret = $this.Client_Secret
}
$response = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$($this.Tenant_Id)/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody -UseBasicParsing
$this.Token = $response.access_token
$this.Token_Expiry = (Get-Date).AddSeconds($response.expires_in - 300)
}
catch {
throw "Unable to query https://login.microsoftonline.com/$($this.Tenant_Id)/oauth2/v2.0/token and receive a token"
}
}
[string]GetToken() {
if ($this.Token_Expiry -lt (get-date)) {
$this.RequestToken()
}
return $this.Token
}
}
I invoked the class object by using this:
$script:graphAPIToken = [GraphAPIToken]::new("client_credentials", 'https://graph.microsoft.com/.default', $azureADCred.clientId, $azureADCred.clientSecret, $azureADCred.tenantId)
Then i made graph calls using this function which was called from my main script:
Function Invoke-SAMLEnablement {
[cmdletbinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory)]
[Microsoft.Open.AzureAD.Model.ServicePrincipal]$spn
)
$accessToken = $script:graphAPIToken.GetToken()
$header = @{Authorization = "Bearer $($accessToken)" }
try {
$spnobject = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$($spn.ObjectId)" -headers $header -UseBasicParsing
}
catch {
Write-Log "Error occuring trying to make graph call. $_" -MessageLevel ERROR
}
if ($null -eq $spnobject.preferredSingleSignOnMode) {
if ($PSCmdlet.ShouldProcess("SPN $($spn.DisplayName) has preferredSingleSignOnMode set to null, setting to saml")) {
write-log "SPN $($spn.DisplayName) has preferredSingleSignOnMode set to null, setting to saml" -MessageLevel INFO
$patch = @{"preferredSingleSignOnMode" = "saml" }
try {
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$($spn.ObjectId)" -headers $header -Method Patch -Body ($patch | ConvertTo-Json) -ContentType application/json -UseBasicParsing
}
catch {
Write-log " Failed to update perferred SSO Mode for enteprise app $($spn.DisplayName), StatusCode: $($_.Exception.Response.StatusCode.value__)" -MessageLevel ERROR
write-log "$_" -MessageLevel ERROR
}
}
}
}
My end solution was terraform creating the app registration and SPN, then a powershell script than ran in a nomad job (think a cron job) that would go and enable the SAML endpoint, check on things like conditional accces policies and add them, then finally flatten our AD groups (as azure hates nesting) and apply those to the ACL of the enterprise app. It would also diff the groups and always made sure they are in sync.
Hope this helps.
Thanks for the workarounds... Are there any updates on progress with the terraform provider?
@dwrusse Please subscribe to #323 for updates, thanks!
@manicminer hi, now that microsoft graph support has been added to the provider, would you have any hint here on how to consume it to be able to resolve this issue (SAML settings on entreprise apps). Thanks a lot.
@Leooo There are a few features requested in this issue which are all due to be added in v2.0. There are also SAML configurations which cannot be added outside the Azure Portal, but I don't believe those have been discussed here (see #395)
Maybe I'm a bit early, but I'm looking at how to create a SAML-enabled service principal in the v2
microsoft graph branch.
Looking at the MS docs it would look like there is no direct way to set the preferredSingleSignOnMode
property on the service principal to saml
- as they are using a PATCH request on the resource instead. Is this correct?
I hope not, but otherwise I would expect to see a preferred_single_sign_on_mode
attribute in the service principal v2 version which is not there yet
@Leooo We'll be supporting that attribute but it isn't yet added to the v2 branch
Hi issue subscribers!
As there are a few different pieces of configuration discussed in this thread, I wanted to clarify the specific needs in respect of configuring a SAML enabled service principal. As I understand from the earlier comments, these are:
To the best of my knowledge, the last item is possible today using the tags
property in azuread_service_principal
. The first two are due to be enabled in v2.0.0.
Is there anything else? I realise this is not a trivial ask, and of course we can only offer whatever the API supports, but I wouldn't want to close this issue prematurely.
I'm not a specialist (learning as I go), but in my case the goal is to setup SAML SSO - so this doc is a good starting point.
Maybe those are already existing, but I see there the need to:
preferredSingleSignOnMode
(you already mentioned it)redirectUris
/ identifierUris
(I think already possible)appRoles
?ClaimsMappingPolicy
?ClaimsMappingPolicy
to a servicePrincipal?preferredTokenSigningKeyThumbprint
Not sure if those are absolutely needed or have already been implemented tbh. Happy to test any branch you have.
Thanks @Leooo, that's super helpful 👍
@manicminer hi, do you know when the v2.0.0 will be available to consume or test please? Thanks
@Leooo It should be out in the next few days
Assigning this to the Future milestone as there are several pieces to achieving what you can get in the portal. We're shipping features as we're able to, but some of these are going to be blocked upstream until there is API support. We'll try to mention this issue on related PRs.
Publishing a comment for those who get following error in AWS Cognito:
Error in SAML response processing: Invalid user attributes: email: Attribute is required.
The field "email" is not included in the SAML response, if the Enterprise Application is created via API.
Set email explicitly in the section optional_claims
:
resource "azuread_application" "this" {
...
optional_claims {
saml2_token {
essential = true
name = "email"
}
}
...
}
Terraform import is not catching this, if an application had been provisioned in the Azure UI.
How can we create the saml single sign on certificate with Terraform for Azure AD enterprise app? Is this supported? Now I have to create the signing certificate from UI. Also this parameter is empty saml_metadata_url
from the resource.
@Satak It is possible: https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/service_principal_certificate However, requires to keep the self-signed certificate somewhere (you don't want to keep it in git) That is why I provisioned it the UI.
As of 19th Aug, 2022, what's the status of adding SAML claims and attributes to a service principal? It seems the claims mapping policy resources do this but can't necessarily do everything? ie group claims?
G'day! Any major update on this as of end of 2024? It would be amazing to fully configure a SAML enterprise app with Terraform (and not using any hacky workarounds)
Hello
I want to define multiple saml based applications in azure AD Enterprise apps. From my understanding i can use tags on the service principal creation which will produce the single sign on options (Disabled, SAML, Password based, Linked). However i want to be able to create this with SAML selected.
I guess i have two questions from this:
Here is my current example which gets me so far:
Im currently running: Terraform v0.12.13
I'll happily do a PR to update the documentation for this if you provide detail. If this is not implemented yet please let me know. If you can point me towards the right API i'm happy to write something to make this happen.
Thanks