Project Zero: Cloud Lab (Part 3)

case study

Storage

last edited 2026-09-02

In this section, I configured AWS storage and recovery capabilities for the production environment. I deployed encrypted EBS storage, created snapshots for backup and recovery, and built a custom AMI of the production web server.

I then launched a new EC2 instance from the AMI and successfully ran the Threat Intelligence Application, validating that the configured workload could be reproduced and restored from the image.

-projectzero-prod-vpc has been created with subnets configured.

-projectzero-prod-jumpbox EC2 instance exists and is accessible.

-projectzero-prod-websvr EC2 instance exists (or any EC2 instance for testing).

-My-Desktop-Key-Pair key pair exists.

-AWS CLI configured with appropriate credentials.


#EBS & Snapshots

This section covers the implementation of persistent and recoverable storage for the production web server. I configured an encrypted EBS volume, attached and mounted it to the EC2 instance, made the mount persistent across reboots, and created an EBS snapshot to provide a point-in-time backup for recovery.

##Create and Configure EBS Volume

In this section, I configured Amazon Elastic Block Store (EBS) to provide persistent storage for the production web server. The volume is encrypted at rest and can be independently attached, detached, backed up, and restored using EBS snapshots, providing a foundation for secure storage and recovery within the AWS environment.

1.Availability Zone

The volume was placed in the same Availability Zone as projectzero-prod-websvr to allow it to be attached to the EC2 instance.

Verified  projectzero-prod-websvr  is deployed in  eu-north-1a , establishing the required Availability Zone for the new EBS volume.
Verified projectzero-prod-websvr is deployed in eu-north-1a, establishing the required Availability Zone for the new EBS volume.

2.Configure Volume Settings

I created a dedicated EBS volume to provide persistent storage for the production web server, configuring the volume with the following settings:

-Volume type: gp3 (General Purpose SSD)

-Size: 10 GiB

-IOPS: Default (3000 for gp3)

-Throughput: Default (125 MiB/s for gp3)

Creating a 10 GiB encrypted gp3 EBS volume in  eu-north-1a  for attachment to the production web server.
Creating a 10 GiB encrypted gp3 EBS volume in eu-north-1a for attachment to the production web server.

3.Enable Encryption at Rest

-KMS key: Default AWS managed key (aws/ebs)

-Encryption at rest is a security best practice. For production, consider using customer managed KMS keys.

-Note: I recorded the Volume ID for use during the attachment and snapshot configuration steps.


##Attach EBS Volume to EC2 Instance

After creating the encrypted EBS volume, I attached it to the production web server. Because EBS volumes are Availability Zone specific, the volume and EC2 instance must reside in the same Availability Zone before they can be attached.

1.Attach Volume via Console

From EC2 → Elastic Block Store → Volumes, I selected the newly created projectzero-volume and chose Actions → Attach volume.

Selected the newly created  projectzero-volume  and initiated the attachment process from the EC2 console.
Selected the newly created projectzero-volume and initiated the attachment process from the EC2 console.

2.Select the Production Web Server

I selected projectzero-prod-websvr as the target EC2 instance and assigned /dev/sdf as the requested Linux device name. AWS may expose the device internally using an NVMe device name on Nitro-based EC2 instances.

Attached  projectzero-volume  to  projectzero-prod-websvr  using  /dev/sdf  as the requested device name.
Attached projectzero-volume to projectzero-prod-websvr using /dev/sdf as the requested device name.

3.Verify the Attached Volume via SSH

I connected to projectzero-prod-websvr through the jumpbox and used lsblk to inspect the available block devices. The newly attached 10 GiB EBS volume appeared as nvme1n1, confirming that the volume was successfully attached and recognized by the operating system.

lsblk  confirms the newly attached 10 GiB EBS volume is available to  projectzero-prod-websvr  as  nvme1n1 .
lsblk confirms the newly attached 10 GiB EBS volume is available to projectzero-prod-websvr as nvme1n1.

##Format and Mount the EBS Volume

After attaching the EBS volume to projectzero-prod-websvr, I prepared it for use by creating an ext4 filesystem, mounting it to a dedicated directory, and validating read/write access. This makes the newly provisioned block storage accessible to the operating system and ready to store application data.

1.Identify the Device

I used lsblk to identify the newly attached EBS volume. The 10 GiB volume was presented to the instance as nvme1n1 and did not yet contain a filesystem or mount point.

2.Create a File System

I formatted the new EBS volume with the ext4 filesystem so it could be used for persistent Linux storage.

sudo mkfs -t ext4 /dev/nvme1n1

Successfully created an ext4 filesystem on the newly attached  nvme1n1  EBS volume.
Successfully created an ext4 filesystem on the newly attached nvme1n1 EBS volume.

3.Create a Mount Point

I created a dedicated directory that will serve as the mount point for the EBS volume.

sudo mkdir /mnt/projectzero-data

4.Mount the EBS Volume

I mounted the formatted EBS volume to /mnt/projectzero-data, making the storage accessible through the production web server's filesystem.

sudo mount /dev/nvme1n1 /mnt/projectzero-data

5.Verify the Mount

I used df -h to confirm that the EBS volume was successfully mounted. The output shows the 10 GiB nvme1n1 device mounted at /mnt/projectzero-data.

Verified that the 10 GiB EBS volume is mounted successfully at  /mnt/projectzero-data .
Verified that the 10 GiB EBS volume is mounted successfully at /mnt/projectzero-data.

6.Test the Volume

Finally, I created a test file on the mounted volume and read its contents back to verify that the filesystem was writable and functioning correctly.

echo "EBS Volume Test - $(date)" | sudo tee /mnt/projectzero-data/test.txt

cat /mnt/projectzero-data/test.txt

Successfully wrote and retrieved a test file from  /mnt/projectzero-data , confirming functional read/write access to the EBS volume.
Successfully wrote and retrieved a test file from /mnt/projectzero-data, confirming functional read/write access to the EBS volume.

7.Make Mount Persistent

To ensure the EBS volume remains available after the EC2 instance is rebooted, I configured a persistent mount using /etc/fstab. I used the filesystem UUID rather than the NVMe device name to provide a stable reference for the volume across reboots.

First, I retrieved the UUID of the EBS filesystem: sudo blkid /dev/nvme1n1

Retrieved the filesystem UUID of  nvme1n1  for use in the persistent mount configuration.
Retrieved the filesystem UUID of nvme1n1 for use in the persistent mount configuration.

Then I edited /etc/fstab:

sudo nano /etc/fstab

and added the EBS volume:

UUID=bba4eff6-1bcf-43c0-82f4-e364a5ddfcd3 /mnt/projectzero-data ext4 defaults,nofail 0 2

Added the EBS filesystem UUID to  /etc/fstab , configuring  /mnt/projectzero-data  to mount automatically during system startup.
Added the EBS filesystem UUID to /etc/fstab, configuring /mnt/projectzero-data to mount automatically during system startup.

Using nofail allows the EC2 instance to continue booting even if the EBS volume is temporarily unavailable. Finally, I validated the configuration:

sudo mount -a

The command completed without errors, validating the /etc/fstab entry and confirming that the EBS volume is configured for persistent mounting.


##Create EBS Snapshot

After configuring and validating the EBS volume, I created a point-in-time snapshot to demonstrate backup and recovery capabilities. EBS snapshots provide a reusable backup of volume data that can later be used to restore or create replacement volumes.

1.Create Snapshot

From EC2 → Elastic Block Store → Volumes, I selected projectzero-volume and chose Actions → Create snapshot. I configured the snapshot with a descriptive name and description so the recovery point could be easily identified.

Selected  projectzero-volume  and initiated creation of an EBS snapshot from the EC2 console.
Selected projectzero-volume and initiated creation of an EBS snapshot from the EC2 console.

2.Verify Snapshot Completion

Snapshot creation occurs asynchronously. I monitored the snapshot until its status changed to Completed and progress reached 100%, confirming that the backup was successfully created.

Verified that the EBS snapshot completed successfully, providing a recoverable point-in-time backup of the production data volume.
Verified that the EBS snapshot completed successfully, providing a recoverable point-in-time backup of the production data volume.

#Lab Cleanup

After completing the EBS storage and snapshot validation, I removed the temporary resources to maintain a clean environment and avoid unnecessary AWS costs.

-Removed the EBS entry from /etc/fstab and unmounted the volume.

-Detached and deleted the temporary EBS volume.

-Deleted the test snapshot after validation.


#Create Web Server AMI

In this section, I created a custom Amazon Machine Image (AMI) from the configured projectzero-prod-websvr EC2 instance. The AMI captures the server configuration and provides a reusable baseline that can be used to deploy additional instances without rebuilding the web server from scratch.

1.Create AMI from the Web Server

I selected the existing projectzero-prod-websvr instance and created an image from its current configuration using: Actions → Image and templates → Create image I configured the image with a descriptive name and included the instance storage configuration as part of the AMI.

Creating a custom AMI from the configured  projectzero-prod-websvr  EC2 instance.
Creating a custom AMI from the configured projectzero-prod-websvr EC2 instance.
Screenshot from project documentation

2.Verify AMI Creation

After the image creation process completed, I verified that the custom AMI was available and recorded its AMI ID for use when launching a new instance.

Verified the custom web server AMI reached the  Available  state and was ready for deployment.
Verified the custom web server AMI reached the Available state and was ready for deployment.

AMI ID: ami-0c09f5dbf3117c39b


#Launch Instance from AMI in Public Subnet

To validate that the custom AMI could be reused successfully, I launched a new EC2 instance from the image. Unlike the original web server, which resides in the private web subnet, this instance was deployed into the public subnet to provide direct network access for testing.

1.Select the Custom AMI I selected the previously created projectzero-prod-websvr-ami as the machine image for the new EC2 instance.

Selected the custom  projectzero-prod-websvr-ami  as the baseline image for the new EC2 instance.
Selected the custom projectzero-prod-websvr-ami as the baseline image for the new EC2 instance.

2.Configure Instance Type and Key Pair

I configured the new instance with the same t3.small instance type as the original web server and selected my existing SSH key pair for administrative access.

-Instance type: t3.small

-Key pair: My-Desktop-Key-Pair

Configured the EC2 instance type and SSH key pair for the AMI-based deployment.
Configured the EC2 instance type and SSH key pair for the AMI-based deployment.

3.Configure Network Settings

I deployed the instance into the existing projectzero-prod-vpc, but selected the Public Subnet instead of the private web subnet. I also enabled automatic public IPv4 assignment so the instance could be accessed directly for validation.

-VPC: projectzero-prod-vpc

-Subnet: Public Subnet

-Auto-assign public IP: Enabled

-Security group: projectzero-prod-websvr-sg

Configured the AMI-based instance in the public subnet with a public IPv4 address and the existing web server security group.
Configured the AMI-based instance in the public subnet with a public IPv4 address and the existing web server security group.

4.Launch the AMI-Based Web Server

I launched a new EC2 instance from the custom AMI using the public subnet configuration. For validation, I updated the security group to permit access to the application on TCP port 4321.

-Name: projectzero-prod-websvr

-AMI: projectzero-prod-websvr-ami

-Instance type: t3.small

-Key pair: My-Desktop-Key-Pair

-VPC: projectzero-prod-vpc

-Subnet: Public Subnet

-Auto-assign public IP: Enabled

-Security group: projectzero-prod-websvr-SG

Updated the web server security group to permit inbound access to the application on TCP port  4321  for validation.
Updated the web server security group to permit inbound access to the application on TCP port 4321 for validation.

5.Validate the AMI Deployment

After the new instance launched, I connected to it and confirmed that the threat-intel-app application files were already present. This verified that the custom AMI successfully preserved the configured web server environment.

Verified that the AMI-based EC2 instance retained the  threat-intel-app  application files from the original web server.
Verified that the AMI-based EC2 instance retained the threat-intel-app application files from the original web server.

1.Start the Threat Intelligence Application

I allowed TCP port 4321 through the host firewall and started the application with the Astro development server, binding it to all network interfaces so it could accept external connections.

sudo ufw allow 4321/tcp npm run dev -- --host

The application successfully started and listened on 0.0.0.0:4321.

Started the Threat Intelligence Application on TCP port  4321 , confirming the application runs successfully on the AMI-based instance.
Started the Threat Intelligence Application on TCP port 4321, confirming the application runs successfully on the AMI-based instance.

6.Verify External Application Access

Finally, I accessed the Threat Intelligence Application using the new EC2 instance's public IPv4 address on port 4321. The application loaded successfully in the browser, validating the AMI deployment from end to end.

Successfully accessed the Threat Intelligence Application through the EC2 instance's public IPv4 address on port  4321 .
Successfully accessed the Threat Intelligence Application through the EC2 instance's public IPv4 address on port 4321.

#Why This Matters

EBS volumes provide persistent storage, while snapshots enable backup and recovery. Custom AMIs allow configured EC2 workloads to be quickly reproduced without rebuilding them from scratch. Together, these capabilities support data protection, disaster recovery, and consistent workload deployment in AWS.