I'm beginning to work with Secrets Manager and created my first secret in AWS. During the process, it gave me some sample code to work with. I put that in a small application and ran it. The code:
String region = "us-east-1";
string secret = "";
MemoryStream memoryStream = new MemoryStream();
IAmazonSecretsManager client = new AmazonSecretsManagerClient(
RegionEndpoint.GetBySystemName(region));
GetSecretValueRequest request = new GetSecretValueRequest();
request.SecretId = "MySecretNameExample";
GetSecretValueResponse response = null;
response = client.GetSecretValue(request);
The problem is that:
I was able to successfully retrieve the secret that I created and
nowhere am I creating a Credentials object with any valid AWS credential data
Where is this code getting the credential information from?
If you refer to the documenation for the API for this line of code:
IAmazonSecretsManager client = new AmazonSecretsManagerClient(
RegionEndpoint.GetBySystemName(region));
AmazonSecretsManagerClient
You will find the following description:
Constructs AmazonSecretsManagerClient with the credentials loaded from
the application's default configuration, and if unsuccessful from the
Instance Profile service on an EC2 instance.
This means that you are either running on an EC2 or ECS service (or related service such as Beanstalk, ...) with a role assigned to the instance or your have configured your credentials in the standard method in a credentials file. The AWS SDK is helping you locate credentials.
This document link will explain in more detail how AWS credentials are managed and selected.
Working with AWS Credentials
I have seen a lot of developers get the little details wrong with how credentials work and how they are used within the SDKs. Given that AWS credentials hold the keys to the AWS kingdom, managing and protecting them is vitally important.
The AWS SDK uses the a resolution strategy that looks in a number of locations until it finds credentials it can use. Typically the DefaultProviderChain class is responsible for performing the resolution. More information is here, but the gist is the lookup is performed in the following order (for Java, other languages are similar):
environment variables
Java system properties
credentials file (e.g. in the home directory)
instance profile credentials (only available when running in AWS)
When you run within AWS infrastructure, you can assign a profile or role to the resource that's running your code. Doing that makes credentials automatically available to your code. The idea is that they've made it easy to avoid putting credentials directly into your code.
Related
We have a java app that runs within an EC2. This uses AWS SDK to interact with AWS services. The app uses the default credentials provider which in turn uses the temporary tokens from the EC2.
The problem is that this temporary token expires after a while and all subsequent AWS SDK calls fail. How can we refresh this temporary credentials so that the app can use the new valid credentials?
InstanceProfileCredentialsProvider retrieves credentials as needed; a client using it should never see a credentials timeout exception.
This implies that either (1) you are explicitly setting instance profile credentials on the client that is timing out, or (2) there is something else in the provider chain that is providing limited-time credentials.
Or, I suppose, you might be using an extremely old version of the SDK. I don't know at what point they added automatic refresh; according to git blame, the fetcher variable was last changed 13 months ago. But I've been using instance credentials with long-running processes for much longer than that.
This article may help you.
If you really need to get a new credentials, the following example shows pseudocode for how to use temporary security credentials if you're using an AWS SDK:
assumeRoleResult = AssumeRole(role-arn);
tempCredentials = new SessionAWSCredentials(
assumeRoleResult.AccessKeyId,
assumeRoleResult.SecretAccessKey,
assumeRoleResult.SessionToken);
s3Request = CreateAmazonS3Client(tempCredentials);
Read further info about temporary credentials in this docs.
I have an EC2 server with multiple applications hosted on it. I currently have to live with this setup for now (I can't put each app on its own server).
I don't want to use a single system wide set of creds for ALL the apps running on the server.
Each app should only have access to only the stuff it needs. This is important for troubleshooting/debugging and isolating the application's access. I'm trying to figure out how this can be done.
I could give the EC2 instance role access to assume application specific roles. So the applications, on initialization, would have access to assume a role just for their use. This seems like the right way to go but these are very long running applications. Even if I set the token expiration very high it will need to be refreshed. Do the STS clients for Java and .net support a way to auto-refresh? Will I have to implement this logic myself somehow? Like have the app check the token isn't expired before every single AWS API call? I don't want to have to implement this in code.
I don't like it, but I could also create IAM users for all the applications and store their credentials in parameter store or the secret manager. The EC2 role would have access to read those secrets and when the apps start they pull down a secret with their IAM users keys and use those in their session. They would not have to use sts or implement refresh logic but I'm using static access keys which I do not like - maybe the secret manager thing can rotate the IAM keys for me?
I know for the AWS SDK for .NET it is possible to have the SDK manage refreshing credentials for you. Below is a small snippet of code to create an AWSCredentials object that under the covers will get credentials by assuming a role using the instance profile credentials. The AssumeRoleAWSCredentials object will automatically refresh before the credentials are expired.
using Amazon.Runtime;
namespace AssumeRoleCredsExample
{
class Program
{
static void Main(string[] args)
{
var roleArn = "your-application-role-arn-here";
var instanceProfileCredentials = FallbackCredentialsFactory.GetCredentials();
var assumeRoleCredentials = new AssumeRoleAWSCredentials(instanceProfileCredentials, roleArn, "Application1SessionName");
}
}
}
I suspect the AWS SDK for Java has very similar feature. Taking a quick look at the JavaDocs for the AWS SDK for Java I would look at the com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider class.
Below code creates AWS Credentials where access and secret keys are explicitly supplied.
AWSCredentials credentials = new BasicAWSCredentials(
"<AWS accesskey>",
"<AWS secretkey>"
);
But the issue with this approach is in production I can not use it.
So what will be an equivalent java code that will obtain credential automatically from the aws credentials chain and create a credential object or some EC2 client.
There are several alternatives you can use to store and recover your credentials in production. You should check the official documentation by AWS about 'Using the Default Credential Provider Chain'. Basically, you can use any of these alternatives:
Environment variables.
Java system properties.
The default credential profiles file.
Amazon ECS container credentials.
Instance profile credentials.
Depending on which one you choose it would use a different code. You have guidelines on how to use them in the above link.
AWS .Net SDK specifies several ways to specify credentials. One of them is SDK store - http://docs.aws.amazon.com/AWSSdkDocsNET/V3/DeveloperGuide/net-dg-config-creds.html#net-dg-config-creds-sdk-store
In that same document two seemingly contradictory things are written:
"SDK Store profiles are specific to a particular user on a particular host. They cannot be copied to other hosts or other users. For this reason, SDK Store profiles cannot be used in production applications."
"The associated credentials are incorporated into the application during the build process."
IF the credentials are incorporated in the program at the build time, then why can't I use the SDK store method in production environment?
That leaves me with either storing credentials in .config files, or credentials files, or using roles.
To clarify, the documentation is stating that if you are only using the SDK store, you can't simply pick up your application and move it to any other machine while expecting it to work as-is. If you are using profile names, your application is referencing the profile name in the local SDK store (or, failing that, the credentials file used by other AWS resources like the AWS CLI).
For example, if you created a profile named dev-Amit on your personal computer and then moved to another machine in production, dev-Amit wouldn't exist there unless you had already configured the SDK store on that machine with the same profile name.
This behavior is contrary to the recommended practice of passing credentials in EC2, using temporary credentials via IAM Roles. Using this method, you can reliably pass credentials to your applications on EC2 instances by simply attaching an IAM role to the instance that has sufficient permissions to do whatever your application needs to do. This method is preferred because you don't have to login to the instance to configure anything; you simply attach the IAM role at creation time.
Further Resources:
AWS Documentation - Tutorial: Grant Access Using an IAM Role and the AWS SDK for .NET
AWS Documentation - Order in which credentials are searched for
I can get a Credential from FederatedTokenResult by querying AWS. Now, I want that credential to be used by another service to create an application stack using CloudFormation API - I can create that with using my root account which I don't want. But as I read from GetFederationToken and Credential Page, I must must pass to the service API to use the temporary credentials.
Is it possible to do things with temporary users (given permissions) to launch a stack, creating a new Key-Pair? Any links, code snippets are highly appreciated.
Seems ruby sdk provides for session tokens. How do I get it done in Java ?
At the moment I create the stack that is similar to CloudFormation given as sample with AWS SDK which does not use temporary credentials.
Once you have the Credentials, you create a BasicSessionCredentials object and pass that into the constructor for the AmazonCloudFormationClient. For example:
// Package the temporary security credentials as
// a BasicSessionCredentials object, for an Amazon S3 client object to use.
BasicSessionCredentials basicSessionCredentials = new BasicSessionCredentials(
sessionCredentials.getAccessKeyId(),
sessionCredentials.getSecretAccessKey(),
sessionCredentials.getSessionToken());
// The following will be part of your less trusted code. You provide temporary security
// credentials so it can send authenticated requests to AWS CloudFormation.
AmazonCloudFormationClient client = new AmazonCloudFormationClient(basicSessionCredentials);
I hope that helps!