Skip to main content

Building a Cloud-Native Spring Boot App on EKS with Secure S3 Access

· 3 min read
Byju Luckose

In this blog post, we'll walk through building a cloud-native Spring Boot application that runs on Amazon EKS (Elastic Kubernetes Service) and securely uploads files to an Amazon S3 bucket using IAM Roles for Service Accounts (IRSA). This allows your microservice to access AWS services like S3 without embedding credentials.

Why IRSA?

Traditionally, applications used access key/secret pairs for AWS SDKs. In Kubernetes, this is insecure and hard to manage. IRSA allows you to:

  • Grant fine-grained access to AWS resources
  • Avoid storing AWS credentials in your app
  • Rely on short-lived credentials provided by EKS

Overview

Here's the architecture we'll implement:

  1. Spring Boot app runs in EKS
  2. The app uses AWS SDK v2
  3. IRSA provides access to S3

Step 1: Create an IAM Policy for S3 Access

Create a policy named S3UploadPolicy with permissions for your bucket:


{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}

Step 2: Create an IAM Role for EKS

Use eksctl to create a service account and bind it to the IAM role:


eksctl create iamserviceaccount \
--name s3-uploader-sa \
--namespace default \
--cluster your-cluster-name \
--attach-policy-arn arn:aws:iam::<ACCOUNT_ID>:policy/S3UploadPolicy \
--approve \
--override-existing-serviceaccounts

Step 3: Spring Boot Setup

Add AWS SDK Dependency


<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
</dependency>

Java Code to Upload to S3


import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

import java.io.InputStream;

@Service
public class S3Uploader {

private final S3Client s3Client;

public S3Uploader() {
this.s3Client = S3Client.builder()
.region(Region.EU_CENTRAL_1)
.credentialsProvider(DefaultCredentialsProvider.create())
.build();
}

public void uploadFile(String bucketName, String key, InputStream inputStream, long contentLength) {
PutObjectRequest putRequest = PutObjectRequest.builder()
.bucket(bucketName)
.key(key)
.build();

s3Client.putObject(putRequest, RequestBody.fromInputStream(inputStream, contentLength));
}
}

DefaultCredentialsProvider automatically picks up credentials from the environment, including those provided by IRSA in EKS.

Step 4: Kubernetes Deployment

Define the Service Account (optional if created via eksctl):


apiVersion: v1
kind: ServiceAccount
metadata:
name: s3-uploader-sa
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/<IRSA_ROLE_NAME>


apiVersion: apps/v1
kind: Deployment
metadata:
name: s3-upload-microservice
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: s3-upload-microservice
template:
metadata:
labels:
app: s3-upload-microservice
spec:
serviceAccountName: s3-uploader-sa
containers:
- name: app
image: 123456789012.dkr.ecr.eu-central-1.amazonaws.com/s3-uploader:latest
ports:
- containerPort: 8080

Final Thoughts

You now have a secure, cloud-native Spring Boot application that uploads to S3 using best practices with AWS and Kubernetes. IRSA removes the need for credentials in your code and aligns perfectly with GitOps, DevSecOps, and Zero Trust principles.

Let your microservices speak AWS securely — the cloud-native way!