How do I authenticate to Azure Storage from Java using MSI? - java

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.

Related

Embedding AWS IAM credentials in the code with the Java SDK

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, .

How to securely reference a .json private key file from a Java app running on Google Cloud

I'm working on an app that will run on the Google Cloud Platform, and it needs to authenticate to the Google Admin 'Directory' SDK. The recommended approach that everyone (including Google) seems to suggest, is to create a service account in the Google Cloud Platform, and use the private key credentials for the service account to authenticate within the app that's running on Google Cloud Platform. Here is Google's recommended approach:
Perform G Suite Domain-Wide Delegation of Authority
To summarise the approach, for a Java app it requires the following:
Upload the private key file to a file location available application (the private key file can be JSON instead of P12 as suggested in the above guide)
Programatically load the file in the application, and use its credentials to authenticate
My question is this - if the file is directly uploaded to the src/main/resources folder for the application that runs on the Google Cloud Platform, is this is a significant security risk? How easy would it be for a hacker to access the file? If it's a risk, then what is a secure alternative to this approach?
For this answer I will assume that you are running on Google Compute Engine. The same type of answer will apply to App Engine, Containers, Kubernetes and Cloud Functions.
My question is this - if the file is directly uploaded to the
src/main/resources folder for the application that runs on the Google
Cloud Platform, is this is a significant security risk?
This is a security risk and is a very poor security practice. Numerous prominent companies have been breached with credentials stored in source code.
How easy would it be for a hacker to access the file?
Unknown. There are many different types of breaches. If a hacker obtains shell access to your instance you are in serious trouble. If a hacker obtains root shell access, they can do almost anything they want.
If it's a risk, then what is a secure alternative to this approach?
Best practices for security regarding credentials: do not store credentials in your source code or on your computing resources.
Normally you would access your credentials from Compute Engine Metadata server. These credentials are created by Google Cloud when your instance starts up. You can control these permissions in the Google Console under "Cloud API access scopes" OR via a service account that you specify for the VM.
However, with G-Suite, you need to create delegated credentials. I do not recommend mixing the credentials that are used by your VM with the credentials used for G-Suite. This means that you still need access to credentials in Json format (or P12 for legacy applications).
Since best security practices are to not store these credentials in source code or on the instance, you need to store them securely someplace else that you can access securely. One option is Google Cloud Storage. Assign a Cloud Storage read-only scope to your instance so that you can read the credentials Json file from Cloud Storage. Read the credentials using your SDK directly into memory and do not involve disk operations or utilities such as gsutil. I recommend that you create a seperate bucket for privileged files such as credentials.
Note that you are using several credentials. 1) the credentials stored in Google's metadata server. 2) the credentials that you download from Cloud Storage. 3) the delegated credentials that you create to access G-Suite and other Google applications.
The first set of credentials (Application Default Credentials - ADC) are used for normal cloud access including reading the second set of credentials from Cloud Storage. The third set are created in your software.
The credentials that you store on Cloud Storage do not need any privileges except domain wide delegation. The privileges are added via scopes when you create the G-Suite credentials (credentials #3).
Note: Do not store the email address used for delegated credentials in your source code. Store this in another Json file on Cloud Storage.

AWS Cognito GetCredentialsForIdentity

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)

Secure way to store and use Amazon Access key for Android

I am trying to build an application for android that uses Amazon SimpleDB. I have viewed the source code of the example code provided by Amazon. However in the demo, the credentials are just stored in a Constants.java and I believe this method is not secure at all as potentially there are people that could decompile the apk to expose the credentials even with Proguard on.
Therefore i went to read up on Amazon article regarding this and I could not quite understand as I am not very familiar with cryptography in android/java.
How am I supposed to actually allow access to Amazon SimpleDB from my application while keeping the access key safe from external parties?
Edit 1:
I want to use the application to retrieve data from the SimpleDB, showing in listview. For example like a simple review on food and other users will be able to retrieve the same review that other users posted. Maybe if the user wants to post a review, they would require to sign up an account and log in.
AWS offers a couple of solutions for delivering credentials to the device outside of hard coding them, one or both may meet your specific needs:
Token Vending Machine. AWS offers example TVMs for both Anonymous and User Authentication that can be customized to meet your needs.
Web identity federation which uses identities from Facebook, Google, and Amazon.
Our samples repository includes samples for integrating with both of these technologies, though not specifically in the SimpleDB example.
There is no foolproof way to do this. Whichever way we do, somebody taking your APK can potentially reverse engineer and crack the password (You make it difficult by obfuscating the code, but it is just making difficult and not foolproof).
If your app requires users to login (with some credential from your backend or using openid), then use this to let users access your server. Then on the server code, you can provide the AWS credentials using IAM Roles (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html).
So your web (REST) API access is allowed by using user-provided password and your server code gets the access by IAM roles. This is the most secure way.
If you dont want to have your server / backend, then there is no real foolproof way.
Answer from #Bob above is precise how to achieve this:
https://stackoverflow.com/a/21839911/2959100

Google App Engine : Read from Google Cloud Storage

I have a Flex/Java application on Google App Engine and all I want is to load large images from Google Cloud Storage using URLRequest in Flex. I'm sure this is simple but I can't get it to work. I will manually upload the images using the Google APIs Console so I don't need to write anything from the App. The images can not be public.
I'm not 100% sure how to access the file so this may be the problem. I tried these:
"/gs/mybucket/myimage.jpg" : not found
"/mybucket/myimage.jpg" : not found
"http://commondatastorage.googleapis.com/mybucket/myimage.jpg" : denied
I added myappid#appspot.gserviceaccount.com in the Team tab in Google APIs Console with Can View permission and I used GSUtil to get and set ACLs on both mybucket and myimage.jpg to add a READ permission for myappid#appspot.gserviceaccount.com but that didn't help.
What am I doing wrong?
I'm not really sure how flex works or how it is trying to access the blobs.
However, if you want to respond to a http request with the content of a Google Storage object then you can use the serve method.
https://developers.google.com/appengine/docs/java/blobstore/overview#Serving_a_Blob
Are you authorizing the URLRequest call with an OAuth token? If not, then even though the request is initiated from an app engine app, it'll look to Google Cloud Storage like an unauthenticated, public read. I don't know if flex has a trace option but if there's a way to examine the request details, I'd check to see if you're setting up the proper authentication.
If it turns out to be too difficult to get flex to play nicely with OAuth, you could also use signed URLs (a.k.a. query string authenticated URLs). This gives you the ability to create a URL with a special signature that implicitly conveys your authorization but only people with that link can access the object. The object's ACL can be be set to disallow public access but your signed URLs will be able to read the object. You can also time limit a signed URLs, if you like. Here's the documentation on how to use this technique.

Categories