Merge pull request #106 from ssumanbiswas/add-aws-security-compliance-skills
Add AWS Security & Compliance skills
This commit is contained in:
10
README.md
10
README.md
@@ -1,6 +1,6 @@
|
||||
# 🌌 Antigravity Awesome Skills: 883+ Agentic Skills for Claude Code, Gemini CLI, Cursor, Kiro & More
|
||||
# 🌌 Antigravity Awesome Skills: 887+ Agentic Skills for Claude Code, Gemini CLI, Cursor, Copilot & More
|
||||
|
||||
> **The Ultimate Collection of 883+ Universal Agentic Skills for AI Coding Assistants — Claude Code, Gemini CLI, Codex CLI, Kiro CLI, Antigravity IDE, GitHub Copilot, Cursor, OpenCode, AdaL**
|
||||
> **The Ultimate Collection of 887+ Universal Agentic Skills for AI Coding Assistants — Claude Code, Gemini CLI, Codex CLI, Antigravity IDE, GitHub Copilot, Cursor, OpenCode, AdaL**
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://claude.ai)
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
If this project helps you, you can [support it here](https://buymeacoffee.com/sickn33) or simply ⭐ the repo.
|
||||
|
||||
**Antigravity Awesome Skills** is a curated, battle-tested library of **883 high-performance agentic skills** designed to work seamlessly across all major AI coding assistants:
|
||||
**Antigravity Awesome Skills** is a curated, battle-tested library of **887 high-performance agentic skills** designed to work seamlessly across all major AI coding assistants:
|
||||
|
||||
- 🟣 **Claude Code** (Anthropic CLI)
|
||||
- 🔵 **Gemini CLI** (Google DeepMind)
|
||||
@@ -41,7 +41,7 @@ This repository provides essential skills to transform your AI assistant into a
|
||||
- [🎁 Curated Collections (Bundles)](#curated-collections)
|
||||
- [🧭 Antigravity Workflows](#antigravity-workflows)
|
||||
- [📦 Features & Categories](#features--categories)
|
||||
- [📚 Browse 883+ Skills](#browse-883-skills)
|
||||
- [📚 Browse 887+ Skills](#browse-887-skills)
|
||||
- [🤝 How to Contribute](#how-to-contribute)
|
||||
- [🤝 Community](#community)
|
||||
- [☕ Support the Project](#support-the-project)
|
||||
@@ -318,7 +318,7 @@ The repository is organized into specialized domains to transform your AI into a
|
||||
|
||||
Counts change as new skills are added. For the current full registry, see [CATALOG.md](CATALOG.md).
|
||||
|
||||
## Browse 883+ Skills
|
||||
## Browse 887+ Skills
|
||||
|
||||
We have moved the full skill registry to a dedicated catalog to keep this README clean.
|
||||
|
||||
|
||||
516
skills/security/aws-compliance-checker/SKILL.md
Normal file
516
skills/security/aws-compliance-checker/SKILL.md
Normal file
@@ -0,0 +1,516 @@
|
||||
---
|
||||
name: aws-compliance-checker
|
||||
description: Automated compliance checking against CIS, PCI-DSS, HIPAA, and SOC 2 benchmarks
|
||||
risk: safe
|
||||
source: community
|
||||
category: security
|
||||
tags: [aws, compliance, audit, cis, pci-dss, hipaa, kiro-cli]
|
||||
---
|
||||
|
||||
# AWS Compliance Checker
|
||||
|
||||
Automated compliance validation against industry standards including CIS AWS Foundations, PCI-DSS, HIPAA, and SOC 2.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when you need to validate AWS compliance against industry standards, prepare for audits, or maintain continuous compliance monitoring.
|
||||
|
||||
## Supported Frameworks
|
||||
|
||||
**CIS AWS Foundations Benchmark**
|
||||
- Identity and Access Management
|
||||
- Logging and Monitoring
|
||||
- Networking
|
||||
- Data Protection
|
||||
|
||||
**PCI-DSS (Payment Card Industry)**
|
||||
- Network security
|
||||
- Access controls
|
||||
- Encryption
|
||||
- Monitoring and logging
|
||||
|
||||
**HIPAA (Healthcare)**
|
||||
- Access controls
|
||||
- Audit controls
|
||||
- Data encryption
|
||||
- Transmission security
|
||||
|
||||
**SOC 2**
|
||||
- Security
|
||||
- Availability
|
||||
- Confidentiality
|
||||
- Privacy
|
||||
|
||||
## CIS AWS Foundations Checks
|
||||
|
||||
### Identity & Access Management (1.x)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# cis-iam-checks.sh
|
||||
|
||||
echo "=== CIS IAM Compliance Checks ==="
|
||||
|
||||
# 1.1: Root account usage
|
||||
echo "1.1: Checking root account usage..."
|
||||
root_usage=$(aws iam get-credential-report --output text | \
|
||||
awk -F, 'NR==2 {print $5,$11}')
|
||||
echo " Root password last used: $root_usage"
|
||||
|
||||
# 1.2: MFA on root account
|
||||
echo "1.2: Checking root MFA..."
|
||||
root_mfa=$(aws iam get-account-summary \
|
||||
--query 'SummaryMap.AccountMFAEnabled' --output text)
|
||||
echo " Root MFA enabled: $root_mfa"
|
||||
|
||||
# 1.3: Unused credentials
|
||||
echo "1.3: Checking for unused credentials (>90 days)..."
|
||||
aws iam get-credential-report --output text | \
|
||||
awk -F, 'NR>1 {
|
||||
if ($5 != "N/A" && $5 != "no_information") {
|
||||
cmd = "date -d \"" $5 "\" +%s"
|
||||
cmd | getline last_used
|
||||
close(cmd)
|
||||
now = systime()
|
||||
days = (now - last_used) / 86400
|
||||
if (days > 90) print " ⚠️ " $1 ": " int(days) " days inactive"
|
||||
}
|
||||
}'
|
||||
|
||||
# 1.4: Access keys rotated
|
||||
echo "1.4: Checking access key age..."
|
||||
aws iam list-users --query 'Users[*].UserName' --output text | \
|
||||
while read user; do
|
||||
aws iam list-access-keys --user-name "$user" \
|
||||
--query 'AccessKeyMetadata[*].[AccessKeyId,CreateDate]' \
|
||||
--output text | \
|
||||
while read key_id create_date; do
|
||||
age_days=$(( ($(date +%s) - $(date -d "$create_date" +%s)) / 86400 ))
|
||||
if [ $age_days -gt 90 ]; then
|
||||
echo " ⚠️ $user: Key $key_id is $age_days days old"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# 1.5-1.11: Password policy
|
||||
echo "1.5-1.11: Checking password policy..."
|
||||
policy=$(aws iam get-account-password-policy 2>&1)
|
||||
if echo "$policy" | grep -q "NoSuchEntity"; then
|
||||
echo " ❌ No password policy configured"
|
||||
else
|
||||
echo " ✓ Password policy exists"
|
||||
echo "$policy" | jq '.PasswordPolicy | {
|
||||
MinimumPasswordLength,
|
||||
RequireSymbols,
|
||||
RequireNumbers,
|
||||
RequireUppercaseCharacters,
|
||||
RequireLowercaseCharacters,
|
||||
MaxPasswordAge,
|
||||
PasswordReusePrevention
|
||||
}'
|
||||
fi
|
||||
|
||||
# 1.12-1.14: MFA for IAM users
|
||||
echo "1.12-1.14: Checking IAM user MFA..."
|
||||
aws iam get-credential-report --output text | \
|
||||
awk -F, 'NR>1 && $4=="false" {print " ⚠️ " $1 ": No MFA"}'
|
||||
```
|
||||
|
||||
### Logging (2.x)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# cis-logging-checks.sh
|
||||
|
||||
echo "=== CIS Logging Compliance Checks ==="
|
||||
|
||||
# 2.1: CloudTrail enabled
|
||||
echo "2.1: Checking CloudTrail..."
|
||||
trails=$(aws cloudtrail describe-trails \
|
||||
--query 'trailList[*].[Name,IsMultiRegionTrail,LogFileValidationEnabled]' \
|
||||
--output text)
|
||||
|
||||
if [ -z "$trails" ]; then
|
||||
echo " ❌ No CloudTrail configured"
|
||||
else
|
||||
echo "$trails" | while read name multi_region validation; do
|
||||
echo " Trail: $name"
|
||||
echo " Multi-region: $multi_region"
|
||||
echo " Log validation: $validation"
|
||||
|
||||
# Check if logging
|
||||
status=$(aws cloudtrail get-trail-status --name "$name" \
|
||||
--query 'IsLogging' --output text)
|
||||
echo " Is logging: $status"
|
||||
done
|
||||
fi
|
||||
|
||||
# 2.2: CloudTrail log file validation
|
||||
echo "2.2: Checking log file validation..."
|
||||
aws cloudtrail describe-trails \
|
||||
--query 'trailList[?LogFileValidationEnabled==`false`].Name' \
|
||||
--output text | \
|
||||
while read trail; do
|
||||
echo " ⚠️ $trail: Log validation disabled"
|
||||
done
|
||||
|
||||
# 2.3: S3 bucket for CloudTrail
|
||||
echo "2.3: Checking CloudTrail S3 bucket access..."
|
||||
aws cloudtrail describe-trails \
|
||||
--query 'trailList[*].S3BucketName' --output text | \
|
||||
while read bucket; do
|
||||
public=$(aws s3api get-bucket-acl --bucket "$bucket" 2>&1 | \
|
||||
grep -c "AllUsers")
|
||||
if [ "$public" -gt 0 ]; then
|
||||
echo " ❌ $bucket: Publicly accessible"
|
||||
else
|
||||
echo " ✓ $bucket: Not public"
|
||||
fi
|
||||
done
|
||||
|
||||
# 2.4: CloudTrail integrated with CloudWatch Logs
|
||||
echo "2.4: Checking CloudWatch Logs integration..."
|
||||
aws cloudtrail describe-trails \
|
||||
--query 'trailList[*].[Name,CloudWatchLogsLogGroupArn]' \
|
||||
--output text | \
|
||||
while read name log_group; do
|
||||
if [ "$log_group" = "None" ]; then
|
||||
echo " ⚠️ $name: Not integrated with CloudWatch Logs"
|
||||
else
|
||||
echo " ✓ $name: Integrated with CloudWatch"
|
||||
fi
|
||||
done
|
||||
|
||||
# 2.5: AWS Config enabled
|
||||
echo "2.5: Checking AWS Config..."
|
||||
recorders=$(aws configservice describe-configuration-recorders \
|
||||
--query 'ConfigurationRecorders[*].name' --output text)
|
||||
|
||||
if [ -z "$recorders" ]; then
|
||||
echo " ❌ AWS Config not enabled"
|
||||
else
|
||||
echo " ✓ AWS Config enabled: $recorders"
|
||||
fi
|
||||
|
||||
# 2.6: S3 bucket logging
|
||||
echo "2.6: Checking S3 bucket logging..."
|
||||
aws s3api list-buckets --query 'Buckets[*].Name' --output text | \
|
||||
while read bucket; do
|
||||
logging=$(aws s3api get-bucket-logging --bucket "$bucket" 2>&1)
|
||||
if ! echo "$logging" | grep -q "LoggingEnabled"; then
|
||||
echo " ⚠️ $bucket: Access logging disabled"
|
||||
fi
|
||||
done
|
||||
|
||||
# 2.7: VPC Flow Logs
|
||||
echo "2.7: Checking VPC Flow Logs..."
|
||||
aws ec2 describe-vpcs --query 'Vpcs[*].VpcId' --output text | \
|
||||
while read vpc; do
|
||||
flow_logs=$(aws ec2 describe-flow-logs \
|
||||
--filter "Name=resource-id,Values=$vpc" \
|
||||
--query 'FlowLogs[*].FlowLogId' --output text)
|
||||
if [ -z "$flow_logs" ]; then
|
||||
echo " ⚠️ $vpc: No flow logs enabled"
|
||||
else
|
||||
echo " ✓ $vpc: Flow logs enabled"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Monitoring (3.x)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# cis-monitoring-checks.sh
|
||||
|
||||
echo "=== CIS Monitoring Compliance Checks ==="
|
||||
|
||||
# Check for required CloudWatch metric filters and alarms
|
||||
required_filters=(
|
||||
"unauthorized-api-calls"
|
||||
"no-mfa-console-signin"
|
||||
"root-usage"
|
||||
"iam-changes"
|
||||
"cloudtrail-changes"
|
||||
"console-signin-failures"
|
||||
"cmk-changes"
|
||||
"s3-bucket-policy-changes"
|
||||
"aws-config-changes"
|
||||
"security-group-changes"
|
||||
"nacl-changes"
|
||||
"network-gateway-changes"
|
||||
"route-table-changes"
|
||||
"vpc-changes"
|
||||
)
|
||||
|
||||
log_group=$(aws cloudtrail describe-trails \
|
||||
--query 'trailList[0].CloudWatchLogsLogGroupArn' \
|
||||
--output text | cut -d: -f7)
|
||||
|
||||
if [ -z "$log_group" ] || [ "$log_group" = "None" ]; then
|
||||
echo " ❌ CloudTrail not integrated with CloudWatch Logs"
|
||||
else
|
||||
echo "Checking metric filters for log group: $log_group"
|
||||
|
||||
existing_filters=$(aws logs describe-metric-filters \
|
||||
--log-group-name "$log_group" \
|
||||
--query 'metricFilters[*].filterName' --output text)
|
||||
|
||||
for filter in "${required_filters[@]}"; do
|
||||
if echo "$existing_filters" | grep -q "$filter"; then
|
||||
echo " ✓ $filter: Configured"
|
||||
else
|
||||
echo " ⚠️ $filter: Missing"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
```
|
||||
|
||||
### Networking (4.x)
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# cis-networking-checks.sh
|
||||
|
||||
echo "=== CIS Networking Compliance Checks ==="
|
||||
|
||||
# 4.1: No security groups allow 0.0.0.0/0 ingress to port 22
|
||||
echo "4.1: Checking SSH access (port 22)..."
|
||||
aws ec2 describe-security-groups \
|
||||
--query 'SecurityGroups[*].[GroupId,GroupName,IpPermissions]' \
|
||||
--output json | \
|
||||
jq -r '.[] | select(.[2][]? |
|
||||
select(.FromPort == 22 and .IpRanges[]?.CidrIp == "0.0.0.0/0")) |
|
||||
" ⚠️ \(.[0]): \(.[1]) allows SSH from 0.0.0.0/0"'
|
||||
|
||||
# 4.2: No security groups allow 0.0.0.0/0 ingress to port 3389
|
||||
echo "4.2: Checking RDP access (port 3389)..."
|
||||
aws ec2 describe-security-groups \
|
||||
--query 'SecurityGroups[*].[GroupId,GroupName,IpPermissions]' \
|
||||
--output json | \
|
||||
jq -r '.[] | select(.[2][]? |
|
||||
select(.FromPort == 3389 and .IpRanges[]?.CidrIp == "0.0.0.0/0")) |
|
||||
" ⚠️ \(.[0]): \(.[1]) allows RDP from 0.0.0.0/0"'
|
||||
|
||||
# 4.3: Default security group restricts all traffic
|
||||
echo "4.3: Checking default security groups..."
|
||||
aws ec2 describe-security-groups \
|
||||
--filters Name=group-name,Values=default \
|
||||
--query 'SecurityGroups[*].[GroupId,IpPermissions,IpPermissionsEgress]' \
|
||||
--output json | \
|
||||
jq -r '.[] | select((.[1] | length) > 0 or (.[2] | length) > 1) |
|
||||
" ⚠️ \(.[0]): Default SG has rules"'
|
||||
```
|
||||
|
||||
## PCI-DSS Compliance Checks
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# pci-dss-checker.py
|
||||
|
||||
import boto3
|
||||
|
||||
def check_pci_compliance():
|
||||
"""Check PCI-DSS requirements"""
|
||||
|
||||
ec2 = boto3.client('ec2')
|
||||
rds = boto3.client('rds')
|
||||
s3 = boto3.client('s3')
|
||||
|
||||
issues = []
|
||||
|
||||
# Requirement 1: Network security
|
||||
sgs = ec2.describe_security_groups()
|
||||
for sg in sgs['SecurityGroups']:
|
||||
for perm in sg.get('IpPermissions', []):
|
||||
for ip_range in perm.get('IpRanges', []):
|
||||
if ip_range.get('CidrIp') == '0.0.0.0/0':
|
||||
issues.append(f"PCI 1.2: {sg['GroupId']} open to internet")
|
||||
|
||||
# Requirement 2: Secure configurations
|
||||
# Check for default passwords, etc.
|
||||
|
||||
# Requirement 3: Protect cardholder data
|
||||
volumes = ec2.describe_volumes()
|
||||
for vol in volumes['Volumes']:
|
||||
if not vol['Encrypted']:
|
||||
issues.append(f"PCI 3.4: Volume {vol['VolumeId']} not encrypted")
|
||||
|
||||
# Requirement 4: Encrypt transmission
|
||||
# Check for SSL/TLS on load balancers
|
||||
|
||||
# Requirement 8: Access controls
|
||||
iam = boto3.client('iam')
|
||||
users = iam.list_users()
|
||||
for user in users['Users']:
|
||||
mfa = iam.list_mfa_devices(UserName=user['UserName'])
|
||||
if not mfa['MFADevices']:
|
||||
issues.append(f"PCI 8.3: {user['UserName']} no MFA")
|
||||
|
||||
# Requirement 10: Logging
|
||||
cloudtrail = boto3.client('cloudtrail')
|
||||
trails = cloudtrail.describe_trails()
|
||||
if not trails['trailList']:
|
||||
issues.append("PCI 10.1: No CloudTrail enabled")
|
||||
|
||||
return issues
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("PCI-DSS Compliance Check")
|
||||
print("=" * 50)
|
||||
|
||||
issues = check_pci_compliance()
|
||||
|
||||
if not issues:
|
||||
print("✓ No PCI-DSS issues found")
|
||||
else:
|
||||
print(f"Found {len(issues)} issues:\n")
|
||||
for issue in issues:
|
||||
print(f" ⚠️ {issue}")
|
||||
```
|
||||
|
||||
## HIPAA Compliance Checks
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# hipaa-checker.sh
|
||||
|
||||
echo "=== HIPAA Compliance Checks ==="
|
||||
|
||||
# Access Controls (164.308(a)(3))
|
||||
echo "Access Controls:"
|
||||
aws iam get-credential-report --output text | \
|
||||
awk -F, 'NR>1 && $4=="false" {print " ⚠️ " $1 ": No MFA (164.312(a)(2)(i))"}'
|
||||
|
||||
# Audit Controls (164.312(b))
|
||||
echo ""
|
||||
echo "Audit Controls:"
|
||||
trails=$(aws cloudtrail describe-trails --query 'trailList[*].Name' --output text)
|
||||
if [ -z "$trails" ]; then
|
||||
echo " ❌ No CloudTrail (164.312(b))"
|
||||
else
|
||||
echo " ✓ CloudTrail enabled"
|
||||
fi
|
||||
|
||||
# Encryption (164.312(a)(2)(iv))
|
||||
echo ""
|
||||
echo "Encryption at Rest:"
|
||||
aws ec2 describe-volumes \
|
||||
--query 'Volumes[?Encrypted==`false`].VolumeId' \
|
||||
--output text | \
|
||||
while read vol; do
|
||||
echo " ⚠️ $vol: Not encrypted (164.312(a)(2)(iv))"
|
||||
done
|
||||
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[?StorageEncrypted==`false`].DBInstanceIdentifier' \
|
||||
--output text | \
|
||||
while read db; do
|
||||
echo " ⚠️ $db: Not encrypted (164.312(a)(2)(iv))"
|
||||
done
|
||||
|
||||
# Transmission Security (164.312(e)(1))
|
||||
echo ""
|
||||
echo "Transmission Security:"
|
||||
echo " Check: All data in transit uses TLS 1.2+"
|
||||
```
|
||||
|
||||
## Automated Compliance Reporting
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# compliance-report.py
|
||||
|
||||
import boto3
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
def generate_compliance_report(framework='cis'):
|
||||
"""Generate comprehensive compliance report"""
|
||||
|
||||
report = {
|
||||
'framework': framework,
|
||||
'generated': datetime.now().isoformat(),
|
||||
'checks': [],
|
||||
'summary': {
|
||||
'total': 0,
|
||||
'passed': 0,
|
||||
'failed': 0,
|
||||
'score': 0
|
||||
}
|
||||
}
|
||||
|
||||
# Run all checks based on framework
|
||||
if framework == 'cis':
|
||||
checks = run_cis_checks()
|
||||
elif framework == 'pci':
|
||||
checks = run_pci_checks()
|
||||
elif framework == 'hipaa':
|
||||
checks = run_hipaa_checks()
|
||||
|
||||
report['checks'] = checks
|
||||
report['summary']['total'] = len(checks)
|
||||
report['summary']['passed'] = sum(1 for c in checks if c['status'] == 'PASS')
|
||||
report['summary']['failed'] = report['summary']['total'] - report['summary']['passed']
|
||||
report['summary']['score'] = (report['summary']['passed'] / report['summary']['total']) * 100
|
||||
|
||||
return report
|
||||
|
||||
def run_cis_checks():
|
||||
# Implement CIS checks
|
||||
return []
|
||||
|
||||
def run_pci_checks():
|
||||
# Implement PCI checks
|
||||
return []
|
||||
|
||||
def run_hipaa_checks():
|
||||
# Implement HIPAA checks
|
||||
return []
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
framework = sys.argv[1] if len(sys.argv) > 1 else 'cis'
|
||||
|
||||
report = generate_compliance_report(framework)
|
||||
|
||||
print(f"\n{framework.upper()} Compliance Report")
|
||||
print("=" * 50)
|
||||
print(f"Score: {report['summary']['score']:.1f}%")
|
||||
print(f"Passed: {report['summary']['passed']}/{report['summary']['total']}")
|
||||
print(f"Failed: {report['summary']['failed']}/{report['summary']['total']}")
|
||||
|
||||
# Save to file
|
||||
with open(f'compliance-{framework}-{datetime.now().strftime("%Y%m%d")}.json', 'w') as f:
|
||||
json.dump(report, f, indent=2)
|
||||
```
|
||||
|
||||
## Example Prompts
|
||||
|
||||
- "Run CIS AWS Foundations compliance check"
|
||||
- "Generate a PCI-DSS compliance report"
|
||||
- "Check HIPAA compliance for my AWS account"
|
||||
- "Audit against SOC 2 requirements"
|
||||
- "Create a compliance dashboard"
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Run compliance checks weekly
|
||||
- Automate with Lambda/EventBridge
|
||||
- Track compliance trends over time
|
||||
- Document exceptions with justification
|
||||
- Integrate with AWS Security Hub
|
||||
- Use AWS Config Rules for continuous monitoring
|
||||
|
||||
## Kiro CLI Integration
|
||||
|
||||
```bash
|
||||
kiro-cli chat "Use aws-compliance-checker to run CIS benchmark"
|
||||
kiro-cli chat "Generate PCI-DSS report with aws-compliance-checker"
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [CIS AWS Foundations Benchmark](https://www.cisecurity.org/benchmark/amazon_web_services)
|
||||
- [AWS Security Hub](https://aws.amazon.com/security-hub/)
|
||||
- [AWS Compliance Programs](https://aws.amazon.com/compliance/programs/)
|
||||
397
skills/security/aws-iam-best-practices/SKILL.md
Normal file
397
skills/security/aws-iam-best-practices/SKILL.md
Normal file
@@ -0,0 +1,397 @@
|
||||
---
|
||||
name: aws-iam-best-practices
|
||||
description: IAM policy review, hardening, and least privilege implementation
|
||||
risk: safe
|
||||
source: community
|
||||
category: security
|
||||
tags: [aws, iam, security, access-control, kiro-cli, least-privilege]
|
||||
---
|
||||
|
||||
# AWS IAM Best Practices
|
||||
|
||||
Review and harden IAM policies following AWS security best practices and least privilege principles.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when you need to review IAM policies, implement least privilege access, or harden IAM security.
|
||||
|
||||
## Core Principles
|
||||
|
||||
**Least Privilege**
|
||||
- Grant minimum permissions needed
|
||||
- Use managed policies when possible
|
||||
- Avoid wildcard (*) permissions
|
||||
- Regular access reviews
|
||||
|
||||
**Defense in Depth**
|
||||
- Enable MFA for all users
|
||||
- Use IAM roles instead of access keys
|
||||
- Implement service control policies (SCPs)
|
||||
- Enable CloudTrail for audit
|
||||
|
||||
**Separation of Duties**
|
||||
- Separate admin and user roles
|
||||
- Use different roles for different environments
|
||||
- Implement approval workflows
|
||||
- Regular permission audits
|
||||
|
||||
## IAM Security Checks
|
||||
|
||||
### Find Overly Permissive Policies
|
||||
|
||||
```bash
|
||||
# List policies with full admin access
|
||||
aws iam list-policies --scope Local \
|
||||
--query 'Policies[*].[PolicyName,Arn]' --output table | \
|
||||
grep -i admin
|
||||
|
||||
# Find policies with wildcard actions
|
||||
aws iam list-policies --scope Local --query 'Policies[*].Arn' --output text | \
|
||||
while read arn; do
|
||||
version=$(aws iam get-policy --policy-arn "$arn" \
|
||||
--query 'Policy.DefaultVersionId' --output text)
|
||||
doc=$(aws iam get-policy-version --policy-arn "$arn" \
|
||||
--version-id "$version" --query 'PolicyVersion.Document')
|
||||
if echo "$doc" | grep -q '"Action": "\*"'; then
|
||||
echo "Wildcard action in: $arn"
|
||||
fi
|
||||
done
|
||||
|
||||
# Find inline policies (should use managed policies)
|
||||
aws iam list-users --query 'Users[*].UserName' --output text | \
|
||||
while read user; do
|
||||
policies=$(aws iam list-user-policies --user-name "$user" \
|
||||
--query 'PolicyNames' --output text)
|
||||
if [ -n "$policies" ]; then
|
||||
echo "Inline policies on user $user: $policies"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### MFA Enforcement
|
||||
|
||||
```bash
|
||||
# List users without MFA
|
||||
aws iam get-credential-report --output text | \
|
||||
awk -F, 'NR>1 && $4=="false" {print $1}'
|
||||
|
||||
# Check if MFA is required in policies
|
||||
aws iam list-policies --scope Local --query 'Policies[*].Arn' --output text | \
|
||||
while read arn; do
|
||||
version=$(aws iam get-policy --policy-arn "$arn" \
|
||||
--query 'Policy.DefaultVersionId' --output text)
|
||||
doc=$(aws iam get-policy-version --policy-arn "$arn" \
|
||||
--version-id "$version" --query 'PolicyVersion.Document')
|
||||
if echo "$doc" | grep -q "aws:MultiFactorAuthPresent"; then
|
||||
echo "MFA enforced in: $arn"
|
||||
fi
|
||||
done
|
||||
|
||||
# Enable MFA for a user (returns QR code)
|
||||
aws iam create-virtual-mfa-device \
|
||||
--virtual-mfa-device-name user-mfa \
|
||||
--outfile /tmp/qr.png \
|
||||
--bootstrap-method QRCodePNG
|
||||
```
|
||||
|
||||
### Access Key Management
|
||||
|
||||
```bash
|
||||
# Find old access keys (>90 days)
|
||||
aws iam list-users --query 'Users[*].UserName' --output text | \
|
||||
while read user; do
|
||||
aws iam list-access-keys --user-name "$user" \
|
||||
--query 'AccessKeyMetadata[*].[AccessKeyId,CreateDate,Status]' \
|
||||
--output text | \
|
||||
while read key_id create_date status; do
|
||||
age_days=$(( ($(date +%s) - $(date -d "$create_date" +%s)) / 86400 ))
|
||||
if [ $age_days -gt 90 ]; then
|
||||
echo "$user: Key $key_id is $age_days days old"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Rotate access key
|
||||
OLD_KEY="AKIAIOSFODNN7EXAMPLE"
|
||||
USER="myuser"
|
||||
|
||||
# Create new key
|
||||
NEW_KEY=$(aws iam create-access-key --user-name "$USER")
|
||||
echo "New key created. Update applications, then run:"
|
||||
echo "aws iam delete-access-key --user-name $USER --access-key-id $OLD_KEY"
|
||||
|
||||
# Deactivate old key (test first)
|
||||
aws iam update-access-key \
|
||||
--user-name "$USER" \
|
||||
--access-key-id "$OLD_KEY" \
|
||||
--status Inactive
|
||||
```
|
||||
|
||||
### Role and Policy Analysis
|
||||
|
||||
```bash
|
||||
# List unused roles (no activity in 90 days)
|
||||
aws iam list-roles --query 'Roles[*].[RoleName,RoleLastUsed.LastUsedDate]' \
|
||||
--output text | \
|
||||
while read role last_used; do
|
||||
if [ "$last_used" = "None" ]; then
|
||||
echo "Never used: $role"
|
||||
fi
|
||||
done
|
||||
|
||||
# Find roles with trust relationships to external accounts
|
||||
aws iam list-roles --query 'Roles[*].RoleName' --output text | \
|
||||
while read role; do
|
||||
trust=$(aws iam get-role --role-name "$role" \
|
||||
--query 'Role.AssumeRolePolicyDocument')
|
||||
if echo "$trust" | grep -q '"AWS":'; then
|
||||
echo "External trust: $role"
|
||||
fi
|
||||
done
|
||||
|
||||
# Analyze policy permissions
|
||||
aws iam simulate-principal-policy \
|
||||
--policy-source-arn arn:aws:iam::123456789012:user/myuser \
|
||||
--action-names s3:GetObject s3:PutObject \
|
||||
--resource-arns arn:aws:s3:::mybucket/*
|
||||
```
|
||||
|
||||
## IAM Policy Templates
|
||||
|
||||
### Least Privilege S3 Access
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"s3:GetObject",
|
||||
"s3:PutObject"
|
||||
],
|
||||
"Resource": "arn:aws:s3:::my-bucket/user-data/${aws:username}/*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:ListBucket",
|
||||
"Resource": "arn:aws:s3:::my-bucket",
|
||||
"Condition": {
|
||||
"StringLike": {
|
||||
"s3:prefix": "user-data/${aws:username}/*"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### MFA-Required Policy
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Deny",
|
||||
"Action": "*",
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"BoolIfExists": {
|
||||
"aws:MultiFactorAuthPresent": "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Time-Based Access
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:*",
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"DateGreaterThan": {
|
||||
"aws:CurrentTime": "2026-01-01T00:00:00Z"
|
||||
},
|
||||
"DateLessThan": {
|
||||
"aws:CurrentTime": "2026-12-31T23:59:59Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### IP-Restricted Access
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Deny",
|
||||
"Action": "*",
|
||||
"Resource": "*",
|
||||
"Condition": {
|
||||
"NotIpAddress": {
|
||||
"aws:SourceIp": [
|
||||
"203.0.113.0/24",
|
||||
"198.51.100.0/24"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## IAM Hardening Checklist
|
||||
|
||||
**User Management**
|
||||
- [ ] Enable MFA for all users
|
||||
- [ ] Remove unused IAM users
|
||||
- [ ] Rotate access keys every 90 days
|
||||
- [ ] Use IAM roles instead of long-term credentials
|
||||
- [ ] Implement password policy (length, complexity, rotation)
|
||||
|
||||
**Policy Management**
|
||||
- [ ] Replace inline policies with managed policies
|
||||
- [ ] Remove wildcard (*) permissions
|
||||
- [ ] Implement least privilege
|
||||
- [ ] Use policy conditions (MFA, IP, time)
|
||||
- [ ] Regular policy reviews
|
||||
|
||||
**Role Management**
|
||||
- [ ] Use roles for EC2 instances
|
||||
- [ ] Implement cross-account roles properly
|
||||
- [ ] Review trust relationships
|
||||
- [ ] Remove unused roles
|
||||
- [ ] Use session tags for fine-grained access
|
||||
|
||||
**Monitoring**
|
||||
- [ ] Enable CloudTrail for IAM events
|
||||
- [ ] Set up CloudWatch alarms for IAM changes
|
||||
- [ ] Use AWS IAM Access Analyzer
|
||||
- [ ] Regular access reviews
|
||||
- [ ] Monitor for privilege escalation
|
||||
|
||||
## Automated IAM Hardening
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# iam-hardening.py
|
||||
|
||||
import boto3
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
iam = boto3.client('iam')
|
||||
|
||||
def enforce_mfa():
|
||||
"""Identify users without MFA"""
|
||||
users = iam.list_users()['Users']
|
||||
no_mfa = []
|
||||
|
||||
for user in users:
|
||||
mfa_devices = iam.list_mfa_devices(
|
||||
UserName=user['UserName']
|
||||
)['MFADevices']
|
||||
|
||||
if not mfa_devices:
|
||||
no_mfa.append(user['UserName'])
|
||||
|
||||
return no_mfa
|
||||
|
||||
def rotate_old_keys():
|
||||
"""Find access keys older than 90 days"""
|
||||
users = iam.list_users()['Users']
|
||||
old_keys = []
|
||||
|
||||
for user in users:
|
||||
keys = iam.list_access_keys(
|
||||
UserName=user['UserName']
|
||||
)['AccessKeyMetadata']
|
||||
|
||||
for key in keys:
|
||||
age = datetime.now(key['CreateDate'].tzinfo) - key['CreateDate']
|
||||
if age.days > 90:
|
||||
old_keys.append({
|
||||
'user': user['UserName'],
|
||||
'key_id': key['AccessKeyId'],
|
||||
'age_days': age.days
|
||||
})
|
||||
|
||||
return old_keys
|
||||
|
||||
def find_overpermissive_policies():
|
||||
"""Find policies with wildcard actions"""
|
||||
policies = iam.list_policies(Scope='Local')['Policies']
|
||||
overpermissive = []
|
||||
|
||||
for policy in policies:
|
||||
version = iam.get_policy_version(
|
||||
PolicyArn=policy['Arn'],
|
||||
VersionId=policy['DefaultVersionId']
|
||||
)
|
||||
|
||||
doc = version['PolicyVersion']['Document']
|
||||
for statement in doc.get('Statement', []):
|
||||
if statement.get('Action') == '*':
|
||||
overpermissive.append(policy['PolicyName'])
|
||||
break
|
||||
|
||||
return overpermissive
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("IAM Hardening Report")
|
||||
print("=" * 50)
|
||||
|
||||
print("\nUsers without MFA:")
|
||||
for user in enforce_mfa():
|
||||
print(f" - {user}")
|
||||
|
||||
print("\nOld access keys (>90 days):")
|
||||
for key in rotate_old_keys():
|
||||
print(f" - {key['user']}: {key['age_days']} days")
|
||||
|
||||
print("\nOverpermissive policies:")
|
||||
for policy in find_overpermissive_policies():
|
||||
print(f" - {policy}")
|
||||
```
|
||||
|
||||
## Example Prompts
|
||||
|
||||
- "Review my IAM policies for security issues"
|
||||
- "Find users without MFA enabled"
|
||||
- "Create a least privilege policy for S3 access"
|
||||
- "Identify overly permissive IAM roles"
|
||||
- "Generate an IAM hardening report"
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use AWS managed policies when possible
|
||||
- Implement policy versioning
|
||||
- Test policies in non-production first
|
||||
- Document policy purposes
|
||||
- Regular access reviews (quarterly)
|
||||
- Use IAM Access Analyzer
|
||||
- Implement SCPs for organization-wide controls
|
||||
|
||||
## Kiro CLI Integration
|
||||
|
||||
```bash
|
||||
kiro-cli chat "Use aws-iam-best-practices to review my IAM setup"
|
||||
kiro-cli chat "Create a least privilege policy with aws-iam-best-practices"
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
|
||||
- [IAM Policy Simulator](https://policysim.aws.amazon.com/)
|
||||
- [IAM Access Analyzer](https://aws.amazon.com/iam/features/analyze-access/)
|
||||
465
skills/security/aws-secrets-rotation/SKILL.md
Normal file
465
skills/security/aws-secrets-rotation/SKILL.md
Normal file
@@ -0,0 +1,465 @@
|
||||
---
|
||||
name: aws-secrets-rotation
|
||||
description: Automate AWS secrets rotation for RDS, API keys, and credentials
|
||||
risk: safe
|
||||
source: community
|
||||
category: security
|
||||
tags: [aws, secrets-manager, security, automation, kiro-cli, credentials]
|
||||
---
|
||||
|
||||
# AWS Secrets Rotation
|
||||
|
||||
Automate rotation of secrets, credentials, and API keys using AWS Secrets Manager and Lambda.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when you need to implement automated secrets rotation, manage credentials securely, or comply with security policies requiring regular key rotation.
|
||||
|
||||
## Supported Secret Types
|
||||
|
||||
**AWS Services**
|
||||
- RDS database credentials
|
||||
- DocumentDB credentials
|
||||
- Redshift credentials
|
||||
- ElastiCache credentials
|
||||
|
||||
**Third-Party Services**
|
||||
- API keys
|
||||
- OAuth tokens
|
||||
- SSH keys
|
||||
- Custom credentials
|
||||
|
||||
## Secrets Manager Setup
|
||||
|
||||
### Create a Secret
|
||||
|
||||
```bash
|
||||
# Create RDS secret
|
||||
aws secretsmanager create-secret \
|
||||
--name prod/db/mysql \
|
||||
--description "Production MySQL credentials" \
|
||||
--secret-string '{
|
||||
"username": "admin",
|
||||
"password": "CHANGE_ME",
|
||||
"engine": "mysql",
|
||||
"host": "mydb.cluster-abc.us-east-1.rds.amazonaws.com",
|
||||
"port": 3306,
|
||||
"dbname": "myapp"
|
||||
}'
|
||||
|
||||
# Create API key secret
|
||||
aws secretsmanager create-secret \
|
||||
--name prod/api/stripe \
|
||||
--secret-string '{
|
||||
"api_key": "sk_live_xxxxx",
|
||||
"webhook_secret": "whsec_xxxxx"
|
||||
}'
|
||||
|
||||
# Create secret from file
|
||||
aws secretsmanager create-secret \
|
||||
--name prod/ssh/private-key \
|
||||
--secret-binary fileb://~/.ssh/id_rsa
|
||||
```
|
||||
|
||||
### Retrieve Secrets
|
||||
|
||||
```bash
|
||||
# Get secret value
|
||||
aws secretsmanager get-secret-value \
|
||||
--secret-id prod/db/mysql \
|
||||
--query 'SecretString' --output text
|
||||
|
||||
# Get specific field
|
||||
aws secretsmanager get-secret-value \
|
||||
--secret-id prod/db/mysql \
|
||||
--query 'SecretString' --output text | \
|
||||
jq -r '.password'
|
||||
|
||||
# Get binary secret
|
||||
aws secretsmanager get-secret-value \
|
||||
--secret-id prod/ssh/private-key \
|
||||
--query 'SecretBinary' --output text | \
|
||||
base64 -d > private-key.pem
|
||||
```
|
||||
|
||||
## Automatic Rotation Setup
|
||||
|
||||
### Enable RDS Rotation
|
||||
|
||||
```bash
|
||||
# Enable automatic rotation (30 days)
|
||||
aws secretsmanager rotate-secret \
|
||||
--secret-id prod/db/mysql \
|
||||
--rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:SecretsManagerRDSMySQLRotation \
|
||||
--rotation-rules AutomaticallyAfterDays=30
|
||||
|
||||
# Rotate immediately
|
||||
aws secretsmanager rotate-secret \
|
||||
--secret-id prod/db/mysql
|
||||
|
||||
# Check rotation status
|
||||
aws secretsmanager describe-secret \
|
||||
--secret-id prod/db/mysql \
|
||||
--query 'RotationEnabled'
|
||||
```
|
||||
|
||||
### Lambda Rotation Function
|
||||
|
||||
```python
|
||||
# lambda_rotation.py
|
||||
import boto3
|
||||
import json
|
||||
import os
|
||||
|
||||
secrets_client = boto3.client('secretsmanager')
|
||||
rds_client = boto3.client('rds')
|
||||
|
||||
def lambda_handler(event, context):
|
||||
"""Rotate RDS MySQL password"""
|
||||
|
||||
secret_arn = event['SecretId']
|
||||
token = event['ClientRequestToken']
|
||||
step = event['Step']
|
||||
|
||||
# Get current secret
|
||||
current = secrets_client.get_secret_value(SecretId=secret_arn)
|
||||
secret = json.loads(current['SecretString'])
|
||||
|
||||
if step == "createSecret":
|
||||
# Generate new password
|
||||
new_password = generate_password()
|
||||
secret['password'] = new_password
|
||||
|
||||
# Store as pending
|
||||
secrets_client.put_secret_value(
|
||||
SecretId=secret_arn,
|
||||
ClientRequestToken=token,
|
||||
SecretString=json.dumps(secret),
|
||||
VersionStages=['AWSPENDING']
|
||||
)
|
||||
|
||||
elif step == "setSecret":
|
||||
# Update RDS password
|
||||
rds_client.modify_db_instance(
|
||||
DBInstanceIdentifier=secret['dbInstanceIdentifier'],
|
||||
MasterUserPassword=secret['password'],
|
||||
ApplyImmediately=True
|
||||
)
|
||||
|
||||
elif step == "testSecret":
|
||||
# Test new credentials
|
||||
import pymysql
|
||||
conn = pymysql.connect(
|
||||
host=secret['host'],
|
||||
user=secret['username'],
|
||||
password=secret['password'],
|
||||
database=secret['dbname']
|
||||
)
|
||||
conn.close()
|
||||
|
||||
elif step == "finishSecret":
|
||||
# Mark as current
|
||||
secrets_client.update_secret_version_stage(
|
||||
SecretId=secret_arn,
|
||||
VersionStage='AWSCURRENT',
|
||||
MoveToVersionId=token,
|
||||
RemoveFromVersionId=current['VersionId']
|
||||
)
|
||||
|
||||
return {'statusCode': 200}
|
||||
|
||||
def generate_password(length=32):
|
||||
import secrets
|
||||
import string
|
||||
alphabet = string.ascii_letters + string.digits + "!@#$%^&*()"
|
||||
return ''.join(secrets.choice(alphabet) for _ in range(length))
|
||||
```
|
||||
|
||||
### Custom Rotation for API Keys
|
||||
|
||||
```python
|
||||
# api_key_rotation.py
|
||||
import boto3
|
||||
import requests
|
||||
import json
|
||||
|
||||
secrets_client = boto3.client('secretsmanager')
|
||||
|
||||
def rotate_stripe_key(secret_arn, token, step):
|
||||
"""Rotate Stripe API key"""
|
||||
|
||||
current = secrets_client.get_secret_value(SecretId=secret_arn)
|
||||
secret = json.loads(current['SecretString'])
|
||||
|
||||
if step == "createSecret":
|
||||
# Create new Stripe key via API
|
||||
response = requests.post(
|
||||
'https://api.stripe.com/v1/api_keys',
|
||||
auth=(secret['api_key'], ''),
|
||||
data={'name': f'rotated-{token[:8]}'}
|
||||
)
|
||||
new_key = response.json()['secret']
|
||||
|
||||
secret['api_key'] = new_key
|
||||
secrets_client.put_secret_value(
|
||||
SecretId=secret_arn,
|
||||
ClientRequestToken=token,
|
||||
SecretString=json.dumps(secret),
|
||||
VersionStages=['AWSPENDING']
|
||||
)
|
||||
|
||||
elif step == "testSecret":
|
||||
# Test new key
|
||||
response = requests.get(
|
||||
'https://api.stripe.com/v1/balance',
|
||||
auth=(secret['api_key'], '')
|
||||
)
|
||||
if response.status_code != 200:
|
||||
raise Exception("New key failed validation")
|
||||
|
||||
elif step == "finishSecret":
|
||||
# Revoke old key
|
||||
old_key = json.loads(current['SecretString'])['api_key']
|
||||
requests.delete(
|
||||
f'https://api.stripe.com/v1/api_keys/{old_key}',
|
||||
auth=(secret['api_key'], '')
|
||||
)
|
||||
|
||||
# Promote to current
|
||||
secrets_client.update_secret_version_stage(
|
||||
SecretId=secret_arn,
|
||||
VersionStage='AWSCURRENT',
|
||||
MoveToVersionId=token
|
||||
)
|
||||
```
|
||||
|
||||
## Rotation Monitoring
|
||||
|
||||
### CloudWatch Alarms
|
||||
|
||||
```bash
|
||||
# Create alarm for rotation failures
|
||||
aws cloudwatch put-metric-alarm \
|
||||
--alarm-name secrets-rotation-failures \
|
||||
--alarm-description "Alert on secrets rotation failures" \
|
||||
--metric-name RotationFailed \
|
||||
--namespace AWS/SecretsManager \
|
||||
--statistic Sum \
|
||||
--period 300 \
|
||||
--evaluation-periods 1 \
|
||||
--threshold 1 \
|
||||
--comparison-operator GreaterThanThreshold \
|
||||
--alarm-actions arn:aws:sns:us-east-1:123456789012:alerts
|
||||
```
|
||||
|
||||
### Rotation Audit Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# audit-rotations.sh
|
||||
|
||||
echo "Secrets Rotation Audit"
|
||||
echo "====================="
|
||||
|
||||
aws secretsmanager list-secrets --query 'SecretList[*].[Name,RotationEnabled,LastRotatedDate]' \
|
||||
--output text | \
|
||||
while read name enabled last_rotated; do
|
||||
echo ""
|
||||
echo "Secret: $name"
|
||||
echo " Rotation Enabled: $enabled"
|
||||
echo " Last Rotated: $last_rotated"
|
||||
|
||||
if [ "$enabled" = "True" ]; then
|
||||
# Check rotation schedule
|
||||
rules=$(aws secretsmanager describe-secret --secret-id "$name" \
|
||||
--query 'RotationRules.AutomaticallyAfterDays' --output text)
|
||||
echo " Rotation Schedule: Every $rules days"
|
||||
|
||||
# Calculate days since last rotation
|
||||
if [ "$last_rotated" != "None" ]; then
|
||||
days_ago=$(( ($(date +%s) - $(date -d "$last_rotated" +%s)) / 86400 ))
|
||||
echo " Days Since Rotation: $days_ago"
|
||||
|
||||
if [ $days_ago -gt $rules ]; then
|
||||
echo " ⚠️ OVERDUE for rotation!"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
## Application Integration
|
||||
|
||||
### Python SDK
|
||||
|
||||
```python
|
||||
import boto3
|
||||
import json
|
||||
|
||||
def get_secret(secret_name):
|
||||
"""Retrieve secret from Secrets Manager"""
|
||||
client = boto3.client('secretsmanager')
|
||||
|
||||
try:
|
||||
response = client.get_secret_value(SecretId=secret_name)
|
||||
return json.loads(response['SecretString'])
|
||||
except Exception as e:
|
||||
print(f"Error retrieving secret: {e}")
|
||||
raise
|
||||
|
||||
# Usage
|
||||
db_creds = get_secret('prod/db/mysql')
|
||||
connection = pymysql.connect(
|
||||
host=db_creds['host'],
|
||||
user=db_creds['username'],
|
||||
password=db_creds['password'],
|
||||
database=db_creds['dbname']
|
||||
)
|
||||
```
|
||||
|
||||
### Node.js SDK
|
||||
|
||||
```javascript
|
||||
const AWS = require('aws-sdk');
|
||||
const secretsManager = new AWS.SecretsManager();
|
||||
|
||||
async function getSecret(secretName) {
|
||||
try {
|
||||
const data = await secretsManager.getSecretValue({
|
||||
SecretId: secretName
|
||||
}).promise();
|
||||
|
||||
return JSON.parse(data.SecretString);
|
||||
} catch (err) {
|
||||
console.error('Error retrieving secret:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
const dbCreds = await getSecret('prod/db/mysql');
|
||||
const connection = mysql.createConnection({
|
||||
host: dbCreds.host,
|
||||
user: dbCreds.username,
|
||||
password: dbCreds.password,
|
||||
database: dbCreds.dbname
|
||||
});
|
||||
```
|
||||
|
||||
## Rotation Best Practices
|
||||
|
||||
**Planning**
|
||||
- [ ] Identify all secrets requiring rotation
|
||||
- [ ] Define rotation schedules (30, 60, 90 days)
|
||||
- [ ] Test rotation in non-production first
|
||||
- [ ] Document rotation procedures
|
||||
- [ ] Plan for emergency rotation
|
||||
|
||||
**Implementation**
|
||||
- [ ] Use AWS managed rotation when possible
|
||||
- [ ] Implement proper error handling
|
||||
- [ ] Add CloudWatch monitoring
|
||||
- [ ] Test application compatibility
|
||||
- [ ] Implement gradual rollout
|
||||
|
||||
**Operations**
|
||||
- [ ] Monitor rotation success/failure
|
||||
- [ ] Set up alerts for failures
|
||||
- [ ] Regular rotation audits
|
||||
- [ ] Document troubleshooting steps
|
||||
- [ ] Maintain rotation runbooks
|
||||
|
||||
## Emergency Rotation
|
||||
|
||||
```bash
|
||||
# Immediate rotation (compromise detected)
|
||||
aws secretsmanager rotate-secret \
|
||||
--secret-id prod/db/mysql \
|
||||
--rotate-immediately
|
||||
|
||||
# Force rotation even if recently rotated
|
||||
aws secretsmanager rotate-secret \
|
||||
--secret-id prod/api/stripe \
|
||||
--rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:RotateStripeKey \
|
||||
--rotate-immediately
|
||||
|
||||
# Verify rotation completed
|
||||
aws secretsmanager describe-secret \
|
||||
--secret-id prod/db/mysql \
|
||||
--query 'LastRotatedDate'
|
||||
```
|
||||
|
||||
## Compliance Tracking
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# compliance-report.py
|
||||
|
||||
import boto3
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
client = boto3.client('secretsmanager')
|
||||
|
||||
def generate_compliance_report():
|
||||
secrets = client.list_secrets()['SecretList']
|
||||
|
||||
compliant = []
|
||||
non_compliant = []
|
||||
|
||||
for secret in secrets:
|
||||
name = secret['Name']
|
||||
rotation_enabled = secret.get('RotationEnabled', False)
|
||||
last_rotated = secret.get('LastRotatedDate')
|
||||
|
||||
if not rotation_enabled:
|
||||
non_compliant.append({
|
||||
'name': name,
|
||||
'issue': 'Rotation not enabled'
|
||||
})
|
||||
continue
|
||||
|
||||
if last_rotated:
|
||||
days_ago = (datetime.now(last_rotated.tzinfo) - last_rotated).days
|
||||
if days_ago > 90:
|
||||
non_compliant.append({
|
||||
'name': name,
|
||||
'issue': f'Not rotated in {days_ago} days'
|
||||
})
|
||||
else:
|
||||
compliant.append(name)
|
||||
else:
|
||||
non_compliant.append({
|
||||
'name': name,
|
||||
'issue': 'Never rotated'
|
||||
})
|
||||
|
||||
print(f"Compliant Secrets: {len(compliant)}")
|
||||
print(f"Non-Compliant Secrets: {len(non_compliant)}")
|
||||
print("\nNon-Compliant Details:")
|
||||
for item in non_compliant:
|
||||
print(f" - {item['name']}: {item['issue']}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_compliance_report()
|
||||
```
|
||||
|
||||
## Example Prompts
|
||||
|
||||
- "Set up automatic rotation for my RDS credentials"
|
||||
- "Create a Lambda function to rotate API keys"
|
||||
- "Audit all secrets for rotation compliance"
|
||||
- "Implement emergency rotation for compromised credentials"
|
||||
- "Generate a secrets rotation report"
|
||||
|
||||
## Kiro CLI Integration
|
||||
|
||||
```bash
|
||||
kiro-cli chat "Use aws-secrets-rotation to set up RDS credential rotation"
|
||||
kiro-cli chat "Create a rotation audit report with aws-secrets-rotation"
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [AWS Secrets Manager Rotation](https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html)
|
||||
- [Rotation Lambda Templates](https://github.com/aws-samples/aws-secrets-manager-rotation-lambdas)
|
||||
- [Best Practices for Secrets](https://docs.aws.amazon.com/secretsmanager/latest/userguide/best-practices.html)
|
||||
369
skills/security/aws-security-audit/SKILL.md
Normal file
369
skills/security/aws-security-audit/SKILL.md
Normal file
@@ -0,0 +1,369 @@
|
||||
---
|
||||
name: aws-security-audit
|
||||
description: Comprehensive AWS security posture assessment using AWS CLI and security best practices
|
||||
risk: safe
|
||||
source: community
|
||||
category: security
|
||||
tags: [aws, security, audit, compliance, kiro-cli, security-assessment]
|
||||
---
|
||||
|
||||
# AWS Security Audit
|
||||
|
||||
Perform comprehensive security assessments of AWS environments to identify vulnerabilities and misconfigurations.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill when you need to audit AWS security posture, identify vulnerabilities, or prepare for compliance assessments.
|
||||
|
||||
## Audit Categories
|
||||
|
||||
**Identity & Access Management**
|
||||
- Overly permissive IAM policies
|
||||
- Unused IAM users and roles
|
||||
- MFA enforcement gaps
|
||||
- Root account usage
|
||||
- Access key rotation
|
||||
|
||||
**Network Security**
|
||||
- Open security groups (0.0.0.0/0)
|
||||
- Public S3 buckets
|
||||
- Unencrypted data in transit
|
||||
- VPC flow logs disabled
|
||||
- Network ACL misconfigurations
|
||||
|
||||
**Data Protection**
|
||||
- Unencrypted EBS volumes
|
||||
- Unencrypted RDS instances
|
||||
- S3 bucket encryption disabled
|
||||
- Backup policies missing
|
||||
- KMS key rotation disabled
|
||||
|
||||
**Logging & Monitoring**
|
||||
- CloudTrail disabled
|
||||
- CloudWatch alarms missing
|
||||
- VPC Flow Logs disabled
|
||||
- S3 access logging disabled
|
||||
- Config recording disabled
|
||||
|
||||
## Security Audit Commands
|
||||
|
||||
### IAM Security Checks
|
||||
|
||||
```bash
|
||||
# List users without MFA
|
||||
aws iam get-credential-report --output text | \
|
||||
awk -F, '$4=="false" && $1!="<root_account>" {print $1}'
|
||||
|
||||
# Find unused IAM users (no activity in 90 days)
|
||||
aws iam list-users --query 'Users[*].[UserName]' --output text | \
|
||||
while read user; do
|
||||
last_used=$(aws iam get-user --user-name "$user" \
|
||||
--query 'User.PasswordLastUsed' --output text)
|
||||
echo "$user: $last_used"
|
||||
done
|
||||
|
||||
# List overly permissive policies (AdministratorAccess)
|
||||
aws iam list-policies --scope Local \
|
||||
--query 'Policies[?PolicyName==`AdministratorAccess`]'
|
||||
|
||||
# Find access keys older than 90 days
|
||||
aws iam list-users --query 'Users[*].UserName' --output text | \
|
||||
while read user; do
|
||||
aws iam list-access-keys --user-name "$user" \
|
||||
--query 'AccessKeyMetadata[*].[AccessKeyId,CreateDate]' \
|
||||
--output text
|
||||
done
|
||||
|
||||
# Check root account access keys
|
||||
aws iam get-account-summary \
|
||||
--query 'SummaryMap.AccountAccessKeysPresent'
|
||||
```
|
||||
|
||||
### Network Security Checks
|
||||
|
||||
```bash
|
||||
# Find security groups open to the world
|
||||
aws ec2 describe-security-groups \
|
||||
--query 'SecurityGroups[?IpPermissions[?IpRanges[?CidrIp==`0.0.0.0/0`]]].[GroupId,GroupName]' \
|
||||
--output table
|
||||
|
||||
# List public S3 buckets
|
||||
aws s3api list-buckets --query 'Buckets[*].Name' --output text | \
|
||||
while read bucket; do
|
||||
acl=$(aws s3api get-bucket-acl --bucket "$bucket" 2>/dev/null)
|
||||
if echo "$acl" | grep -q "AllUsers"; then
|
||||
echo "PUBLIC: $bucket"
|
||||
fi
|
||||
done
|
||||
|
||||
# Check VPC Flow Logs status
|
||||
aws ec2 describe-vpcs --query 'Vpcs[*].VpcId' --output text | \
|
||||
while read vpc; do
|
||||
flow_logs=$(aws ec2 describe-flow-logs \
|
||||
--filter "Name=resource-id,Values=$vpc" \
|
||||
--query 'FlowLogs[*].FlowLogId' --output text)
|
||||
if [ -z "$flow_logs" ]; then
|
||||
echo "No flow logs: $vpc"
|
||||
fi
|
||||
done
|
||||
|
||||
# Find RDS instances without encryption
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[?StorageEncrypted==`false`].[DBInstanceIdentifier]' \
|
||||
--output table
|
||||
```
|
||||
|
||||
### Data Protection Checks
|
||||
|
||||
```bash
|
||||
# Find unencrypted EBS volumes
|
||||
aws ec2 describe-volumes \
|
||||
--query 'Volumes[?Encrypted==`false`].[VolumeId,Size,State]' \
|
||||
--output table
|
||||
|
||||
# Check S3 bucket encryption
|
||||
aws s3api list-buckets --query 'Buckets[*].Name' --output text | \
|
||||
while read bucket; do
|
||||
encryption=$(aws s3api get-bucket-encryption \
|
||||
--bucket "$bucket" 2>&1)
|
||||
if echo "$encryption" | grep -q "ServerSideEncryptionConfigurationNotFoundError"; then
|
||||
echo "No encryption: $bucket"
|
||||
fi
|
||||
done
|
||||
|
||||
# Find RDS snapshots that are public
|
||||
aws rds describe-db-snapshots \
|
||||
--query 'DBSnapshots[*].[DBSnapshotIdentifier]' --output text | \
|
||||
while read snapshot; do
|
||||
attrs=$(aws rds describe-db-snapshot-attributes \
|
||||
--db-snapshot-identifier "$snapshot" \
|
||||
--query 'DBSnapshotAttributesResult.DBSnapshotAttributes[?AttributeName==`restore`].AttributeValues' \
|
||||
--output text)
|
||||
if echo "$attrs" | grep -q "all"; then
|
||||
echo "PUBLIC SNAPSHOT: $snapshot"
|
||||
fi
|
||||
done
|
||||
|
||||
# Check KMS key rotation
|
||||
aws kms list-keys --query 'Keys[*].KeyId' --output text | \
|
||||
while read key; do
|
||||
rotation=$(aws kms get-key-rotation-status --key-id "$key" \
|
||||
--query 'KeyRotationEnabled' --output text 2>/dev/null)
|
||||
if [ "$rotation" = "False" ]; then
|
||||
echo "Rotation disabled: $key"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Logging & Monitoring Checks
|
||||
|
||||
```bash
|
||||
# Check CloudTrail status
|
||||
aws cloudtrail describe-trails \
|
||||
--query 'trailList[*].[Name,IsMultiRegionTrail,LogFileValidationEnabled]' \
|
||||
--output table
|
||||
|
||||
# Verify CloudTrail is logging
|
||||
aws cloudtrail get-trail-status --name my-trail \
|
||||
--query 'IsLogging'
|
||||
|
||||
# Check if AWS Config is enabled
|
||||
aws configservice describe-configuration-recorders \
|
||||
--query 'ConfigurationRecorders[*].[name,roleARN]' \
|
||||
--output table
|
||||
|
||||
# List S3 buckets without access logging
|
||||
aws s3api list-buckets --query 'Buckets[*].Name' --output text | \
|
||||
while read bucket; do
|
||||
logging=$(aws s3api get-bucket-logging --bucket "$bucket" 2>&1)
|
||||
if ! echo "$logging" | grep -q "LoggingEnabled"; then
|
||||
echo "No access logging: $bucket"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
## Automated Security Audit Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# comprehensive-security-audit.sh
|
||||
|
||||
echo "=== AWS Security Audit Report ==="
|
||||
echo "Generated: $(date)"
|
||||
echo ""
|
||||
|
||||
# IAM Checks
|
||||
echo "## IAM Security"
|
||||
echo "Users without MFA:"
|
||||
aws iam get-credential-report --output text | \
|
||||
awk -F, '$4=="false" && $1!="<root_account>" {print " - " $1}'
|
||||
|
||||
echo ""
|
||||
echo "Root account access keys:"
|
||||
aws iam get-account-summary \
|
||||
--query 'SummaryMap.AccountAccessKeysPresent' --output text
|
||||
|
||||
# Network Checks
|
||||
echo ""
|
||||
echo "## Network Security"
|
||||
echo "Security groups open to 0.0.0.0/0:"
|
||||
aws ec2 describe-security-groups \
|
||||
--query 'SecurityGroups[?IpPermissions[?IpRanges[?CidrIp==`0.0.0.0/0`]]].GroupId' \
|
||||
--output text | wc -l
|
||||
|
||||
# Data Protection
|
||||
echo ""
|
||||
echo "## Data Protection"
|
||||
echo "Unencrypted EBS volumes:"
|
||||
aws ec2 describe-volumes \
|
||||
--query 'Volumes[?Encrypted==`false`].VolumeId' \
|
||||
--output text | wc -l
|
||||
|
||||
echo ""
|
||||
echo "Unencrypted RDS instances:"
|
||||
aws rds describe-db-instances \
|
||||
--query 'DBInstances[?StorageEncrypted==`false`].DBInstanceIdentifier' \
|
||||
--output text | wc -l
|
||||
|
||||
# Logging
|
||||
echo ""
|
||||
echo "## Logging & Monitoring"
|
||||
echo "CloudTrail status:"
|
||||
aws cloudtrail describe-trails \
|
||||
--query 'trailList[*].[Name,IsLogging]' \
|
||||
--output table
|
||||
|
||||
echo ""
|
||||
echo "=== End of Report ==="
|
||||
```
|
||||
|
||||
## Security Score Calculator
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
# security-score.py
|
||||
|
||||
import boto3
|
||||
import json
|
||||
|
||||
def calculate_security_score():
|
||||
iam = boto3.client('iam')
|
||||
ec2 = boto3.client('ec2')
|
||||
s3 = boto3.client('s3')
|
||||
|
||||
score = 100
|
||||
issues = []
|
||||
|
||||
# Check MFA
|
||||
try:
|
||||
report = iam.get_credential_report()
|
||||
users_without_mfa = 0
|
||||
# Parse report and count
|
||||
if users_without_mfa > 0:
|
||||
score -= 10
|
||||
issues.append(f"{users_without_mfa} users without MFA")
|
||||
except:
|
||||
pass
|
||||
|
||||
# Check open security groups
|
||||
sgs = ec2.describe_security_groups()
|
||||
open_sgs = 0
|
||||
for sg in sgs['SecurityGroups']:
|
||||
for perm in sg.get('IpPermissions', []):
|
||||
for ip_range in perm.get('IpRanges', []):
|
||||
if ip_range.get('CidrIp') == '0.0.0.0/0':
|
||||
open_sgs += 1
|
||||
break
|
||||
|
||||
if open_sgs > 0:
|
||||
score -= 15
|
||||
issues.append(f"{open_sgs} security groups open to internet")
|
||||
|
||||
# Check unencrypted volumes
|
||||
volumes = ec2.describe_volumes()
|
||||
unencrypted = sum(1 for v in volumes['Volumes'] if not v['Encrypted'])
|
||||
|
||||
if unencrypted > 0:
|
||||
score -= 20
|
||||
issues.append(f"{unencrypted} unencrypted EBS volumes")
|
||||
|
||||
print(f"Security Score: {score}/100")
|
||||
print("\nIssues Found:")
|
||||
for issue in issues:
|
||||
print(f" - {issue}")
|
||||
|
||||
return score
|
||||
|
||||
if __name__ == "__main__":
|
||||
calculate_security_score()
|
||||
```
|
||||
|
||||
## Compliance Mapping
|
||||
|
||||
**CIS AWS Foundations Benchmark**
|
||||
- 1.1: Root account usage
|
||||
- 1.2-1.14: IAM policies and MFA
|
||||
- 2.1-2.9: Logging (CloudTrail, Config, VPC Flow Logs)
|
||||
- 4.1-4.3: Monitoring and alerting
|
||||
|
||||
**PCI-DSS**
|
||||
- Requirement 1: Network security controls
|
||||
- Requirement 2: Secure configurations
|
||||
- Requirement 8: Access controls and MFA
|
||||
- Requirement 10: Logging and monitoring
|
||||
|
||||
**HIPAA**
|
||||
- Access controls (IAM)
|
||||
- Audit controls (CloudTrail)
|
||||
- Encryption (EBS, RDS, S3)
|
||||
- Transmission security (TLS/SSL)
|
||||
|
||||
## Remediation Priorities
|
||||
|
||||
**Critical (Fix Immediately)**
|
||||
- Root account access keys
|
||||
- Public RDS snapshots
|
||||
- Security groups open to 0.0.0.0/0 on sensitive ports
|
||||
- CloudTrail disabled
|
||||
|
||||
**High (Fix Within 7 Days)**
|
||||
- Users without MFA
|
||||
- Unencrypted data at rest
|
||||
- Missing VPC Flow Logs
|
||||
- Overly permissive IAM policies
|
||||
|
||||
**Medium (Fix Within 30 Days)**
|
||||
- Old access keys (>90 days)
|
||||
- Missing S3 access logging
|
||||
- Unused IAM users
|
||||
- KMS key rotation disabled
|
||||
|
||||
## Example Prompts
|
||||
|
||||
- "Run a comprehensive security audit on my AWS account"
|
||||
- "Check for IAM security issues"
|
||||
- "Find all unencrypted resources"
|
||||
- "Generate a security compliance report"
|
||||
- "Calculate my AWS security score"
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Run audits weekly
|
||||
- Automate with Lambda/EventBridge
|
||||
- Export results to S3 for trending
|
||||
- Integrate with SIEM tools
|
||||
- Track remediation progress
|
||||
- Document exceptions with business justification
|
||||
|
||||
## Kiro CLI Integration
|
||||
|
||||
```bash
|
||||
kiro-cli chat "Use aws-security-audit to assess my security posture"
|
||||
kiro-cli chat "Generate a security audit report with aws-security-audit"
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [AWS Security Best Practices](https://aws.amazon.com/security/best-practices/)
|
||||
- [CIS AWS Foundations Benchmark](https://www.cisecurity.org/benchmark/amazon_web_services)
|
||||
- [AWS Security Hub](https://aws.amazon.com/security-hub/)
|
||||
@@ -539,6 +539,24 @@
|
||||
"risk": "unknown",
|
||||
"source": "community"
|
||||
},
|
||||
{
|
||||
"id": "aws-compliance-checker",
|
||||
"path": "skills/security/aws-compliance-checker",
|
||||
"category": "security",
|
||||
"name": "aws-compliance-checker",
|
||||
"description": "Automated compliance checking against CIS, PCI-DSS, HIPAA, and SOC 2 benchmarks",
|
||||
"risk": "safe",
|
||||
"source": "community"
|
||||
},
|
||||
{
|
||||
"id": "aws-iam-best-practices",
|
||||
"path": "skills/security/aws-iam-best-practices",
|
||||
"category": "security",
|
||||
"name": "aws-iam-best-practices",
|
||||
"description": "IAM policy review, hardening, and least privilege implementation",
|
||||
"risk": "safe",
|
||||
"source": "community"
|
||||
},
|
||||
{
|
||||
"id": "aws-penetration-testing",
|
||||
"path": "skills/aws-penetration-testing",
|
||||
@@ -548,6 +566,24 @@
|
||||
"risk": "unknown",
|
||||
"source": "community"
|
||||
},
|
||||
{
|
||||
"id": "aws-secrets-rotation",
|
||||
"path": "skills/security/aws-secrets-rotation",
|
||||
"category": "security",
|
||||
"name": "aws-secrets-rotation",
|
||||
"description": "Automate AWS secrets rotation for RDS, API keys, and credentials",
|
||||
"risk": "safe",
|
||||
"source": "community"
|
||||
},
|
||||
{
|
||||
"id": "aws-security-audit",
|
||||
"path": "skills/security/aws-security-audit",
|
||||
"category": "security",
|
||||
"name": "aws-security-audit",
|
||||
"description": "Comprehensive AWS security posture assessment using AWS CLI and security best practices",
|
||||
"risk": "safe",
|
||||
"source": "community"
|
||||
},
|
||||
{
|
||||
"id": "aws-serverless",
|
||||
"path": "skills/aws-serverless",
|
||||
|
||||
Reference in New Issue
Block a user