I am running a console app via Visual Studio and I am getting the error:
AADSTS53000: Device is not in required device state: compliant. Conditional Access policy requires a compliant device, and the device is not compliant. The user must enroll their device with an approved MDM provider like Intune.
However, it seems that my device (the machine running the app), as far as I can tell, is compliant with my company's policies. I've omitted some parts of my code that I think are not relevant to keep the example succinct, but I'm happy to add them in as part of an edit later. The error is being triggered on this line:
// Build ConfidentialClientApplication
IConfidentialClientApplication application = ConfidentialClientApplicationBuilder
.Create(ClientId)
.WithTenantId(TenantId)
.WithCertificate(certificateStoreReader.FindBySubject(certificateSubject))
.Build();
// instantiate a new DataRetriever; this is an internal class I've
// omitted for the purposes of this question
DataRetriever DataRetriever = new DataRetriever(application);
// this method retrieves an accessToken for an API
accessToken = DataRetriever.GetTokenApiA();
// finally, exchange access token in on-behalf-of flow for API B
List<string> scopes = new List<string> { "https://database.windows.net/.default" };
UserAssertion userAssertion = new UserAssertion(
accessToken,
"urn:ietf:params:oauth:grant-type:jwt-bearer");
var result = await application.AcquireTokenOnBehalfOf(scopes, userAssertion).ExecuteAsync(); // this line the error is thrown
return result.AccessToken;
I'm not sure what could be causing this error...I'm somewhat new to C#. Is it possible that the "device" in this case is something other than my actual physical machine? Or perhaps my version of dotnet isn't correct (it is currently getFramework>net6.0-windows10.0.17763.0</TargetFramework>).
I've tried a few different things and looked at this for a while so I'm reaching out to the community for any thoughts if this issue has been seen before.
I'm developing a Blazor Server App with VS2019. When running locally (debug or release) it is running and working fine. After publishing it to Azure App Services I get the remote certificate invalid message. At the moment I call a controller method.
Part if the razor page code is:
protected override async Task OnParametersSetAsync()
{
await Task.Run(async () => await GetExperimentInfo());
}
protected async Task GetExperimentInfo()
{
if (string.IsNullOrEmpty(eid))
{
ExperimentName = "Experiment entity not provided";
return;
}
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(NavigationManager.BaseUri);
ExpInfo = await client.GetFromJsonAsync<ExperimentInfo>("api/experiment/" + eid);
if (ExpInfo == null)
{
ExperimentName = "Error: Experiment not found";
return;
}
ExperimentName = ExpInfo.Name;
}
The 'eid' is specified as an argument calling the razor page.
When calling the controller GET method in the server app on Azure App Service directly returns the correct information.
Calling the same controller GET method from within the razor page returns the AuthenticationException of invalid remote certificate!
The method called in the controller is:
[Route("api/experiment/{eid}")]
[HttpGet]
public ExperimentInfo GetExperimentInfo(string eid)
{
var ExpInfo = GetSNExperimentData(eid);
return ExpInfo;
}
I've browsed a lot of articles on the web, but so far did not find a correct answer why and how to resolve this.
Anyone any idea or experience? Thx
The problem was solved by Microsoft Azure Support (by Kevin Kessler) with the following explanation:
This indicates that whichever Root CA is within the remote web service's certificate chain, is not trusted. This is due to the Root CA not being contained within the app service's Trusted Root store.
The Azure web app resides on an App Service Environment (ASE). In this case you may be able to resolve the issue by uploading the needed certificates and assigning their thumbprint values to the app service settings.
Please see this document, which covers the use of certificates on an ASE and how to configure on an app service:
https://learn.microsoft.com/en-us/azure/app-service/environment/certificates#private-client-certificate
Additionally, this StackOverflow article may provide further guidance:
How to make the azure app service trust the certificates issued by the OnPrem CA?
Resolution: Uploaded Root and intermediate certificates to ASE
I have written a .NET Core 3.0 console application that accesses SSM for some encrypted credentials to run a job. When I run it locally, it works fine and I can access the parameters from my account's SSM. However, when I deploy this via docker and ECS Fargate and run it as a task, it seems like it can't access the parameters. I get the following error:
Unable to get IAM security credentials from EC2 Instance Metadata Service.
This is coupled with a ParameterNotFound exception.
As I understand it,AmazonSimpleSystemsManagementClient is trying to grab the default app config and use the aws credentials from there to access other aws resources. This works fine when I run it locally since I have the AWS CLI configured and my credentials are accessible. When this runs through ECS, I guess that it can't find this config so it then tries to look for the EC2 Meta config, which may not exist in ecs?
I have attached the SSM Full access policy to the task definition's role and even the AdministratorFullAccess role and still doesn't seem to fix the exception. Am I missing something?
public static async Task<Login> GetCredentialsAsync(string parameterName)
{
var request = new GetParameterRequest()
{
Name = $"/credentials/{parameterName}",
WithDecryption = true
};
using (var client = new AmazonSimpleSystemsManagementClient())
{
try
{
var response = await client.GetParameterAsync(request);
var responseObject = JsonConvert.DeserializeObject<Login>(response.Parameter.Value);
return responseObject;
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error occurred: {ex.Message}");
}
}
throw new ParameterNotFoundException($"Could not find credentials for {parameterName}");
}
As it turns out, I needed to set a Task Role for the instance in the Task Definition. I had only set an Execution Role.
I am trying to test a .NET core console program to publish a message to SNS. As I had issues trying to get it to work in Lambda, I want to try it in a non-Lambda environment. In Lambda, security is covered by the role, but in a console program, I presume that I have to specify my access key and secret somehow.
I've read this page: http://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#net-dg-config-creds-sdk-store, but still totally confused.
I'm running on my local development computer, not an EC2 instance. No intent to go to production with this, just trying to test some code.
I'm on Visual Studio 2015, .NET Core 1.0. I've used Nuget to get the following:
"AWSSDK.Extensions.NETCore.Setup": "3.3.3",
"AWSSDK.SimpleNotificationService": "3.3.0.23",
Based on the answer to How to set credentials on AWS SDK on NET Core? I created the /user/.aws/credentials file (assuming credentials was the file name and not the directory name).
But that question/answer doesn't address how to actually use this file. The code I'm running is below.
public static void Main(string[] args)
{
Console.WriteLine("Started");
//var awsCredentials = new Amazon.Runtime.AWSCredentials()
var client = new Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.EUWest2);
//var client = new Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient(awsCredentials, Amazon.RegionEndpoint.EUWest2);
//Amazon.SimpleNotificationService.Model.PublishResponse publishResp = null;
SendMessage(client).Wait();
Console.WriteLine("Completed call to SendMessage: Press enter to end:");
Console.ReadLine();
}
The error I'm getting on the new client is:
An unhandled exception of type 'Amazon.Runtime.AmazonServiceException' occurred in AWSSDK.Core.dll
Additional information: Unable to find credentials
I see there is a way to pass an AWSCredentials object to that constructor, but I don't understand how to build it. Amazon.Runtime.AWSCredentials is an abstract class, so I can't use it in a "new" statement.
Based on Dan Pantry's answer, here is a simple short answer with code highlighted (note the region enum in the second line):
var awsCredentials = new Amazon.Runtime.BasicAWSCredentials("myaccesskey", "mysecretkey");
var client = new Amazon.SimpleNotificationService.AmazonSimpleNotificationServiceClient(
awsCredentials, Amazon.RegionEndpoint.EUWest2);
Use a role if possible, but above works when needed. Then the question is where to store the access key/secret key; could be environment variable, config file, prompt the user, or any of the usual suspects.
AWS-CLI and Python use credentials from here: c:\Users\username\.aws\credentials, so the C# could just read that file so as not to put the codes in the C# program itself. But then each user/developer that runs the program would need to set their credentials there.
There is also now a concept of running Lambda on your local machine, but I haven't tried it yet:
https://dzone.com/articles/run-aws-lambda-functions-locally-on-windows-machin#:~:text=Step%201%3A%20Download%20SAM%20local,version%20with%20the%20command%20below.&text=Step%203%3A%20Write%20your%20lambda,yaml%20on%20the%20root%20level.
So the point is that if you are going to do Lambda, but you need to test locally first, this would probably be worth trying.
You'll want to construct one of its child classes instead of the abstract one. You can take a look at the class hierarchy here.
For posterity, the options are:
AnonymousAWSCredentials - Authenticates as an anonymous user.
BasicAWSCredentials - You provide your credentials to the class constructor directly.
EnvironmentAWSCredentials - Credentials are pulled from the environment variables of the running executable.
InstanceProfileAWSCredentials - Pulls credentials from the Instance Profile of the EC2 instance running the executable. This, obviously, only works on EC2.
SessionAWSCredentials - Similar to BasicAWSCredentials, except utilises an AWS Session using a temporary session token from AWS STS.
RefreshingSessionAWSCredentials - Similar to SessionAWSCredentials, but refreshes when the STS token expires.
Note that the default strategy in the absence of a credentials object involves checking the Environment Variables and then the instance profile.
If you want to have the program pull credentials from ~/.aws/credentials, you'll need to do some legwork. There used to be a StoredProfileAWSCredentials class, but that appears to have been removed - you can find more information by looking at this github issue. This is only useful, really, in development as you won't be using ~/.aws/credentials in production but probably instance profiles - I'd suggest instead using the default strategy and using Environment AWS credentials in test or development environments.
I take this approach at work since we use a command line tool to grab us limited time tokens from AWS STS and plunk them into the current shell for use for the next hour.
EDIT: It appears you're using AWS Lambda. These have federated access to AWS resources based on the roles assigned to them, so this should work using the default credential strategy in the aws-sdk library which uses instance profiles. So this is only really necessary for development/testing, in which case I would again recommend just using environment variables.
This is a really old question, and the existing answers work, but I really don't like hard-coding my Access Key Id and Secret Key values directly into source code, even for throw-away projects I'm doing on my local machine. For one thing, I might revoke those keys in the future, so I want to leverage the credentials in my .aws\credentials file.
To do that for my .NET core apps (including console apps, etc), I first add two NuGet packages:
Microsoft.Extensions.Configuration.Json
AWSSDK.Extensions.NETCore.Setup
Then, I add an applications.json file to my project, which contains the following (note - you need to right-click the file, and set "Copy to output" as either "copy if newer" or "always"):
{
"AWS": {
"Profile": "default",
"ProfilesLocation": "C:\\Users\\my-user-profile-folder\\.aws\\credentials",
"Region": "us-west-2"
}
}
Finally, I create an instance of the AWS SDK client using the following:
var builder = new ConfigurationBuilder().AddJsonFile("appsettings.Development.json", optional: false, reloadOnChange: true);
var options = builder.Build().GetAWSOptions();
var s3client = options.CreateServiceClient<IAmazonS3>();
This way, if I update my credentials file, I'm fine. Or if my code gets zipped up and emailed to a friend or co-worker, I don't accidentally send them my credentials also.
There is another way to do this, without needing to add the NuGet packages also, which many people might prefer. You can use the new SharedCredentialsFile class and AWSCredentialsFactory, like this (using the "default" profile here, and assumes your credential file is in the default location, same as the other method):
var sharedFile = new SharedCredentialsFile();
sharedFile.TryGetProfile("default", out var profile);
AWSCredentialsFactory.TryGetAWSCredentials(profile, sharedFile, out var credentials);
var s3Client = new AmazonS3Client(credentials);
Note - I'm not checking that the two Try* methods are succeeding here, which you probably should do. Details on using these classes are here: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#how-to-create-an-amazons3client-using-the-sharedcredentialsfile-class
While keeping your credentials in the shared "credentials" file, you can redefine the ProfilesLocation when creating the CredentialProfileStoreChain
//define your file location here:
var chain = new CredentialProfileStoreChain(#"C:\aws\credentials");
// input the name of your credentials here:
if (chain.TryGetAWSCredentials("nameofprofile", out AWSCredentials awsCredentials))
{
//executes if the credentials were found and inserted into awsCredentials
}
else
{
// executes if the credentials were not found
}
Taken from here: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/creds-locate.html
For those struggling with profile names, here is where you can find it.
Contents of your ~/.aws/credentials:
[YOUR_PROFILE_NAME]
aws_access_key_id = ***
aws_secret_access_key = ***
aws_security_token = ***
aws_session_expiration = ***
aws_session_token = ***
So then in your application you access the credentials like this:
var chain = new CredentialProfileStoreChain();
var result = chain.TryGetAWSCredentials("YOUR_PROFILE_NAME", out var credentials);
Resources:
accessing credentials and profiles: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#creds-locate
named profiles: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
I have an U-SQL script with custom extractor, which access Azure Key Vault to get some credentials.
I followed this tutorial. And I have equivalent code to get token from AD and then to call provided URI for actual credentials:
public static async Task<string> GetToken(string authority, string resource, string scope)
{
var authContext = new AuthenticationContext(authority);
var clientCred = new ClientCredential(applicationId, authenticationKey);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the AD token");
}
return result.AccessToken;
}
public static async Task<string> GetSecret(string secretUri)
{
var keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(GetToken)
);
var sec = await keyVaultClient.GetSecretAsync(secretUri);
return sec.Value;
}
My credentials were put into vault successfully, and I have an URI to access them - something like:
https://my-key-vault-name.vault.azure.net:443/secrets/MyCredentialsName/123abc
I've registered my app in Azure AD and got application-id and authentication-key for it and I allowed my app to read secret from Key Vault. In my U-SQL script I've referenced all needed assemblies.
When I run my script locally everything works great (that means connection from local machine to AD and to Key Vault are OK), but when I submit it for execution on remote Data Lake Analytics account I got the following error:
The remote name could not be resolved:
'my-key-vault-name.vault.azure.net'
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult
asyncResult) at
System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
My administrative rights on Azure resource group are limited, but I can access Firewall tab on Data Lake Analytics blade - I've tried enabling and disabling firewall, switching on/off Allow access to Azure services, still the error persists.
As dependencies, I am referencing Microsoft.Azure.KeyVault 2.0.6, Microsoft.Azure.KeyVaultWebKey 2.0.4, Microsoft.IdentityModel.Clients.ActiveDirectory 3.13.9.
Any ideas on how can I attempt to resolve it?
U-SQL code running in ADLA does not allow you to connect to resources outside the container/VM. The reason is:
U-SQL's custom code calls possibly scaled out over 100 to 1000s of containers getting invoked millions for millions of rows. This can easily lead to a (hopefully unintended) distributed denial of service attach against the service you are trying to reach, leading to possibly DDOSing the service and getting the Azure IP ranges blocked.
Local run does not currently run in a container so has no such limit enforcement.
What are you trying to achieve with this call? Note that the data in storage can already be transparently encoded with Azure Key Vault.