| name | ikb42603-cloud-security-essentials |
| description | AWS cloud security lab exercises covering IAM, VPC, encryption, monitoring, and incident detection for hands-on security learning |
| triggers | ["help me with AWS cloud security labs","how do I configure IAM security in AWS","set up VPC isolation and security groups","implement AWS KMS encryption","configure CloudTrail and CloudWatch monitoring","complete cloud computing security exercises","AWS security best practices lab","hands-on AWS security configuration"] |
IKB42603 Cloud Security Essentials Skill
Skill by ara.so — Security Skills collection.
Overview
IKB42603-CLOUD-COMPUTING-SECURITY-ESSENTIALS is an educational repository containing hands-on laboratory exercises for learning AWS cloud security fundamentals. The project covers five core security domains: IAM and account security, secure isolation and multitenancy, encryption and key management, access control and network security, and monitoring/logging/incident detection.
This skill helps developers and students complete practical AWS security implementations using the AWS Console, AWS CLI, and infrastructure-as-code approaches.
Repository Structure
The project is organized into five lab modules:
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
Installation & Setup
Clone the Repository
git clone https://github.com/<username>/IKB42603-CLOUD-COMPUTING-SECURITY-ESSENTIALS.git
cd IKB42603-CLOUD-COMPUTING-SECURITY-ESSENTIALS
Prerequisites
- AWS Account (Free Tier eligible)
- AWS CLI installed and configured
- Git for version control
- Text editor (VS Code, Vim, etc.)
Configure AWS CLI
aws configure
aws sts get-caller-identity
Lab 1: Account Security and IAM
Create IAM Users with Policies
aws iam create-user --user-name security-admin
cat > security-admin-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:*",
"cloudtrail:*",
"cloudwatch:*"
],
"Resource": "*"
}
]
}
EOF
aws iam create-policy \
--policy-name SecurityAdminPolicy \
--policy-document file://security-admin-policy.json
aws iam attach-user-policy \
--user-name security-admin \
--policy-arn arn:aws:iam::${AWS_ACCOUNT_ID}:policy/SecurityAdminPolicy
Enable MFA for Root Account
aws iam create-virtual-mfa-device \
--virtual-mfa-device-name root-mfa \
--outfile mfa-qr.png \
--bootstrap-method QRCodePNG
aws iam enable-mfa-device \
--user-name root \
--serial-number arn:aws:iam::${AWS_ACCOUNT_ID}:mfa/root-mfa \
--authentication-code1 <CODE1> \
--authentication-code2 <CODE2>
Create IAM Groups with Least Privilege
aws iam create-group --group-name Developers
aws iam attach-group-policy \
--group-name Developers \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess
aws iam add-user-to-group \
--user-name security-admin \
--group-name Developers
Lab 2: Secure Isolation and Multitenancy
Create Isolated VPC
aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=SecureVPC}]'
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}]'
aws ec2 create-subnet \
--vpc-id <VPC_ID> \
--cidr-block 10.0.2.0/24 \
--availability-zone us-east-1a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=PrivateSubnet}]'
aws ec2 create-internet-gateway \
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=SecureIGW}]'
aws ec2 attach-internet-gateway \
--internet-gateway-id <IGW_ID> \
--vpc-id <VPC_ID>
Configure Security Groups
aws ec2 create-security-group \
--group-name web-tier-sg \
--description "Security group for web tier" \
--vpc-id <VPC_ID>
aws ec2 authorize-security-group-ingress \
--group-id <SG_ID> \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0
aws ec2 create-security-group \
--group-name db-tier-sg \
--description "Security group for database tier" \
--vpc-id <VPC_ID>
aws ec2 authorize-security-group-ingress \
--group-id <DB_SG_ID> \
--protocol tcp \
--port 3306 \
--source-group <WEB_SG_ID>
Create Network ACLs
aws ec2 create-network-acl \
--vpc-id <VPC_ID> \
--tag-specifications 'ResourceType=network-acl,Tags=[{Key=Name,Value=PrivateNACL}]'
aws ec2 create-network-acl-entry \
--network-acl-id <NACL_ID> \
--ingress \
--rule-number 100 \
--protocol tcp \
--port-range From=443,To=443 \
--cidr-block 10.0.1.0/24 \
--rule-action allow
aws ec2 create-network-acl-entry \
--network-acl-id <NACL_ID> \
--egress \
--rule-number 100 \
--protocol tcp \
--port-range From=1024,To=65535 \
--cidr-block 0.0.0.0/0 \
--rule-action allow
Lab 3: Encryption and Key Management
Create KMS Key
aws kms create-key \
--description "Data encryption key for Lab 3" \
--key-usage ENCRYPT_DECRYPT \
--origin AWS_KMS
aws kms create-alias \
--alias-name alias/lab3-encryption-key \
--target-key-id <KEY_ID>
cat > key-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${AWS_ACCOUNT_ID}:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow use of the key for encryption",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${AWS_ACCOUNT_ID}:user/security-admin"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "*"
}
]
}
EOF
aws kms put-key-policy \
--key-id <KEY_ID> \
--policy-name default \
--policy file://key-policy.json
Encrypt S3 Bucket with KMS
aws s3api create-bucket \
--bucket secure-data-bucket-${AWS_ACCOUNT_ID} \
--region us-east-1
aws s3api put-bucket-encryption \
--bucket secure-data-bucket-${AWS_ACCOUNT_ID} \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "alias/lab3-encryption-key"
},
"BucketKeyEnabled": true
}]
}'
aws s3 cp sensitive-data.txt \
s3://secure-data-bucket-${AWS_ACCOUNT_ID}/ \
--server-side-encryption aws:kms \
--ssekms-key-id alias/lab3-encryption-key
Encrypt EBS Volume
aws ec2 create-volume \
--availability-zone us-east-1a \
--size 10 \
--volume-type gp3 \
--encrypted \
--kms-key-id alias/lab3-encryption-key \
--tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=EncryptedVolume}]'
aws ec2 attach-volume \
--volume-id <VOLUME_ID> \
--instance-id <INSTANCE_ID> \
--device /dev/sdf
Encrypt Data at Application Level
aws kms encrypt \
--key-id alias/lab3-encryption-key \
--plaintext fileb://plaintext.txt \
--output text \
--query CiphertextBlob > encrypted.bin
aws kms decrypt \
--ciphertext-blob fileb://encrypted.bin \
--output text \
--query Plaintext | base64 --decode
Lab 4: Access Control and Network Security
Create VPC Endpoints
aws ec2 create-vpc-endpoint \
--vpc-id <VPC_ID> \
--service-name com.amazonaws.us-east-1.s3 \
--route-table-ids <ROUTE_TABLE_ID>
aws ec2 create-vpc-endpoint \
--vpc-id <VPC_ID> \
--vpc-endpoint-type Interface \
--service-name com.amazonaws.us-east-1.secretsmanager \
--subnet-ids <SUBNET_ID> \
--security-group-ids <SG_ID>
Configure AWS WAF
aws wafv2 create-ip-set \
--name BlockedIPs \
--scope REGIONAL \
--ip-address-version IPV4 \
--addresses 192.0.2.0/24 203.0.113.0/24
aws wafv2 create-web-acl \
--name SecurityLabWAF \
--scope REGIONAL \
--default-action Allow={} \
--rules file://waf-rules.json \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=SecurityLabWAF
Configure AWS Systems Manager Session Manager
cat > ec2-role-trust.json <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
EOF
aws iam create-role \
--role-name SSMRole \
--assume-role-policy-document file://ec2-role-trust.json
aws iam attach-role-policy \
--role-name SSMRole \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
aws ssm start-session --target <INSTANCE_ID>
Lab 5: Monitoring, Logging, and Incident Detection
Enable CloudTrail
aws s3api create-bucket \
--bucket cloudtrail-logs-${AWS_ACCOUNT_ID} \
--region us-east-1
cat > trail-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:::cloudtrail-logs-${AWS_ACCOUNT_ID}"
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": {"Service": "cloudtrail.amazonaws.com"},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::cloudtrail-logs-${AWS_ACCOUNT_ID}/*",
"Condition": {
"StringEquals": {"s3:x-amz-acl": "bucket-owner-full-control"}
}
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket cloudtrail-logs-${AWS_ACCOUNT_ID} \
--policy file://trail-bucket-policy.json
aws cloudtrail create-trail \
--name security-audit-trail \
--s3-bucket-name cloudtrail-logs-${AWS_ACCOUNT_ID} \
--is-multi-region-trail \
--enable-log-file-validation
aws cloudtrail start-logging --name security-audit-trail
Configure CloudWatch Alarms
aws sns create-topic --name SecurityAlerts
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:${AWS_ACCOUNT_ID}:SecurityAlerts \
--protocol email \
--notification-endpoint ${ALERT_EMAIL}
aws logs put-metric-filter \
--log-group-name CloudTrail/DefaultLogGroup \
--filter-name UnauthorizedAPICalls \
--filter-pattern '{ ($.errorCode = "*UnauthorizedOperation") || ($.errorCode = "AccessDenied*") }' \
--metric-transformations \
metricName=UnauthorizedAPICalls,metricNamespace=CloudTrailMetrics,metricValue=1
aws cloudwatch put-metric-alarm \
--alarm-name UnauthorizedAPICallsAlarm \
--alarm-description "Triggers when unauthorized API calls are detected" \
--metric-name UnauthorizedAPICalls \
--namespace CloudTrailMetrics \
--statistic Sum \
--period 300 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:${AWS_ACCOUNT_ID}:SecurityAlerts
Query CloudTrail Logs with Athena
CREATE EXTERNAL TABLE cloudtrail_logs (
eventversion STRING,
useridentity STRUCT<
type:STRING,
principalid:STRING,
arn:STRING,
accountid:STRING,
username:STRING>,
eventtime STRING,
eventsource STRING,
eventname STRING,
awsregion STRING,
sourceipaddress STRING,
useragent STRING,
errorcode STRING,
errormessage STRING,
requestparameters STRING,
responseelements STRING
)
ROW FORMAT SERDE 'com.amazon.emr.hive.serde.CloudTrailSerde'
STORED AS INPUTFORMAT 'com.amazon.emr.cloudtrail.CloudTrailInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://cloudtrail-logs-${AWS_ACCOUNT_ID}/AWSLogs/${AWS_ACCOUNT_ID}/CloudTrail/';
SELECT
eventtime,
useridentity.username,
sourceipaddress,
errorcode,
errormessage
FROM cloudtrail_logs
WHERE eventname = 'ConsoleLogin'
AND errorcode IS NOT NULL
ORDER BY eventtime DESC
LIMIT 50;
Configure AWS GuardDuty
aws guardduty create-detector --enable
DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text)
aws guardduty create-threat-intel-set \
--detector-id ${DETECTOR_ID} \
--name CustomThreatList \
--format TXT \
--location s3://threat-intel-bucket/threats.txt \
--activate
aws guardduty list-findings \
--detector-id ${DETECTOR_ID} \
--finding-criteria '{"Criterion":{"severity":{"Gte":7}}}'
Common Patterns
Secure EC2 Instance Launch
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.micro \
--subnet-id <PRIVATE_SUBNET_ID> \
--security-group-ids <RESTRICTED_SG_ID> \
--iam-instance-profile Name=SSMRole \
--metadata-options HttpTokens=required,HttpPutResponseHopLimit=1 \
--block-device-mappings '[
{
"DeviceName": "/dev/xvda",
"Ebs": {
"VolumeSize": 20,
"VolumeType": "gp3",
"Encrypted": true,
"KmsKeyId": "alias/lab3-encryption-key",
"DeleteOnTermination": true
}
}
]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=SecureInstance}]'
Rotate IAM Access Keys
#!/bin/bash
USER_NAME="security-admin"
NEW_KEY=$(aws iam create-access-key --user-name ${USER_NAME} --output json)
NEW_ACCESS_KEY=$(echo ${NEW_KEY} | jq -r '.AccessKey.AccessKeyId')
NEW_SECRET_KEY=$(echo ${NEW_KEY} | jq -r '.AccessKey.SecretAccessKey')
echo "New Access Key: ${NEW_ACCESS_KEY}"
echo "New Secret Key: ${NEW_SECRET_KEY}"
aws configure set aws_access_key_id ${NEW_ACCESS_KEY} --profile ${USER_NAME}
aws configure set aws_secret_access_key ${NEW_SECRET_KEY} --profile ${USER_NAME}
OLD_KEYS=$(aws iam list-access-keys --user-name ${USER_NAME} --query 'AccessKeyMetadata[?AccessKeyId!=`'${NEW_ACCESS_KEY}'`].AccessKeyId' --output text)
for KEY in ${OLD_KEYS}; do
aws iam update-access-key --user-name ${USER_NAME} --access-key-id ${KEY} --status Inactive
echo "Deactivated old key: ${KEY}"
done
Automated Security Group Auditing
#!/bin/bash
echo "Auditing Security Groups for 0.0.0.0/0 access..."
aws ec2 describe-security-groups --query 'SecurityGroups[*].[GroupId,GroupName,IpPermissions]' --output json | \
jq -r '.[] | select(.[2][]?.IpRanges[]?.CidrIp == "0.0.0.0/0") | "Security Group: \(.[1]) (\(.[0])) has unrestricted access"'
Troubleshooting
IAM Permission Errors
aws sts decode-authorization-message \
--encoded-message <ENCODED_MESSAGE> \
--query DecodedMessage \
--output text | jq '.'
VPC Connectivity Issues
aws ec2 describe-route-tables --filters "Name=vpc-id,Values=<VPC_ID>"
aws ec2 describe-network-acls --filters "Name=vpc-id,Values=<VPC_ID>"
aws ec2 describe-security-groups --group-ids <SG_ID>
aws ec2 create-network-insights-path \
--source <SOURCE_ENI_ID> \
--destination <DEST_ENI_ID> \
--protocol tcp \
--destination-port 443
aws ec2 start-network-insights-analysis \
--network-insights-path-id <PATH_ID>
KMS Key Access Issues
aws kms list-grants --key-id alias/lab3-encryption-key
aws kms get-key-policy \
--key-id alias/lab3-encryption-key \
--policy-name default \
--output text | jq '.'
aws kms describe-key --key-id alias/lab3-encryption-key
CloudTrail Logging Not Working
aws cloudtrail get-trail-status --name security-audit-trail
aws s3api get-bucket-policy \
--bucket cloudtrail-logs-${AWS_ACCOUNT_ID} \
--output text | jq '.'
aws cloudtrail get-event-selectors --trail-name security-audit-trail
Environment Variables
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_DEFAULT_REGION=us-east-1
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export VPC_ID=vpc-xxxxx
export SUBNET_ID=subnet-xxxxx
export KMS_KEY_ALIAS=alias/lab3-encryption-key
export ALERT_EMAIL=security@example.com
Documentation Best Practices
Each lab should include:
# Lab X: [Title]
## Objective
Brief description of what you'll learn
## Prerequisites
- AWS account configured
- IAM permissions required
- Any other dependencies
## Implementation Steps
### Step 1: [Task Name]
\`\`\`bash
# Commands with explanations
\`\`\`
### Step 2: [Task Name]
Screenshots and evidence
## Verification
How to verify the implementation works
## Cleanup
Commands to remove resources and avoid charges
## Lessons Learned
Key takeaways and security insights
## References
- AWS documentation links
- Security best practices
Best Practices
- Always use least privilege: Grant minimum permissions required
- Enable MFA: For all human users, especially privileged accounts
- Encrypt data: At rest and in transit using KMS
- Use private subnets: For resources that don't need internet access
- Enable logging: CloudTrail, VPC Flow Logs, and application logs
- Automate security: Use AWS Config rules and Security Hub
- Regular audits: Review IAM policies, security groups, and access logs
- Tag resources: For cost allocation and security tracking
- Use Systems Manager: Instead of SSH for instance access
- Clean up resources: Delete unused resources to avoid costs
Additional Resources