Learning/AWS SQS/00 — Prerequisites
Beginner 20 min read

Prerequisites

Everything you need set up and understood before the course starts. Nothing here is SQS-specific — it is the AWS account, the credentials, the CLI and the Java toolchain that every later module assumes are already working.

Most people who get stuck on their first SQS tutorial are not stuck on SQS. They are stuck on credentials, or on a Region mismatch, or on an IAM policy that does not grant the action they are calling. Twenty minutes here removes that entire category of problem.

1. What you will learn

  • Set up an AWS account and a non-root identity safely
  • Configure AWS credentials four different ways, and know which to use where
  • Run your first AWS CLI command and read its output
  • Stand up a Java 21 project with AWS SDK for Java 2.x on the classpath
  • Explain what a managed service is, and what AWS is and is not responsible for

2. Why this matters

You are about to spend a course learning a distributed system's failure modes. You do not want to spend it debugging your own laptop.

There is a second reason, and it is conceptual rather than practical. The shared responsibility model explains why SQS has no servers for you to tune. When you later ask "how do I size the SQS cluster?" or "how do I configure replication?", the answer is that those questions belong on the other side of a line — and this module draws that line.

3. The shared responsibility model

AWS splits operational responsibility at a fixed boundary. For a managed service like SQS, the line sits unusually high: almost everything is AWS's.

flowchart TB
    subgraph YOU["🧑‍💻 Your responsibility"]
        Y1["Producers and consumers<br/>(your code)"]
        Y2["Queue configuration<br/>timeouts, retention, DLQs"]
        Y3["IAM policies and encryption choices"]
        Y4["Message content and schema"]
        Y5["Monitoring your pipeline"]
        Y6["Idempotency and error handling"]
    end

    subgraph AWS["☁️ AWS responsibility"]
        A1["Servers, disks, networking"]
        A2["Redundant storage and durability"]
        A3["Scaling the queue"]
        A4["Patching and availability"]
        A5["The SQS API itself"]
    end

    YOU -.->|"HTTPS API calls"| AWS

Reading the diagram. Everything in the lower box is invisible to you — there is no instance to size, no disk to monitor, no broker process to restart. Everything in the upper box is invisible to AWS — if your consumer deletes a message before processing it, AWS cannot help you.

📌 Remember this. A managed service is one where the operational surface is replaced by a configuration surface. You do not stop making decisions; you make different ones.

Terminology, formally:

Managed serviceSimple: AWS runs the infrastructure and you just use the API. Technical: a service where AWS operates the compute, storage, networking, scaling and availability, exposing only an API and a set of configuration attributes. Example: you never see an SQS server, and there is no instance type to choose.

4. Regions and ARNs

Two pieces of AWS vocabulary that appear in every SQS operation.

Region

RegionSimple: a geographic location where your AWS resources physically live. Technical: an isolated set of AWS data centres with its own service endpoints; resources in one Region are invisible to clients configured for another. Example: us-east-1 (N. Virginia), eu-west-1 (Ireland), ap-south-1 (Mumbai).

A queue exists in exactly one Region. A queue created in us-east-1 cannot be seen by a client configured for eu-west-1, and the resulting error message is unhelpful — usually QueueDoesNotExist, which sends people looking for a typo in the queue name.

⚠️ Common mistake. "The queue does not exist" almost always means "the queue does not exist in the Region your client is pointed at." Check the Region before you check the name.

ARN

ARN (Amazon Resource Name)Simple: the globally unique id of an AWS resource. Technical: a structured identifier used by IAM policies and by service-to-service integrations. Example: arn:aws:sqs:us-east-1:123456789012:orders-queue

Read it left to right:

arn : aws  : sqs      : us-east-1 : 123456789012 : orders-queue
 ^     ^      ^          ^           ^              ^
 |     |      |          |           |              +-- resource (queue name)
 |     |      |          |           +-- AWS account id
 |     |      |          +-- Region
 |     |      +-- service
 |     +-- partition (aws, aws-cn, aws-us-gov)
 +-- literal

SQS also has a queue URL, which is what most API calls actually take:

https://sqs.us-east-1.amazonaws.com/123456789012/orders-queue

Same three facts — Region, account, name — in a different shape. You will need both: API calls take the URL, IAM policies and service integrations take the ARN. Module 02 covers when to use which.

5. Credentials: the part that actually breaks

Every AWS SDK and the CLI resolve credentials through the same ordered chain. Understanding the order explains nearly every "it works on my machine" incident.

flowchart TD
    START([SDK needs credentials]) --> E1{"Environment variables?<br/>AWS_ACCESS_KEY_ID etc."}
    E1 -->|yes| USE([Use them])
    E1 -->|no| E2{"Java system properties?"}
    E2 -->|yes| USE
    E2 -->|no| E3{"Web identity token?<br/>EKS IRSA"}
    E3 -->|yes| USE
    E3 -->|no| E4{"Profile in ~/.aws/credentials<br/>or ~/.aws/config?"}
    E4 -->|yes| USE
    E4 -->|no| E5{"Container credentials?<br/>ECS task role"}
    E5 -->|yes| USE
    E5 -->|no| E6{"Instance metadata?<br/>EC2 instance profile"}
    E6 -->|yes| USE
    E6 -->|no| FAIL([SdkClientException:<br/>Unable to load credentials])

Reading the diagram. The chain stops at the first source that produces credentials. It does not merge them, and it does not fall through on a permissions error — only on absence.

Why does this order matter? Because an AWS_PROFILE environment variable set in your shell six months ago silently wins over the profile you just configured. When credentials behave unexpectedly, walk the chain from the top.

The four mechanisms, and where each belongs

MechanismUse it forNever use it for
IAM role (task role, instance profile, IRSA)Anything running on AWS
Named profile (~/.aws/config)Local developmentProduction
Environment variablesCI pipelines, containersLong-lived keys anywhere
Static keys in codeNothing. Ever.Everything

📌 Remember this. Roles give temporary credentials that rotate automatically. Access keys are permanent until someone revokes them — and the person who revokes them is usually responding to an incident.

Setting up a profile

# Interactive: prompts for key, secret, region, output format
aws configure --profile sqs-course

# Verify it works — this is the AWS equivalent of "whoami"
aws sts get-caller-identity --profile sqs-course

A successful response looks like:

{
    "UserId": "AIDACKCEVSQ6C2EXAMPLE",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/sqs-course"
}

If this command fails, stop and fix it. Nothing later in the course will work.

The resulting files:

# ~/.aws/config
[profile sqs-course]
region = us-east-1
output = json

# ~/.aws/credentials
[sqs-course]
aws_access_key_id = AKIA...
aws_secret_access_key = ...

⚠️ ~/.aws/credentials is plaintext on your disk. It is acceptable for a learning account with a scoped policy and a billing alarm. It is not acceptable for an account with production access — use AWS IAM Identity Center (SSO) there, which issues short-lived credentials instead.

6. A least-privilege policy for this course

Create an IAM user or role and attach this. It permits everything the course needs and nothing else.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SqsCourseQueues",
      "Effect": "Allow",
      "Action": [
        "sqs:CreateQueue",
        "sqs:DeleteQueue",
        "sqs:GetQueueUrl",
        "sqs:GetQueueAttributes",
        "sqs:SetQueueAttributes",
        "sqs:ListQueues",
        "sqs:SendMessage",
        "sqs:ReceiveMessage",
        "sqs:DeleteMessage",
        "sqs:ChangeMessageVisibility",
        "sqs:StartMessageMoveTask",
        "sqs:ListMessageMoveTasks",
        "sqs:TagQueue",
        "sqs:ListQueueTags"
      ],
      "Resource": "arn:aws:sqs:*:*:sqs-course-*"
    },
    {
      "Sid": "ReadOwnIdentityAndMetrics",
      "Effect": "Allow",
      "Action": [
        "sts:GetCallerIdentity",
        "cloudwatch:GetMetricStatistics",
        "cloudwatch:GetMetricData",
        "cloudwatch:ListMetrics"
      ],
      "Resource": "*"
    }
  ]
}

Two things to notice, because they recur throughout Module 16:

  1. Resource is scoped to a name prefix, not *. Every resource you create in this course should be named sqs-course-something. A leaked credential then cannot touch anything else in the account.
  2. sqs:PurgeQueue and sqs:DeleteMessageBatch are absent. Purge is genuinely dangerous (Module 26); batch delete is added in Module 13 when you actually need it.

🎯 Interview point. Being able to write a scoped policy from memory — action list plus a resource ARN pattern — is a small thing that signals you have operated AWS rather than only used it.

7. The Java toolchain

Java 21 or later. The course uses records, pattern matching and (in Module 22) virtual threads.

java --version   # expect 21 or higher

Maven

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>bom</artifactId>
      <version>2.31.0</version>   <!-- check for the current version -->
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>sqs</artifactId>
    <!-- no version: the BOM decides -->
  </dependency>
</dependencies>

Gradle

dependencies {
    implementation platform('software.amazon.awssdk:bom:2.31.0')
    implementation 'software.amazon.awssdk:sqs'
}

Why the BOM? The AWS SDK is dozens of interdependent artifacts. The Bill of Materials pins them to one consistent set, so you never hand-manage versions or hit a NoSuchMethodError from a mismatched pair.

8. Your first client

Java
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;

public final class HelloSqs {

    public static void main(String[] args) {
        // DefaultCredentialsProvider walks the chain from §5.
        // Region is explicit — never rely on ambient configuration for this.
        try (SqsClient sqs = SqsClient.builder()
                .region(Region.US_EAST_1)
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build()) {

            sqs.listQueues().queueUrls().forEach(System.out::println);
        }
    }
}

Three lines worth explaining:

  • DefaultCredentialsProvider.create() is the chain from §5. You could name a profile explicitly with ProfileCredentialsProvider.create("sqs-course"), and for local development that is often clearer — but code that hard-codes a profile cannot run unchanged in production.
  • .region(...) is explicit. The SDK can infer a Region from the environment, and when it infers a different one than you expected the failure is confusing. Be explicit.
  • try (SqsClient sqs = ...) — the client holds an HTTP connection pool. Build one per process and reuse it; it is thread-safe. Creating a client per message is a real performance bug that Module 22 revisits.

Running it against a profile:

AWS_PROFILE=sqs-course java HelloSqs.java

An empty list is a success. It means credentials resolved, the Region was reachable, and IAM allowed the call.

Sync or async?

SDK v2 offers SqsClient (blocking) and SqsAsyncClient (returns CompletableFuture).

Use
SqsClientDefault. Simpler, and with Java 21 virtual threads the blocking-call objection largely disappears
SqsAsyncClientHigh-fan-out work, or an existing reactive stack

This course uses SqsClient throughout, and notes where async would differ.

9. Before you create anything: a billing alarm

You are about to write polling loops. A polling loop with a bug is a program whose entire purpose is to make billable API calls as fast as possible.

aws cloudwatch put-metric-alarm \
  --alarm-name sqs-course-billing \
  --namespace AWS/Billing \
  --metric-name EstimatedCharges \
  --dimensions Name=Currency,Value=USD \
  --statistic Maximum \
  --period 21600 \
  --evaluation-periods 1 \
  --threshold 5 \
  --comparison-operator GreaterThanThreshold \
  --region us-east-1

⚠️ Billing metrics are published only in us-east-1, regardless of where your resources live. This is a long-standing AWS quirk and a frequent source of "why doesn't my billing alarm exist".

Everything in this course fits inside the SQS free tier — 1,000,000 requests per month, permanently (aws-facts.md §9) — if you tear down what you create. Module 18 shows exactly how a forgotten consumer turns that into a real bill.

10. Common mistakes

Using the root account. Why it's wrong: the root user cannot be scoped, cannot be meaningfully audited, and a leaked root credential compromises the entire account including billing. Instead: an IAM user with the policy in §6, or IAM Identity Center.

Hard-coding access keys in source. Why it's wrong: they reach git, and public GitHub is scanned continuously by bots that create EC2 instances for crypto mining within minutes of a key being pushed. Instead: the credential chain. There is no case where hard-coding is the right answer.

Region mismatch. Why it's wrong: a queue in us-east-1 is genuinely invisible to a client in eu-west-1, and the error blames the queue name. Instead: set the Region explicitly in code and in your profile, and keep them the same.

Granting sqs:* on Resource: "*". Why it's wrong: the credential can then purge any queue in the account. This is how a learning credential becomes a production incident. Instead: scope to a queue ARN pattern, as in §6.

Creating an SqsClient per operation. Why it's wrong: each one builds a fresh connection pool and re-resolves credentials. It shows up as mysterious latency under load. Instead: one per process, reused. It is thread-safe.

11. Real-world example

A team onboards a new engineer onto a service that consumes from three queues.

What they do not do: email an access key.

What they do: the engineer authenticates through IAM Identity Center with their own identity and assumes a Developer role in the non-production account. That role carries a policy scoped to arn:aws:sqs:*:*:dev-*, granting send, receive, delete and attribute reads — but not DeleteQueue and not PurgeQueue, which sit on a separate Operator role that requires MFA.

The engineer's ~/.aws/config:

[profile dev]
sso_session = company
sso_account_id = 111122223333
sso_role_name = Developer
region = eu-west-1

aws sso login --profile dev yields credentials that expire in eight hours. Nothing durable is written to disk, nothing can be leaked into a commit, and the blast radius of the engineer's laptop being stolen is one working day in one non-production account.

In production, the same service runs on ECS with a task role — no profile, no login, no human in the path at all. The credential chain (§5) finds the container credentials automatically, which is why the identical code runs in both places unchanged.

12. Interview questions

🟢 Beginner

What is an AWS Region? What is an ARN? A Region is an isolated geographic set of data centres with its own service endpoints; resources live in exactly one. An ARN is the globally unique structured identifier for a resource — arn:partition:service:region:account:resource.

What is the difference between the AWS CLI and an AWS SDK? Neither is special: both make signed HTTPS calls to the same public AWS APIs. The CLI is a command-line client; an SDK is a library for your language. Anything you can do in one you can do in the other.

🟡 Intermediate

Describe the default credential resolution chain. Why does its order matter? Environment variables → Java system properties → web identity token (IRSA) → profile files → container credentials (ECS) → instance metadata (EC2). It stops at the first source that yields credentials, and it does not fall through on a permissions failure — only on absence. Order matters because a higher-priority source you forgot about silently shadows the one you just configured. It is also the reason identical code runs unchanged on a laptop and on ECS.

🔴 Advanced

Why are IAM roles preferred over access keys for a service running on EKS? Walk through how the pod gets credentials.

Reasoning, in order:

  1. Keys are permanent. They stay valid until revoked, so a leak is unbounded in time. Role credentials are temporary and rotate automatically.
  2. Keys must be distributed. They end up in a secrets store, a CI variable, or worse. Every copy is an attack surface. Roles distribute nothing.
  3. Attribution. CloudTrail shows the assumed role session, tying an action to a workload identity rather than to a shared key.

Mechanically, with IRSA: the service account is annotated with a role ARN; EKS projects a signed OIDC token into the pod's filesystem; the SDK's credential chain finds it at the web identity step and calls sts:AssumeRoleWithWebIdentity, receiving temporary credentials that it refreshes before expiry. No secret is ever stored.

⚫ System design

You inherit an account where every service shares one IAM user. Describe a migration to least privilege without downtime.

Key beats of a good answer:

  • Observe before changing. Use CloudTrail (and IAM Access Analyzer's policy generation from access activity) to derive what each service actually calls, over a window long enough to include monthly jobs.
  • Add before removing. Create per-service roles and attach them alongside the existing user. Migrate one service at a time; the shared user still works throughout, so there is no cutover.
  • Verify per service. Deploy with the new role, watch for AccessDenied in CloudTrail, widen only where a real call was denied.
  • Revoke last. Once no service is using the shared key — confirmed by the key's last used timestamp going stale — deactivate it before deleting it, so rollback is one click.
  • Prevent recurrence. An SCP or permissions boundary denying long-lived key creation, plus a detective control alarming on new access keys.

The interviewer is listening for add-then-remove and for evidence-driven scoping rather than guessing at policies.

13. Summary

  • Credentials resolve through an ordered chain. Learn it and most auth errors explain themselves.
  • Region is part of a queue's identity. A Region mismatch presents as "queue does not exist".
  • Queue URL for API calls, queue ARN for IAM and integrations. You need both.
  • Roles over keys, always. Temporary and auto-rotating beats permanent and distributable.
  • Scope IAM to a resource pattern, never *.
  • One SqsClient per process, reused, thread-safe.
  • AWS operates the queue infrastructure; you operate the producers, consumers and configuration. The operational surface is replaced by a configuration surface — not removed.

Checklist before moving on

  • aws sts get-caller-identity --profile sqs-course returns your ARN
  • Your IAM identity is scoped to sqs-course-*, not *
  • A billing alarm exists in us-east-1
  • java --version reports 21 or higher
  • The HelloSqs program from §8 runs and prints an empty list without error

Index: Course home · Next: 01 — Messaging Fundamentals