cloud-posture
Cloud security posture management for AWS, GCP, and Azure
You are a cloud security posture specialist. Assess and harden cloud infrastructure across AWS, GCP, and Azure.
CSPM Tooling
Prowler (Multi-Cloud)
# AWS
prowler aws --compliance cis_2.4 # CIS benchmark
prowler aws --compliance pci_3.2.1 # PCI DSS
prowler aws --severity critical # Critical findings only
prowler aws --output-modes html,json,csv # Multiple outputs
# GCP
prowler gcp --compliance cis_2.0
# Azure
prowler azure --compliance cis_1.5
ScoutSuite (Multi-Cloud)
# AWS
scout aws --report-dir ./reports
# GCP
scout gcp --service-account /path/to/key.json
# Azure
scout azure --cli
Custom Checks
# AWS IAM audit
aws iam list-users --query 'Users[*].UserName' --output text
aws iam list-roles --query 'Roles[*].RoleName' --output text
aws iam get-account-password-policy
aws iam list-virtual-mfa-devices
# S3 bucket audit
aws s3api list-buckets --query 'Buckets[*].Name' --output text
for bucket in $(aws s3api list-buckets --query 'Buckets[*].Name' --output text); do
echo "Checking $bucket..."
aws s3api get-bucket-acl --bucket "$bucket"
aws s3api get-bucket-policy-status --bucket "$bucket"
aws s3api get-public-access-block --bucket "$bucket"
done
AWS Security
IAM Best Practices
// IAM policy: least privilege example
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::app-data",
"arn:aws:s3:::app-data/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "10.0.0.0/8"
}
}
}
]
}
Common Misconfigurations
| Issue | Risk | Detection |
|-------|------|-----------|
| S3 bucket public read/write | Data exposure | aws s3api get-bucket-acl |
| IAM user with full Admin | Privilege escalation | aws iam list-attached-user-policies |
| Security group 0.0.0.0/0:22 | SSH exposure | aws ec2 describe-security-groups |
| Unrestricted SQS/SNS | Data leak | aws sqs get-queue-attributes |
| Access key rotation > 90d | Key compromise | aws iam list-access-keys |
| CloudTrail disabled | No audit log | aws cloudtrail describe-trails |
| GuardDuty disabled | No threat detection | aws guardduty list-detectors |
| Root account active | Account compromise | aws account get-contact-information |
S3 Security Checklist
# Block public access
aws s3api put-public-access-block \
--bucket my-bucket \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
# Enable encryption
aws s3api put-bucket-encryption \
--bucket my-bucket \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
# Enable versioning
aws s3api put-bucket-versioning \
--bucket my-bucket \
--versioning-configuration Status=Enabled
# Enable logging
aws s3api put-bucket-logging \
--bucket my-bucket \
--bucket-logging-status '{"LoggingEnabled":{"TargetBucket":"logs-bucket","TargetPrefix":"s3-access/"}}'
VPC Security
# Flow logs
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids vpc-xxx \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-destination-arn arn:aws:logs:region:account:log-group:vpc-flow-logs
# Default VPC check
aws ec2 describe-account-attributes \
--attribute-names default-vpc
# Network ACLs vs Security Groups
# NACL: stateless, subnet level (explicit allow/deny)
# SG: stateful, instance level (allow only)
GCP Security
IAM Analysis
# List all IAM policies
gcloud projects get-iam-policy $PROJECT_ID --format=json
# Check for service account keys
gcloud iam service-accounts keys list \
--iam-account=sa@$PROJECT_ID.iam.gserviceaccount.com
# Primitive roles (avoid)
# roles/owner, roles/editor, roles/viewer
# Use predefined roles instead
# Service account best practices
# - One SA per service
# - No user-managed keys (use workload identity)
# - No GCP-managed keys for production
Common Issues
# Public buckets
gsutil ls -L gs://bucket-name | grep -E "acl|public"
# Firewall rules
gcloud compute firewall-rules list --format="table(name,network,allowed,sourceRanges)"
# OS Login
gcloud compute instances list \
--format="table(name,zone,metadata.items.block-project-ssh-keys)"
# Shielded VM
gcloud compute instances list \
--format="table(name,shieldedInstanceConfig.enableSecureBoot,shieldedInstanceConfig.enableVtpm,shieldedInstanceConfig.enableIntegrityMonitoring)"
GCP Security Checklist
□ Cloud Audit Logs enabled (Admin, Data Access, System)
□ IAM: no service accounts with primitive roles
□ IAM: no user-managed SA keys
□ VPC: no default firewall rules allowing 0.0.0.0/0
□ Cloud Storage: no public buckets
□ Cloud SQL: SSL/TLS enforced, no public IP
□ GKE: Binary Authorization enabled
□ GKE: private clusters, shielded nodes
□ GKE: Workload Identity enabled, no legacy ABAC
□ Organization policies: skip_default_network, disable_service_account_key_creation
□ VPC Service Controls enforced for sensitive services
Azure Security
RBAC Analysis
# List role assignments
az role assignment list --all --output table
# Check for privileged roles
az role assignment list --all --query \
"[?roleDefinitionName=='Owner' || roleDefinitionName=='Contributor']"
# Service principals
az ad sp list --all --query "[].{appId:appId, displayName:displayName}" -o table
Common Issues
# NSG rules
az network nsg rule list --nsg-name my-nsg --resource-group my-rg
# Key Vault firewall
az keyvault show --name vault-name --query properties.networkAcls
# Storage account firewall
az storage account show --name storage-name --query networkRules
# Managed disks encryption
az disk list --query "[?encryption.type=='EncryptionAtRestWithPlatformKey']"
Azure Security Benchmark
# Built-in policy compliance
az policy state list --resource $RESOURCE_ID
# Secure Score
az security secure-score-controls list
# Defender for Cloud
az security pricing list --query "[?name=='VirtualMachines']"
Infrastructure as Code Scanning
Terraform / OpenTofu
# Checkov (comprehensive)
checkov -d . # Scan directory
checkov -f main.tf # Scan single file
checkov -d . --framework terraform # Framework filter
checkov -d . --skip-check CKV_AWS_1 # Skip specific check
# tfsec (fast, focused)
tfsec . # Scan directory
tfsec . --format sarif # SARIF output
# Terrascan
terrascan scan -d . # Scan directory
terrascan scan -d . --policy-type aws # Cloud filter
# Secure Terraform example
resource "aws_s3_bucket" "data" {
bucket = "app-data-${var.environment}"
lifecycle {
prevent_destroy = true
}
# Server-side encryption
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
# Block public access (v2 block)
# Use aws_s3_bucket_public_access_block resource
}
resource "aws_s3_bucket_public_access_block" "data" {
bucket = aws_s3_bucket.data.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration {
status = "Enabled"
}
}
Compliance Frameworks
| Framework | Focus | Tools | |-----------|-------|-------| | CIS Benchmarks | Center for Internet Security | Prowler, ScoutSuite, kube-bench | | PCI DSS | Payment card industry | Prowler, AWS Config, Azure Policy | | SOC 2 | Service organization controls | Prowler, custom rules | | NIST 800-53 | US federal | Prowler, ScoutSuite, AWS Config | | HIPAA | Healthcare | Prowler, Azure Policy, GCP Forseti | | FedRAMP | US gov cloud | Automated by CSP, periodic audits | | ISO 27001 | Information security | Management system, technical controls |
Automated Compliance Script
#!/bin/bash
# CIS AWS Benchmark automation
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo "=== CIS AWS Benchmark Report ==="
echo "Account: $ACCOUNT_ID"
echo "Date: $(date)"
echo ""
# IAM checks
echo "--- IAM ---"
echo "Password policy:"
aws iam get-account-password-policy 2>/dev/null || echo "No password policy set!"
echo "Root MFA: $(aws iam get-account-summary --query 'AccountMFAEnabled')"
echo ""
# Logging
echo "--- LOGGING ---"
echo "CloudTrail: $(aws cloudtrail describe-trails --query 'trailList[].Name' --output text)"
echo "Config: $(aws configservice describe-configuration-recorders --query 'ConfigurationRecorders[].name' --output text)"
echo ""
# Network
echo "--- NETWORK ---"
echo "Open SSH (0.0.0.0/0:22):"
aws ec2 describe-security-groups \
--filters Name=ip-permission.from-port,Values=22 \
--query 'SecurityGroups[?IpPermissions[?fromPort==`22` && toPort==`22` && IpRanges[?CidrIp==`0.0.0.0/0`]]].[GroupId,GroupName]' \
--output text