aws / aws-sdk-net

The official AWS SDK for .NET. For more information on the AWS SDK for .NET, see our web site:
http://aws.amazon.com/sdkfornet/
Apache License 2.0
2.06k stars 854 forks source link

Not able to get Credentials by calling CredentialProfileStoreChain when ProfilesLocation is null or empty #1364

Closed hanslai closed 5 years ago

hanslai commented 5 years ago

According to Accessing Credentials and Profiles in an Application, I do not need to set ProfilesLocation to retrieve Credential. But I am only able to retrieve the Credential when I specific the ProfilesLocation. Below is my code which is in a DLL Project.

        public CognitoAuthUserManagementService(string cognitoUserPoolId, string awsRegion)
        {
            _awsRegion = Amazon.RegionEndpoint.GetBySystemName(awsRegion);

            _cognitoUserPoolId = string.IsNullOrEmpty(cognitoUserPoolId) ? throw new SystemException(nameof(_cognitoClientProvider)) : cognitoUserPoolId;

            //var profileChain = new CredentialProfileStoreChain(@"C:\Users\hansl\.aws\credentials");
            var profileChain = new CredentialProfileStoreChain();

            if (profileChain.TryGetAWSCredentials("default", out AWSCredentials awsCredentials) == false)
            {
               // throw new Exception($"Not able to get AWSCredentials.");
            }

            _cognitoClientProvider = new AmazonCognitoIdentityProviderClient(awsCredentials, _awsRegion)
                              ?? throw new SystemException(nameof(_cognitoClientProvider));
        }

TryGetAWSCredentials() will always return false if I do not pass the shared credentials file path to CredentialProfileStoreChain constructor.

Even, I can specific the shared credentials file path in development, but what confuse me is how does this code work in production? How should one get AWS credential profile in production in an Applicaiton? I read that in production, an EC2 instance role credential will be used instead, but I do not see how this work with the code example of Configuring AWS Credentials

Expected Behavior

TryGetAWSCredentials() should return true even ProfilesLocation is null or empty

Current Behavior

TryGetAWSCredentials() will return false if ProfilesLocation is null or empty

Possible Solution

Steps to Reproduce (for bugs)

Call the above code from a windows console app

Context

How to get aws credentials without setting ProfilesLocation in production environment?

Your Environment

.NET Core Info

.NET Core SDK (reflecting any global.json):
 Version:   3.0.100-preview7-012821
 Commit:    6348f1068a

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18362
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.0.100-preview7-012821\

Host (useful for support):
  Version: 3.0.0-preview7-27912-14
  Commit:  4da6ee6450

.NET Core SDKs installed:
  2.1.701 [C:\Program Files\dotnet\sdk]
  2.1.801 [C:\Program Files\dotnet\sdk]
  2.2.301 [C:\Program Files\dotnet\sdk]
  3.0.100-preview7-012821 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:

  Microsoft.AspNetCore.All 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0-preview7.19365.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Project File

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Extensions.CognitoAuthentication" Version="1.0.3" />
    <PackageReference Include="AWSSDK.CognitoIdentity" Version="3.3.100.52" />
    <PackageReference Include="AWSSDK.CognitoIdentityProvider" Version="3.3.102.37" />
  </ItemGroup>

</Project>
klaytaybai commented 5 years ago

Hi @hanslai,

I'm not sure why this isn't working for you, but I can try to provide some guidance around it. If what I say doesn't help, please provide more information regarding how you have tried to setup your credentials and what version of the Visual Studio Toolkit you are using, if any.

In the credentials configuration documentation that you previously linked, there are notes that should help you. One thing that may be a potential problem is if @"C:\Users\hansl.aws\credentials" isn't resolved by %HOME%.aws\credentials wherever you are executing your code. If you do have a file at %HOME%.aws\credentials with the proper format defined in the documentation, you should be getting credentials without having to define the location in your code.

First search the .NET credentials file for a profile with the specified name. If the profile isn't there, search %HOME%.aws\credentials. If the profile isn't there, search %HOME%.aws\config.

You may also want to verify that you haven't misconfigured credential-related environment variables or app settings.

Furthermore, there isn't a need to use the CredentialProfileStoreChain class in your code unless you want to create an abstraction between the NetSDKCredentialsFile (legacy, used in VS Toolkit and Powershell) and the AWSSharedCredentialsFile.
You could simply write new AmazonCognitoIdentityProviderClient(_awsRegion);

If your production environment is running in EC2, this should also work based on your IAM credentials and roles.

Credential and Profile Resolution

The AWS SDK for .NET searches for credentials in the following order and uses the first available set for the current application.

The client configuration, or what is explicitly set on the AWS service client.

BasicAWSCredentials that are created from the AWSAccessKey and AWSSecretKey AppConfig values, if they're available.

A credentials profile with the name specified by a value in AWSConfigs.AWSProfileName (set explicitly or in AppConfig).

The default credentials profile.

SessionAWSCredentials that are created from the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables, if they're all non-empty.

BasicAWSCredentials that are created from the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, if they're both non-empty.

IAM Roles for Tasks for Amazon EC2 Container Service (Amazon ECS) tasks.

EC2 instance metadata.
hanslai commented 5 years ago

@klaytaybai Thanks for you help.

I found out that there is a C:\Users\hansl\AppData\Local\AWSToolkit\RegisteredAccounts.json in my user folder. I tried so many things, I have no idea how or when that file was there and get created. but once I delete that file. just new AmazonCognitoIdentityProviderClient(_awsRegion); works fine now.

in fact, I was just use new AmazonCognitoIdentityProviderClient(_awsRegion); at first, but it throw 503 Service Unavalilable Exception because of the RegisteredAccounts.json file was there. That is why, I tried the CredentialProfileStoreChain class from Configuring AWS Credentials,

I am not sure what is the purpose of RegisteredAccounts.json file, is it safe to delete it? and what is the purpose of that file if @"C:\Users\.aws\credentials" is already there?

klaytaybai commented 5 years ago

Hi @hanslai. I'm glad you were able to get it working. I should have asked about that file too. The RegisteredAccounts.json file is an encrypted credentials file that is specific to the .NET team's offerings and predates the cross-SDK SharedCredentialsFile found at ~/.aws/credentials or the config at ~/.aws/config. It is created when setting profiles via the AWS Tools for Powershell or the AWS Visual Studio Toolkit. In order to support backwards compatibility, these profiles have taken precedence. Unfortunately this has resulted in many issues like yours, and we'll probably revisit whether we want to change how this is handled. It is safe to delete the RegisteredAccounts.json file so long as you have your credentials backed up somewhere else and an alternative method for getting credentials in your projects, such as using the SharedCredentialsFile.

Now that you have deleted the RegisteredAccounts.json file, can you please try the simplified constructor new AmazonCognitoIdentityProviderClient(_awsRegion);? I'd like to verify that it doesn't return that error for you.

hanslai commented 5 years ago

Hi @klaytaybai thank you for you help. just using new AmazonCognitoIdentityProviderClient(_awsRegion) is working now. Thanks.

hanslai commented 5 years ago

Hi @klaytaybai I would also like to point of that the .net AWS document is kind of confusing and outdated especially with .net core. Very often I spend hours search and reading document other then actual coding. I believe if the document style is more clear and be more up to date, a lot more .net developer like myself will choice and enjoy AWS. Thanks

klaytaybai commented 5 years ago

Thanks for the feedback. If you have more specific feedback about the documentation, please submit feedback via the buttons on the bottom of the documentation pages or create a GitHub issue for code-based documentation feedback. We are ramping up our efforts to improve our documentation quality, so any customer feedback on documentation will help us focus our strategies and tasks.