Reputation: 353
I am trying to get a msi token for a specific User defined identity. Our app service has 2 user defined identities and I want a token on behalf of one of the user assigned identity.
Here is the code:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&object_id=<ObjectId>&client_id=<clientId>");
req.Headers["Metadata"] = "true";
req.Method = "GET";
try
{
// Call /token endpoint
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
// Pipe response Stream to a StreamReader, and extract access token
StreamReader streamResponse = new StreamReader(response.GetResponseStream());
string stringResponse = streamResponse.ReadToEnd();
Dictionary<string, string> list =
JsonConvert.DeserializeObject<Dictionary<string, string>>(stringResponse);
string accessToken = list["access_token"];
System.IO.File.WriteAllText(@".\Log.txt", accessToken);
}
catch (Exception e)
{
string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
System.IO.File.WriteAllText(@".\Log.txt", errorText);
throw;
}
It is deployed in an azure app service. When I hit this section I see this error: An attempt was made to access a socket in a way forbidden by its access permissions
I tried connecting to http://169.254.169.254 to get the token using kudu console. But this endpoint does not seem to accessible there.
I did try to use AzureServiceTokenProvider from Microsoft.Azure.Services.AppAuthentication for generating msi token but could not find any documentation about how to use it for multiple user assigned identities.
Edit:
Update 1:
I tried to use endpoint from MSI_ENDPOINT environment variable instead of 169.254.169.254. But it looks like MSI_ENDPOINT value is not set when I run the app service. Here is the code I have tried:
var endpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
string apiVersion = "2018-02-01";
string resource = "https://management.azure.com/";
string objectId = "<objectid>";
string clientId = "<clientId>";
// Build request to acquire managed identities for Azure resources token
//HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
// "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&object_id=4aef1720-b3b1-4935-8d68-e330508907fa&client_id=558ecc75-8697-4419-bab9-aa2c87043cfd");
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
String.Format(
"{0}?resource={1}&api-version={2}&object_id={3}&client_id={4}",
endpoint,
resource,
apiVersion,
objectId,
clientId));
req.Headers["Metadata"] = "true";
req.Method = "GET";
try
{
// Call /token endpoint
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
// Pipe response Stream to a StreamReader, and extract access token
StreamReader streamResponse = new StreamReader(response.GetResponseStream());
string stringResponse = streamResponse.ReadToEnd();
Dictionary<string, string> list =
JsonConvert.DeserializeObject<Dictionary<string, string>>(stringResponse);
string accessToken = list["access_token"];
System.IO.File.WriteAllText(@".\Log.txt", accessToken);
}
catch (Exception e)
{
string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
string log = "MSI_ENDPOINT : " + endpoint + "\n";
log += ("ErrorText : " + errorText + "\n");
System.IO.File.WriteAllText(@".\Log.txt", errorText);
throw;
}
Upvotes: 2
Views: 9073
Reputation: 9664
Firstly, this link How to use managed identities for App Service and Azure Functions provides good documentation specific to MSI for App Services.
Here is quick sample code.. to get token for a specific user assigned managed service identity as you've asked in your question.
clientId - The ID of the user-assigned identity to be used. If omitted, the system-assigned identity is used.
public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
Overall I see a few changes that you should notice in the sample code above:
About your issue with MSI_ENDPOINT value not being set when you run the app service, please take a look at this note from same link in Microsoft Docs
Screenshot from documentation that is relevant for all parameters used
Upvotes: 6