Cloud Security Lab
Checking access...
This lab provides hands-on experience with cloud security across AWS, Azure, and GCP.
Prerequisites
# AWS CLIpip install awscliaws configure
# Azure CLIcurl -sL https://aka.ms/InstallAzureCLIDeb | sudo bashaz login
# GCP CLI (gcloud)curl https://sdk.cloud.google.com | bashgcloud init
# Terraformsudo apt install -y terraform
# Toolspip install scoutsuite cloudsploit pacuExercise 1: AWS IAM Least Privilege Audit
Objective
Audit IAM policies for over-permissive access and remediate.
# 1. Find users with excessive permissionsecho "=== Users with AdministratorAccess ==="aws iam list-attached-user-policies | jq -r '.AttachedPolicies[] | select(.PolicyName == "AdministratorAccess")'aws iam list-users | jq -r '.Users[].UserName' | while read user; do policies=$(aws iam list-attached-user-policies --user-name $user 2>/dev/null) inline=$(aws iam list-user-policies --user-name $user 2>/dev/null) if echo "$policies" | grep -q "AdministratorAccess" || echo "$inline" | grep -q "Admin"; then echo "⚠ $user has admin access" fidone
# 2. Find IAM roles with trust policies that allow any principalecho ""echo "=== Roles with wildcard trust policies ==="aws iam list-roles | jq -r '.Roles[].RoleName' | while read role; do trust=$(aws iam get-role --role-name $role --query 'Role.AssumeRolePolicyDocument') if echo "$trust" | grep -q '"AWS":\s*"*"'; then echo "⚠ $role trusts ANY AWS account (potential privilege escalation)" fidone
# 3. Check for unused IAM credentialsecho ""echo "=== Users with unused access keys ==="aws iam list-users | jq -r '.Users[].UserName' | while read user; do keys=$(aws iam list-access-keys --user-name $user 2>/dev/null) echo "$keys" | jq -r '.AccessKeyMetadata[] | select(.Status == "Active") | .AccessKeyId' | while read key; do last_used=$(aws iam get-access-key-last-used --access-key-id $key | jq -r '.AccessKeyLastUsed.LastUsedDate // "never"') echo "$user ($key): last used $last_used" donedone
# 4. Generate IAM credential reportaws iam generate-credential-reportaws iam get-credential-report --output text --query Content | base64 -d | head -20Deliverable
- List of users/groups with admin access (and whether justified)
- Wide-open trust policies identified
- Unused or old access keys (90+ days)
- Remediation plan for each finding
Exercise 2: S3 Security Audit
Objective
Find and fix S3 bucket misconfigurations.
# 1. Find publicly accessible bucketsecho "=== Public S3 Buckets ==="aws s3api list-buckets | jq -r '.Buckets[].Name' | while read bucket; do acl=$(aws s3api get-bucket-acl --bucket $bucket 2>/dev/null) policy=$(aws s3api get-bucket-policy --bucket $bucket 2>/dev/null)
if echo "$acl" | grep -q "AllUsers\|AuthenticatedUsers"; then echo "⚠ PUBLIC ACL: $bucket" fi if echo "$policy" | grep -q '"Effect":"Allow".*"Principal":"\*"'; then echo "⚠ PUBLIC POLICY: $bucket" fidone
# 2. Check encryption statusecho ""echo "=== S3 Bucket Encryption ==="aws s3api list-buckets | jq -r '.Buckets[].Name' | while read bucket; do enc=$(aws s3api get-bucket-encryption --bucket $bucket 2>&1) if echo "$enc" | grep -q "ServerSideEncryptionConfigurationNotFoundError"; then echo "⚠ NO ENCRYPTION: $bucket" fidone
# 3. Check versioningecho ""echo "=== S3 Versioning Status ==="aws s3api list-buckets | jq -r '.Buckets[].Name' | while read bucket; do versioning=$(aws s3api get-bucket-versioning --bucket $bucket | jq -r '.Status // "Disabled"') echo "$bucket: $versioning"done
# 4. Enable security features on a bucketaws s3api put-public-access-block \ --bucket my-company-data \ --public-access-block-configuration \ BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api put-bucket-encryption \ --bucket my-company-data \ --server-side-encryption-configuration \ '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
aws s3api put-bucket-versioning \ --bucket my-company-data \ --versioning-configuration Status=EnabledDeliverable
- List of all buckets with public access status
- Unencrypted buckets identified
- Versioning status for critical buckets
- Automated fix script applied to at least one bucket
Exercise 3: GuardDuty Analysis
Objective
Review GuardDuty findings and set up automated response.
# 1. List GuardDuty findingsecho "=== GuardDuty Findings ==="aws guardduty list-detectors | jq -r '.DetectorIds[]' | while read detector; do aws guardduty list-findings --detector-id $detector \ --query 'FindingIds[0:10]' | jq -r '.[]' | while read finding; do aws guardduty get-findings --detector-id $detector \ --finding-ids $finding | jq -r '.Findings[] | { type: .Type, severity: .Severity, description: .Description, region: .Region }' donedone
# 2. Create automated response (EventBridge → Lambda)cat > guardduty_auto_response.py << 'PYEOF'import boto3import json
def lambda_handler(event, context): detail = event['detail'] finding_type = detail['type'] resource = detail.get('resource', {})
if 'UnauthorizedAccess' in finding_type: # Block the offending IP via NACL ec2 = boto3.client('ec2') ip = resource.get('networkInterface', {}).get('publicIp') if ip: ec2.create_network_acl_entry( NetworkAclId='acl-12345', RuleNumber=500, Protocol='-1', PortRange={'From': 0, 'To': 65535}, CidrBlock=f'{ip}/32', RuleAction='deny', Egress=False ) print(f"Blocked IP {ip} via NACL")
return {"status": "remediated", "finding": finding_type}PYEOFDeliverable
- GuardDuty findings summary (types, severities, counts)
- Automated response Lambda function code
- EventBridge rule configuration
Exercise 4: Azure Conditional Access
Objective
Create and test Conditional Access policies.
# 1. List existing policiesConnect-MgGraph -Scopes "Policy.Read.All"Get-MgIdentityConditionalAccessPolicy | Select-Object DisplayName, State
# 2. Create MFA policy for all users$body = @{ displayName = "Require MFA for All Users" state = "enabled" conditions = @{ users = @{ includeUsers = @("All") } applications = @{ includeApplications = @("All") } clientAppTypes = @("all") } grantControls = @{ builtInControls = @("mfa") operator = "OR" }} | ConvertTo-Json
Invoke-MgGraphRequest -Method POST ` -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" ` -Body $body -ContentType "application/json"
# 3. Create risk-based policy (requires Azure AD Premium P2)$riskBody = @{ displayName = "Block High Risk Sign-ins" state = "enabled" conditions = @{ users = @{ includeUsers = @("All") } signInRiskLevels = @("high") } grantControls = @{ builtInControls = @("block") operator = "OR" }} | ConvertTo-Json
# 4. Test what-if analysis$testBody = @{ signInEvent = @{ userId = "user@company.com" appId = "00000003-0000-0000-c000-000000000000" # Graph API ipAddress = "203.0.113.42" country = "RU" }} | ConvertTo-Json
Invoke-MgGraphRequest -Method POST ` -Uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/evaluate" ` -Body $testBodyDeliverable
- Two Conditional Access policies: MFA for all + risk-based blocking
- Policy test results for different scenarios
- Documented policy enforcement effects
Exercise 5: Terraform Compliance Automation
Objective
Write Terraform with compliance validation.
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } required_version = ">= 1.0"}
provider "aws" { region = var.region}
# S3 bucket with compliance requirements enforcedresource "aws_s3_bucket" "compliance_bucket" { bucket = "company-compliance-data"
# Required: encryption server_side_encryption_configuration { rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } }
# Required: versioning versioning { enabled = true }
tags = { Environment = var.environment Compliance = "pci" DataClass = "restricted" }}
# Block public accessresource "aws_s3_bucket_public_access_block" "compliance_block" { bucket = aws_s3_bucket.compliance_bucket.id
block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true}
# Variablesvariable "region" { description = "AWS region" type = string default = "us-east-1"}
variable "environment" { description = "Environment name" type = string validation { condition = contains(["dev", "staging", "production"], var.environment) error_message = "Environment must be dev, staging, or production." }}
# Outputsoutput "bucket_arn" { value = aws_s3_bucket.compliance_bucket.arn}Deliverable
- Terraform configuration with compliance controls enforced
- Successful
terraform planandterraform apply - Validation that encryption, versioning, and public access block are set
Lab Completion Checklist
- Exercise 1: IAM least privilege audit with remediation plan
- Exercise 2: S3 security audit with fixes applied
- Exercise 3: GuardDuty analysis and automated response Lambda
- Exercise 4: Azure Conditional Access policies created and tested
- Exercise 5: Terraform compliance configuration validated
- All findings documented with commands, outputs, and analysis