Cloud Security Audit: AWS Misconfigurations Indian Startups Make

"We're on AWS, so we're secure." I hear this from Indian startup CTOs more often than I'd like. AWS provides the infrastructure security (physical, network, hypervisor), but everything you deploy ON AWS is your responsibility. And most Indian startups are getting it catastrophically wrong.
After auditing 50+ Indian startups' AWS environments over the past two years, I've identified the 10 most common and most dangerous misconfigurations. Some of these take 5 minutes to fix. Others require architectural changes. All of them are being actively exploited in the wild.
The AWS Shared Responsibility Model
Before diving into misconfigurations, understand what AWS is and isn't responsible for:
flowchart TD
subgraph Customer["YOUR Responsibility (Security IN the Cloud)"]
A1[Customer Data]
A2[Application Security]
A3[IAM & Access Control]
A4[OS Patching & Firewall]
A5[Network Configuration]
A6[Encryption Configuration]
A7[Security Groups / NACLs]
end
subgraph AWS["AWS Responsibility (Security OF the Cloud)"]
B1[Physical Data Centers]
B2[Hardware & Infrastructure]
B3[Hypervisor]
B4[Network Infrastructure]
B5[Global Infrastructure]
B6[Managed Service Infrastructure]
end
style Customer fill:#ef4444,color:#fff
style AWS fill:#22c55e,color:#fffMisconfiguration #1: Public S3 Buckets
Severity: Critical | Found in 71% of audits
The single most common and most dangerous misconfiguration. Indian startups routinely leave S3 buckets publicly accessible, exposing customer data, backups, and application secrets.
# Check if your bucket is publicly accessible
aws s3api get-bucket-acl --bucket your-bucket-name
aws s3api get-public-access-block --bucket your-bucket-name
# Check for public objects
aws s3api list-objects --bucket your-bucket-name --query 'Contents[].Key' | head -20
# FIX: Enable public access block on ALL buckets
aws s3api put-public-access-block \
--bucket your-bucket-name \
--public-access-block-configuration \
'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'
# FIX: Enable for entire AWS account
aws s3control put-public-access-block \
--account-id YOUR_ACCOUNT_ID \
--public-access-block-configuration \
'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'Misconfiguration #2: Overprivileged IAM Roles
Severity: Critical | Found in 89% of audits
The classic mistake: giving AdministratorAccess to every Lambda function, EC2 instance, and developer because "it's easier."
# Find all IAM entities with AdministratorAccess
aws iam list-entities-for-policy \
--policy-arn arn:aws:iam::aws:policy/AdministratorAccess
# Find users with console access but no MFA
aws iam generate-credential-report
aws iam get-credential-report --query 'Content' --output text | base64 -d | \
awk -F, '$4=="true" && $8=="false" {print $1, "HAS NO MFA"}'| Role | What It Has | What It Should Have |
|---|---|---|
| Lambda Function | AdministratorAccess | S3 read on specific bucket + CloudWatch logs |
| EC2 App Server | AdministratorAccess | S3 read/write + RDS connect + SES send |
| Developer User | AdministratorAccess | PowerUserAccess + deny IAM/billing |
| CI/CD Pipeline | AdministratorAccess | Specific deploy permissions only |
flowchart LR
subgraph BAD["❌ Common Setup"]
A1[Lambda] -->|AdministratorAccess| A2[Entire AWS Account]
A3[EC2] -->|AdministratorAccess| A2
A4[Developer] -->|AdministratorAccess| A2
end
subgraph GOOD["✅ Least Privilege"]
B1[Lambda] -->|S3:GetObject on 1 bucket| B2[Specific Bucket]
B3[EC2] -->|RDS:Connect| B4[Specific DB]
B5[Developer] -->|PowerUser - IAM| B6[Non-IAM Resources]
endKnow your vulnerabilities before attackers do
Run a free VAPT scan — takes 5 minutes, no signup required.
Book Your Free ScanMisconfiguration #3: Unencrypted RDS Databases
Severity: High | Found in 56% of audits
# Find all unencrypted RDS instances
aws rds describe-db-instances \
--query 'DBInstances[?StorageEncrypted==`false`].[DBInstanceIdentifier,Engine,StorageEncrypted]' \
--output table
# You CANNOT enable encryption on an existing unencrypted RDS instance
# You must: Create encrypted snapshot → Restore from encrypted snapshot → Switch DNS/connection
# For new instances, ALWAYS enable encryption:
aws rds create-db-instance \
--db-instance-identifier my-db \
--storage-encrypted \
--kms-key-id arn:aws:kms:ap-south-1:ACCOUNT:key/KEY_ID \
... other paramsMisconfiguration #4: Wide-Open Security Groups
Severity: High | Found in 43% of audits
# Find security groups allowing 0.0.0.0/0 on non-web ports
aws ec2 describe-security-groups \
--query 'SecurityGroups[].IpPermissions[?contains(IpRanges[].CidrIp, `0.0.0.0/0`) && FromPort!=`443` && FromPort!=`80`]' \
--output json
# Common dangerous open ports found in Indian startup audits:
# Port 22 (SSH) open to 0.0.0.0/0 — found in 62% of audits
# Port 3306 (MySQL) open to 0.0.0.0/0 — found in 18% of audits
# Port 5432 (PostgreSQL) open to 0.0.0.0/0 — found in 15% of audits
# Port 27017 (MongoDB) open to 0.0.0.0/0 — found in 12% of audits
# Port 6379 (Redis) open to 0.0.0.0/0 — found in 21% of audits| Port | Service | Should Be Open To |
|---|---|---|
| 80/443 | HTTP/HTTPS | 0.0.0.0/0 (via ALB/CloudFront only) |
| 22 | SSH | Your office IP / VPN only |
| 3306/5432 | MySQL/PostgreSQL | App server security group only |
| 27017 | MongoDB | App server security group only |
| 6379 | Redis | App server security group only |
| 9200 | Elasticsearch | Never public, always private subnet |
Misconfiguration #5: CloudTrail Not Enabled
Severity: Critical | Found in 34% of audits
Without CloudTrail, you have zero visibility into who did what in your AWS account.
# Check if CloudTrail is enabled
aws cloudtrail describe-trails --query 'trailList[].{Name:Name,IsLogging:IsLogging}'
# Enable CloudTrail for all regions (MUST DO)
aws cloudtrail create-trail \
--name main-trail \
--s3-bucket-name your-cloudtrail-bucket \
--is-multi-region-trail \
--enable-log-file-validation
aws cloudtrail start-logging --name main-trailMisconfiguration #6: Default VPC Usage
Severity: Medium | Found in 67% of audits
flowchart TD
subgraph Default["❌ Default VPC (Common)"]
D1[Internet Gateway]
D2[Single Public Subnet]
D1 --> D2
D2 --> D3[EC2 - App Server]
D2 --> D4[RDS - Database]
D2 --> D5[Redis Cache]
end
subgraph Proper["✅ Proper VPC Design"]
P1[Internet Gateway]
P2[Public Subnet]
P3[Private Subnet - App]
P4[Private Subnet - Data]
P1 --> P2
P2 --> P6[ALB/NAT Gateway]
P6 --> P3
P3 --> P7[EC2 - App Server]
P3 --> P4
P4 --> P8[RDS - Database]
P4 --> P9[Redis Cache]
endMisconfiguration #7: No AWS Config Rules
Severity: Medium | Found in 78% of audits
AWS Config can automatically detect and alert on misconfigurations. Essential rules:
# Enable AWS Config with essential rules
# These rules continuously monitor your account
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "s3-bucket-public-read-prohibited",
"Source": {"Owner": "AWS", "SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"}
}'
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "encrypted-volumes",
"Source": {"Owner": "AWS", "SourceIdentifier": "ENCRYPTED_VOLUMES"}
}'
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "rds-storage-encrypted",
"Source": {"Owner": "AWS", "SourceIdentifier": "RDS_STORAGE_ENCRYPTED"}
}'
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "root-account-mfa-enabled",
"Source": {"Owner": "AWS", "SourceIdentifier": "ROOT_ACCOUNT_MFA_ENABLED"}
}'Misconfiguration #8-10: Quick Fixes
#8: No MFA on Root Account (Found in 28%)
# Check root account MFA status
aws iam get-account-summary --query 'SummaryMap.AccountMFAEnabled'
# If returns 0 → ROOT HAS NO MFA. Fix immediately!#9: Access Keys on Root Account (Found in 15%)
# Check for root access keys
aws iam get-account-summary --query 'SummaryMap.AccountAccessKeysPresent'
# If returns 1+ → Root has access keys. Delete them immediately!#10: No Budget Alerts (Found in 72%)
This isn't strictly security, but cryptomining attacks often go undetected because there are no billing alerts.
# Create a budget alert (catches cryptomining early)
aws budgets create-budget \
--account-id YOUR_ACCOUNT_ID \
--budget '{
"BudgetName": "Monthly-Alert",
"BudgetLimit": {"Amount": "5000", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}' \
--notifications-with-subscribers '[{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80
},
"Subscribers": [{
"SubscriptionType": "EMAIL",
"Address": "cto@yourcompany.com"
}]
}]'The 15-Minute AWS Security Audit Script
Run this to get a quick security posture check:
#!/bin/bash
# aws-security-audit.sh — Quick AWS security check
echo "=== AWS Security Audit ==="
echo ""
echo "1. Checking S3 Public Access Block (Account Level)..."
aws s3control get-public-access-block --account-id $(aws sts get-caller-identity --query Account --output text) 2>/dev/null || echo "❌ NO ACCOUNT-LEVEL S3 BLOCK"
echo ""
echo "2. Checking CloudTrail..."
aws cloudtrail get-trail-status --name main-trail 2>/dev/null | jq '.IsLogging' || echo "❌ CLOUDTRAIL NOT CONFIGURED"
echo ""
echo "3. Checking Root MFA..."
MFA=$(aws iam get-account-summary --query 'SummaryMap.AccountMFAEnabled' --output text)
[ "$MFA" == "1" ] && echo "✅ Root MFA enabled" || echo "❌ ROOT MFA DISABLED"
echo ""
echo "4. Checking Root Access Keys..."
KEYS=$(aws iam get-account-summary --query 'SummaryMap.AccountAccessKeysPresent' --output text)
[ "$KEYS" == "0" ] && echo "✅ No root access keys" || echo "❌ ROOT HAS ACCESS KEYS"
echo ""
echo "5. Checking Unencrypted RDS..."
aws rds describe-db-instances --query 'DBInstances[?StorageEncrypted==`false`].DBInstanceIdentifier' --output text
echo ""
echo "6. Checking Wide-Open Security Groups (SSH)..."
aws ec2 describe-security-groups --filters 'Name=ip-permission.from-port,Values=22' 'Name=ip-permission.cidr,Values=0.0.0.0/0' --query 'SecurityGroups[].GroupId' --output text
echo ""
echo "=== Audit Complete ==="- AWS provides infrastructure security — everything you deploy on it is YOUR responsibility
- Enable S3 Block Public Access at the account level, not just individual buckets
- 89% of Indian startups use overprivileged IAM roles — implement least privilege immediately
- You cannot encrypt an existing unencrypted RDS instance — plan encryption from day one
- CloudTrail is mandatory for CERT-In compliance — enable it in all regions
- Set up billing alerts — cryptomining attacks are detected through unusual bills, not security tools
- Run the 15-minute audit script above as a starting point for your AWS security review
Want a comprehensive cloud security audit? Get started with Bachao.AI — we assess your AWS, GCP, or Azure environment against CIS benchmarks and map findings to Indian compliance requirements.