Courses / Hands-on Cloud for Freshers

Session 6 of 8

Data that outlives the server: DynamoDB

Overview

Unit 6 — Data That Outlives the Server: DynamoDB

Course: Hands-on Cloud for Freshers

Prerequisites: You can sign in to the AWS CLI with short-lived credentials and run commands against your account, and you can read an IAM policy document and say what its Effect, Action and Resource elements grant (Unit 2). You have launched and terminated an EC2 instance and know that anything stored on its disk goes with it (Unit 4). You can write a JSON object by hand. No database experience is assumed.

What the reader can do after this unit:

  • Create a DynamoDB table with a partition key chosen for how the data will be fetched, and write, read, query and scan its items from both the console and the AWS CLI using DynamoDB’s typed JSON.
  • Explain why fetching an item by its key and reading the whole table give the same answer on a small table and very different costs on a large one, and choose the operation an application should use.
  • Write a least-privilege IAM policy that lets an application role use one table and nothing else, attach it to a role, and prove with the IAM policy simulator which requests it allows and which it denies.

Core question this unit answers: How does an application keep its records somewhere that outlives any one server, and how do you let that application’s code touch exactly that data and nothing else?

Connections:

  • Builds on: Unit 2’s policies, which you now scope to a single resource by its ARN, and Unit 4’s instance, whose disk disappeared at termination — the problem a managed table solves.
  • Leads into: Unit 7, where a Lambda function named hoc-notes-api runs with the role you create here, hoc-notes-api-role, and reads and writes the table hoc-notes you build here.

Your answers are scored

This unit is assessed. The quiz is marked against a key held separately from your materials. Its first eight questions are multiple choice. Its last two ask you to write a short answer — a DynamoDB item and a set of allow-or-deny decisions — in a format the question states exactly.

Two consequences worth knowing before you start:

  • Each written answer is marked by fixed checks, not by opinion. The question tells you every requirement your answer must meet; a grader runs the same checks on every submission.
  • Formatting is not marked. Spacing, line breaks and the order of keys inside a JSON object do not change the score. What is marked is whether your answer means the right thing.

Notes

Hands-on Cloud for Freshers — Unit 6: Data That Outlives the Server: DynamoDB

Before you start

You need an AWS account, an everyday administrator identity that is not the root user, and the AWS CLI signed in as that identity, in the Asia Pacific (Mumbai) Region, ap-south-1. If you set these up in Units 1 and 2, nothing more is needed; skip to the account ID below.

If you are starting here, without an account or an administrator identity:

  1. Create the account. Open the Sign up for AWS page, https://signin.aws.amazon.com/signup?request_type=register. You need an email address you can receive mail at (it becomes the root user’s sign-in name), a phone number that can receive an SMS, and a valid payment method; you choose an account plan during sign-up. Wait for the email confirming that the account is activated before you sign in (Sign up for AWS (advanced)).
  2. Protect the root user. Sign in at https://console.aws.amazon.com/ as Root user and turn on MFA (multi-factor authentication: a one-time code from a device you hold, asked for at each console sign-in) for it. The IAM User Guide’s advice is not to use the root user for daily tasks (Setting up your AWS account).
  3. Create the everyday administrator. Still as root, open the IAM console and choose Users → Create user. Enter a user name such as hoc-admin, tick Provide user access to the AWS Management Console and choose I want to create an IAM user, and set a password. On Set permissions choose Add user to group → Create group, name the group hoc-admins, select the AWS managed policy AdministratorAccess, choose Create user group, select the new group, then Next and Create user (Create an IAM user for emergency access shows these screens).
  4. Switch to it. Sign out of root and sign in at https://<your-account-id>.signin.aws.amazon.com/console as hoc-admin (How IAM users sign in to AWS). Use this identity for everything below.

Then sign in the AWS CLI, if it is not signed in already:

  1. Install the AWS CLI version 2 for your operating system by following the AWS CLI install guide (Sources). aws login needs version 2.32.0 or later, so check with aws --version and update if it reports anything older (Sign in with aws login).
  2. Run aws login. The first time, it asks for a Region: enter ap-south-1. It then opens your browser, you sign in as your everyday administrator (not the root user), and the CLI receives temporary credentials that it refreshes on its own — no long-term access key is stored. An IAM identity needs the SignInLocalDevelopmentAccess managed policy or equivalent permissions; AdministratorAccess allows every action, so it covers this.
  3. To change the Region later, run aws configure set region ap-south-1.

You also need your 12-digit account ID, because permissions in this unit name resources by their full address. Print it with:

aws sts get-caller-identity

The Account field of the output is the ID. The AWS CLI documentation notes that no permissions are required to run this command, so it works whatever identity you are signed in as.

What costs money here. The table in this unit uses on-demand capacity, which the DynamoDB documentation describes as the default and recommended mode: you are billed per read or write request, and “if you are driving zero traffic to your table, then with on-demand, you are not charged for any throughput.” Storage is billed separately. The DynamoDB pricing page lists 25 GB of data storage per Region as part of the AWS Free Tier; the free 25 read and 25 write capacity units it also lists apply to the provisioned capacity mode, not to on-demand requests. The few dozen requests in this unit are billed per request on on-demand, which on the Free account plan is drawn from your credits. IAM roles and policies cost nothing themselves: the IAM User Guide states that IAM is a feature of your AWS account “offered at no additional charge”, and you are charged only for the other services you use with it. Tag the table with project = hands-on-cloud like everything else.

Nothing here needs a VPC, a subnet or an instance. That is part of the point.

Summary

When Unit 4’s instance was terminated, everything on its disk went with it. An application whose records live on its own server loses them the day the server is replaced, so real applications keep their data in a service that outlives any one server. Amazon DynamoDB is such a service: you create a table, choose a partition key that identifies each record, and read and write records through an AWS API, with no database server of your own to run, patch or size. Two ideas decide whether you use it well. The first is that the partition key is how DynamoDB finds an item, so fetching by key goes straight to one item while Scan reads every item in the table, which on a large table is the difference between one read and millions. The second is that an application should be allowed to touch its own table and nothing else, which you express as an IAM policy whose Resource is that one table’s ARN — and then prove with the IAM policy simulator rather than assume.

Key concepts

Term Definition
Table A collection of items, the unit DynamoDB stores data in. You name it and choose its primary key when you create it
Item A group of attributes that is uniquely identifiable among all the other items in the table — similar to a row or record
Attribute A single named data element of an item, such as title — similar to a field or column
Primary key The attribute, or pair of attributes, that uniquely identifies each item. Every item must have it; no two items share it
Partition key The first attribute of the primary key. On its own it is the whole primary key (a simple primary key); combined with a sort key it forms a composite primary key. DynamoDB uses its value as input to an internal hash function that decides where the item is stored
Sort key An optional second key attribute. Items with the same partition key are stored together, ordered by sort key
Schemaless Apart from the primary key, attributes and their types are not declared in advance; each item can carry different ones
On-demand capacity mode A table setting in which you pay per read and write request, with no capacity to plan. The default and recommended mode
GetItem Reads one item, given its full primary key
Query Reads the items that share one partition key value, optionally narrowed by a sort-key condition
Scan Reads every item in the table, up to 1 MB per request, and can filter what it returns only after reading
Typed JSON (attribute value) The CLI’s way of writing an item: each value is wrapped in its type, such as {"S": "text"} for a string or {"N": "2"} for a number
ARN Amazon Resource Name: the full address of one AWS resource, such as a table, used in policies to say exactly which resource is meant
Execution role An IAM role a service such as AWS Lambda assumes to act on your behalf; its trust policy names the service, its permissions policies say what it may do

Explanations

The failure, before the explanation

You keep notes in a table. Each note is identified by noteId. You add a note:

aws dynamodb put-item --table-name hoc-notes \
    --item '{"noteId": {"S": "n-001"}, "title": {"S": "Buy milk"}, "body": {"S": "Two litres"}}'

Later, a different part of your code adds what it thinks is a new note and reuses the same id:

aws dynamodb put-item --table-name hoc-notes \
    --item '{"noteId": {"S": "n-001"}, "title": {"S": "Call home"}}'

Both commands succeed. Neither prints an error or a warning. Read the item back and you find only Call home, with no body at all: the first note is gone. The AWS documentation’s own description of a put is exact about why — it “creates a new item, or replaces an existing item with a new item.” The primary key is the item’s identity. Two writes with the same key are two versions of one item, and the second replaces the first entirely, attributes and all.

This is the most important property of a primary key, and it is why choosing the key is the first design decision for any table: the key is not a label on the data, it is which item you are talking about.

Two ways to picture a table and its key

As a wall of numbered lockers. The table is the wall. The partition key value is the number on a locker door. To fetch an item you name the number and walk straight to that locker: DynamoDB runs the number through its hash function and knows exactly where the item is stored. Putting a new item with a number already in use does not add a second locker; it empties the existing one and puts the new contents in. And the only way to find “every locker containing a red bag” is to open every locker — which is what a Scan does.

As the contacts app on your phone. Each contact is an item, and its unique key might be a contact ID. Some contacts have an email address, some have a birthday, some have neither: the app does not make every contact fill in the same fields. That is what schemaless means — only the key is required, and each item carries whatever other attributes it has. Looking up one contact by ID is instant; reading through all of them to find who lives in one city takes as long as your contact list is long.

Creating a table, and why the key matters first

The table for this unit is hoc-notes, with partition key noteId, a string, and no sort key. The console path, per the DynamoDB getting-started guide, is Tables → Create table, then a Table name and a Partition key, leaving Sort key empty, with Table settings left on Default settings. The CLI form, which also lets you tag the table at creation, is:

aws dynamodb create-table \
    --table-name hoc-notes \
    --attribute-definitions AttributeName=noteId,AttributeType=S \
    --key-schema AttributeName=noteId,KeyType=HASH \
    --billing-mode PAY_PER_REQUEST \
    --tags Key=project,Value=hands-on-cloud

Three parts of that command carry the teaching:

  • --attribute-definitions declares only the key attribute. You do not list title or body: apart from the key, the table is schemaless.
  • KeyType=HASH marks noteId as the partition key. (The documentation explains the old name: the partition key is also called the hash attribute, after the hash function that places items. A sort key is RANGE.) A key attribute must be a string, number or binary.
  • PAY_PER_REQUEST is on-demand capacity.

The command returns at once with "TableStatus": "CREATING". Wait until it reports ACTIVE:

aws dynamodb describe-table --table-name hoc-notes --query "Table.TableStatus"

Why noteId and not title? Because the key is how the application will fetch a note — by its id, from a link or an API path — and because it must be unique. Titles repeat; two notes called “Shopping” would overwrite each other, exactly as in the failure above.

Writing items in typed JSON

The CLI writes items in a form where every value is wrapped in its type:

You mean You write
the string Buy milk {"S": "Buy milk"}
the number 2 {"N": "2"}

The number is written inside quotes. That looks wrong the first time and is correct: the type descriptor N says it is a number, and the value travels as a string. Writing {"N": 2} without quotes is a mistake to watch for in hand-written items: the value must be the quoted string "2".

A complete item, then, is an object whose keys are attribute names and whose values are these typed wrappers:

{"noteId": {"S": "n-002"}, "title": {"S": "Read chapter 3"}, "priority": {"N": "2"}}

In the console the same item is built with Explore table items → Create item, where Add new attribute asks you to choose each attribute’s type before you type its value.

Three ways to read: GetItem, Query and Scan

Your notes app needs to do two different things. When someone opens a link to note n-002, it must show that one note. When someone opens the home page, it must list every note. The first job knows the key; the second does not. DynamoDB gives you a different read for each situation, and choosing the wrong one is the commonest way to make a table slow and expensive.

Fetching the one note you can name. Back at the wall of lockers: you know the number, so you walk straight to locker n-002 and open only that door. On the command line:

aws dynamodb get-item --table-name hoc-notes --key '{"noteId": {"S": "n-002"}}'

That is GetItem: you give it the full primary key and it returns that one item, or nothing. By default DynamoDB reads are eventually consistent; adding --consistent-read asks for a strongly consistent read, which costs twice as much and reflects every write that completed before it.

Fetching everything filed under one name. Picture the documentation’s own Music table, keyed by Artist and SongTitle. Asking for one artist is like pulling out the one drawer labelled with that artist’s name: every song in it comes out, already in title order, and no other drawer is touched. The same request against this unit’s table looks like this, with the value passed through a placeholder that starts with a colon:

aws dynamodb query --table-name hoc-notes \
    --key-condition-expression "noteId = :id" \
    --expression-attribute-values '{":id": {"S": "n-002"}}'

That is Query: it returns the items that share one partition key value, and its key condition must name the partition key with an equality test. On hoc-notes this returns at most one item, because in a table with only a partition key no two items can share that value. Query earns its place when a table has a sort key, as Music does, where a query for one artist returns all of that artist’s songs, in sort-key order. On this unit’s table, GetItem and Query reach the same single item; the application in Unit 7 uses GetItem for that.

Listing everything, when you cannot name anything. For the home page there is no key to walk to, so you open every locker on the wall, one after another, and note what is inside:

aws dynamodb scan --table-name hoc-notes --return-consumed-capacity TOTAL

That is Scan: it reads every item in the table. On five notes it looks harmless, and it is the only way here to list all notes. Its cost is the point to understand. The documentation is precise about three behaviours:

  • A Scan reads every item, up to 1 MB per request, and the CLI keeps requesting pages until the whole table has been read.
  • A filter expression is applied after the items are read: “a Scan consumes the same amount of read capacity, regardless of whether a filter expression is present.” Filtering makes the answer smaller, not the work — like opening every locker and then keeping only the red bags.
  • The response shows both ScannedCount, the items read, and Count, the items returned. A large ScannedCount with a small Count is the signature of an inefficient Scan.

So a Scan that “finds the one note titled X” in a table of a million notes reads a million notes. GetItem by key reads one. On on-demand capacity you pay for what is read, which makes this a bill as well as a speed problem. Listing a handful of notes for a practice app is a fair use of Scan; looking up a single item with it is not.

Least privilege: one role, one table

Think of the staff card a shop gives a delivery worker: it opens the loading bay and nothing else, not the till and not the manager’s office. If the card is lost, the damage is limited to the loading bay. An application should hold its permissions the same way — exactly the ones it needs, and no more. In Unit 7 the code that serves the notes API will run as a Lambda function, and Lambda acts with an execution role — an IAM role whose trust policy names the Lambda service as allowed to assume it:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "lambda.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }
  ]
}

That document answers who may use the role. A separate permissions policy answers what the role may do. For the notes API — create a note, fetch one note, delete one, list them all — that is four DynamoDB actions on one table:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "HocNotesTableOnly",
      "Effect": "Allow",
      "Action": [
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:Scan"
      ],
      "Resource": "arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes"
    }
  ]
}

Read the Resource from the right: the table hoc-notes, in account <ACCOUNT_ID>, in Region ap-south-1, in the DynamoDB service. That is the table’s ARN, the same form the DynamoDB documentation uses in its own single-table policy example. Two consequences follow:

  • A request to read another table, such as hoc-orders, matches no statement and is denied. IAM denies anything not explicitly allowed.
  • A request to delete the table itself (dynamodb:DeleteTable) is denied too, because that action is not listed. The code can manage notes; it cannot destroy where they live.

Compare the tempting shortcut, "Action": "dynamodb:*" with "Resource": "*". It makes every permission error disappear, and with it every protection: a bug in the notes code could then read or delete any table in the account. The documentation’s single-table example also lists the table/<name>/index/* ARN, which a policy needs only when the table has secondary indexes; hoc-notes has none, so it is left out.

Proving a policy, rather than assuming it

Suppose you have just typed the policy above and want to know whether a typo in the account ID has quietly denied everything, or whether DeleteTable slipped in. You could run real requests and find out the hard way — or you could ask IAM what it would decide. That is what the simulator is for.

The IAM console has a Policy simulator (in the IAM navigation pane). In Principal mode you pick an identity — here, the role hoc-notes-api-role — and it evaluates the policies attached to that role against the actions and resource ARNs you enter. Each result row says whether the action is allowed, implicitly denied (nothing allowed it) or explicitly denied (a Deny statement matched), with a short explanation.

The documentation is explicit that the simulator “does not make an actual AWS service request”, so you can test a dangerous action such as DeleteTable without any risk of it happening. It also warns that simulator results can differ from the live environment in some advanced cases, so the final proof is always a real request — which Unit 7 makes when the function runs.

The useful habit is to test both sides: the actions that must be allowed, and at least one that must not — a different table, and an action you deliberately left out. A policy that has only ever been shown to allow things has not been shown to be least-privilege.

Flashcards

Say the answer aloud before revealing it. Speaking it is what exposes the gaps that reading past a written answer hides.

You `put-item` twice with the same `noteId`. How many items exist?

One. A put creates a new item or replaces an existing item with the same primary key, entirely, with no error.

What does the partition key do besides identify the item?

Its value is the input to DynamoDB’s internal hash function, which decides where the item is stored — which is why fetching by key goes straight to the item.

Which attributes do you declare when you create a table?

Only the key attributes. Everything else is schemaless and can differ from item to item.

How do you write the number 2 in a CLI item?

{"N": "2"}: the type descriptor N, with the value in quotes.

What is the difference between GetItem and Scan?

GetItem reads the one item whose full key you give. Scan reads every item in the table, a page of up to 1 MB at a time.

Does a filter expression make a Scan cheaper?

No. It is applied after the items are read, so the read capacity consumed is the same with or without it.

On a table with only a partition key, how many items can a Query return?

At most one, since no two items share a partition key value there. Query becomes useful when a table has a sort key.

What are you billed for on an on-demand table with no traffic?

No throughput charge; you are billed per request, and zero requests means zero request charges. Stored data is billed separately.

Do the Free Tier's 25 read and 25 write capacity units cover on-demand requests?

No. Per the pricing page they apply to provisioned capacity mode; on-demand requests are billed per request.

What does a role's trust policy say, and what does its permissions policy say?

The trust policy says who may assume the role (here, lambda.amazonaws.com). The permissions policy says what the role may then do.

Your role's policy allows four actions on `table/hoc-notes`. What happens to `GetItem` on `table/hoc-orders`?

It is denied: no statement allows it, and IAM denies anything not explicitly allowed.

Why test a denied action in the policy simulator, not only the allowed ones?

Because a policy shown only to allow things has not been shown to be least-privilege. The simulator makes no real request, so testing a dangerous action is safe.

Model answer

The question: “Your application needs to store users’ notes. Talk me through how you would set up the storage and its access.”

There are five beats, and they come in this order. Missing any one is a failure state rather than a stylistic gap: each beat is a decision that, skipped, produces either lost data or excess access.

  1. Key. Choose the partition key from how the data is fetched and what makes it unique — a note id, not a title — and say what happens on a duplicate key: the put replaces the item.
  2. Access pattern. Name the operations the application performs and match each to GetItem, Query or Scan, saying where a Scan is acceptable (a small list) and where it is not (finding one item in a large table).
  3. Capacity and cost. Choose on-demand capacity and say what is billed: requests and stored data, with nothing charged for throughput when there is no traffic.
  4. Least privilege. Give the application a role whose permissions policy lists only the actions from beat two, on only this table’s ARN.
  5. Proof. Test the role in the policy simulator for the allowed actions and for at least one action and one resource that must be denied, then confirm with a real request.

Spoken, the answer sounds like this:

“I would start with the key, because it decides how every note is found: each note gets a unique noteId, not its title, since two notes can share a title — and I know a put with an existing key replaces the whole item, so ids must never be reused. Next, the access patterns: the app creates a note, fetches one by id, deletes one, and lists them. Fetching and deleting use the key directly, so they are GetItem and DeleteItem; listing is a Scan, which is fine for one user’s small list but would read every item in a large table, so it is not how I would find a single note. Then capacity and cost: on-demand mode, so I pay per request and for stored data, and an idle table has no throughput charge. Fourth, least privilege: the app runs as a role whose policy allows only those four actions, on only this table’s ARN — nothing on other tables, and no DeleteTable. Finally, the proof: I run the role through the policy simulator for the allowed actions and for a different table and a left-out action that must be denied, and then confirm with a real request.”

Beat five is the one most answers drop, and beat four without it is a claim, not a control.

Why this matters

  • A web app that loses data on redeploy. An app that writes to a file on its server loses every record when the server is replaced. Moving the records to a managed table is what lets the server become disposable — which Unit 8 relies on.
  • Silent overwrites in production. Two parts of a system generate ids the same way and collide. No error is raised; one record replaces another. Knowing that a put replaces is how you know to design unique keys, or to add a condition that refuses to overwrite.
  • A bill driven by one endpoint. A “search” feature implemented as a Scan with a filter reads the whole table on every request. It works in testing on a hundred items and becomes the largest line on the bill at a million.
  • A leaked credential with a small blast radius. If the notes service’s role can touch only table/hoc-notes, a bug or a stolen credential in that service cannot read the users table or delete anything else. Least privilege is what limits how bad a bad day gets.

After this unit

The project for this unit is A Notes Table and the Role That May Use It (project.md). You create hoc-notes, write and read items from the CLI, measure what a Scan reads compared with a GetItem, create the role hoc-notes-api-role with the permissions policy above, and prove in the policy simulator what it allows and denies.

Unit 7 writes the Lambda function hoc-notes-api, attaches this role to it, and serves the notes over a function URL — the first time your code, rather than you at a command line, reads the table.

Sources

Every AWS behaviour, console label, command and price statement in these notes was checked against the pages below.

Project

Hands-on Project — A Notes Table and the Role That May Use It

Objective

Create the DynamoDB table hoc-notes, fill it and read it back from the CLI, measure what a Scan reads compared with fetching one item by its key, then create the role hoc-notes-api-role with a policy that reaches only this table and prove in the IAM policy simulator what that role may and may not do. The point is not the table. The point is that you finish holding a table and a role whose behaviour you have measured and tested rather than assumed — and both are what Unit 7’s code will run against.

What you need: the AWS CLI version 2 signed in with short-lived credentials, Region ap-south-1, and your 12-digit account ID, which aws sts get-caller-identity prints. Units 1 and 2 set these up. If you are starting here, follow If you are starting here under Before you start in this unit’s notes: it creates the account and an everyday administrator identity, then signs the CLI in with aws login, which needs AWS CLI version 2.32.0 or later (Sign in with aws login). No task needs a VPC or an instance.

What costs money. An on-demand table is billed per read and write request and for the data it stores (DynamoDB on-demand pricing); on the Free account plan those charges are drawn from your Free Tier credits. Tasks 1 and 2 make a few dozen requests. IAM roles and policies carry no charge (What is IAM?).

Conventions for every task:

  • Every resource carries the tag project = hands-on-cloud.
  • Every output file is plain text in the shape given. Where a shape is given, follow it exactly: the parts in <angle brackets> are what you fill in, without the brackets, and every other character is copied as shown.
  • On Windows, the CLI commands below need the quoting changes the DynamoDB getting-started guide shows for Windows CMD; the simplest route is to put each item in a file and pass --item file://item.json.

Task 1 — Create the table and fill it

Scope: one table, five notes, one deliberate overwrite. Stop once the five notes read back correctly.

  1. Create the table:

    aws dynamodb create-table \
        --table-name hoc-notes \
        --attribute-definitions AttributeName=noteId,AttributeType=S \
        --key-schema AttributeName=noteId,KeyType=HASH \
        --billing-mode PAY_PER_REQUEST \
        --tags Key=project,Value=hands-on-cloud

    It returns at once with a TableStatus of CREATING; you can read and write items only once the table is ACTIVE. Wait for that:

    aws dynamodb wait table-exists --table-name hoc-notes

    It checks every 20 seconds and returns with no output once the table is ACTIVE. If it exits with return code 255 instead, it gave up after 25 checks: run it again. Then confirm with aws dynamodb describe-table --table-name hoc-notes --query "Table.TableStatus", which must print "ACTIVE".

    If create-table fails with ResourceInUseException, a table named hoc-notes already exists in this Region, left by an earlier attempt. Delete it and wait for it to go, exactly as in Task 4 (step 1, then the wait table-not-exists command), and run create-table again, so that you start from an empty table.

  2. Write five notes, n-001 to n-005, each with a title string and a priority number from 1 to 3. The first one is:

    aws dynamodb put-item --table-name hoc-notes \
        --item '{"noteId": {"S": "n-001"}, "title": {"S": "Buy milk"}, "priority": {"N": "2"}}'

    Choose your own titles for the other four. Give n-003 an extra body string attribute that the others do not have.

  3. The deliberate overwrite. Put an item with noteId n-001 and only a title of Overwritten. Read n-001 back:

    aws dynamodb get-item --table-name hoc-notes \
        --key '{"noteId": {"S": "n-001"}}' --consistent-read

    --consistent-read asks for a strongly consistent read, which returns the most up-to-date data. Without it the read is eventually consistent, the default, and might not yet reflect a write that has only just completed. Note what is left of the original item. Then put the original n-001 back with the same command you used in step 2, and run the get-item above once more: it must show priority again. If it does not, repeat the put.

  4. Open the table in the console with Explore table items and confirm all five notes are listed, with body showing only on n-003. If a note is missing, or body shows on another note, run that note’s put-item again with the corrected item and reload the page.

Time budget: 30 minutes

Output: items.txt, in this shape:

$ <a command you ran>
<its output, pasted as it is, if it printed anything>
$ <the next command you ran>
...
survived: <attribute>,<attribute>,...

The commands, in the order you ran them, are the five put-item commands from step 2, the overwrite put-item from step 3, and the get-item straight after it, with its output. Write each command on a single line starting with $ (a dollar sign and a space), joining any continued lines into one. Do not include the restoring put or the second get-item. The last line lists, comma-separated with no spaces, the attribute names present in that get-item output.


Task 2 — Measure what each read costs

Scope: three reads, compared. Stop once the table below is filled.

Run each command and copy the numbers it reports. --return-consumed-capacity TOTAL makes DynamoDB report the capacity each request consumed.

aws dynamodb get-item --table-name hoc-notes \
    --key '{"noteId": {"S": "n-003"}}' \
    --return-consumed-capacity TOTAL

aws dynamodb scan --table-name hoc-notes \
    --return-consumed-capacity TOTAL

aws dynamodb scan --table-name hoc-notes \
    --filter-expression "priority = :p" \
    --expression-attribute-values '{":p": {"N": "3"}}' \
    --return-consumed-capacity TOTAL

Write reads.txt in this shape, one line per command:

get-item n-003      | items returned: 1 | items read: 1 | capacity: <CapacityUnits>
scan                | items returned: <Count> | items read: <ScannedCount> | capacity: <CapacityUnits>
scan priority = 3   | items returned: <Count> | items read: <ScannedCount> | capacity: <CapacityUnits>

Before you go on, check the scan line: its items returned must equal the number of notes you wrote in Task 1, five. If it is lower, a note did not land: go back to Task 1, step 4, then run the three commands again.

Then add two lines in this shape:

filter-changed-items-read: <yes|no>
million-note-scan-reads: <integer>

The first says whether the second and third lines show a different items read. The second says how many items the third command would read if the table held exactly one million notes; reason it out from your own measurements and the notes’ section on Scan. Write the number as plain digits, with no commas or spaces.

Time budget: 20 minutes

Output: reads.txt with the three measurement lines and the two lines above.


Task 3 — Create the role and prove what it may do

Scope: one policy, one role, six simulated requests. Stop once all six results are recorded.

  1. The permissions policy. In the IAM console choose Policies → Create policy, choose the JSON option, and paste this policy, with <ACCOUNT_ID> replaced by your 12-digit account ID:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "HocNotesTableOnly",
          "Effect": "Allow",
          "Action": [
            "dynamodb:PutItem",
            "dynamodb:GetItem",
            "dynamodb:DeleteItem",
            "dynamodb:Scan"
          ],
          "Resource": "arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes"
        }
      ]
    }

    Resolve anything policy validation reports, choose Next, name it hoc-notes-table-access, add the project tag, and choose Create policy.

  2. The role. Choose Roles → Create role. For Trusted entity type choose AWS service; for Service or use case choose Lambda. Choose Next. Under Permissions policies select hoc-notes-table-access only. Choose Next, name the role hoc-notes-api-role, add the project tag, review, and choose Create role. Open the role and check two things: its trust policy names lambda.amazonaws.com, and its Permissions tab lists hoc-notes-table-access and no other policy. If the trust policy names a different service, you chose another use case: delete the role as in Task 4, step 2, and create it again. If the policy is missing, choose Add permissions → Attach policies on that tab and attach it.

  3. The proof. In the IAM console’s navigation pane choose Policy simulator, and use Principal mode. Select the role hoc-notes-api-role as the identity; the side panel then lists the policies attached to it, and it must show hoc-notes-table-access. Add the actions below. For each, enter the specific resource ARN shown (replace <ACCOUNT_ID>) rather than testing against all resources; for dynamodb:GetItem enter both ARNs, the one in row 2 and the one in row 5. Then run the simulation.

# Action Resource
1 dynamodb:PutItem arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes
2 dynamodb:GetItem arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes
3 dynamodb:DeleteItem arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes
4 dynamodb:Scan arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes
5 dynamodb:GetItem arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-orders
6 dynamodb:DeleteTable arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes

The simulator does not make a real request, so no row can change anything in your account. Before you run it, write down for each row what you predict from the policy’s Action and Resource. Each result the simulator shows says the action is allowed, implicitly denied or explicitly denied; record allowed as allowed, and either kind of denied as denied. Write simulator.txt one line per row, in row order, with the resource name being the part of the ARN after table/:

<row> | <action> | <resource name> | predicted: <allowed|denied> | simulator: <allowed|denied>

If the role is missing from the list, its side panel shows no policy, or every row is denied straight after you created them, IAM may not yet show your new role and policy everywhere: changes in IAM take time to become visible (Troubleshoot IAM). Wait a few minutes and run the simulation again before you change anything. If a result still differs from your prediction, find out which of the two is wrong. When the policy is the cause — most often a mistyped account ID or Region in the ARN — fix it and run the simulation again.

Time budget: 40 minutes

Output: simulator.txt with six lines in the shape above.


Task 4 — Write the hand-off record for Unit 7: keep, or tear down

Scope: a decision, a check, and a seven-line record. This task is not optional. Its output, teardown.txt, is the hand-off record Unit 7 opens with: the first thing Unit 7 does is check whether hoc-notes and hoc-notes-api-role exist, and this file already holds that answer, the role’s ARN, and what the simulator said the role may do.

Unit 7 uses hoc-notes and hoc-notes-api-role as they are now. If you are going straight on to Unit 7, keep both: an on-demand table with no traffic makes no requests to be billed for, only its small stored data, and IAM resources carry no charge.

If you are stopping here, or will not return soon, delete them, and Unit 7 rebuilds them from its own appendix:

  1. Delete the table: aws dynamodb delete-table --table-name hoc-notes. Its status becomes DELETING, and the table and all its items are removed.
  2. In the IAM console choose Roles, select hoc-notes-api-role, choose Delete, type the role name to confirm, and choose Delete. Deleting a role in the console detaches its managed policies for you (Delete roles or instance profiles).
  3. In the IAM console choose Policies, select the button next to hoc-notes-table-access (the search box filters the list), choose Actions → Delete, follow the instructions to confirm, and choose Delete (Delete IAM policies (console)). Delete the role first: a policy that is still attached cannot be deleted, and the CLI reports DeleteConflict (iam delete-policy).

The check, either way. If you deleted the table, first wait for the deletion to finish, because straight after delete-table the table still exists with status DELETING:

aws dynamodb wait table-not-exists --table-name hoc-notes

This command polls describe-table until DynamoDB reports ResourceNotFoundException, then returns with no output. If it instead exits with return code 255, it gave up before the table was gone: run it again (dynamodb wait table-not-exists). If you kept the table, skip the wait. Then run:

aws sts get-caller-identity --query "Account" --output text
aws dynamodb describe-table --table-name hoc-notes --query "Table.TableStatus" --output text
aws iam get-role --role-name hoc-notes-api-role --query "Role.Arn" --output text

--output text prints each value without quotation marks. The first prints your 12-digit account ID. If you kept the resources, the second prints the table’s status and the third the role’s ARN. If you deleted them, the second fails with ResourceNotFoundException and the third with NoSuchEntity — the errors the DynamoDB and IAM API references name for a table or role that does not exist. If you deleted the role but the third command still prints its ARN, the deletion is not yet visible everywhere, because changes in IAM take time to become visible (Troubleshoot IAM): wait a few minutes and run it again.

If you deleted them, also confirm the policy is gone. This lists only the policies you created (--scope Local) and prints nothing once hoc-notes-table-access no longer exists:

aws iam list-policies --scope Local \
    --query "Policies[?PolicyName=='hoc-notes-table-access'].Arn" --output text

Write two files.

teardown.txt holds exactly these seven lines and nothing else:

decision: <kept|deleted>
region: ap-south-1
account: <the 12-digit account ID>
table: hoc-notes | <the status printed, or ResourceNotFoundException>
role: hoc-notes-api-role | <the role ARN printed, or NoSuchEntity>
simulator-allowed: <the actions simulator.txt records as allowed, comma-separated>
unit7-starts-with: <attach logging to the kept role|rebuild table and role from the appendix>

Fill it from the commands above and from simulator.txt. On the simulator-allowed line, list the action of every simulator.txt row that says simulator: allowed, in row order, each action once, separated by commas with no spaces. On the last line, write the first choice if you kept the resources and the second if you deleted them.

teardown-check.txt holds the evidence the record was filled from: every command you ran in this task, in the order you ran it, each followed by what it printed, in the same shape as items.txt:

$ <a command you ran in this task>
<its output or error message, pasted as it is, or (empty) if it printed nothing>
$ <the next command you ran>
...

Before you finish, check teardown.txt against the one case that applies to you. This check is for you; it goes in neither file:

  • Kept: the table line shows ACTIVE, the role line shows an ARN ending in role/hoc-notes-api-role, and the last line says attach logging to the kept role.
  • Deleted: the table and role lines show ResourceNotFoundException and NoSuchEntity, the list-policies command printed nothing, and the last line says rebuild table and role from the appendix.

If a line does not match, run the command it comes from again and correct the line.

Time budget: 10 minutes

Output: two files — teardown.txt, the seven-line hand-off record above and nothing else; and teardown-check.txt, the commands you ran in this task with their output.


What this feeds

Unit 7 opens by deploying a Lambda function, hoc-notes-api, and before its first task it needs exactly what teardown.txt records. Its opening check — do hoc-notes and hoc-notes-api-role exist? — is answered by your table and role lines, and your unit7-starts-with line tells you where Unit 7 begins: attaching a logging policy to the role you kept, or rebuilding both from Unit 7’s appendix. The role ARN is the identity the function runs as, and the simulator-allowed line is what IAM said that role may do with hoc-notes; when the function first runs, its real requests are the live confirmation of those results.


Sources

Quiz

Online marking is not open yet. Work through the questions and check the written ones against the criteria printed with each question. The answer key is kept back for now.

Quiz — Unit 6: Data That Outlives the Server: DynamoDB

Instructions: Ten questions in two parts, and both parts are scored.

  • Questions 1–8 are multiple choice. Pick one option per question. They are marked by comparing your letter against the key.
  • Questions 9–10 ask you to write a short answer in a stated format. Each is marked by a grader that runs fixed checks on what you submit; the checks and the marking rubric are held in the answer key, not here.

Work closed-book on the whole quiz. Submit plain text exactly in the format each question states.

Every question uses the table from this unit: hoc-notes, partition key noteId (string), no sort key, on-demand capacity, in Region ap-south-1.


1. You run put-item for an item with noteId n-001, then run put-item again with the same noteId and a different set of attributes. Both commands succeed. What does the table now hold for n-001?

a) Two items, because DynamoDB keeps every put as a separate version stored under the same key value b) One item holding only the second write’s attributes, because a put replaces the whole existing item c) One item holding the attributes of both writes, because a put merges new attributes into the old d) The first item unchanged, because a put that reuses an existing key value is ignored by DynamoDB


2. Which operation reads every item in the table?

a) GetItem, when it is called with only a partition key on a table that also defines a sort key b) Query, when its key condition names the partition key and leaves the sort key unrestricted c) PutItem, because it checks every existing item for a matching key before it writes a new one d) Scan, which reads each item in the table one page at a time, whether or not it is filtered


3. What does DynamoDB do with an item’s partition key value?

a) It uses the value as input to an internal hash function that decides which partition stores the item b) It uses the value to sort the results of a Scan, which returns items in partition key order c) It indexes only that attribute, so every other attribute must be declared when the table is made d) It uses the value’s type to set the maximum size of the item, so a string key allows larger items


4. In a put-item command, how do you write a priority attribute holding the number 2?

a) "priority": 2, because the CLI infers the type from the JSON value and needs no type wrapper b) "priority": {"N": 2}, because the descriptor goes in the wrapper and the value stays numeric c) "priority": {"N": "2"}, because the descriptor marks a number and the value travels as text d) "priority": {"S": "2"}, because DynamoDB stores every scalar value as a string on its disks


5. A table holds one million notes. A Scan with a filter expression returns three of them. What read capacity does that Scan consume?

a) Capacity for the three items returned, because the filter runs before items are read from storage b) No capacity, because a Scan with a filter is answered from an index at no extra request charge c) Capacity for every item read, because the filter is applied only after the Scan has read them d) Capacity for one item, because a Scan is billed as a single request whatever the number of items


6. The DynamoDB pricing page (Sources, below) lists 25 read and 25 write capacity units as part of the Free Tier. Which tables does that allowance cover?

a) Tables in provisioned capacity mode, so the requests made to an on-demand table are billed per request b) Tables in on-demand capacity mode, so a provisioned table’s capacity is billed from its first unit c) Tables in both modes alike, so the first 25 requests made each month cost nothing on any table d) No tables at all, because the Free Tier for DynamoDB covers stored data and never covers capacity


7. A role’s only policy allows PutItem, GetItem, DeleteItem and Scan on arn:aws:dynamodb:ap-south-1:<ACCOUNT_ID>:table/hoc-notes. Code running as that role calls GetItem on the table hoc-orders in the same account and Region. What happens?

a) Allowed, because GetItem is in the policy’s action list and IAM evaluates the action before the resource b) Allowed, because both tables are in the same account and Region as the table named in the policy c) Denied with an explicit deny, because a policy that names one table writes a Deny for all the others d) Denied, because no statement allows that action on that resource, and IAM denies anything not allowed


8. You run a Query on hoc-notes with the key condition noteId = :id. What can it return?

a) Every note whose title contains the value, because a key condition is matched against all attributes b) At most one item, because in a table with only a partition key no two items share a key value c) All of the items, sorted by noteId, because a Query on a table without a sort key reads every item d) An error, because a Query needs a condition on a sort key and this table does not define a sort key


Part 2 — Constructed response

Submit plain text exactly in the format each question states, with no surrounding quotes and no extra commentary.


9. Write the JSON object you would pass to put-item --item for this note:

  • noteId is the string n-010
  • title is the string Pay fees
  • priority is the number 1

The item must hold exactly these three attributes, each written in the form DynamoDB’s put-item expects. Format: one JSON object; spacing, line breaks and the order of keys are not marked.


10. A role’s only policy is:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Scan"],
      "Resource": "arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-notes"
    }
  ]
}

For each request below, made by code running as that role, decide whether it is allowed.

# Action Resource
1 dynamodb:GetItem arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-notes
2 dynamodb:DeleteItem arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-notes
3 dynamodb:Scan arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-notes
4 dynamodb:GetItem arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-orders
5 dynamodb:PutItem arn:aws:dynamodb:us-east-1:111122223333:table/hoc-notes
6 dynamodb:DeleteTable arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-notes
7 dynamodb:Query arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-notes
8 dynamodb:PutItem arn:aws:dynamodb:ap-south-1:111122223333:table/hoc-notes

Write eight words separated by commas, in row order, each either ALLOW or DENY — for example ALLOW, DENY, …. Words are compared without regard to case or spaces. Your answer is marked against how IAM evaluates this policy for each request.


Sources

The AWS behaviour these questions test is taught in this unit’s notes, from these pages:

TechEazy Consulting training material — not affiliated with or endorsed by Amazon Web Services (AWS).