Full Stack • Java • System Design • Cloud • AI Engineering

AWS CLI, AWS SDK & Spring Boot Integration

In this article, we will implement AWS integration with Spring Boot using the **AWS SDK for Java 2.x**.

Introduction

In the previous AWS articles, we understood AWS Regions, Availability Zones, IAM, billing, and account basics.

Now we will learn how Java/Spring Boot applications communicate with AWS services.

In real-time projects, developers usually interact with AWS in two ways:

  1. AWS CLI - Used by developers, DevOps engineers, and automation scripts.
  2. AWS SDK - Used inside applications like Java, Spring Boot, Python, Node.js, etc.

In this article, we will implement AWS integration with Spring Boot using the AWS SDK for Java 2.x.


What You Will Learn

By the end of this article, you will understand:

  • What is AWS CLI?
  • What is AWS SDK?
  • Difference between AWS CLI and AWS SDK
  • How to configure AWS credentials
  • How Spring Boot connects with AWS
  • How to upload files to Amazon S3 using Spring Boot
  • Best practices for credentials and security
  • Real-time architecture flow

High Level Architecture

flowchart TD
    A[Developer Machine] --> B[AWS CLI]
    A --> C[Spring Boot Application]

    B --> D[AWS Account]
    C --> E[AWS SDK for Java]

    E --> F[Amazon S3]
    E --> G[Amazon DynamoDB]
    E --> H[Amazon SQS]
    E --> I[Amazon SNS]

    D --> F

1. What is AWS CLI?

AWS CLI stands for Amazon Web Services Command Line Interface.

It allows us to interact with AWS services using terminal commands.

Example:

aws s3 ls
aws ec2 describe-instances
aws iam list-users

Instead of opening AWS Console manually, we can use CLI commands to automate AWS tasks.


Common AWS CLI Use Cases

Use Case Example
List S3 buckets aws s3 ls
Upload file to S3 aws s3 cp file.txt s3://bucket-name/
Check EC2 instances aws ec2 describe-instances
Deploy scripts Shell scripts using AWS CLI
CI/CD automation GitHub Actions, Jenkins, GitLab

2. What is AWS SDK?

AWS SDK is a set of libraries provided by AWS to interact with AWS services from application code.

For Java applications, we use:

AWS SDK for Java 2.x

Using AWS SDK, Spring Boot applications can directly call AWS services like:

Amazon S3
Amazon DynamoDB
Amazon SQS
Amazon SNS
Amazon SES
AWS Lambda
Secrets Manager
CloudWatch

AWS CLI vs AWS SDK

Feature AWS CLI AWS SDK
Used By Developers / DevOps Application code
Access Type Terminal commands Java code
Example aws s3 ls s3Client.listBuckets()
Best For Manual tasks, automation scripts Production applications
Language Command line Java, Python, Node.js, Go, etc.

3. Real-Time Example

Assume you are building an application where users upload profile images.

The flow:

sequenceDiagram
    participant User
    participant UI
    participant SpringBoot
    participant S3
    participant DB

    User->>UI: Upload profile image
    UI->>SpringBoot: POST /api/files/upload
    SpringBoot->>S3: Upload file using AWS SDK
    S3-->>SpringBoot: Return S3 object key
    SpringBoot->>DB: Save file metadata
    SpringBoot-->>UI: Upload successful

4. Prerequisites

Before implementation, you need:

AWS Account
IAM User or IAM Role
AWS CLI installed
Java 17+
Spring Boot 3+
Maven
IDE like IntelliJ
S3 Bucket

5. Install AWS CLI

macOS

brew install awscli

Verify:

aws --version

Expected output:

aws-cli/2.x.x

Windows

Download and install AWS CLI from the official AWS website.

Then verify:

aws --version

6. Configure AWS CLI

Run:

aws configure

It will ask:

AWS Access Key ID:
AWS Secret Access Key:
Default region name:
Default output format:

Example:

AWS Access Key ID: AKIAxxxxxxxxxxxx
AWS Secret Access Key: xxxxxxxxxxxxx
Default region name: us-east-1
Default output format: json

This creates two files:

~/.aws/credentials
~/.aws/config

Credentials File

cat ~/.aws/credentials

Example:

[default]
aws_access_key_id=AKIAxxxxxxxxxxxx
aws_secret_access_key=xxxxxxxxxxxxx

Config File

cat ~/.aws/config

Example:

[default]
region=us-east-1
output=json

7. Test AWS CLI

List S3 buckets:

aws s3 ls

Check current identity:

aws sts get-caller-identity

Expected output:

{
  "UserId": "AIDA...",
  "Account": "123456789012",
  "Arn": "arn:aws:iam::123456789012:user/dev-user"
}

8. Create S3 Bucket

You can create from AWS Console or CLI.

Example:

aws s3 mb s3://codewithvenu-demo-bucket

Upload test file:

echo "Hello AWS" > hello.txt

aws s3 cp hello.txt s3://codewithvenu-demo-bucket/

List bucket files:

aws s3 ls s3://codewithvenu-demo-bucket/

9. Spring Boot Project Setup

Create Spring Boot project with:

Java 17
Spring Boot 3.x
Maven
Spring Web
Validation
Lombok optional

Project structure:

aws-springboot-demo
 ┣ src/main/java/com/codewithvenu/aws
 ┃ ┣ AwsSpringBootApplication.java
 ┃ ┣ config
 ┃ ┃ ┗ AwsS3Config.java
 ┃ ┣ controller
 ┃ ┃ ┗ FileUploadController.java
 ┃ ┣ service
 ┃ ┃ ┗ S3FileService.java
 ┃ ┗ dto
 ┃   ┗ FileUploadResponse.java
 ┣ src/main/resources
 ┃ ┗ application.yml
 ┗ pom.xml

10. Add Maven Dependencies

Update pom.xml:

<dependencies>

    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- AWS SDK S3 -->
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
        <version>2.25.60</version>
    </dependency>

    <!-- AWS SDK Auth -->
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>auth</artifactId>
        <version>2.25.60</version>
    </dependency>

    <!-- Lombok Optional -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

</dependencies>

11. Configure application.yml

server:
  port: 8080

aws:
  region: us-east-1
  s3:
    bucket-name: codewithvenu-demo-bucket

Important:

Do not store access keys directly in application.yml.

Avoid this:

aws:
  access-key: AKIAxxxx
  secret-key: xxxxx

This is not secure.


12. AWS S3 Configuration Class

Create:

src/main/java/com/codewithvenu/aws/config/AwsS3Config.java
package com.codewithvenu.aws.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

@Configuration
public class AwsS3Config {

    @Value("${aws.region}")
    private String awsRegion;

    @Bean
    public S3Client s3Client() {
        return S3Client.builder()
                .region(Region.of(awsRegion))
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build();
    }
}

How DefaultCredentialsProvider Works

AWS SDK checks credentials in this order:

flowchart TD
    A[AWS SDK Starts] --> B[Check Environment Variables]
    B --> C[Check Java System Properties]
    C --> D[Check AWS Credentials File]
    D --> E[Check ECS Task Role]
    E --> F[Check EC2 Instance Role]
    F --> G[Use Credentials]

This means locally it can use:

~/.aws/credentials

In AWS cloud, it can use:

IAM Role

That is why we should not hardcode access keys.


13. Create Response DTO

Create:

src/main/java/com/codewithvenu/aws/dto/FileUploadResponse.java
package com.codewithvenu.aws.dto;

public class FileUploadResponse {

    private String fileName;
    private String bucketName;
    private String objectKey;
    private String message;

    public FileUploadResponse(String fileName, String bucketName, String objectKey, String message) {
        this.fileName = fileName;
        this.bucketName = bucketName;
        this.objectKey = objectKey;
        this.message = message;
    }

    public String getFileName() {
        return fileName;
    }

    public String getBucketName() {
        return bucketName;
    }

    public String getObjectKey() {
        return objectKey;
    }

    public String getMessage() {
        return message;
    }
}

14. Create S3 File Service

Create:

src/main/java/com/codewithvenu/aws/service/S3FileService.java
package com.codewithvenu.aws.service;

import com.codewithvenu.aws.dto.FileUploadResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Service
public class S3FileService {

    private final S3Client s3Client;

    @Value("${aws.s3.bucket-name}")
    private String bucketName;

    public S3FileService(S3Client s3Client) {
        this.s3Client = s3Client;
    }

    public FileUploadResponse uploadFile(MultipartFile file) throws IOException {

        String objectKey = generateObjectKey(file.getOriginalFilename());

        PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(objectKey)
                .contentType(file.getContentType())
                .build();

        s3Client.putObject(
                putObjectRequest,
                RequestBody.fromBytes(file.getBytes())
        );

        return new FileUploadResponse(
                file.getOriginalFilename(),
                bucketName,
                objectKey,
                "File uploaded successfully"
        );
    }

    private String generateObjectKey(String originalFileName) {
        String timestamp = LocalDateTime.now()
                .format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

        return "uploads/" + timestamp + "-" + originalFileName;
    }
}

15. Create File Upload Controller

Create:

src/main/java/com/codewithvenu/aws/controller/FileUploadController.java
package com.codewithvenu.aws.controller;

import com.codewithvenu.aws.dto.FileUploadResponse;
import com.codewithvenu.aws.service.S3FileService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController
@RequestMapping("/api/files")
public class FileUploadController {

    private final S3FileService s3FileService;

    public FileUploadController(S3FileService s3FileService) {
        this.s3FileService = s3FileService;
    }

    @PostMapping("/upload")
    public ResponseEntity<FileUploadResponse> uploadFile(
            @RequestParam("file") MultipartFile file
    ) throws IOException {

        FileUploadResponse response = s3FileService.uploadFile(file);
        return ResponseEntity.ok(response);
    }
}

16. Main Application Class

package com.codewithvenu.aws;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AwsSpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(AwsSpringBootApplication.class, args);
    }
}

17. Run Application

Start Spring Boot:

mvn spring-boot:run

Upload file using curl:

curl -X POST http://localhost:8080/api/files/upload \
  -F "[email protected]"

Expected response:

{
  "fileName": "hello.txt",
  "bucketName": "codewithvenu-demo-bucket",
  "objectKey": "uploads/20260625103045-hello.txt",
  "message": "File uploaded successfully"
}

Verify from AWS CLI:

aws s3 ls s3://codewithvenu-demo-bucket/uploads/

18. Download File from S3

Add method in S3FileService:

public byte[] downloadFile(String objectKey) {

    return s3Client.getObjectAsBytes(builder -> builder
            .bucket(bucketName)
            .key(objectKey)
            .build()
    ).asByteArray();
}

Add controller endpoint:

@GetMapping("/download")
public ResponseEntity<byte[]> downloadFile(
        @RequestParam String key
) {
    byte[] fileContent = s3FileService.downloadFile(key);
    return ResponseEntity.ok(fileContent);
}

Test:

curl "http://localhost:8080/api/files/download?key=uploads/20260625103045-hello.txt"

19. Delete File from S3

Add service method:

public String deleteFile(String objectKey) {

    s3Client.deleteObject(builder -> builder
            .bucket(bucketName)
            .key(objectKey)
            .build()
    );

    return "File deleted successfully: " + objectKey;
}

Add controller endpoint:

@DeleteMapping("/delete")
public ResponseEntity<String> deleteFile(
        @RequestParam String key
) {
    return ResponseEntity.ok(s3FileService.deleteFile(key));
}

Test:

curl -X DELETE "http://localhost:8080/api/files/delete?key=uploads/20260625103045-hello.txt"

20. IAM Permission Required

For this demo, the application needs S3 permissions.

Minimum IAM policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ApplicationAccess",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::codewithvenu-demo-bucket",
        "arn:aws:s3:::codewithvenu-demo-bucket/*"
      ]
    }
  ]
}

Avoid giving full admin access.

Do not use:

AdministratorAccess

for application runtime.


21. Local Development Credentials

For local development, use:

aws configure

or environment variables:

export AWS_ACCESS_KEY_ID=your-access-key
export AWS_SECRET_ACCESS_KEY=your-secret-key
export AWS_REGION=us-east-1

Then run:

mvn spring-boot:run

22. Production Credentials

In production, do not use access keys.

Use IAM roles.

Example:

flowchart LR
    A[Spring Boot App on EC2/ECS/EKS] --> B[IAM Role]
    B --> C[Temporary Credentials]
    C --> D[Amazon S3]

Production options:

Platform Recommended Auth
EC2 IAM Instance Profile
ECS ECS Task Role
EKS IAM Role for Service Account
Lambda Lambda Execution Role
Local Dev AWS CLI profile

23. Multiple AWS Profiles

You can configure multiple profiles:

aws configure --profile dev
aws configure --profile prod

Use profile:

aws s3 ls --profile dev

Run Spring Boot with profile:

export AWS_PROFILE=dev
mvn spring-boot:run

24. Common Errors and Fixes

Error 1: Unable to locate credentials

Unable to load credentials from any of the providers

Fix:

aws configure
aws sts get-caller-identity

Error 2: Access Denied

software.amazon.awssdk.services.s3.model.S3Exception: Access Denied

Fix:

Check IAM permissions:

s3:PutObject
s3:GetObject
s3:DeleteObject
s3:ListBucket

Also check bucket policy.


Error 3: Wrong Region

The bucket is in this region: us-east-1

Fix:

Update:

aws:
  region: us-east-1

Error 4: Bucket Not Found

NoSuchBucket

Fix:

aws s3 ls

Check bucket name in:

aws:
  s3:
    bucket-name: your-bucket-name

25. Best Practices

Security Best Practices

Never hardcode access keys
Use IAM roles in production
Use least privilege permissions
Rotate access keys regularly
Use separate AWS accounts for dev/test/prod
Enable CloudTrail
Enable S3 bucket encryption
Block public access unless required

Application Best Practices

Validate file size
Validate file type
Generate unique object keys
Store metadata in database
Use pre-signed URLs for downloads
Use async processing for large files
Add retry and timeout configuration
Monitor failures using CloudWatch

26. Better Production Architecture

flowchart TD
    A[User] --> B[React / Next.js UI]
    B --> C[Spring Boot API]
    C --> D[Validate File]
    D --> E[Upload to S3]
    E --> F[Save Metadata in DB]
    F --> G[Return File URL]

    C --> H[CloudWatch Logs]
    E --> I[S3 Bucket Encryption]
    C --> J[IAM Role]

27. Real-Time Enterprise Use Cases

Use Case AWS Service Example
File upload S3 Profile image upload
Async processing SQS Process uploaded Excel file
Notification SNS Send upload success notification
Database DynamoDB / RDS Store file metadata
Secrets Secrets Manager Store DB password
Monitoring CloudWatch Logs and metrics
Email SES Send user emails

28. Interview Explanation

If interviewer asks:

How does Spring Boot connect to AWS?

Answer:

Spring Boot connects to AWS using AWS SDK for Java. We create AWS service clients like S3Client, DynamoDbClient, or SqsClient. These clients use region and credentials from the AWS default credentials provider chain. Locally, credentials usually come from ~/.aws/credentials. In production, credentials should come from IAM roles attached to EC2, ECS, EKS, or Lambda.


Why should we avoid hardcoding AWS keys?

Answer:

Hardcoded keys can be leaked through GitHub, logs, build artifacts, or shared configuration files. If leaked, attackers can access AWS resources. The best practice is to use IAM roles and temporary credentials in production.


AWS CLI vs AWS SDK?

Answer:

AWS CLI is used from the terminal for manual operations and automation scripts. AWS SDK is used inside application code to call AWS services programmatically.


29. Summary

In this article, we learned:

AWS CLI is used for command line access
AWS SDK is used for application integration
Spring Boot can connect to AWS using AWS SDK for Java 2.x
S3Client is used to upload, download, and delete files
Credentials should not be hardcoded
IAM roles are best for production
Least privilege access is mandatory

30. Complete Flow Recap

flowchart LR
    A[Install AWS CLI] --> B[Configure Credentials]
    B --> C[Test with aws sts get-caller-identity]
    C --> D[Create S3 Bucket]
    D --> E[Create Spring Boot App]
    E --> F[Add AWS SDK Dependency]
    F --> G[Create S3Client Bean]
    G --> H[Upload File API]
    H --> I[Test API]
    I --> J[Verify File in S3]

Loading likes...

Comments

Share a question, correction, or practical insight about this article.

Loading approved comments...