How can I set up my Azure account in order to make ARM deployments via the REST API? - azure

I have an Azure accounts and I want to make deployment of ARM templates using the ASP.NET libraries. I've noticed that in the Azure Portal generated Deployment class (in the DeploymentHelper.cs file that I've downloaded from the Portal) I have the following fields that I need to provide my own data:
string subscriptionId = "your-subscription-id";
string clientId = "your-service-principal-clientId";
string clientSecret = "your-service-principal-client-secret";
string resourceGroupName = "resource-group-name";
string deploymentName = "deployment-name";
string resourceGroupLocation = "resource-group-location";
string pathToTemplateFile = "path-to-template.json-on-disk";
string pathToParameterFile = "path-to-parameters.json-on-disk";
string tenantId = "tenant-id";
I'm having a hard time with these:
string clientId = "your-service-principal-clientId";
string clientSecret = "your-service-principal-client-secret";
I know that the subscriptionId I can get in the Subscriptions blade. I also know that the tenantId I can get in the Azure Active Directory > Properties blade under the Directory ID field.
I have followed this documentation page in order to try and set up an App Registration on Azure Active Directory, which I've read is what I need to obtain the cliendId and clientSecret values. I think it's worth mentioning I have no experience whatsoever with Active Directory or Azure Active Directory.
When following the docs my first issue is with this blade:
I don't know what I should put in the "Sign-on URL" field. I've tried filling it with my personal website just because it's required (probably my first mistake). Then with the Registered App I go in "Application ID" and use the value as clientId within my code.
I then generate the key in the "Settings" blade and use it as the clientSecret within my code.
However when I run my code I get the following error:
Exception thrown: 'Microsoft.Rest.Azure.CloudException' in System.Private.CoreLib.dll
An exception of type
'Microsoft.Rest.Azure.CloudException' occurred in System.Private.CoreLib.dll but was not handled in user code
Operation returned an invalid status code 'Forbidden'
I wouldn't want to do any fancy Azure AD set up in order to make deployments via Azure. I'm trying this on my personal account, so it's not like a have an AD environment set up.

I don't know what I should put in the "Sign-on URL" field. I've tried filling it with my personal website just because it's required (probably my first mistake).
If you develop a WebApplication, you could Webapplication address it as sign-on url. In your case your could add a vaild url address. And you could add your personal website.
Operation returned an invalid status code 'Forbidden'
It means that you have no access to deploy the resource to the subscription.
You need to assgin role to the WebApplication. For more information, refer to how to registry an Azure AD application and assigin role.

Related

How can I identify what the "first party service" is when failing to authenticate to Azure KeyVault?

Despite multiple hours of troubleshooting, I cannot get Visual Studio to authenticate to an Azure KeyVault. No matter what I try, I get the following unhelpful error:
Service request failed.
Status: 403 (Forbidden)
Content:
{"error":{"code":"Forbidden","message":"Access denied to first party service.\r\nCaller: name=from-infra;tid=GUID_REDACTED;appid=GUID_REDACTED;iss=https://sts.windows.net/GUID_REDACTED/\r\nVault: VAULT_NAME;location=westus","innererror":{"code":"AccessDenied"}}}
Is there anything in here (maybe one of the redacted GUID values) I can use to determine what the "First Party Service" it is having a problem with is?
I am signed in with my MSDN account in the "Azure Service Authentication" section. The KeyVault exists in that MSDN account. There are also Access policies in that KeyVault for both my MSDN account and the principal ID of my App Service. These appear to be completely ignored when trying to authenticate.
Here is the basic code I have been trying to use.
var credential = new VisualStudioCredential(new VisualStudioCredentialOptions { TenantId = "GUID from tid in above error" });
// Create a secret client using the DefaultAzureCredential
var client = new SecretClient(new Uri("https://MY_VAULT.vault.azure.net/"), new DefaultAzureCredential());
var secret = client.GetSecret("MySecretId");
I have tried multiple versions of the VisualStudioCredential and DefaultAzureCredential. No matter what I do, I cannot get away from this "Access denied to first party service" error, so I think the next step is to find out what the "first party service" is, because it does not seem to be my MSDN account nor my App Service.
Tenant f8cdef31-a31e-4b4a-93e4-5f571e91255a is a special tenant where Microsoft first party applications are defined. Certain ARM and Compute scenarios access Key Vault using tokens from this tenant, but in general Key Vault rejects tokens from this tenant and it is not available for use by customers.
The tenant you should use is the one that shows up under "Tenant ID" when you look at the "Azure Active Directory" section in the Azure Portal. Personal accounts, such as outlook.com accounts, can get tokens issued by the first party tenant if they do not specify their own tenant ID. Organization accounts get tokens from their home tenant based on the verified domains associated with the tenant, so they generally do not need to specify a tenant ID explicitly.

Unable to get access token. 'AADSTS500011: The resource principal named 'xxx' was not found in the tenant -tenantid

I am trying to get the access token for the Azure function app. I have enabled managed identity for the function app(system assigned). but while fetching the token using the nuget Azure.Identity.
var tokenCredential = new DefaultAzureCredential();
var accessToken = await tokenCredential.GetTokenAsync(
new TokenRequestContext(scopes: new string[] { "https://xxx.azure-api.net/" + "/.default" }) { }
);
I am getting the error.
The resource principal named 'xxx.azure-api.net' was not found in
the tenant 123
but when run az cli to check the subscription details, the subscription indeed part of the tenant 123 only.
Here is what I have finally done.
I have registered an App in AD. and Exposed the API of that App.
I have assigned System Assigned Managed Identity to the Function.
In the local I am not able to request token because Azure CLI is not given consent.
After deploying the application in Function my Function app can request a token using its identity.
You need to register the application in azure ad and enable the access token. Once that is done the you need to provide RBAC access to your xxx.azurewebsites.net
Follow this article for the step by step documentation Microsoft Document Reference
Unfortunately, the error message is not really helpful. But adding a scope to the app registration solved the problem for me:
In Azure Portal navigate to App Registrations
Find your app, in the left side menu select Manage => Expose an API
Add a scope. I named mine api_access as this was where this error occurred.
In my case I then got an API URI (like api://client-id/scope_name) which I used in my Angular app. Error message was gone.
Also, make sure that in the Enterprise Application you have created, under Manage => Properties, "Assignment required" and "Visible to users" is turned on.

Azure Service Bus managed identity in Visual Studio returning 401 - Token issuer is invalid

I'm attempting to access Azure Service Bus using a managed identity from my code. At the moment I'm just trying this locally.
When I debug my code I get the following error
System.UnauthorizedAccessException: Put token failed. status-code: 401, status-description: InvalidIssuer: Token issuer is invalid
Here is my service bus instance
Here is my user with Azure Service Bus Data Owner permissions
And here is my code
_client = new ServiceBusClient("oconnorevents.servicebus.windows.net", new DefaultAzureCredential());
I am logged into Visual Studio as the same user added to the service bus. I also tried logging in via the CLI but it didn't help.
Where am I going wrong here?
I've looked at this similar recent question here but the solutions proposed didn't work for me.
Since I have access to several different tenants, Visual Studio sometimes gets confused. Another way you can handle this is to continue to use the DefaultAzureCredential, but to give Visual Studio a hint about which tenant to use.
First left click the your project and examine the properties and then:
Left-click "Debug"
Left-click the "Add" button to add an environment variable
For name use "AZURE_TENANT_ID" and for value use your tenant id. Yes, that is a bogus tenant id in the picture :-)
Reference
https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet
https://damienbod.com/2020/10/09/using-key-vault-certificates-with-microsoft-identity-web-and-asp-net-core-applications/
If you use DefaultAzureCredential to auth, it will try several credential types to auth as mentioned here, one of them is VisualStudioCredential, but it will auth to the home AAD tenant of the user logged in VS, in your case, I suppose the service bus is in a subscription which is not under the home tenant of the user.
I can also reproduce your issue on my side.
To solve the issue, just use VisualStudioCredential directly, then simply specify the TenantId via VisualStudioCredentialOptions, then it will work fine.
Sample:
To find the TenantId, just navigate to the Azure Active Directory which the subscription of your service bus located.
TokenCredential tokenCredential = new VisualStudioCredential(new VisualStudioCredentialOptions {TenantId = "xxxxxxx" });
ServiceBusClient client = new ServiceBusClient("xxx.servicebus.windows.net", tokenCredential);
Specify the exact tenant id by adding the following key to local.settings.json.
"AZURE_TENANT_ID": "your tenant id"
I tried to create an azure function that receives messages from a service bus queue using a managed identity trigger and it worked for me.
late to the party but I got it working on my local Visual Studio with this code
var tokenCredential = new VisualStudioCredential(new VisualStudioCredentialOptions { TenantId = "xxx-xxx" });
ServiceBusClient client = new ServiceBusClient("my-name-space.servicebus.windows.net", tokenCredential);
sender = client.CreateSender('my-topic');
var msgBody = new Person{ Name = 'joe'};
await sender.SendMessageAsync(new ServiceBusMessage(JsonConvert.SerializeObject(msgBody)));
Also, remember to sign in to Azure in your Visual Studio,
and assign your account to the role "Azure Service bus Data Sender" , see below:

How can I allow a service account to access my REST API when using Roles-based Authorization in Azure?

Summary: I have a REST API that I use for functional testing. I only allow people or groups in a specific "Tester" role to hit the API. I want to trigger this functional testing during an Azure DevOps Release Pipeline automatically, but I can't figure out how to authorize the machine account to hit the API.
Details:
I have this API secured with [Authorize(Roles = "Tester")]
[Route("quotas/developers")]
[HttpGet]
[Authorize(Roles = "Tester")]
[SwaggerResponse(HttpStatusCode.OK, "Successful operation", Type = typeof(DeveloperQuota[]))]
public async Task<List<DeveloperQuota>> GetDeveloperQuota([FromUri]string developerUpn)
To set this up, I have an Enterprise Application registered in Azure Active Directory. In the manifest, I declare the role.
And then in the Enterprise Application I add some users and groups which are assigned the role "Tester."
This works fine for running my functional tests by hand. I run the tests, it pops up an oauth dialog for me to enter my credentials, it grabs my Bearer token from the successful auth request then passes it along to the APIs.
private string GetActiveDirectoryToken()
{
string authority = this.configuration.ActiveDirectoryAuthority;
string resource = this.configuration.ActiveDirectoryAudience;
string keyVaultUri = this.configuration.KeyVaultUri;
IKeyVaultAdapterFactory keyVaultAdapterFactory = new KeyVaultAdapterFactory();
var keyVaultAdapter = keyVaultAdapterFactory.CreateInstance(KeyVaultServicePrincipal.PowerShellAppId);
SecureString clientIdSecure = keyVaultAdapter.GetAzureKeyVaultSecretSecure(keyVaultUri, "GasCallbackRegistrationClientID", null).Result;
SecureString redirectUriSecure = keyVaultAdapter.GetAzureKeyVaultSecretSecure(keyVaultUri, "GasCallbackRegistrationClientIDRedirectUri", null).Result;
var authContext = new AuthenticationContext(authority);
var result = authContext.AcquireTokenAsync(
resource,
SecureStringUtilities.DecryptSecureString(clientIdSecure),
new Uri(SecureStringUtilities.DecryptSecureString(redirectUriSecure)),
new PlatformParameters(PromptBehavior.Auto)).Result;
return result.AccessToken;
}
Of course, if I'm running this during automation, there will be nothing to fill in the dialog with creds, nor do I want to be storing a copy of these creds, especially since these creds roll on a schedule which are maintained elsewhere.
My thought was that I could create an Azure Service Principal, associate a cert with the service principal, install the cert on my deployment machine, login as the Service Principal if the cert was available, and then put that Service Principal in the "Tester" role. The problem is I can't add a Service Principal as a user in the Enterprise Application. It only appears to allow me to add "Users and groups." I similarly can't add a service principal to a group.
Any thoughts on how I can authorize my deployment box to hit these APIs?
Roles published for applications are treated as application permissions and not assignable to other apps via the "Users and Groups" assignment screen.
To assign the app permissions to a client app, go to the client app's registration page, click on Api Permissions and then Add a Permission. Select the My Api tab, search for your application that published the app roles and you'd see the app role listed in the list below. Select that, save and then grant admin consent.

Access denied linking variable group to key vault in VSTS

When I try to link a variable group to key vault in VSTS, every time I select my endpoint, it tells me:
"Specified Azure endpoint needs to have "Get, List" secret management permissions on the selected key vault. Click "Authorize" to enable VSTS to set these permissions or manage secret permissions in Azure portal."
It makes no sense. That specific endpoint has Get and List for secrets, keys, certificates. The endpoint is using the correct Service Principal Client ID- I know because I pulled its corresponding app registration up in Azure by searching with that ID. And the app registration is specifically listed in the key vault's Access policies, with the correct permissions.
Trying to click "Authorize" in VSTS just give me
"Resource not found for the segment 'DirectoryDataService.getServicePrincipalsByAppIds'. For troubleshooting refer to https://go.microsoft.com/fwlink/?linkid=835898"
and the endpoint is broken until I re-verify it.
I'm kind of at my wit's end here- everything is set exactly as https://learn.microsoft.com/en-us/vsts/build-release/concepts/library/variable-groups?view=vsts says it should be.
Edit: Turns out the Azure tried to add the app reg as a person instead of an app when I listed it in the ARM template by object ID (app ID most definitely does not work there). So now I just need to figure out how to add it as an application in the ARM template...
Edit Edit: Soooo... the Object ID the Azure Portal shows for an App Registration? That's not the Object ID the ARM template wants. It wants the... I'm not sure what you'd call it. In Powershell, you use it with -Object ID, but when you list the properties, it's under "Id". Whatever. To get it, you run
Get-AzureRmADServicePrincipal -SearchString "[your-app-reg-name]"
And it shows up under Id. That's what you want to use as an object ID in your ARM template.
According to the error Resource not found for the segment 'DirectoryDataService.getServicePrincipalsByAppIds, the issue seems more related to Azure side.
To access azure-keyvault you need four things :
- clientId = "<client id of your application registed on Azure AD>";
- domain = "<your talnet id>";
- secret = "<client key of your application registed on Azure AD>";
- subscription = "<your subscription id>";
Then these will combine ApplicationTokenCredentials, finally Authorize to KeyVaultClient . Suggest you take a look at this question: Azure keyvault client 1.0.0 initiate client
Besides also double check/confirm the specific endpoint has Get and List for secrets, keys, certificates.

Resources