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)