I am using the Java AWS IoT SDK, and i'm I'm stuck with a problem whereby I have to embed my AWS IAM access key and secret key credentials into my Java application code on my devices.
The credentials are just used initially to create the client in my code, then X.509 certificates are used after for the MQTT authentication and communication. .
I've heard of a way to avoid the need of embedding IAM credentials in the code by using AWSCredentialsProvider with tokens etc. However, I don't see any actual examples of how to achieve this without embedding credentials. Below is a snippet of my code showing how I create the client object using the credentials. Thanks.
String AWS_ACCESSKEY = "AKXXXXXXXXXXXXX"; // not real key
String AWS_SECRETKEY = "ABCXXXXXXXXXXXXXXXXXXXXXX"; // not real key
Regions AWS_REGION = Regions.US_EAST_2;
AWSIot client = AWSIotClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(new
BasicAWSCredentials(AWS_ACCESSKEY, AWS_SECRETKEY))).withRegion(AWS_REGION).build();
You can pass this credentials to normal application.properties file.
You just need to do 2 things.
Create public class AwsCredentials with annotations #ConfigurationProperties and #Configuration.
Pass Your access and secret to application.properties file
You can read more in this tutorial : click
Next when You want to use this properties in builder You need to call it like this:
AWSIot client = AWSIotClientBuilder.standard()
.withCredentials(
new AWSStaticCredentialsProvider(
new BasicAWSCredentials(
this.awsCredentials.getAccessKey(),
this.awsCredentials.getSecretKey()
)
)
)
.withRegion(AWS_REGION)
.build();
PS. You can export region to properties too.
You can use temporary security credentials instead of actual access keys. Do check this link.
https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html
To get credentials to access AWS IoT (or other services) you could get temporary security credentials from Cognito Identity Pool. You can find the simplest way and steps needed to do get credentials here.
Also consider that, to get idToken (JWT) from Cognito user pool and then access and secret token Cognito Identity pool, you need to use AWS Java SDK in your mobile or desktop application. You can find more information about AWS JAVA SDK here and some samples here, here, .
Related
The Amazon documentation says to use:
AwsBasicCredentials awsCreds = AwsBasicCredentials.create(
"your_access_key_id",
"your_secret_access_key");
S3Client s3 = S3Client.builder()
.credentialsProvider(StaticCredentialsProvider.create(awsCreds))
.build();
But that's for the S3Client, when I try to use the same structure for my AthenaClient my app won't even run and it fails to initialize.
For my application I'm grabbing the credentials from a repo with a configuration file for this app.
static #Value("${AWS_ACCESS_KEY_ID}") String amazonAccessId;
static #Value("${AWS_SECRET_ACCESS_KEY}") String amazonSecretKey;
AwsBasicCredentials awsCreds = AwsBasicCredentials.create(
"your_access_key_id",
"your_secret_access_key");
AthenaClient athenaClient = AthenaClient.builder()
.region(Region.US_WEST_2)
.credentialsProvider(StaticCredentialsProvider.create(awsCreds))
.build();
I want to provide the credentials this way so that when I push the code from my local machine the code still functions, instead of relying on my environment variables. Please tell me what I'm doing wrong, because the documentation does not.
Understand how credentials work when using the AWS SDK for Java V2 SDK. You can read about them in the AWS Java V2 Developer Guide here:
Using credentials
Specifically, read about the Credential retrieval order in that doc topic.
As far as what service you are using, it does not matter. An S3 Service Client works the same way as other Java Service clients in terms of handling creds.
The topic linked about describes this way to handle creds. As described in this topic, you can use the shared credentials and config files:
The SDK uses the ProfileCredentialsProvider to load credentials from the [default] credentials profile in the shared credentials and config files.
You can create a file named credentials - as shown here:
In that file - specify your keys:
[default]
aws_access_key_id=Axxxxxxxxxxxxxxxxxxxxxxxxxxx
aws_secret_access_key=Kxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Then you can use this code to create a service client:
AthenaClient athenaClient = AthenaClient.builder()
.region(Region.US_WEST_2)
.credentialsProvider(ProfileCredentialsProvider.create())
.build();
And also - ensure you are using the correct POM in your Java project that uses Amazon Athena. See:
https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/athena
I want to connect to azure key vault using quarkus application. I have stored some secrets on azure key vault , need to connect to azure key vault (without exposing service principal secret) , retrieve the values of the secret configured in azue key vault and use that in my application. I am not getting how to achieve this. can someone help.
I never did something like that using Quarkus, but there a few ways:
1-
You'll need to authenticate and get an access token from Azure Active Directory. Then, you'll pass the token into the request to get the secret:
https://learn.microsoft.com/en-us/azure/key-vault/general/authentication-requests-and-responses
https://learn.microsoft.com/en-us/rest/api/keyvault/
2-
As another alternative, you can use an Azure Function + Key Vault Reference to get the secrets, then pass them to your Quarkus application. You can do it using Azure Functions Custom Handlers:
https://techcommunity.microsoft.com/t5/apps-on-azure/azure-functions-in-any-language-with-custom-handlers/ba-p/1942744
3-I'm not 100% sure, but I guess you can use regular java to retrieve the secrets in your quarkus app too:
https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-java
There are multiple ways to authenticate to an Azure Key Vault to choose from and not all of them need you to provide your service principal's secret. Just remember to make sure that you pass the selected Credential object to your Key Vault Secrets client when instantiating it a SecretClientBuilder:
SecretClient secretClient = new SecretClientBuilder()
.vaultUrl("<your-key-vault-url>")
.credential(new DefaultAzureCredentialBuilder().build()) // This is one of many types of credentials you can use
.buildClient();
I can't figure out how to create a BlobClient, or a StorageAccount reference using a Managed Identity (MI/MSI) in Java. Creating and using the MI to asign RBAC on the storage is straightforward, but I can't work out how to make use of this in my code.
I got this working previously with KeyVault, because I found a lot more examples online of other people doing this, and it was ultimately really simple:
MSICredentials credentials = new MSICredentials(AzureEnvironment.AZURE);
KeyVaultClient kvClient = new KeyVaultClient(credentials);
But I can't find a similar Storage class that will take the MSICredentials as parameter, nor find a way to create StorageCredentials using the MSICredentials.
Has anyone else got this working or have any bright ideas?
There is also a way for Azure Storage Account to authenticate from MSI in Java. Just in a different way from KeyVault.
It also shows in the document Azure AD Authentication for Azure Blobs and Queues now in public preview. There are three ways to authenticate for Azure Storage, see Credential in Azure Storage Java V10 Overview.
You should first get the access token with the MSI and then use TokenCredentials to authenticate. See the way that Getting a token for system assigned identity.
I am trying to use the approach outlined in the following blog article to authenticate a cognito identity to S3 from Java:
https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-4-enhanced-flow/
I have successfully implemented the developer authentication provider and can retrieve a valid OpenId token for my cognito identity. That token works in both the iOS and Android SDKs when uploading/downloading files to S3. Unfortunately, I have not been able to successfully authenticate the same identity to S3 in my Java app. Here is the code I am using:
Map<String, String> logins = new HashMap();
logins.put("cognito-identity.amazonaws.com", cognitoOpenIdToken);
GetCredentialsForIdentityRequest getCredentialsRequest =
new GetCredentialsForIdentityRequest()
.withIdentityId(cognitoIdentityId)
.withLogins(logins);
AmazonCognitoIdentityClient cognitoIdentityClient =
new AmazonCognitoIdentityClient();
GetCredentialsForIdentityResult getCredentialsResult =
cognitoIdentityClient.getCredentialsForIdentity(getCredentialsRequest);
The call to getCredentialsForIdentity fails with the error "com.amazonaws.AmazonClientException: Unable to load AWS credentials from any provider in the chain". This method is documented as a public API that does not require authentication. However, I have noticed that the call succeeds if done from an environment where there are valid IAM credentials configured in the system variables. It fails in environments where that is not the case.
Am I missing something simple?
Have you tried initializing the AmazonCognitoIdentityClient in following manner?
new AmazonCognitoIdentityClient(new AnonymousAWSCredentials());
Otherwise, by design of AWS Java SDK, the service clients look for AWS credentials, because same client can be used for accessing Authenticated APIs as well.
maybe is not that you need to be as another IAM user... but that the user that is running you method has a "deny" on sts:* (or some other actions that you need)
I created IAM role associated with the EC2 instance on AMAZON and as I understood from the amazon docs I can retrieve temp AWS credentials and do some stuff with that.I read that the EC2 metadata api(which is used internally by InstanceProfileCredentialsProvider) is only available for calls from within the instance, not from the outside world.
What this means? How can I get secure communication with AWS when develop app on local tomcat server?
You should use the The default provider chain and EC2 instance profiles. In your case, since you've already added the role to your instance, and considering you are using the Java SDK, you need to call:
InstanceProfileCredentialsProvider mInstanceProfileCredentialsProvider = new InstanceProfileCredentialsProvider();
AWSCredentials credentials = mInstanceProfileCredentialsProvider.getCredentials();
Or, if you are using a specific service, such as AWS S3, you can directly call:
AmazonS3 s3Client = new AmazonS3Client(new DefaultAWSCredentialsProviderChain());
For more information: http://docs.aws.amazon.com/java-sdk/latest/developer-guide/java-dg-roles.html
And just a reminder: you should NEVER leave your Access Key and Key Secret in your code.
It appears that your situation is:
You have an application running on a computer that is not an Amazon EC2 instance
You wish to give that application the ability to make API calls to AWS services
In this situation, it is not appropriate to use an IAM role.
Instead, you will need to provide your application with a set of valid AWS credentials (Access Key + Secret Key). This can be done by creating an IAM User, copying the credentials provided and placing them in your application's configuration.
When making an API call from an application that uses an AWS SDK, the SDK will automatically look in various location for valid credentials. In the case of Java, the DefaultAWSCredentialsProviderChain that looks for credentials in this order:
Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (RECOMMENDED since they are recognized by all the AWS SDKs and CLI except for .NET), or AWS_ACCESS_KEY and AWS_SECRET_KEY (only recognized by Java SDK)
Java System Properties - aws.accessKeyId and aws.secretKey
Credential profiles file at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI
Credentials delivered through the Amazon EC2 container service if AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" environment variable is set and security manager has permission to access the variable,
Instance profile credentials delivered through the Amazon EC2 metadata service
Therefore, store the credentials in one of the first three options.