How to specify AWS credentials in C# .NET core con

2020-05-25 05:20发布

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.

3条回答
乱世女痞
2楼-- · 2020-05-25 05:30

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

查看更多
家丑人穷心不美
3楼-- · 2020-05-25 05:40

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.AmazonSimpleNotificationSer‌​viceClient(
                              awsCreden‌​tials, 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.

查看更多
Evening l夕情丶
4楼-- · 2020-05-25 05:46

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.

查看更多
登录 后发表回答