ikb42603-cloud-security-labs

v2026.09.24

AWS cloud computing security essentials lab exercises covering IAM, encryption, network security, and monitoring

GitHub
Install command
npx skhub add reason-machines/ikb42603-cloud-security-labs
Markdown
SKILL.md

IKB42603 Cloud Security Labs Skill

Skill by ara.so — Security Skills collection.

Overview

This project provides hands-on laboratory exercises for learning AWS cloud computing security essentials. It covers five core security domains: account security and IAM, secure isolation and multitenancy, encryption and key management, access control and network security, and monitoring/logging/incident detection.

The labs are designed for educational purposes and follow a structured approach to implementing AWS security best practices using real AWS services.

Repository Structure

The project organizes labs into separate markdown files:

IKB42603-CLOUD-COMPUTING-SECURITY-ESSENTIALS/
├── README.md
├── Lab0_Environment_Setup.md
├── Lab1_Account_Security_and_IAM.md
├── Lab2_Secure_Isolation_and_Multitenancy.md
├── Lab3_Encryption_and_Key_Management.md
├── Lab4_Access_Control_and_Network_Security.md
└── Lab5_Monitoring_Logging_and_Incident_Detection.md

Prerequisites

Required Tools

  1. AWS Account - Free tier eligible
  2. AWS CLI - Command line interface for AWS services
  3. Git - Version control
  4. Text Editor - VS Code, Vim, or similar

AWS CLI Installation

# macOS
brew install awscli

# Linux
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# Windows (PowerShell)
msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi

AWS CLI Configuration

# Configure AWS credentials
aws configure

# Enter your credentials when prompted
# AWS Access Key ID: ${AWS_ACCESS_KEY_ID}
# AWS Secret Access Key: ${AWS_SECRET_ACCESS_KEY}
# Default region: us-east-1
# Default output format: json

Lab 1: Account Security and IAM

Creating IAM Users

# Create a new IAM user
aws iam create-user --user-name lab-user-01

# Create access key for programmatic access
aws iam create-access-key --user-name lab-user-01

# Attach policy to user
aws iam attach-user-policy \
  --user-name lab-user-01 \
  --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess

Creating IAM Groups and Roles

# Create IAM group
aws iam create-group --group-name Developers

# Add user to group
aws iam add-user-to-group \
  --user-name lab-user-01 \
  --group-name Developers

# Create IAM role with trust policy
cat > trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

aws iam create-role \
  --role-name EC2-S3-ReadOnly-Role \
  --assume-role-policy-document file://trust-policy.json

# Attach policy to role
aws iam attach-role-policy \
  --role-name EC2-S3-ReadOnly-Role \
  --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

Enabling MFA

# Create virtual MFA device
aws iam create-virtual-mfa-device \
  --virtual-mfa-device-name lab-user-mfa \
  --outfile qr-code.png \
  --bootstrap-method QRCodePNG

# Enable MFA for user (requires two consecutive authentication codes)
aws iam enable-mfa-device \
  --user-name lab-user-01 \
  --serial-number arn:aws:iam::${ACCOUNT_ID}:mfa/lab-user-mfa \
  --authentication-code-1 123456 \
  --authentication-code-2 789012

Custom IAM Policy Example

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

Apply custom policy:

aws iam put-user-policy \
  --user-name lab-user-01 \
  --policy-name S3BucketAccess \
  --policy-document file://custom-policy.json

Lab 2: Secure Isolation and Multitenancy

Creating VPC with Subnets

# Create VPC
aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=LabVPC}]'

# Store VPC ID
VPC_ID=$(aws ec2 describe-vpcs \
  --filters "Name=tag:Name,Values=LabVPC" \
  --query 'Vpcs[0].VpcId' \
  --output text)

# Create public subnet
aws ec2 create-subnet \
  --vpc-id ${VPC_ID} \
  --cidr-block 10.0.1.0/24 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PublicSubnet}]'

# Create private subnet
aws ec2 create-subnet \
  --vpc-id ${VPC_ID} \
  --cidr-block 10.0.2.0/24 \
  --availability-zone us-east-1b \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet}]'

Internet Gateway and Route Tables

# Create and attach Internet Gateway
aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=LabIGW}]'

IGW_ID=$(aws ec2 describe-internet-gateways \
  --filters "Name=tag:Name,Values=LabIGW" \
  --query 'InternetGateways[0].InternetGatewayId' \
  --output text)

aws ec2 attach-internet-gateway \
  --vpc-id ${VPC_ID} \
  --internet-gateway-id ${IGW_ID}

# Create route table for public subnet
aws ec2 create-route-table \
  --vpc-id ${VPC_ID} \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=PublicRouteTable}]'

RT_ID=$(aws ec2 describe-route-tables \
  --filters "Name=tag:Name,Values=PublicRouteTable" \
  --query 'RouteTables[0].RouteTableId' \
  --output text)

# Add route to Internet Gateway
aws ec2 create-route \
  --route-table-id ${RT_ID} \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id ${IGW_ID}

# Associate route table with public subnet
SUBNET_ID=$(aws ec2 describe-subnets \
  --filters "Name=tag:Name,Values=PublicSubnet" \
  --query 'Subnets[0].SubnetId' \
  --output text)

aws ec2 associate-route-table \
  --route-table-id ${RT_ID} \
  --subnet-id ${SUBNET_ID}

NAT Gateway for Private Subnet

# Allocate Elastic IP
aws ec2 allocate-address --domain vpc

EIP_ID=$(aws ec2 describe-addresses \
  --query 'Addresses[0].AllocationId' \
  --output text)

# Create NAT Gateway in public subnet
aws ec2 create-nat-gateway \
  --subnet-id ${SUBNET_ID} \
  --allocation-id ${EIP_ID} \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=LabNAT}]'

Lab 3: Encryption and Key Management

Creating KMS Keys

# Create customer managed key
aws kms create-key \
  --description "Lab encryption key for S3" \
  --key-usage ENCRYPT_DECRYPT \
  --origin AWS_KMS

KEY_ID=$(aws kms list-keys --query 'Keys[0].KeyId' --output text)

# Create alias for the key
aws kms create-alias \
  --alias-name alias/lab-s3-key \
  --target-key-id ${KEY_ID}

# Get key details
aws kms describe-key --key-id alias/lab-s3-key

S3 Bucket Encryption

# Create S3 bucket with encryption
aws s3api create-bucket \
  --bucket my-encrypted-lab-bucket-${RANDOM} \
  --region us-east-1

BUCKET_NAME=$(aws s3api list-buckets \
  --query 'Buckets[-1].Name' \
  --output text)

# Enable default encryption with KMS
aws s3api put-bucket-encryption \
  --bucket ${BUCKET_NAME} \
  --server-side-encryption-configuration '{
    "Rules": [
      {
        "ApplyServerSideEncryptionByDefault": {
          "SSEAlgorithm": "aws:kms",
          "KMSMasterKeyID": "'${KEY_ID}'"
        },
        "BucketKeyEnabled": true
      }
    ]
  }'

# Upload encrypted object
aws s3 cp document.txt s3://${BUCKET_NAME}/ \
  --sse aws:kms \
  --sse-kms-key-id ${KEY_ID}

EBS Volume Encryption

# Create encrypted EBS volume
aws ec2 create-volume \
  --size 10 \
  --encrypted \
  --kms-key-id ${KEY_ID} \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=EncryptedVolume}]'

# Enable encryption by default for the region
aws ec2 enable-ebs-encryption-by-default

RDS Encryption

# Create encrypted RDS instance
aws rds create-db-instance \
  --db-instance-identifier lab-encrypted-db \
  --db-instance-class db.t3.micro \
  --engine mysql \
  --master-username admin \
  --master-user-password ${DB_PASSWORD} \
  --allocated-storage 20 \
  --storage-encrypted \
  --kms-key-id ${KEY_ID}

Lab 4: Access Control and Network Security

Security Groups

# Create security group for web server
aws ec2 create-security-group \
  --group-name WebServerSG \
  --description "Security group for web servers" \
  --vpc-id ${VPC_ID}

SG_ID=$(aws ec2 describe-security-groups \
  --filters "Name=group-name,Values=WebServerSG" \
  --query 'SecurityGroups[0].GroupId' \
  --output text)

# Allow HTTP traffic
aws ec2 authorize-security-group-ingress \
  --group-id ${SG_ID} \
  --protocol tcp \
  --port 80 \
  --cidr 0.0.0.0/0

# Allow HTTPS traffic
aws ec2 authorize-security-group-ingress \
  --group-id ${SG_ID} \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0

# Allow SSH from specific IP
aws ec2 authorize-security-group-ingress \
  --group-id ${SG_ID} \
  --protocol tcp \
  --port 22 \
  --cidr ${MY_IP}/32

Network ACLs

# Create Network ACL
aws ec2 create-network-acl \
  --vpc-id ${VPC_ID} \
  --tag-specifications 'ResourceType=network-acl,Tags=[{Key=Name,Value=CustomNACL}]'

NACL_ID=$(aws ec2 describe-network-acls \
  --filters "Name=tag:Name,Values=CustomNACL" \
  --query 'NetworkAcls[0].NetworkAclId' \
  --output text)

# Allow inbound HTTP
aws ec2 create-network-acl-entry \
  --network-acl-id ${NACL_ID} \
  --rule-number 100 \
  --protocol tcp \
  --port-range From=80,To=80 \
  --cidr-block 0.0.0.0/0 \
  --egress false \
  --rule-action allow

# Allow outbound traffic
aws ec2 create-network-acl-entry \
  --network-acl-id ${NACL_ID} \
  --rule-number 100 \
  --protocol -1 \
  --cidr-block 0.0.0.0/0 \
  --egress true \
  --rule-action allow

VPC Flow Logs

# Create CloudWatch Log Group
aws logs create-log-group --log-group-name /aws/vpc/flowlogs

# Create IAM role for Flow Logs
cat > flow-logs-trust.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "vpc-flow-logs.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

aws iam create-role \
  --role-name VPCFlowLogsRole \
  --assume-role-policy-document file://flow-logs-trust.json

# Enable VPC Flow Logs
aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids ${VPC_ID} \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name /aws/vpc/flowlogs \
  --deliver-logs-permission-arn arn:aws:iam::${ACCOUNT_ID}:role/VPCFlowLogsRole

Lab 5: Monitoring, Logging, and Incident Detection

CloudTrail Setup

# Create S3 bucket for CloudTrail logs
aws s3api create-bucket \
  --bucket cloudtrail-logs-${ACCOUNT_ID}-${RANDOM} \
  --region us-east-1

TRAIL_BUCKET=$(aws s3api list-buckets \
  --query 'Buckets[-1].Name' \
  --output text)

# Apply bucket policy for CloudTrail
cat > cloudtrail-bucket-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailAclCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::${TRAIL_BUCKET}"
    },
    {
      "Sid": "AWSCloudTrailWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::${TRAIL_BUCKET}/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}
EOF

aws s3api put-bucket-policy \
  --bucket ${TRAIL_BUCKET} \
  --policy file://cloudtrail-bucket-policy.json

# Create CloudTrail
aws cloudtrail create-trail \
  --name lab-security-trail \
  --s3-bucket-name ${TRAIL_BUCKET}

# Start logging
aws cloudtrail start-logging --name lab-security-trail

# Enable log file validation
aws cloudtrail update-trail \
  --name lab-security-trail \
  --enable-log-file-validation

CloudWatch Alarms

# Create SNS topic for alerts
aws sns create-topic --name SecurityAlerts

TOPIC_ARN=$(aws sns list-topics \
  --query 'Topics[?contains(TopicArn, `SecurityAlerts`)].TopicArn' \
  --output text)

# Subscribe email to topic
aws sns subscribe \
  --topic-arn ${TOPIC_ARN} \
  --protocol email \
  --notification-endpoint ${EMAIL_ADDRESS}

# Create CloudWatch alarm for unauthorized API calls
aws cloudwatch put-metric-alarm \
  --alarm-name UnauthorizedAPICalls \
  --alarm-description "Alert on unauthorized API calls" \
  --metric-name UnauthorizedAPICalls \
  --namespace AWS/CloudTrail \
  --statistic Sum \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --evaluation-periods 1 \
  --alarm-actions ${TOPIC_ARN}

CloudWatch Logs Insights Queries

# Query CloudTrail logs for failed login attempts
aws logs start-query \
  --log-group-name /aws/cloudtrail \
  --start-time $(date -u -d '1 hour ago' +%s) \
  --end-time $(date -u +%s) \
  --query-string '
    fields @timestamp, userIdentity.principalId, eventName, errorCode
    | filter eventName = "ConsoleLogin" and errorMessage = "Failed authentication"
    | sort @timestamp desc
    | limit 20
  '

GuardDuty Enablement

# Enable GuardDuty
aws guardduty create-detector --enable

DETECTOR_ID=$(aws guardduty list-detectors \
  --query 'DetectorIds[0]' \
  --output text)

# Get findings
aws guardduty list-findings --detector-id ${DETECTOR_ID}

# Get finding details
FINDING_ID=$(aws guardduty list-findings \
  --detector-id ${DETECTOR_ID} \
  --query 'FindingIds[0]' \
  --output text)

aws guardduty get-findings \
  --detector-id ${DETECTOR_ID} \
  --finding-ids ${FINDING_ID}

Common Patterns

Lab Documentation Structure

Each lab should follow this structure in its markdown file:

# Lab X: [Title]

## Objective
Brief description of what students will learn.

## Prerequisites
- AWS Account
- AWS CLI configured
- Specific permissions needed

## Tasks

### Task 1: [Task Name]
Step-by-step instructions with commands.

### Task 2: [Task Name]
More detailed steps.

## Verification
How to verify the lab was completed successfully.

## Screenshots
![Description](path/to/screenshot.png)

## Cleanup
Commands to remove resources and avoid charges.

## Reflection
Questions for students to consider.

Resource Cleanup Script

#!/bin/bash
# cleanup.sh - Remove all lab resources

# Delete EC2 instances
aws ec2 terminate-instances --instance-ids $(aws ec2 describe-instances \
  --filters "Name=tag:Lab,Values=CloudSecurity" \
  --query 'Reservations[].Instances[].InstanceId' \
  --output text)

# Delete Security Groups
for sg in $(aws ec2 describe-security-groups \
  --filters "Name=tag:Lab,Values=CloudSecurity" \
  --query 'SecurityGroups[].GroupId' \
  --output text); do
  aws ec2 delete-security-group --group-id $sg
done

# Delete S3 buckets
for bucket in $(aws s3api list-buckets \
  --query 'Buckets[?contains(Name, `lab`)].Name' \
  --output text); do
  aws s3 rm s3://$bucket --recursive
  aws s3api delete-bucket --bucket $bucket
done

# Delete IAM users
for user in $(aws iam list-users \
  --query 'Users[?contains(UserName, `lab`)].UserName' \
  --output text); do
  aws iam delete-user --user-name $user
done

# Delete CloudTrail trails
aws cloudtrail delete-trail --name lab-security-trail

# Disable GuardDuty
DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text)
aws guardduty delete-detector --detector-id ${DETECTOR_ID}

Troubleshooting

AWS CLI Authentication Issues

# Verify credentials are configured
aws sts get-caller-identity

# Check if credentials are expired
aws sts get-session-token

# Reconfigure credentials
aws configure

Permission Denied Errors

# Check effective permissions for current user
aws iam get-user

# Simulate policy to test permissions
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::${ACCOUNT_ID}:user/lab-user-01 \
  --action-names s3:GetObject \
  --resource-arns arn:aws:s3:::my-bucket/file.txt

VPC Connectivity Issues

# Check VPC configuration
aws ec2 describe-vpcs --vpc-ids ${VPC_ID}

# Verify Internet Gateway attachment
aws ec2 describe-internet-gateways \
  --filters "Name=attachment.vpc-id,Values=${VPC_ID}"

# Check route tables
aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=${VPC_ID}"

# Verify security group rules
aws ec2 describe-security-groups --group-ids ${SG_ID}

S3 Encryption Issues

# Verify bucket encryption settings
aws s3api get-bucket-encryption --bucket ${BUCKET_NAME}

# Check KMS key permissions
aws kms get-key-policy \
  --key-id ${KEY_ID} \
  --policy-name default

# Test encryption with a small file
echo "test" > test.txt
aws s3 cp test.txt s3://${BUCKET_NAME}/ \
  --sse aws:kms \
  --sse-kms-key-id ${KEY_ID} \
  --debug

CloudTrail Not Logging

# Check trail status
aws cloudtrail get-trail-status --name lab-security-trail

# Verify S3 bucket policy
aws s3api get-bucket-policy --bucket ${TRAIL_BUCKET}

# Check CloudTrail event selectors
aws cloudtrail get-event-selectors --trail-name lab-security-trail

# Manually validate logs are being written
aws cloudtrail lookup-events --max-results 10

Best Practices

  1. Always tag resources with Lab and Environment tags for easy identification
  2. Use least privilege when creating IAM policies
  3. Enable MFA on all user accounts
  4. Encrypt sensitive data at rest and in transit
  5. Enable logging for all services (CloudTrail, VPC Flow Logs, S3 access logs)
  6. Clean up resources after completing labs to avoid unnecessary charges
  7. Use CloudFormation or Terraform for repeatable deployments
  8. Document everything with screenshots and explanations
  9. Test security controls by attempting unauthorized access
  10. Review costs regularly using AWS Cost Explorer

Environment Variables Reference

Store these in .env file (never commit to repository):

# AWS Credentials
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_DEFAULT_REGION=us-east-1

# Account Information
export ACCOUNT_ID=123456789012
export MY_IP=203.0.113.0

# Database Credentials
export DB_PASSWORD=SecurePassword123!

# Notification
export EMAIL_ADDRESS=student@example.com

Load environment variables:

source .env
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

NOASSERTION

Source path

skills/ikb42603-cloud-security-labs

Default branch

main

Latest commit

304c245

Tree SHA

010f47d