Springboot with AWS SNS - amazon-web-services

Actually Iam trying to set email subscription to SNS topic in AWS through springboot and publish the message to SNS topic. But facing issue in configuring the AWS access key and secret key. Do I need to create a separate IAM user for accessing SNS or it is fine to have a IAM user already created with administrator access to SNS topic. Below is the configuration file I created.
#Configuration
public class AmazonSNSConfiguration {
#Bean
#Primary
public AmazonSNSClient amazonSNSClient() {
return (AmazonSNSClient) AmazonSNSClientBuilder
.standard()
.withRegion(Regions.US_EAST_1)
.withCredentials(
new AWSStaticCredentialsProvider(
new BasicAWSCredentials(
"**********",
"***********"
)
)
)
.build();
}
}

When working with Spring BOOT and the Java SNS V2 API, you can create an IAM role that has a policy to use SNS.
Also, there is no reason to Hard Code the key creds in the Java code. You can create an SNSClient object like this:
Region region = Region.US_WEST_2;
SnsClient snsClient = SnsClient.builder()
.region(region)
.build();
This code assumes you have set the creds in a file named credentials located in .aws. See this doc (under heading Configure credentials) for more information:
Get started with the AWS SDK for Java 2.x
Here is an AWS developer tutorial that steps you through How To create a Spring BOOT app that uses the SNS service to create a Sub/Pub app:
Creating a Publish/Subscription Spring Boot Application

Related

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?

Spring boot application can't find aws credentials from any credentials chain

I'm trying to migrate Several spring boot services to EKS and they can't retrieve aws credentials from credentials chain and pods are failing with following error: Unable to load credentials from any of the providers in the chain AwsCredentialsProviderChain
These are what I've tried so far:
I'm using Web identity token from AWS STS for credentials retrieval.
#Bean
public AWSCredentialsProvider awsCredentialsProvider() {
if (System.getenv("AWS_WEB_IDENTITY_TOKEN_FILE") != null) {
return WebIdentityTokenCredentialsProvider.builder().build();
}
return new DefaultAWSCredentialsProviderChain();
}
#Bean
public SqsClient sqsClient(AWSCredentialsProvider awsCredentialsProvider) {
return SqsClient
.builder()
.credentialsProvider(() -> (AwsCredentials) awsCredentialsProvider.getCredentials())
.region(Region.EU_WEST_1).build();
}
#Bean
public SnsClient snsClient(AWSCredentialsProvider awsCredentialsProvider) {
return SnsClient
.builder()
.credentialsProvider(() -> (AwsCredentials) awsCredentialsProvider.getCredentials())
.region(Region.EU_WEST_1).build();
}
The services also have aws-java-sdk-sts maven dependency packaged.
IAM role for the services is also fine and AWS_WEB_IDENTITY_TOKEN_FILE is a also automatically created within pod after each Jenkins build based on K8s manifest file.
From pod I can make GET and POST request to SNS and SQS without any problem.
Problem was fixed.
Main issue was conflicting AWS SDK BOM version with individual models. Also previous version of BOM I was using wasn't supporting AWS SDK v2.x .
These are the main take aways from the issue:
AWS SDK authenticate services using credentials provider chain . The default credential provider chain of the AWS SDK for Java 2.x searches for credentials in your environment using a predefined sequence.
1.1 As of AWS SDK for Java 2.x Web identity token from AWS STS is within default provider chain.
1.2 As long as using v2 of the SDK and having the STS dependency makes explicit configuration of Web identity token redundant.
1.3 Make sure candidate service is using AWS SDK v2 as it’ll reduce the configuration code to minimum.
If a candidate service using AWS SDK v1 following configuration should be added as Web identity token isn’t in default provider chain for v1.
#Bean
public AWSCredentialsProvider awsCredentialsProvider() {
if (System.getenv("AWS_WEB_IDENTITY_TOKEN_FILE") != null) {
return WebIdentityTokenCredentialsProvider.builder().build();
}
return new DefaultAWSCredentialsProviderChain();
}
Last but not least try to use try to use latest AWS SDK BOM dependency . (currently all modules have the same version, but this may not always be the case)
You should have roleArn, sessionname and token details in the identity token cred provider build.
Try this
return WebIdentityTokenCredentialsProvider.builder()
.roleArn(System.getenv("AWS_ROLE_ARN"))
.roleSessionName(System.getenv("AWS_ROLE_SESSION_NAME"))
.webIdentityTokenFile(System.getenv("AWS_WEB_IDENTITY_TOKEN_FILE"))
.build();
than just returning as return WebIdentityTokenCredentialsProvider.builder().build();
You can try to create the file:
Windows: C:\Users[username].aws\config
Mac: /Users/[username]/.aws/config
Linux: /home/[username]/.aws/config
and add an AWS credential to it.
Ex:
[default]
aws_access_key_id = key_value
aws_secret_access_key = secret_value

Get secrets from AWS Secret manager without passing access key and secret key from config

I am using AWS Secret Manager Service to retrieve some confidential information like SMTP details or connection strings. However, to get secret value from AWS Secret Manager Service it seems like we need to pass the Access key and secret key apart from which secret we want to retrieve. So I am maintaining those values in config file.
public AwsSecretManagerService(IOptions<AwsAppSettings> settings)
{
awsAppSettings = settings.Value;
amazonSecretsManagerClient = new AmazonSecretsManagerClient
(awsAppSettings.Accesskey, awsAppSettings.SecretKey, RegionEndpoint.GetBySystemName(awsAppSettings.Region));
}
public async Task<SecretValueResponse> GetSecretValueAsync(SecretValueRequest secretValueRequest)
{
return _mapper.Map<SecretValueResponse>(await amazonSecretsManagerClient.GetSecretValueAsync(_mapper.Map<GetSecretValueRequest>(secretValueRequest)));
}
So I am thinking I am kind of defeating the whole purpose of using secret manager by maintaining the AWS credentials in app settings file. I am wondering what is the right way to do this
It is not a good practice to pass or add AWS credentials of an IAM User (access key and secret access key) in the code.
Instead, don't pass it and update your code as follows:
amazonSecretsManagerClient = new AmazonSecretsManagerClient
(RegionEndpoint.GetBySystemName(awsAppSettings.Region));
Question: Then how would it access the AWS services?
Answer: If you are going to execute your code on your local system, install and configure AWS CLI instead of passing AWS credentials via CLI or Terminal, it will use those AWS configured credentials to access the AWS services.
Reference for AWS CLI Installation: Installing the AWS CLI
Reference for AWS CLI Configuration: Configuring the AWS CLI
If you are going to execute your code on an AWS service (e.g., EC2 instance), attach an IAM role with that AWS resource (e.g., EC2 instance) having sufficient permissions, it will use that IAM role to access the AWS services.

How to set aws-sdk credentials using Elastic Beanstalk?

I'm running an express app in Elastic Beanstalk and in one route I'm using the aws-sdk to publish a notification to sns.
This works when running locally, but in the Elastic Beanstalk environment how would/could I set up the credentials 'myprofile'?
router.post('/publish', async (req, res) => {
var AWS = require('aws-sdk')
AWS.config.update({region: 'us-east-2'})
// myprofile exists locally, but how do I deal with this in the elastic beanstalk environment?
var credentials = new AWS.SharedIniFileCredentials({profile: 'myprofile'})
AWS.config.credentials = credentials
//...more stuff
})
You can use IAM instance profile to provide permissions to your ec2 instance, so when your application loads the SDK, the credentials passed will be automatically loaded.
Check this link https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts-roles.html - what you will need is the instance profile. In order to create a instance profile go to the IAM console > Roles, then choose the service EC2 as a service that can assume this role. Then attach the policies that your application needs calling (SNS stuff).
On the beanstalk settings, under security, you will be able to set the IAM instance profile that you just created - so the instances on this environment should have the role associated with it.
Your code should look like then:
router.post('/publish', async (req, res) => {
var AWS = require('aws-sdk')
AWS.config.update({region: 'us-east-2'})
//...more stuff
})
Also check if you can require and set the region outside of the controller ;)

Getting credentials for AWS V4 Signing when running on a EC2 instance with IAM role

I have the following AWS Javascript SDK code, to sign requests for AWS Elasticsearch:
var signer = new AWS.Signers.V4(req, 'es');
signer.addAuthorization(creds, new Date());
I need credentials (creds) for the addAuthorization() call. When running locally I do this:
var creds = AWS.config.credentials;
But this does not work on an EC2 instance running with an IAM role.
My question is how to get the credentials object to do the manual signing?
Or, if there is another way to V4 sign with running under IAM, what is it?
Have you tried this?
var creds = new AWS.EnvironmentCredentials('AWS');