You can use an approach that does not rely on Amazon AWS credentials directly in your code, but uses a credential that you generate.
Create a unique token for each customer. This token will be used for the customer to make requests to a system of his or her own. You can revoke this customer token at the time you think best, if the contract is terminated or you suspect that the token has leaked.
Let’s say the token generated for your X client is d17ce9bd-98d2-4f98-add3-f0af4d49620b
. With this token in hand, when you need to upload some 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 this request will return a signed Amazon AWS URL to which the application must upload, with a validity determined by you.
The code to generate the URL will be more or less 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);
Since the URL has validity, if it happens to leak, it will become useless after the expiration date. This approach is interesting because you don’t need to distribute your credentials along with your code.
The complete documentation of 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)