AWS IAM: AssumeRole vs GetSessionToken - amazon-web-services

I'm trying to generate a temporary credentials access key and secret key. I've used AssumeRole. The description says it generates an access key and secret key. But GetSessionTokenResult can also generate an access key and secret key. Then what's the use of assumeRole?
AWSSecurityTokenService awsSecurityTokenService =
AWSSecurityTokenServiceClientBuilder
.standard().withCredentials(new ProfileCredentialsProvider())
.withRegion(region).build();
AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest()
.withRoleArn(
"arn:aws:iam::account-id:role/p-27c229ade194_ec2")
.withRoleSessionName("RedshiftSession");
AssumeRoleResult assumeRoleResult = awsSecurityTokenService
.assumeRole(assumeRoleRequest);
GetSessionTokenRequest getSessionTokenRequest = new GetSessionTokenRequest();
getSessionTokenRequest.setDurationSeconds(1200);
GetSessionTokenResult getSessionTokenResult = awsSecurityTokenService
.getSessionToken(getSessionTokenRequest);
Credentials sessionCredentials = getSessionTokenResult.getCredentials();
final String adminAccessKeyId = sessionCredentials.getAccessKeyId();
final String adminAccessSecretKey = sessionCredentials
.getSecretAccessKey();
Earlier using assumeRole it showed error => aws:iam::user/admin is not sts:assumeRole on resource role aws:iam::role/role_id.
By adding aws:iam::user/admin in trusted relationship of role_id it worked.
If I will comment out AccessRole and its other called class. I can generate an access key and secret key. What's the purpose of using AssumeRole?

There are several methods to obtain temporary credentials, depending upon your requirements:
GetSessionToken gives you a set of temporary credentials based on your own IAM User. This is commonly used to activate Multi-Factor Authentication (MFA), or to create some scoped-down credentials for a situation where you want to limit access (eg giving access to an application that uploads/downloads data to S3, without giving any non-S3 access). The new credentials have, at most, the same permissions as you have (and never any more).
AssumeRole is used to obtain credentials that have a totally different set of permissions. For example, you might not have permission to access S3, but you might have permission to assume an "S3 access" role. The credentials returned then allow you to temporarily access S3. Another example is providing access to administrator permissions — rather than always using an account with Admin permissions, it is safer to temporarily assume an Admin role, do the admin activity, then return to using normal credentials. Less is likely to go wrong than always using Admin-level access.
Also, AssumeRole can be used to gain cross-account access. For example, a user in Account A could assume a role in Account B, which grants access to resources in Account B. This is not possible via GetSessionToken.
I always find this article useful to explain the differences: Understanding the API Options for Securely Delegating Access to Your AWS Account | AWS Security Blog

Related

Update secret value across accounts

I wrote a Python script on a function in one account that tries to get a secret value from a second account using boto3 with client.get_secret_value(). However, client.update_secret() only seems to be working for secrets in the same account, not secrets in the second account.
secretUpdated = client.update_secret(
SecretId=’arn for my test secret',
Description='',
KmsKeyId='kms key arn’,
SecretString='the Secret string for my test secret with key values'
)
I get back Access denied but as far as I can tell it should have secretsmanager:UpdateSecret both from the function in the first account and to the secret in the other account with it being set in all the same places I added getsecret (function policy on role and the resource policy on the secret) so I don't know if there are any extra parameters I need to add to the script when it is cross-account?
Secrets can only be accessed/updated in the account associated with the IAM credentials that you are using. (Otherwise, I would be able to view/change the secrets in your account!)
You have two options:
Option 1: Use credentials associated with the 'other' account
Obtain an Access Key and Secret Key for an IAM User in the 'other' account that has permissions to use Secrets Manager. Then, use those credentials with boto3. This can be done in a couple of ways:
Store the credentials as a different profile, using aws configure --profile account2
Then use the profile like this:
import boto3
session = boto3.Session(profile_name='account2')
secrets_client = session.client('secretsmanager')
OR
Pass the credentials to the client with:
import boto3
secrets_client = boto3.client('secretsmanager', aws_access_key_id='AKIAxxx', aws_secret_access_key='xyz')
The secrets_client will then be accessing the other account.
See: Credentials — Boto3 Docs documentation
Option 2: Assume an IAM Role in the 'other' account
Create an IAM Role in the 'other' account and grant it permissions for Secrets Manager
Add a Trust Policy to the IAM Role that allows it to be 'assumed' by the IAM User in your 'normal' account
Using boto3, call assume_role() to assume the IAM Role in the other account
import boto3
from boto3.session import Session
client = boto3.client('sts')
response = client.assume_role(RoleArn='arn:aws:iam::00000000000000:role/example-role`, RoleSessionName='account2')
session = Session(aws_access_key_id='AKIAxxx', aws_secret_access_key='xyz')
secrets_client = session.client('secretsmanager')
See: Switching to an IAM role (AWS API) - AWS Identity and Access Management

How to create recordset in Account2 from Account1

I am trying to create a route53 recordset from Account1 in Account2.
From reading other posts and online search I am thinking of doing something like this:
from boto3 import Session
session = Session(aws_access_key_id=*****,aws_secret_access_key=****,region_name='us-east-1')
r53_client = session.client('route53')
r53_resource = session.resource('route53')
Want to know from someone experienced if this is the right way to do this? Or is there a better way to achieve above?
Here is updated code:
def lambda_handler(event, context):
sts = boto3.client('sts')
response = sts.assume_role(
RoleArn='arn:aws:iam::***123:role/lambda',
RoleSessionName='my-random-session-name',
DurationSeconds= 900 # how many seconds these credentials will work
)
tempAccessKeyId = response['Credentials']['AccessKeyId']
tempSecretAccessKey = response['Credentials']['SecretAccessKey']
tempSessionToken = response['Credentials']['SessionToken']
client = boto3.client('route53',
region_name = 'us-west-2',
aws_access_key_id=tempAccessKeyId,
aws_secret_access_key=tempSecretAccessKey,
aws_session_token=tempSessionToken)
response = client.list_resource_record_sets(
HostedZoneId='***',
StartRecordName='test.example.com.',
StartRecordType='A'
)
print(response)
Based on the fact that you are doing this from an AWS Lambda function, the most secure way to do it would be:
In Account 1:
Create an IAM Role (Role 1) that will be used by the Lambda function
Assign permissions to the role that allows it to assume Role-2
Also assign any other permissions the Lambda function requires (you would normally add the AWSLambdaBasicExecutionRole managed policy to allow logging)
Assign Role 1 to the Lambda function
In Account 2:
Create an IAM Role (Role 2) with trust permissions that allows Role 1 in Account 1 to assume it
Grant Role 2 appropriate permissions to use Amazon Route 53
In your Lambda code, you would call AssumeRole() on Role 2. This will provide a set of temporary credentials that can be used to access Account 2 (as per your code, above).
See: Switching to an IAM Role (AWS API) - AWS Identity and Access Management
To make an API call to an AWS account, you either need credentials from that AWS account (eg credentials associated with an IAM User), or you need the ability to assume an IAM Role in that account.
So, in your example, if the credentials being provided belong to Account2, then you will be able to make API calls to Account2 (if that IAM User has been granted the necessary Route 53 permissions).
If you are frequently moving between accounts, you can instead specify a profile, which retrieves a different set of credential from the credentials file.
See: python - How to choose an AWS profile when using boto3 to connect to CloudFront - Stack Overflow

boto3 s3 role arn

I can't use boto3 to connect to S3 with a role arn provided 100% programmatically.
session = boto3.Session(role_arn="arn:aws:iam::****:role/*****",
RoleSessionName="****")
s3_client = boto3.client('s3',
aws_access_key_id="****",
aws_secret_access_key="****")
for b in s3_client.list_buckets()["Buckets"]:
print (b["Name"])
I can't provide arn info to Session and also client and there is no assume_role() on a client based on s3.
I found a way with a sts temporary token but I don't like that.
sess = boto3.Session(aws_access_key_id="*****",
aws_secret_access_key="*****")
sts_connection = sess.client('sts')
assume_role_object = sts_connection.assume_role(RoleArn="arn:aws:iam::***:role/******",
RoleSessionName="**",
DurationSeconds=3600)
session = boto3.Session(
aws_access_key_id=assume_role_object['Credentials']['AccessKeyId'],
aws_secret_access_key=assume_role_object['Credentials']['SecretAccessKey'],
aws_session_token=assume_role_object['Credentials']['SessionToken'])
s3_client = session.client('s3')
for b in s3_client.list_buckets()["Buckets"]:
print (b["Name"])
Do you have any idea ?
You need to understand how temporary credentials are created.
First you need to create a client using your current access keys. These credentials are then used to verify that you have the permissions to call assume_role and have the rights to issue credentials from the IAM role.
If someone could do it your way, there would be a HUGE security hole with assume_role. Your rights must be validated first, then you can issue temporary credentials.
Firstly, never put an Access Key and Secret Key in your code. Always store credentials in a ~/.aws/credentials file (eg via aws configure). This avoids embarrassing situations where your credentials are accidentally released to the world. Also, if you are running on an Amazon EC2 instance, then simply assign an IAM Role to the instance and it will automatically obtain credentials.
An easy way to assume a role in boto3 is to store the role details in the credentials file with a separate profile. You can then reference the profile when creating a client and boto3 will automatically call assume-role on your behalf.
See: boto3: Assume Role Provider

How to use the Amazon web services credentials (Access keys) in my project?

We want to use AWS services via API calls, CLI, Etc., from our on-premise infrastructure as well as from AWS cloud infrastructure.
As we know, we can use the AWS access key as follow:
This is a snippet from an example
// Setup AWS SNS
AWS.config.update({
region: 'eu-west-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
var sns = new AWS.SNS();
var params = {
Message: "SMS message test",
MessageStructure: 'string',
PhoneNumber: '0045xxxxxxxx',
Subject: 'Alarm',
MessageAttributes :{
'AWS.SNS.SMS.SenderID': {
'DataType': 'String',
'StringValue': 'MySender'
},
'AWS.SNS.SMS.SMSType': 'Transactional'
}
};
sns.publish(params, function(err_publish, data) {
if (err_publish) {}
});
This code uses the access keys through the environment variables. That approach is partially accepted because you're tied to modify those environment variables to update access keys.
So, what are the best practices or different approaches for using the access keys in a good manner?
AWS Documentation
Access keys consist of an access key ID (for example, AKIAIOSFODNN7EXAMPLE) and a secret access key (for example, wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY). You use access keys to sign programmatic requests that you make to AWS if you use the AWS SDKs, REST, or Query API operations. The AWS SDKs use your access keys to sign requests for you, so that you don't have to handle the signing process. You can also sign requests manually. For more information, see Signing AWS API Requests.
Access keys are also used with command line interfaces (CLIs). When you use a CLI, the commands that you issue are signed by your access keys. You can pass access keys either with the command or store as configuration settings on your computer.
Temporary access keys, known as temporary security credentials
In addition to the access key ID and secret access key, temporary security credentials include a security token that you must send to AWS when you use temporary security credentials
Advantages
They are short term.
After they expire, they're no longer valid.
You can use temporary access keys in less secure environments or distribute them to grant users temporary access to resources in your AWS account.
For example, you can grant entities from other AWS accounts access to resources in your AWS account (cross-account access). You can also grant users who don't have AWS security credentials access to resources in your AWS account (federation). For more information, see Temporary Security Credentials in the IAM User Guide.
Approaches for using Access keys
Access keys in Environment variables
This approach is the most common for development and testing environments because they will test their developments using a close scope, likewise for scenarios where our apps are deployed within an on-premise infrastructure.
Usage of Access keys through Environment variables (NodeJs)
// Setup AWS SNS
AWS.config.update({
region: 'eu-west-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
var sns = new AWS.SNS();
var params = {...});
sns.publish(params, function(err_publish, data) {...});
Access keys through instance metadata
This is the most secure way to use the Access keys within an EC2 or container because you don't need to put any Access keys neither in your code nor in Environment variables.
Retrieving Security Credentials from Instance Metadata
The following command retrieves the security credentials for an IAM role named s3access.
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access
The following is an example output
{
"Code" : "Success",
"LastUpdated" : "2012-04-26T16:39:16Z",
"Type" : "AWS-HMAC",
"AccessKeyId" : "ASIAIOSFODNN7EXAMPLE",
"SecretAccessKey" : "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token" : "token",
"Expiration" : "2017-05-17T15:09:54Z"
}
IAM Roles
The IAM Roles provide a good and secure way to grant permissions to your services.
IAM Role console: This is how looks like
The IAM Role allows you to describe a policy with the specific permissions. That role could be attached to an EC2 instance and automatically the service within it will be granted with those permissions. So, we can execute API calls without the need to put the Access keys:
var s3 = new AWS.S3({params:{Bucket: 'bucketname', Key: 'filename'}});
var body = fs.createReadStream('file_to_upload');
s3.upload({Body:body})
.on('httpUploadProgress',function(evt){
console.log(evt);
})
.send(function(err,data){
console.log(err,data);
});
As you can see, there is any Access keys in that code because the SDK will get the Access keys from /latest/meta-data/iam/security-credentials/s3access.
Access keys within Named Profiles
The Named profiles are used for CLI (Command line interface), so you can create profiles with different usages. For example, you can use the AWS access keys from a specific region.
The AWS CLI supports named profiles stored in the config and credentials files. You can configure additional profiles by using aws configure with the --profile option or by adding entries to the config and credentials files.
The following example shows a credentials file with two profiles:
~/.aws/credentials
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[user2]
aws_access_key_id=AKIAI44QH8DHBEXAMPLE
aws_secret_access_key=je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
Each profile uses different credentials—perhaps from two different IAM users—and can also use different regions and output formats.
~/.aws/config
[default]
region=us-west-2
output=json
[profile user2]
region=us-east-1
output=text
Using Profiles with the AWS CLI
$ aws ec2 describe-instances --profile user2
The command above will use the credentials within profile user2
Best practices for using Access keys
Remove (or Don't Generate) Account Access Key
An access key is required in order to sign requests that you make using the AWS Command Line Tools, the AWS SDKs, or direct API calls. Anyone who has the access key for your AWS account root user has unrestricted access to all the resources in your account, including billing information. You cannot restrict the permissions for your AWS account root user.
Use Temporary Security Credentials (IAM Roles) Instead of Long-Term Access Keys
In many scenarios, you don't need a long-term access key that never expires (as you have with an IAM user). Instead, you can create IAM roles and generate temporary security credentials. Temporary security credentials consist of an access key ID and a secret access key, but they also include a security token that indicates when the credentials expire.
Manage IAM User Access Keys Properly
If you do need to create access keys for programmatic access to AWS, create an IAM user and grant that user only the permissions he or she needs. Then generate an access key for that user. For details, see Managing Access Keys for IAM Users in the IAM User Guide.
Precautions when using access keys
Don't embed access keys directly into code.
Use different access keys for different applications.
Rotate access keys periodically.
Remove unused access keys.
Configure multi-factor authentication for your most sensitive operations.
Resources
AWS Security Credentials
AWS Account Root User Credentials vs. IAM User Credentials
AWS Security Audit Guidelines
AWS Account Identifiers
Using Instance Profiles

AWS STS AssumeRole: Are IAM user credentials needed, or not?

Conflicting documentation
The documentation here, pertaining to AssumeRole, seems to contradict itself in one continuous block:
You must call this API using existing IAM user credentials. For more
information, see Creating a Role to Delegate Permissions to an IAM
User and Configuring MFA-Protected API Access.
This is an unsigned call, meaning that the app does not need to have
access to any AWS security credentials in order to make the call.
The contradictions are given bold emphasis.
Code sample
The code sample provided here certainly seems to require credentials:
AmazonSecurityTokenServiceClient securityTokenServiceClient = new AmazonSecurityTokenServiceClient(
Config.AccessKey,
secretKeyAsString,
securityTokenServiceConfig);
…
AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest
{
DurationSeconds = sessionDurationSec,
RoleArn = roleArn,
RoleSessionName = awsUsername,
ExternalId = groupSid
};
…
assumeRoleResponse = securityTokenServiceClient.AssumeRole(assumeRoleRequest);
In conclusion
Which is true? Are the requests in the code sample truly redundant?
Thank you!
The AssumeRole API call does require existing AWS credentials.
In order to assume an IAM role, an existing set of credentials must be used so that AWS knows who is assuming the role. This is so that AWS can verify that the assuming party is allowed to assume the role.
In the documentation:
This is an unsigned call, meaning that the app does not need to have access to any AWS security credentials in order to make the call.
This does appear to be incorrect information.
This is indeed an error in the docs, which is in the process of being corrected. AssumeRole does require existing long-term (IAM User) or temp credentials credentials to call. It is the two federation equivalents, AssumeRoleWithSAML and AssumeRoleWithWebIdentity that can be called without credentials. Sorry for the confusion!