Retrieve web site deployment credentials in ARM template - azure

I have an ARM template that creates, among other resources, a web site that hosts a webjob and a job that is part of a scheduler. I have managed to get everything configured through the ARM template except for the authentication.
When the job needs to run, it creates an HTTP request that should kick off the webjob. Unfortunately, the webjob is never started. If I go into the Azure portal and update the settings for the job (Action settings) and configure Basic authentication (with the deployment credentials) everything starts working as expected, but I'm not sure how I can retrieve those credentials from the ARM template. I could run it once, create the web site, get the credentials then update the ARM template, but that defeats the whole reason I'm building the ARM template in the first place.

I found an answer that got me most of the way there; you can set the Uri of the request to list(resourceId('Microsoft.Web/sites/config', variables('webSiteName'), 'publishingcredentials'), '2016-08-01').properties.scmUri. You will also need to concatinate the rest of the path (e.g. /api/triggeredwebjobs/{webjobname}/run)
The Uri produced by the above code includes the basic auth credentials, and that is parsed at some point and the username and password are taken out of the Uri so they aren't visible in the Azure portal and the authentication is set to 'Basic', and the credentials are set to the extracted values.
However, my Uri had query string appended to the end to pass parameters into the webjob. During the deployment process, the query string gets mangled (the question mark is escaped to %3F and if you have any escaped characters in your arguments value, they will get unescaped.
I managed to work around this by concatinating strings together to make up the Uri (NOT using the scmUri property), and then setting the authentication property, which is a sibling to the uri property to look like the following
"authentication": {
"type": "Basic",
"username": "[list(resourceId('Microsoft.Web/sites/config', variables('webSiteName'), 'publishingcredentials'), '2016-08-01').properties.publishingUserName]",
"password": "[list(resourceId('Microsoft.Web/sites/config', variables('webSiteName'), 'publishingcredentials'), '2016-08-01').properties.publishingPassword]"
}

Related

Deploying Azure Cloud Service (extended support) via REST API

I'm in the process of migrating from Cloud Service (classic) to Cloud Service (extended support) in Azure. Unfortunately, CS extended support documentation is very scarce and often inaccurate, so the process if very much not straight forward. At this point, I'm working on the deployment pipelines. With CS classic, we used management APIs to deploy/update/etc. The API for extended support is more straight forward, however, again, the documentation is lacking. The best I found was this page: Cloud Service - create or update. While this provides fairly good starting points, I'm struggling to find any info on the following points:
ServiceConfiguration element - what format is this in? Is it pure XML (encoded within JSON, of course) or something else? For classic API, service configuration was passed as a BASE64 encoded XML.
The request body (JSON) contains some of the same elements as in the service configuration - what happens if they don't match?
Package URL - what format is this in? The package is stored in an azure storage account - so how do I reference it? Also, for authentication, I can't grant the CS any permissions to the storage account, as it's not created yet (it doesn't exist!) - but it seemingly needs this permission in order to be created.
RDP extension - what format is "password" in? Is this really just a plain password? For classic, RDP password was encrypted using a certificate, which was separately uploaded into the service.
SSL certificate from the vault - how is authentication going to work? Again, the CS doesn't exist yet, so I can't grant it any permissions in the vault.
On authentication front, I managed to send the auth request and get the oauth2 token, which I would then use for this API - could this be enough? Of course, I can try this, but need to understand the other things first (i.e. format of some elements).
Note separately that deployment pipeline is executed from Jenkins and must stay that way - I don't have any control over that.
UPDATE: I tested this as best I could with service configuration being plain xml, with content matching the rest of json input, plain text password for RDP extension, and hoping for the auth to use bearer token. The response I received was 400, with the following details:
{
"error": {
"code": "InvalidParameter",
"message": "The value of parameter packageUrl is invalid."
}
}
So, back to my point 3 above - what is the format of package url?
UPDATE 2: After some experimenting, it did accept the package URL with the SAS token. Now I'm stuck with this error:
{
"error": {
"code": "StandardPublicIPAddressNotSupportedCloudService",
"message": "Standard public IP not supported for cloud services."
}
}
Web search for that string returns 0 matches. The template I'm using is copy/paste from MS documentation; the process I'm using is exactly per MS documentation. Any further help massively appreciated.
This isn't exactly what you're after, but I used the following article to help with generating a template.json and parameter.json file which then could be used through Powershell.
https://techcommunity.microsoft.com/t5/azure-paas-blog/how-to-use-azure-devops-to-publish-cloud-service-extended/ba-p/3675180
This is what my Powershell script eventually looked like:
New-AzResourceGroupDeployment -ResourceGroupName "cses-rg" -TemplateFile DeployArm.template.json -TemplateParameterFile DeployArm.parameter.json -packageSasUri $cspkg -configurationSasUri $cscfg -cloudServiceName cldcsestest -deploymentLabel myDeploymentLabel -publicIPName 'MyPublicReservedIp' -rdpPassword $rdpPassword
I only used the Powershell script locally for quicker testing, but my goal was to get it working with Azure Dev Ops.

Oauth 2 Generic Provider Template Examples

Looking over the possible connection provider in Azure Portal, I've determined that my use case requires the the "OAuth 2 Generic Provider" (rather than the "Generic OAuth 2" provider). However, I can't seem to find any documentation on how the templating should work or what variables are passed to the template.
I'm attempting to setup a connection with Azure DevOps. First I tried using the "Generic OAuth 2" provider and the test flow works up until the botframework's token service receives the authorization code from Azure DevOps. It'll redirect me to a "Bad Request" page. I can take the authorization code from the redirected url and construct the token call as Azure DevOps' documentation describes and it works correctly so I'm guessing this is an issue with how the botframework's token service is calling Azure DevOps hence why I need to use the "OAuth 2 Generic Provider" since it allows me to specify how the token service calls Azure DevOps.
Ideally, this would be added to the documentation somewhere or - even better - as hints on the Azure portal page.
Edit: Added a screenshot of the page. What do you put in the "Template" fields on that form?
I got a hold of the team behind that form. Commenting here for anyone that searches for something similar on Google.
These are the values that worked for me, you'll need to set your own id/secrets/scopes
Scope List Delimiter: ,
Authorization URL Template: https://app.vssps.visualstudio.com/oauth2/authorize
Authorization URL Query String Template: ?client_id={ClientId}&response_type=Assertion&state={State}&scope={Scopes}&redirect_uri={RedirectUrl}
Token URL Template: https://app.vssps.visualstudio.com/oauth2/token
Token URL Query String Template: ?
Token Body Template: client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={ClientSecret}&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={Code}&redirect_uri={RedirectUrl}
Refresh URL Template: https://app.vssps.visualstudio.com/oauth2/token
Refresh URL Query String Template: ?
Refresh Body Template: client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={ClientSecret}&grant_type=refresh_token&assertion={RefreshToken}&redirect_uri={RedirectUrl}

In Azure API Management, is it possible to have a template parameter that allows slashes (e.g., a path)?

I'm using Azure Data Lake Storage to store a large amount of files. I'm setting up an Azure API Management gateway in front of it, which rewrites the URI and sets the backend service to the ADLS REST API (Gen2).
At this point I'm trying to configure the Path - Read pass-through. My operation in APIM is /data/{filesystem}/{path}?timeout={timeout}, which I would like to be able to call as follows:
(timeout is optional)
filesystem: MyFileSystem
path: Path/To/File.json
GET https://example.com/api/data/MyFileSystem/Path/To/File.json
However, when I navigate to this operation in the Azure Portal and use the Test feature, it reports the following error:
{ "message": "Unable to identify Api or Operation for this request. Responding to the caller with 404 Resource Not Found." }
I understand that APIM is likely looking for an operation matching /MyFileSystem/Path/To/File.json and cannot find one.
For what it's worth, my Path - List endpoint works as I'd expect, which is why I know it's specifically the {path} that's holding me up.
GET https://example.com/api/data/MyFileSystem?recursive=true&resource=filesystem
200 OK
I imagine I can change from a template parameter to a query parameter, but I'd prefer to avoid that route for now. So, is there a way to have a template parameter that allows slashes?
Yes. Last template parameter may have slashes. Use {*path}.
You are right Santi, slashes in template param will make APIM unable to find corresponding operation to handle requests.What's more, it is useless that you URL-encode the slashes as APIM will URL-encode your param again if it includes special characters which will mass the path.
I tested your scenario on Azure storage, if your use "\" to replace "/" it works well , you can have a try on it :

azure api management retrieving password from shell script ,saving it and deploying it

I had seen multiple examples how to use Azure API manager using powershell to retreive password for SCM but unable to find any example using it without powershell i.e. something execution in shell command line. i am also looking for example for saving and deploying my api
You can always inspect any Azure service API in action by doing what you need in Azure portal and seeing what requests get sent. Correlating them with documentation helps. So to get access token for SCM endpoint in APIM you need:
With any Azure credentials make a GET call to https://management.azure.com/subscriptions/.../resourceGroups/.../providers/Microsoft.ApiManagement/service/.../tenant/access/git?api-version=2018-01-01
in response you will get a payload similar to:
{
"id": "XXX",
...
}
Take "id" from that payload and make a POST call to https://management.azure.com/subscriptions/.../resourceGroups/.../providers/Microsoft.ApiManagement/service/.../users/XXX/token?api-version=2018-01-01
you will get your token:
{
"value":"..."
}

Email verification code in app url (deployed on azure) not finding endpoint

I have .net core identity email verification endpoint setup like this:
/api/[controller]/{userId}/{emailVerificationCode}
and I encoded it in registration endpoint with Uri. EscapeDataString (decoding with Uri. UnescapeDataString but that's irrelevant here). So when I get email and I click the link, locally I hit endpoint and can debug it, but after deploying to azure (web app resource group) I get this response:
The resource you are looking for has been removed, had its name changed,
or is temporarily unavailable.
When I shorten code to not contain any special characters (which are now encoded so they are for example %2F, %3D etc) endpoint is hit (but ofc token is invalid).
Any idea what could be the case?
The code that is generated is Base64 encoded, and certain characters in Base64 are not allowed in the path segment of a URL by default, for security reasons, even when URL-encoded. While it's possible to change that, you should not, as the security concerns are valid, and you don't want to expose your app to exploits.
Instead, you can simply let the code be part of the query string. The same vulnerabilities do not exist for the query string portion of a URL, and the characters will be allowed there. Alternatively, you can use a different type of code. The token providers used by Identity for things like email confirmation and password resets can be customized.
Identity includes other token providers for the purposes of two-factor auth that you can switch out with, if you like. These use TOTP-based tokens (the 6-7 digit numbers you see all the time with 2FA). Or, you can create your own custom provider and handle it however you like. To change providers, you simply configure the Tokens member when setting up Identity:
services.AddIdentity<ApplicationUser, IdentityRole>(o =>
{
// other options here like password reqs, etc.
o.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
o.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
o.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
}
The above will cause those three scenarios to generate tokens via EmailTokenProvider, which is one of the TOTP-based providers builtin.
If you want to use a custom provider, you simply create a class that implements IUserTwoFactorTokenProvider<TUser> and register that:
services.AddIdentity<ApplicationUser, IdentityRole>(o =>
{
...
})
.AddTokenProvider<MyCustomTokenProvider<ApplicationUser>>("MyTokenProviderName");
The string you use as the "name" is what you would use to assign it as a token provider in the previous code above, i.e.:
o.Tokens.PasswordResetTokenProvider = "MyTokenProviderName";

Resources