How to use Terraform `google_app_engine_domain_mapping` with service account? - google-app-engine

I'm trying to create a GCP App Engine domain mapping via Terraform with the following configuration:
provider "google" {
version = "3.36.0"
region = var.region
}
resource "google_app_engine_domain_mapping" "domain_mapping" {
project = local.project_id
domain_name = var.domain_name
ssl_settings {
ssl_management_type = "AUTOMATIC"
}
depends_on = [
google_app_engine_application.backend_app
]
}
Terraform is configured to use an organization level service account for the GCP provider with the following IAM permissions (no conditions):
Billing Account User
Project Creator
Service Config Editor (I've added this thinking it would resolve the issue based on this and this doc page.)
The Google account that is the owner of the organization has verified the domain in question, yet I'm getting the following error:
Error: Error creating DomainMapping: googleapi: Error 403: Caller is not authorized to administer the domain 'testing.redacted.com'. If you own 'testing.redacted.com', you can obtain authorization by verifying ownership of the domain, or any of its parent domains, via the Webmaster Central portal: https://www.google.com/webmasters/verification/verification?domain=testing.redacted.com. We recommend verifying ownership of the largest scope you wish to use with subdomains (eg. verify 'example.com' if you wish to map 'subdomain.example.com').
I've also tried adding the service account's email as a user in the Google Search Console to the domain to no avail.

The solution is rather simple but sort of hidden in the docs. You need to add your service account email as owner of the domain.
Go here
Select the property you want
Tap the "Add an owner" button at the bottom of the page and add the email address (e.g. terraform#<PROJECT_ID>.iam.gserviceaccount.com)

Related

Microsoft OAuth authorization for specific user roles

I have to limit which users can access an Azure App. For now, only Global Admins can access using this link:
login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=client_id_goes_here&scope=user.read.all&response_type=code&redirect_uri=https://myredirectbacklink.com/aad/auth&response_mode=query&state=portal&prompt=consent
After redirect back I get Token using
https://login.microsoftonline.com/common/oauth2/v2.0/token and the query contains the same scope as the authorized link.
The flow of the app is the same as documented in Microsoft identity platform and OAuth 2.0 authorization code flow.
My problem is that client wants to allow Billing Admins to access their app. I went through all Graph Permission Scopes, but could not find any related to Billing Admin.
My knowledge of Microsoft's authorization is somewhat limited. I do know that limitations are done by scope. But if it's just link change or is it in Authentication App in Azure (there is one but I don't know how it's related to actual login permissions).
Should I look in a different direction or is it just simply changing the link? Microsoft's documentation didn't help a lot because it's mostly about calendars and other simple stuff.
Careful, requesting a permission that normally requires admin consent and causing the user consent prompt is not the proper way to ensure the user signing in is actually an admin. A non-admin user could simply modify the URL to scope=User.ReadBasic.All and remove prompt=consent. If the user is allowed to consent for User.ReadBasic.All (which is true in many organizations), they'd be able to continue the sign-in. (Or if the organization had granted admin consent for "User.Read.All", the non-admin user would only need to remove prompt=consent.)
If you need to ensure the user is an administrator, you need to explicitly check for directory role assignments.
You can choose from one of three different ways to do this:
You can configure your app to receive the wids claim, which will include the role template IDs of the directory roles for which the user has an active assignment. This is probably the simplest approach.
Using the Azure portal, you can do this under App registrations > (choose your app) > Token configuration > + Add groups claim. You must include "Directory roles" in your selection:
Another option is to a Microsoft Graph API request to check which of a given list of directory roles the user has been assigned:
POST https://graph.microsoft.com/v1.0/me/checkMemberObjects
Content-type: application/json
{
"ids": [
"fdd7a751-b60b-444a-984c-02652fe8fa1c",
"b0f54661-2d74-4c50-afa3-1ec803f12efe"
]
}
A third option is to make a Microsoft Graph API request to list the directory role assignments granted to the user:
GET https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments
?$filter=principalId eq '{id}'
All three of these approaches involve using directory role template IDs to identify the directory role you are checking for. They're all listed here: https://learn.microsoft.com/azure/active-directory/roles/permissions-reference
Some examples you may be interested in:
Application administrator: 9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3
Cloud application administrator: 158c047a-c907-4556-b7ef-446551a6b5f7
Global administrator: fdd7a751-b60b-444a-984c-02652fe8fa1c
Privileged role administrator: e8611ab8-c189-46e8-94e1-60213ab1f814
Billing administrator: b0f54661-2d74-4c50-afa3-1ec803f12efe
(I included the first four because those are the directory roles which would, by default, be allowed to grant consent for User.Read.All.)
If someone needs solution and uses php:
You can use https://github.com/microsoftgraph/msgraph-sdk-php
$accessToken = 'token from redirect back, called access_token';
$body = [
"ids" => [
"fdd7a751-b60b-444a-984c-02652fe8fa1c",
"b0f54661-2d74-4c50-afa3-1ec803f12efe"
]
];
$graph = new Graph();
$graph->setAccessToken($accessToken);
$user = $graph->createRequest("post", "/me/checkMemberObjects")
->attachBody($body)
->execute();

user does not exists in the tenant directory error when calling microsoft graph api

I'am trying to call microsoft graph api, I have did the instructions by microsoft documnets as bellow:
1- app registration in azure portal
Supported account types : all microsoft account users
2- calling 'https://login.microsoftonline.com/',tenant_id,'/oauth2/v2.0/authorize' by these parameters:
client_id <- #Application Id - on the azure app overview page
client_secret <-# the secret key for my app from azure portal
scope <- 'https://graph.microsoft.com/.default'
grant_type <- 'password'
username <- 'XXX#outlook.com'
password <- # the user password
tenant_id <-# tenant id for my app from azure portal
but it has this error:
AADSTS50034: The user account {EmailHidden} does not exist in the <tenant_ID> directory. To sign into this application, the account must be added to the directory.
I have registered my app by the same account that I passed through api.
I want to call my todo list from the graph.
based on #MdFaridUddinKiron's response I added some more explanation:
I think something in my domain in azure is wrong, these are some screenshot of it:
1- it shows "common" for endpoints, what should I use? "common" or my tenant:
2- my app authentication tab has some differences, is it important?
3- My domain overview page is look like this:
4- user is added in my active directory 5- user application page:
6- user assigned role:
I tested microsoft graph api successfully by the same user in the graph explorer, I am getting confused how the authentication flow must be.
I just want to call my own todo tasks
As per your comment, please follow the detail steps:
Make sure email you are trying to get token with is exists in azure ad
user list which showed below in details.
https://login.microsoftonline.com/YourTenant.onmicrosoft.com/oauth2/v2.0/token
client_id:b603c7be_Client_id_e61f925
scope:https://graph.microsoft.com/.default
client_secret:NpmwO/KDJ_client_secret:NpmwO_W0kWf1SbnL
username:tenentUser.onmicrosoft.com
password:YourUserPassword
grant_type:password
See the screen shot:
I am getting token as expected
Step: 1
Step: 2
Step: 3
Step: 4
Filter your user from your azure active directory user list as shown below.
Note:
Requested token user must be a tenant user for example YourUser#Yourtenant.onmicrosoft.com
User password must be correct that you are suing to token request.
Make sure your user belong to azure portal on your tenant
Your Client Id belongs to that tenant
Application secret is valid or not expired.
Update:
What should I use? "common" or my tenant?
It depends if you have many tenant in that case you can use common.
For example user need not to remember specific tenant they would
automatically redirected to specific tenant as per the credentials
they given.
For more information you could refer Official document
Feel free to share still you are having problem.

Grant service principal access to application in other tenant

I have an Azure AD service principal in one tenant (OneTenant) that I would like to give access to an application in another tenant (OtherTenant).
The service principal in tenant OneTenant is a managed service identity for an Azure Logic App. So what I actually want is to call an API from my Logic App. This API is protected by an Azure AD application in OtherTenant.
The application in OtherTenant defines a number of roles and the service principal in OneTenant should have one of these roles so it can call the API.
I tried the following:
set the app in OtherTenant to multi-tenant
ran the following PS command to attempt to add the SP to a role in the app:
New-AzureADServiceAppRoleAssignment `
-ObjectId <object-id-of-sp-in-one-tenant> `
-Id <role-id> `
-PrincipalId <object-id-of-sp-in-one-tenant> `
-ResourceId <app-id-in-other-tenant>
(both logged in in OneTenant and OtherTenant)
This gives an error stating that either app-id-in-other-tenant or object-id-of-sp-in-one-tenant can not be found, depending on where I am signed in.
I also tried creating a Service Principal in OneTenant based on the app-id from OtherTenant In that case I get an error message: Authenticating principal does not have permission to instantiate multi-tenantapplications and there is not matching Applicationin the request tenant.
Ok, I finally got around to testing if the solution presented by Rohit Saigal works. It does point in the right direction but is not complete.
First step is to create a service principal in OneTenant that represents the application in OtherTenant. So while signed in to OneTenant, run the following script:
$spInOneTenant = New-AzureADServicePrincipal -AppId <app-id-in-other-tenant>
Next step is to run the New-AzureADServiceAppRoleAssignment cmdlet with the following parameters:
New-AzureADServiceAppRoleAssignment `
-Id <role-id> `
-ObjectId <object-id-of-sp-in-one-tenant> `
-PrincipalId <object-id-of-sp-in-one-tenant> `
-ResourceId $spInOneTenant.ObjectId
The trick is to use the object id of the service principal you created in the previous step as the ResourceId.
Taking the command as is from your question:
New-AzureADServiceAppRoleAssignment `
-ObjectId <object-id-of-sp-in-one-tenant> `
-Id <role-id> `
-PrincipalId <object-id-of-sp-in-one-tenant> `
-ResourceId <app-id-in-other-tenant>
Try changing the last parameter value i.e. ResourceId
Currently you're passing <app-id-in-other-tenant>
Replace that with <object-id-of-API-in-other-tenant>
The question/answers presented here were helpful, but yet it took me some time to work through the details and actually make it work, so allow me to elaborate some more on the above, as it might help others too.
Scenario
Two tenants:
Home Tenant.
Other Tenant.
One Azure App Service API app, with access managed by the Home Tenant.
One Logic app placed in a subscription in Other Tenant that need to securely access the API app in the Home Tenant.
Approach
Application registration
For the API app to delegate identity and access management to Azure AD an application is registered in the home tenant’s Azure Active Directory. The application is registered as a multi-tenant app.
You also need to create an app role (see documentation: How to: Add app roles in your application and receive them in the token), lets call it read.weather.
Configuration of Other Tenant and Logic App
To provide the Logic App access to the API app do this:
Enable a system assigned identity for the logic app - i.e. use Managed Identity. Note down the system assigned managed identity Object ID ({18a…}), you will need it in a minute.
Create a service principal for the application in the Other Tenant using this command, where appId is the appId of the application registered in Home Tenant (e.g. lets say it’s {1a3} here):
New-AzureADServicePrincipal -AppId {appId}
This command will output a json document which includes among other things an objectId for the service principal just created.
[... more json ...]
"objectId": "b08{…}",
[... more json...]
You should also see the appRoles, including the app role read.weather you just created, om the json output from the New-AzureADServicePrincipal command:
[... more json...]
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Read the weather.",
"displayName": "Read Weather",
"id": "46f{…}",
"isEnabled": true,
"value": "read.weather"
}
],
[... more json...]
To tie it all together make an app role assignment using the command:
New-AzureADServiceAppRoleAssignment -Id {app role ide} -ObjectId {system assigned identity object id} -PrincipalId {system assigned identity object id} -ResourceId {object id of service principal}
E.g. something like this:
New-AzureADServiceAppRoleAssignment -Id 46f… -ObjectId 18a… -PrincipalId 18a… -ResourceId b08…
Now we are ready to set up the HTTP request in the Logic App using the URI to the API app using Managed Identity for authentication.
Notice that the audience is needed and has the form: api://{appId}.
But wait…!
Does this mean that anyone could do this, if only they know the appId of your application registration, and wouldn’t this compromise the security of the API app?
Yes, it does, and yes indeed it could compromise the security of the API app.
If you look at the access token being created and used as bearer from the Logic App it is a valid access token, which contains all the necessary claims, including the app role(s). The access token is however issued by Other Tenant and not Home Tenant.
Therefore, if you have a multi tenanted application and you want to guard it against this scenario, then you could check the issuer (tid more likely) of the incoming access token calling the API and only accept it if the issuer is the Home Tenant, or you could make the application a single tenant app.
Or, you could require that the issuer matches a list of tenants that the API trusts.

Allowing access to the Google Admin SDK Directory API in Python

I'm trying to setup a google group for marketing purposes, in which when certain users sign up to my application, I send their email to this google group with the following code
# google_admin_apis.py
def add_member(member):
if not member.email:
return False
try:
service = build('admin', 'directory_v1')
except DefaultCredentialsError: # For developers
return False
group_key = 'mygroup#mydomain.com'
body = {
"email": member.email
}
members = service.members()
request = members.insert(groupKey=group_key, body=body)
response = request.execute()
return True
My application is hosted on Google App Engine, so by default ADC will use the default service account when run on the server. I have tried to run this code locally by using gcloud auth application-default-account login and logging in with my G Suite admin account, and also my personal account (both are owners of the GCP project). After this failed, I did some research and realised that to enable OAuth2 to access my G Suite User data (I'm not really accessing anything by inserting a user?!?) I had to 'enable domain wide delegation' on the default service account, so I did this, I then downloaded the service account JSON and attempted to manually authorise with $GOOGLE_APPLICATION_CREDENTIALS, but was still getting a 403. I then went one step further and followed these instructions. Giving my Client ID access to https://www.googleapis.com/auth/admin.directory.group and group.member.
After all this, I still get a 403 error.
With the application-default-credentials I get:
<HttpError 403 when requesting
https://www.googleapis.com/admin/directory/v1/groups/groupKey/members?alt=json
returned "Insufficient Permission">
When using the app engine default service account through .json with either activate-service-account or through the GOOGLE_APPLICATION_CREDENTIALS, I get:
<HttpError 403 when requesting
https://www.googleapis.com/admin/directory/v1/groups/groupKey/members?alt=json
returned "Not Authorized to access this resource/api">
(groupKey intentially censored)
In short, I have an app-engine default service account with domain wide delegation and have given it's client ID access to both roles required for the Directory API's member.insert() function, yet I am still not allowed to call the API as above.
Any help would be greatly appreciated.
I followed this tutorial https://developers.google.com/admin-sdk/directory/v1/quickstart/python to run a similar function locally using Google's google_auth_oauthlib to set up OAuth2 credentials
service = build('admin', 'directory_v1', credentials=creds)

gcloud app ssl cert update failing with PERMISSION_DENIED

I am trying to update a SSL certificate for a Google App Engine project via CLI:
gcloud app ssl-certificates update NNNN --project XXX --configuration XXX --display-name=xxx.co.za --certificate=./fullchain.pem --private-key=./privkey_gae.pem
This command used to work previously but I am now getting the following error:
ERROR: (gcloud.app.ssl-certificates.update) PERMISSION_DENIED: Caller is not authorized to administer this certificate. You must be a verified owner of the certificate's domain(s) [xxx.co.za, *.xxx.co.za] to create, modify, or delete this resource. Your authorized domain(s) are []. If you own the certificate domain(s), you can obtain authorization by verifying ownership via the Webmaster Central portal: https://www.google.com/webmasters/verification/verification.
This error does not make sense as the domains are verified according to the URL (as they are also the custom domain used by the app itself). Also this was working just last month, so it seems that something changed?
I found the issue. Domains are verified by an IAM user, but I use a different IAM/Service-account for the CI/CD server.
It seems that the security around accessing verified domains has changed, in that the Service-account will not automatically have access to the verified domains, even though the App does.
I was able to fix this issue by adding the service-account (jenkins#XXX-ci.iam.gserviceaccount.com) as verified owner here: https://www.google.com/webmasters/verification/verification

Resources