How to securely store AWS credentials in a Java application?

0

I have a Java Desktop application that is distributed to clients.

I now need to send data from this application to Amazon S3. For this you need to set AWS credentials ( accessKeyId and secretKey ).

Among the possible options in documentation (variables environment, file with data on the machine and file properties), at first none of them protects the application user.

I have seen in other languages the use of RSA encryption where the key to encrypt the data was compiled into the application itself. However, the Java binary is easily "decompiled", which makes this method unfeasible.

In this scenario, how can I securely distribute / store AWS credentials for use by my Java application?

    
asked by anonymous 13.03.2017 / 14:16

2 answers

1

You can use an approach that does not rely on Amazon AWS credentials straight from your code, but uses a credential you generate.

Create a unique token for each client. This token will be used for the client to make requests to a system of your own. You can revoke this client token at a time that you think is best if the contract is terminated or you suspect the token has leaked.

Let's say that the token generated for your client X is d17ce9bd-98d2-4f98-add3-f0af4d49620b . With this token in hand, when you need to upload a file to Amazon S3, the application will access a URL, say https://meu.sistema.com.br/getUploadUrl?token=d17ce9bd-98d2-4f98-add3-f0af4d49620b , and the return of that request will return a signed Amazon AWS URL to which the application should upload, with a validity determined by you.

The code to generate the URL will look something like the code below:

System.out.println("Generating pre-signed URL.");
java.util.Date expiration = new java.util.Date();
long milliSeconds = expiration.getTime();
milliSeconds += 1000 * 60 * 60; // Adiciona 1 hora.
expiration.setTime(milliSeconds);

GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey);
generatePresignedUrlRequest.setMethod(HttpMethod.PUT); 
generatePresignedUrlRequest.setExpiration(expiration);

URL url = s3client.generatePresignedUrl(generatePresignedUrlRequest); 

Because the URL is valid, if it accidentally leaks, it will become useless after the expiration time. This approach is interesting because you do not need to distribute the credentials along with your code.

The complete documentation on how to generate these URLs is in the official Amazon AWS documentation, at Upload an Object Using a Pre-Signed URL (AWS SDK for Java)

    
13.03.2017 / 14:59
1

As @eduardosouza, I also recommend that you do not store these keys in your code, or even in bundled files. Your application probably does not need to store these credentials, but the most secure way depends on where your application is running:

  • In EC2 or Lambda all you have to do is assign an IAM Role to the instance or function that the java SDK automatically finds temporary credentials through the metadata service.
  • Outside of AWS, just like on your development machine, you can use environment variables to configure access.
  • Even if your application accesses AWS on behalf of a client, where some applications store keys, it is safer to use IAM Roles. In this case, consider Amazon Cognito to manage this authentication and authorization process automatically.

Related documentation links:

Roles of IAM

Credentials in the Java SDK

Amazon Cognito

    
17.03.2017 / 17:50