AmazonCognitoIdentity AccessDeniedException - amazon-web-services

I am developing an app and I need use Amazon Cognito for access to AS3 services.
I created an IdentityPool and I have my IdentityPoolId and I created my Developer provider so, I have my Developer provider name. But when I execute getOpenIdTokenForDeveloperIdentity, the response is null:
(Service: AmazonCognitoIdentity; Status Code: 400; Error Code: AccessDeniedException;
try{
AmazonCognitoIdentity identityClient = new AmazonCognitoIdentityClient(
new BasicAWSCredentials(accessKeyId, secretAccessKey)
);
GetOpenIdTokenForDeveloperIdentityRequest tokenRequest = new GetOpenIdTokenForDeveloperIdentityRequest();
tokenRequest.setIdentityPoolId("us-east-1:xxxxxx-xxxx-xxxxx-xxxx-xxxxxxxxx");
HashMap<String, String> providerTokens = new HashMap<String, String>();
providerTokens.put(<developer provider name>,<some identifier backend>);
String token = result.getToken();
System.out.println(token);
}catch (Exception e) {
System.out.println(e.getMessage());
}
And it always fails in catch.

I only have to attach the AmazonCognitoDeveloperAuthenticatedIdentities policy to the user with whom I connect to Amazon and that's it.
amazon Identity and Access Management console

AccessDenied in this case points to that the policies on the IAM user/role do not allow the action you are trying to do. If you have any other questions please refer our developer guide or feel free to post on our forum.

Related

Using IAM to connect to AWS s3 without credentials in Java

I am new to AWS. I am trying to connect to AmazonS3 using IAM role. I am not using secret keys here. Changes have been done at AWS side regarding IAM.
I have to create AmazonS3 client object. I tried to create object by following code:
public AmazonS3 AmazonS3Provider() {
AmazonS3ClientBuilder.defaultClient();
}
But it is returning :
"status":500,"exception":"AmazonS3Exception","message":"Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied;
Next, I tried to connect AWS s3 using AWSSecretsManagerClient using the following code:
public AmazonS3 AmazonS3Provider() {     
return (AmazonS3) AWSSecretsManagerClientBuilder.defaultClient();
}
But it was throwing error that AWSSecretsManagerClient object cannot be cast to AmazonS3.
Also, I tried to build client object using the following code:
AWSCredentials credentials;
try {
credentials = new ProfileCredentialsProvider().getCredentials();
} catch (Exception e) {
throw new AmazonClientException(
"Cannot load the credentials from the credential profiles file.", e);
}
return AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(s3EndPoint)
.build();
But is throwing AmazonClientException.
Can someone guide me how to build client object using IAM role.
IAM access key and secret key (AWS credential) path locations are stored in environment variable. I was able to create client object using WebIdentityTokenCredentialsProvider with the following code:
AmazonS3 client = AmazonS3ClientBuilder.standard()
.withCredentials(WebIdentityTokenCredentialsProvider.create())
.withRegion("Region-name")
.build();

Downloading video from AWS S3 using Cognito identity pool for authentication - Access denied

I would like to download a video file from AWS S3 using Cognito identity pool for authentication. I created a identity pool role in AWS and added it to my code. Unfortunately I get the error 403 (access denied).
My code looks like this:
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
activity,
"eu-xxxxxx-x:xxxxxxx-xxx-xxxx-xx-xxxx",
Regions.EU_XXXXXX_X // Region
);
s3Client = new AmazonS3Client(credentialsProvider, RegionUtils.getRegion("eu-xxxxxx-x"));
TransferUtility transferUtility =
TransferUtility.builder()
.context(activity)
.s3Client(s3Client)
.build();
TransferNetworkLossHandler.getInstance(activity);
TransferObserver downloadObserver =
transferUtility.download(BUCKETNAME,
"videos/example.mp4",
new File(activity.getFilesDir(), "example.mp4"));
Do you have any idea what configuration is required on AWS to make a download possible?

AWS Role vs. Keys

AWS Roles are meant for services which requires access to AWS Services e.g. S3 etc. using temporary credentials. These are done using STS. This is useful when a user/application from one account needs access to a different account-owned resources on a temporary-basis.
However, STS will only issue a temporary credentials when the credentials are passed using Profile properties. At least that's what the code provided by AWS implies anyway
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
import com.amazonaws.services.securitytoken.model.AssumeRoleResult;
import com.amazonaws.services.securitytoken.model.Credentials;
public class MakingRequestsWithIAMTempCredentials {
public static void main(String[] args) {
String clientRegion = "*** Client region ***";
String roleARN = "*** ARN for role to be assumed ***";
String roleSessionName = "*** Role session name ***";
String bucketName = "*** Bucket name ***";
try {
// Creating the STS client is part of your trusted code. It has
// the security credentials you use to obtain temporary security credentials.
AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
.withCredentials(new ProfileCredentialsProvider())
.withRegion(clientRegion)
.build();
// Obtain credentials for the IAM role. Note that you cannot assume the role of an AWS root account;
// Amazon S3 will deny access. You must use credentials for an IAM user or an IAM role.
AssumeRoleRequest roleRequest = new AssumeRoleRequest()
.withRoleArn(roleARN)
.withRoleSessionName(roleSessionName);
AssumeRoleResult roleResponse = stsClient.assumeRole(roleRequest);
Credentials sessionCredentials = roleResponse.getCredentials();
// Create a BasicSessionCredentials object that contains the credentials you just retrieved.
BasicSessionCredentials awsCredentials = new BasicSessionCredentials(
sessionCredentials.getAccessKeyId(),
sessionCredentials.getSecretAccessKey(),
sessionCredentials.getSessionToken());
// Provide temporary security credentials so that the Amazon S3 client
// can send authenticated requests to Amazon S3. You create the client
// using the sessionCredentials object.
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.withRegion(clientRegion)
.build();
// Verify that assuming the role worked and the permissions are set correctly
// by getting a set of object keys from the bucket.
ObjectListing objects = s3Client.listObjects(bucketName);
System.out.println("No. of Objects: " + objects.getObjectSummaries().size());
}
catch(AmazonServiceException e) {
// The call was transmitted successfully, but Amazon S3 couldn't process
// it, so it returned an error response.
e.printStackTrace();
}
catch(SdkClientException e) {
// Amazon S3 couldn't be contacted for a response, or the client
// couldn't parse the response from Amazon S3.
e.printStackTrace();
}
}
}
The above code will only work without providing some credentials. So my question is, how is Role useful here when I can just simply use access/secret key ?
Exactly the point you mentioned that the credentials are temporary is one of the many reasons why IAM roles are the recommended approach.
A role can be applied to AWS services as well as resources, for example an EC2 instance can have a role attached with AWS automatically rotating these. Additionally you can use STS to assume a role as role, this can be assumed from an IAM user, a role or a federated user.
You should try to avoid using IAM users where possible, there are some usecases such as signed URLs (where you would like it to last more than a few hours) as well as in an on-premise location. If you must use an IAM key you should make sure to rotate the key frequently.
For more information take a look at the IAM Identities (users, groups, and roles) and Security best practices in IAM pages.

How do I deploy my AWS Secret Manager retrieval code in production with AWS CLI?

I have written some code to retrieve my secrets from the AWS Secrets Manager to be used for further processing of other components. In my development environment I configured my credentials using AWS CLI. Once the code was compiled I am able to run it from VS and also from the exe that is generated.
Here is the code to connect to the secrets manager and retrieve the secrets
public static string Get(string secretName)
{
var config = new AmazonSecretsManagerConfig { RegionEndpoint = RegionEndpoint.USWest2 };
IAmazonSecretsManager client = new AmazonSecretsManagerClient(config);
var request = new GetSecretValueRequest
{
SecretId = secretName
};
GetSecretValueResponse response = null;
try
{
response = Task.Run(async () => await client.GetSecretValueAsync(request)).Result;
}
catch (ResourceNotFoundException)
{
Console.WriteLine("The requested secret " + secretName + " was not found");
}
catch (InvalidRequestException e)
{
Console.WriteLine("The request was invalid due to: " + e.Message);
}
catch (InvalidParameterException e)
{
Console.WriteLine("The request had invalid params: " + e.Message);
}
return response?.SecretString;
}
This code pulls credentials from the AWS CLI but when I try to run this code in another PC, it gives an IAM security error as expected, because it cannot figure out what the credentials are to connect to the secret manager.
What would be the best approach to deploy such a configuration in production? Would I need to install and configure AWS CLI in each and every deployment?
If you're deploying the code in AWS you can use IAM Role, with a policy that allows getting secrets from Secret Manager, and attach this role in EC2 or ECS, etc
If you are in a corporate environment with existing authentication infrastructure in place, you probably want to look at identity federation solutions to use with AWS.

DynamoDBLocal Fails on Credentials

DynamoDBLocal is rejecting my credentials in spite of the documentation indicating that valid credentials are unnecessary:
The AWS SDKs for DynamoDB require that your application configuration specify an access key value and an AWS region value...these do not have to be valid AWS values in order to run locally.
In this case, I've set up my credentials ~/.aws/credentials as:
[default]
aws_access_key_id = BogusAwsAccessKeyId
aws_secret_access_key = BogusAwsSecretAccessKey
run DynamoDBLocal using:
java -Djava.library.path=./DynamoDBLoc_lib -jar DynamoDBLocal.jar
checked that it's working by hitting http://localhost:8000/shell/
then run my test Java app:
DefaultAWSCredentialsProviderChain credentialProvider = new DefaultAWSCredentialsProviderChain();
AWSCredentials awsCredentials = credentialProvider.getCredentials();
log.info("creds \"{}\", \"{}\"", awsCredentials.getAWSAccessKeyId(), awsCredentials.getAWSSecretKey());
AmazonDynamoDBClient client = new AmazonDynamoDBClient(credentialProvider);
client.withEndpoint("http://localhost:8000");
client.withRegion(Regions.US_WEST_2);
dynamoDB = new DynamoDB(client);
try {
TableCollection<ListTablesResult> tables = dynamoDB.listTables();
while (tables.iterator().hasNext()) { // <-- exception thrown here
log.info(tables.iterator().next().getTableName());
}
} catch (Exception e) {
log.error("", e);
}
which results in this output:
creds "BogusAwsAccessKeyId", "BogusAwsSecretAccessKey"
com.amazonaws.AmazonServiceException: The security token included in the request is invalid. (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: UnrecognizedClientException
Any thoughts on why it is concerned with the validity of the credentials?
In your code, you are calling withRegion() after calling setEndpoint(). The call to withRegion() is setting the endpoint to DynamoDB's us-west-2 endpoint and that's why your authentication is failing (because it's actually going to the DynamoDB us-west-2 region). Remove the withRegion() line.