Create a DynamoDB table with EC2 instance

Patrick René
7 min readJan 11, 2023

--

What is AWS DynamoDB?

AWS DynamoDB is a NoSQL(Not Only SQL) database, which means it is great use case for unstructured data. AWS DynamoDB uses four types of data models; Column-oriented, Key-Value, Document and Graph.

Structured vs Unstructured data

Structured data is data that is highly organized, predefined and formatted to a set structure. An example of structured data is an online travel booking system

Unstructured data is data that does not have a predefined data model and grows and changes rapidly. An example of unstructured data would be social media platforms such as Facebook.

Scenario:

  • Create DynamoDB table
  • Create t.2micro EC2 instance
  • Create IAM role using the principle of least privilege
  • Grant EC2 instance read permissions to the DynamoDB instance
  • Using AWS CLI in EC2 scan DynamoDB table
  • Using AWS CLI in EC2 instance validate we cannot write to the DynamoDb table

In this article I will walk you through deploying AWS DynamoDB table, since I’m a big fan of BMW vehicles(Bimmers) we are populating it with BMW models, vehicle class and years in production. We will also deploy an EC2 instance with an IAM role with read access. We will scan the AWS DynamoDB table and test the role by attempting to write to our table.

  1. Create AWS DynamoDB Table
DynamoDB Service Page

From the DynamoDB service page select → Create Table
In the table details lets populate the fields Table name [BMWModels], Partition key[Key], Sort Key[Model]

Create Table fields

We are going to use the default settings for the Table Settings and select Create

Default table Settings

Next we are going to create the Items: ModelSeries, Years, and VehicleClass using a JSON file

{
"BMWCars": [
{
"PutRequest": {
"Item": {
"ModelSeries": {
"S": "1 Series (F20/F21)"
},
"Years": {
"S": "2011-2019"
},
"VehicleClass": {
"S": "Subcompact car"

}

}
}
},
{
"PutRequest": {
"Item": {
"ModelSeries": {
"S": "1 Series (F40)"
},
"Years": {
"S": "2019-Present"
},
"VehicleClass": {
"S": "Subcompact car"
}

}
}
},
{
"PutRequest": {
"Item": {
"ModelSeries": {
"S": "1 Series (F52)"
},
"Years": {
"S": "2017-Present"
},
"VehicleClass": {
"S": "Subcompact executive car"
}

}
}
},
{
"PutRequest": {
"Item": {
"ModelSeries": {
"S": "2 Series (F22/F23)"
},
"Years": {
"S": "2013-2021"
},
"VehicleClass": {
"S": "Subcompact car"
}

}
}
}

Once created we will execute the command using AWSCLI. An indication of a successfully run of the command is: “UnprocessedItems”: {}

aws dynamodb batch-write-item --request-items file://bmwlist.json
{
"UnprocessedItems": {}
}

This a screenshot of the console after running the ‘aws dynamodb batch-write-item command referencing the JSON file.

2. Create EC2 instance
Lets create an EC2 instance using the AWS CLI, I chose the CLI for this step because I was curious. The AWS CLI is fairly easy to use and become familiar with.

aws ec2 run-instances --image-id ami-0b5eea76982371e91 --count 1 --instance-type t2.micro --key-name prene-keypair --security-group-ids sg-095e3a98320d4ca39 --subnet-id subnet-06b3ae16a2ffa81c0
{
"Groups": [],
"Instances": [
{
"AmiLaunchIndex": 0,
"ImageId": "ami-0b5eea76982371e91",
"InstanceId": "i-0cb74d72dfcb8d382",
"InstanceType": "t2.micro",
"KeyName": "prene-keypair",
"LaunchTime": "2023-01-10T09:37:05+00:00",
"Monitoring": {
"State": "disabled"
},
"Placement": {
"AvailabilityZone": "us-east-1e",
"GroupName": "",
"Tenancy": "default"
},
"PrivateDnsName": "ip-172-31-58-183.ec2.internal",
"PrivateIpAddress": "172.31.58.183",
"ProductCodes": [],
"PublicDnsName": "",
"State": {
"Code": 0,
"Name": "pending"
},
"StateTransitionReason": "",
"SubnetId": "subnet-06b3ae16a2ffa81c0",
"VpcId": "vpc-0a79efd0e55843891",
"Architecture": "x86_64",
"BlockDeviceMappings": [],
"ClientToken": "08802126-1bdd-43b0-a66c-ff3edd281da0",
"EbsOptimized": false,
"EnaSupport": true,
"Hypervisor": "xen",
"NetworkInterfaces": [
{
"Attachment": {
"AttachTime": "2023-01-10T09:37:05+00:00",
"AttachmentId": "eni-attach-0053b2af0d8d6fd6c",
"DeleteOnTermination": true,
"DeviceIndex": 0,
"Status": "attaching",
"NetworkCardIndex": 0
},
"Description": "",
"Groups": [
{
"GroupName": "launch-wizard-1",
"GroupId": "sg-095e3a98320d4ca39"
}
],
"Ipv6Addresses": [],
"MacAddress": "06:92:a1:6f:39:8d",
"NetworkInterfaceId": "eni-044251892f167bfab",
"OwnerId": "401972318485",
"PrivateDnsName": "ip-172-31-58-183.ec2.internal",
"PrivateIpAddress": "172.31.58.183",
"PrivateIpAddresses": [
{
"Primary": true,
"PrivateDnsName": "ip-172-31-58-183.ec2.internal",
"PrivateIpAddress": "172.31.58.183"
}
],
"SourceDestCheck": true,
"Status": "in-use",
"SubnetId": "subnet-06b3ae16a2ffa81c0",
"VpcId": "vpc-0a79efd0e55843891",
"InterfaceType": "interface"
}
],
"RootDeviceName": "/dev/xvda",
"RootDeviceType": "ebs",
"SecurityGroups": [
{
"GroupName": "launch-wizard-1",
"GroupId": "sg-095e3a98320d4ca39"
}
],
"SourceDestCheck": true,
"StateReason": {
"Code": "pending",
"Message": "pending"
},
"VirtualizationType": "hvm",
"CpuOptions": {
"CoreCount": 1,
"ThreadsPerCore": 1
},
"CapacityReservationSpecification": {
"CapacityReservationPreference": "open"
},
"MetadataOptions": {
"State": "pending",
"HttpTokens": "optional",
"HttpPutResponseHopLimit": 1,
"HttpEndpoint": "enabled",
"HttpProtocolIpv6": "disabled",
"InstanceMetadataTags": "disabled"
},
"EnclaveOptions": {
"Enabled": false
},
"PrivateDnsNameOptions": {
"HostnameType": "ip-name",
"EnableResourceNameDnsARecord": false,
"EnableResourceNameDnsAAAARecord": false
},
"MaintenanceOptions": {
"AutoRecovery": "default"
}
}
],
"OwnerId": "401972318485",
"ReservationId": "r-03da4de632577d09f"
}

3. Create IAM role using the principle of least privilege(ReadOnly)
We are going to create the BMWDynamoDBReadOnly role.

Role Creation

Search for ‘DynamoDB’ and then select ‘AmazonDynamoDBReadOnlyAccess’ select Next

Assign the role a name, we are naming the role ‘BMWDynamoDBReadOnly’ review and create it.

4. Grant EC2 instance read permissions to the DynamoDB by modifying the EC2 IAM role and assign the role ‘BMWDynamoDBReadOnly’

Modify Instance
Modify the IAM role

5. Using AWS CLI in EC2 scan DynamoDB table from the EC2 instance, Login to the EC2 we created earlier and run the following command:

aws dynamodb scan --table-name BMWCars

The scan was successful! See the output below:

{
"Count": 14,
"Items": [
{
"ModelSeries": {
"S": "3 Series (E46)"
},
"VehicleClass": {
"S": "Compact executive car"
},
"Years": {
"S": "1998-2006"
}
},
{
"ModelSeries": {
"S": "2 Series (F22/F23)"
},
"VehicleClass": {
"S": "Subcompact car"
},
"Years": {
"S": "2013-2021"
}
},
{
"ModelSeries": {
"S": "1 Series (F52)"
},
"VehicleClass": {
"S": "Subcompact executive car"
},
"Years": {
"S": "2017-Present"
}
},
{
"ModelSeries": {
"S": "2 Series (G42)"
},
"VehicleClass": {
"S": "Subcompact car"
},
"Years": {
"S": "2014-Present"
}
},
{
"ModelSeries": {
"S": "1 Series (F40)"
},
"VehicleClass": {
"S": "Subcompact car"
},
"Years": {
"S": "2019-Present"
}
},
{
"ModelSeries": {
"S": "3 Series (E36)"
},
"VehicleClass": {
"S": "Compact executive car"
},
"Years": {
"S": "1990-2000"
}
},
{
"ModelSeries": {
"S": "1 Series (E81/E82/E87/E88)"
},
"VehicleClass": {
"S": "Hatchback, coupé, convertible"
},
"Years": {
"S": "2004-2013"
}
},
{
"ModelSeries": {
"S": "3 Series (E30)"
},
"VehicleClass": {
"S": "Compact executive car"
},
"Years": {
"S": "1982-1994"
}
},
{
"ModelSeries": {
"S": "1 Series (F20/F21)"
},
"VehicleClass": {
"S": "Subcompact car"
},
"Years": {
"S": "2011-2019"
}
},
{
"ModelSeries": {
"S": "3 Series (E21)"
},
"VehicleClass": {
"S": "Compact executive car"
},
"Years": {
"S": "1975-1983"
}
},
{
"ModelSeries": {
"S": "3 Series (E90/E91/E92/E93)"
},
"VehicleClass": {
"S": "Compact executive car"
},
"Years": {
"S": "2005-2013"
}
},
{
"ModelSeries": {
"S": "2 Series (F44)"
},
"VehicleClass": {
"S": "Subcompact car"
},
"Years": {
"S": "2019-Present"
}
},
{
"ModelSeries": {
"S": "2 Series (U06)"
},
"VehicleClass": {
"S": "Subcompact MPV"
},
"Years": {
"S": "2021-Present"
}
},
{
"ModelSeries": {
"S": "2 Series (F45/F46)"
},
"VehicleClass": {
"S": "Subcompact MPV"
},
"Years": {
"S": "2014-Present"
}
}
],
"ScannedCount": 14,
"ConsumedCapacity": null

6. Using AWS CLI in EC2 instance validate we cannot write to the DynamoDb table

[ec2-user@ip-172-31-54-131 ~]$ aws dynamodb put-item --region us-east-1 --table-name BMWCars --item '{"m3": {"S": "e46"}, "years": {"S": "2023"}}'

An error occurred (AccessDeniedException) when calling the PutItem operation: User: arn:aws:sts::401972318485:assumed-role/BMWDynamoDBReadOnly/i-07d8be113102e357b is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:us-east-1:401972318485:table/BMWCars because no identity-based policy allows the dynamodb:PutItem action

Success!! We cannot write to DynamoDB!

Thank you for reading my article. If you found this article useful show your support by clapping.

--

--