Zero-Trust Security
Implementing zero-trust on AWS with encryption, secrets management, and security services
Zero-Trust Security on AWS
Master Zero-Trust Security architecture on AWS with free flashcards and spaced repetition practice. This lesson covers identity verification principles, network segmentation, least-privilege access, and continuous monitoringβessential concepts for building secure cloud infrastructure that assumes breach by default.
Welcome to Zero-Trust Security π
The traditional "castle-and-moat" security model is dead. In today's cloud-native world, the network perimeter has dissolved. Employees work remotely, applications span multiple clouds, and APIs expose services to countless external systems. Zero-Trust Security represents a fundamental shift: never trust, always verify.
Unlike legacy models that grant broad access once someone is "inside" the network, Zero-Trust assumes that threats exist both outside and inside the network. Every requestβregardless of sourceβmust be authenticated, authorized, and encrypted before access is granted. On AWS, this means rethinking how we design IAM policies, network architecture, logging, and monitoring.
π‘ Key Philosophy: Trust nothing by default. Verify everything explicitly.
Core Concepts of Zero-Trust Architecture ποΈ
1. Identity-Centric Security (Not Network-Centric) π€
Traditional security focused on network location: "Are you inside the VPC?" Zero-Trust focuses on identity: "Who are you, and what do you need?"
AWS Implementation:
- AWS IAM Identity Center (formerly SSO): Centralized identity management with multi-factor authentication (MFA)
- IAM Roles and Policies: Fine-grained permissions attached to identities, not network segments
- AWS Cognito: User identity management for applications
- Temporary Credentials: Use AWS STS (Security Token Service) to issue short-lived tokens instead of long-term access keys
Traditional Model vs Zero-Trust TRADITIONAL ZERO-TRUST βββββββββββββββββββ βββββββββββββββββββ β π° Firewall β β π Identity β β (Hard Shell) β β (Every Request)β βββββββββββββββββββ€ βββββββββββββββββββ€ β β Inside = Trustβ β β Verify Always β β β Outside = No β β β Least Privilegeβ β β Lateral Move β β β Micro-segment β β β Broad Access β β β Monitor All β βββββββββββββββββββ βββββββββββββββββββ
Example IAM Policy (Least-Privilege):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-app-bucket/user-uploads/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": ["203.0.113.0/24"]
},
"Bool": {
"aws:SecureTransport": "true"
},
"StringEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
}
}
]
}
π Notice: This policy grants access ONLY to specific objects, from specific IPs, over encrypted connections, with server-side encryption required. This is Zero-Trust in action.
2. Micro-Segmentation (Not Broad Network Zones) π§©
Instead of large security groups that trust everything within a zone, Zero-Trust creates tiny segmentsβoften per-workload or per-service.
AWS Implementation:
- Security Groups: Act as stateful firewalls for individual EC2 instances, Lambda functions, or RDS databases
- NACLs (Network Access Control Lists): Stateless subnet-level controls for additional defense-in-depth
- AWS PrivateLink: Private connectivity between VPCs and AWS services without traversing the internet
- VPC Endpoints: Direct, private access to S3, DynamoDB, etc., without internet gateways
Example Security Group Design:
## Web tier - only accepts HTTPS from internet
resource "aws_security_group" "web_tier" {
name = "web-tier-sg"
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.app_tier.id]
}
}
## App tier - only accepts from web tier
resource "aws_security_group" "app_tier" {
name = "app-tier-sg"
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.web_tier.id]
}
egress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.db_tier.id]
}
}
## DB tier - only accepts from app tier
resource "aws_security_group" "db_tier" {
name = "db-tier-sg"
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app_tier.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Micro-Segmentation Architecture
Internet
β
βΌ
βββββββββββββββββββββββ
β π ALB (HTTPS) β
β (443 only) β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β π₯οΈ Web Tier SG β
β Allows: 443 from β¬ β
β Allows: 8080 to β¬ β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β βοΈ App Tier SG β
β Allows: 8080 from β¬β
β Allows: 5432 to β¬ β
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β ποΈ DB Tier SG β
β Allows: 5432 from β¬β
β Denies: all else β
βββββββββββββββββββββββ
3. Continuous Verification and Monitoring π
Zero-Trust doesn't verify once and forget. It continuously validates that access is appropriate and monitors for anomalies.
AWS Implementation:
- AWS CloudTrail: Logs every API call across your AWS account
- Amazon GuardDuty: Threat detection using machine learning to identify unusual behavior
- AWS Security Hub: Centralized security findings aggregation
- AWS Config: Continuous compliance monitoring and configuration tracking
- Amazon Detective: Investigates security incidents by analyzing CloudTrail, VPC Flow Logs, and GuardDuty findings
Example CloudTrail Query (Athena):
SELECT
useridentity.principalid,
eventname,
sourceipaddress,
COUNT(*) as event_count,
MIN(eventtime) as first_seen,
MAX(eventtime) as last_seen
FROM cloudtrail_logs
WHERE
eventtime > date_add('day', -7, now())
AND errorcode IS NOT NULL
AND useridentity.type = 'IAMUser'
GROUP BY
useridentity.principalid,
eventname,
sourceipaddress
HAVING COUNT(*) > 100
ORDER BY event_count DESC;
π‘ Use Case: This query identifies IAM users with unusually high error ratesβpotential indicators of compromised credentials or misconfigured applications.
GuardDuty Finding Example:
{
"schemaVersion": "2.0",
"accountId": "123456789012",
"region": "us-east-1",
"type": "UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration",
"severity": 8,
"title": "API calls from an unauthorized location",
"description": "APIs commonly used to discover resources in an AWS environment were invoked from an IP address in a country that you don't typically use.",
"resource": {
"instanceDetails": {
"instanceId": "i-0abcd1234efgh5678",
"instanceType": "t3.medium"
}
},
"service": {
"action": {
"actionType": "AWS_API_CALL",
"awsApiCallAction": {
"api": "DescribeInstances",
"remoteIpDetails": {
"ipAddressV4": "198.51.100.42",
"country": {
"countryName": "Unknown"
}
}
}
}
}
}
β οΈ Action Required: This finding suggests credentials may be compromised. Immediately rotate credentials, review CloudTrail logs, and investigate the instance.
4. Encryption Everywhere π
Zero-Trust mandates encryption for data at rest and in transit. Never assume the network is safe.
AWS Implementation:
- TLS/SSL Everywhere: Use ACM (AWS Certificate Manager) for free certificates
- S3 Encryption: Server-side encryption (SSE-S3, SSE-KMS, SSE-C) or client-side encryption
- EBS Encryption: Encrypt volumes using KMS keys
- RDS Encryption: Encrypt databases at rest and enforce SSL connections
- AWS KMS: Centralized key management with audit trails
- AWS Secrets Manager: Encrypted storage and automatic rotation of credentials
Enforce SSL on S3 Bucket Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-secure-bucket",
"arn:aws:s3:::my-secure-bucket/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
RDS SSL Connection (Python):
import psycopg2
import ssl
conn = psycopg2.connect(
host="mydb.cluster-abc123.us-east-1.rds.amazonaws.com",
database="myapp",
user="dbuser",
password="secure_password",
sslmode="verify-full",
sslrootcert="/path/to/rds-ca-cert.pem"
)
cursor = conn.cursor()
cursor.execute("SELECT version();")
print(cursor.fetchone())
5. Least-Privilege Access (Just Enough, Just in Time) β±οΈ
Grant the minimum permissions necessary for the shortest time required.
AWS Implementation:
- IAM Access Analyzer: Identifies resources shared with external entities
- AWS IAM Policy Simulator: Test policies before deployment
- Service Control Policies (SCPs): Organization-wide guardrails
- Permission Boundaries: Maximum permissions limit for IAM entities
- Session Policies: Further restrict temporary credentials
Example: Assume Role with Session Duration:
import boto3
sts_client = boto3.client('sts')
response = sts_client.assume_role(
RoleArn='arn:aws:iam::123456789012:role/DataAnalystRole',
RoleSessionName='data-analysis-session',
DurationSeconds=3600, # 1 hour only
Policy='''
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::analytics-bucket/2024/01/*"
}]
}
'''
)
temp_credentials = response['Credentials']
s3_client = boto3.client(
's3',
aws_access_key_id=temp_credentials['AccessKeyId'],
aws_secret_access_key=temp_credentials['SecretAccessKey'],
aws_session_token=temp_credentials['SessionToken']
)
π‘ Notice: This assumes a role with a 1-hour session AND further restricts it to read-only access to a specific S3 prefix. This is Just-Enough-Just-In-Time (JEJIT) access.
IAM Access Analyzer Findings:
aws accessanalyzer list-findings --analyzer-arn arn:aws:access-analyzer:us-east-1:123456789012:analyzer/MyAnalyzer
Output:
{
"findings": [
{
"id": "finding-12345",
"resourceType": "AWS::S3::Bucket",
"resource": "arn:aws:s3:::public-data-bucket",
"condition": {},
"principal": {"AWS": "*"},
"action": ["s3:GetObject"],
"status": "ACTIVE",
"createdAt": "2024-01-15T10:30:00Z"
}
]
}
β οΈ Warning: This finding shows an S3 bucket accessible to the public. Review immediately to determine if this is intentional.
Detailed Examples π―
Example 1: Implementing Zero-Trust for a Three-Tier Web Application
Scenario: You're deploying a web application with a React frontend, Node.js API backend, and PostgreSQL database.
Zero-Trust Implementation:
- Identity Layer:
## Cognito User Pool for authentication
Resources:
UserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: MyAppUserPool
MfaConfiguration: REQUIRED
EnabledMfas:
- SOFTWARE_TOKEN_MFA
Policies:
PasswordPolicy:
MinimumLength: 12
RequireUppercase: true
RequireLowercase: true
RequireNumbers: true
RequireSymbols: true
AccountRecoverySetting:
RecoveryMechanisms:
- Name: verified_email
Priority: 1
- Network Segmentation:
import aws_cdk as cdk
from aws_cdk import aws_ec2 as ec2
vpc = ec2.Vpc(self, "AppVpc",
max_azs=3,
nat_gateways=1,
subnet_configuration=[
ec2.SubnetConfiguration(
name="Public",
subnet_type=ec2.SubnetType.PUBLIC,
cidr_mask=24
),
ec2.SubnetConfiguration(
name="Private",
subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS,
cidr_mask=24
),
ec2.SubnetConfiguration(
name="Isolated",
subnet_type=ec2.SubnetType.PRIVATE_ISOLATED,
cidr_mask=24
)
]
)
## ALB in public subnet
alb_sg = ec2.SecurityGroup(self, "AlbSg",
vpc=vpc,
description="ALB security group",
allow_all_outbound=False
)
alb_sg.add_ingress_rule(ec2.Peer.any_ipv4(), ec2.Port.tcp(443))
alb_sg.add_egress_rule(app_sg, ec2.Port.tcp(8080))
## ECS Fargate in private subnet
app_sg = ec2.SecurityGroup(self, "AppSg",
vpc=vpc,
description="Application security group",
allow_all_outbound=False
)
app_sg.add_ingress_rule(alb_sg, ec2.Port.tcp(8080))
app_sg.add_egress_rule(db_sg, ec2.Port.tcp(5432))
## RDS in isolated subnet
db_sg = ec2.SecurityGroup(self, "DbSg",
vpc=vpc,
description="Database security group",
allow_all_outbound=False
)
db_sg.add_ingress_rule(app_sg, ec2.Port.tcp(5432))
- API Gateway with IAM Authorization:
Resources:
ApiGateway:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: MyAppApi
ProtocolType: HTTP
CorsConfiguration:
AllowOrigins:
- https://app.example.com
AllowMethods:
- GET
- POST
AllowHeaders:
- Authorization
- Content-Type
ApiRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref ApiGateway
RouteKey: 'POST /data'
AuthorizationType: JWT
AuthorizerId: !Ref JwtAuthorizer
Target: !Join
- '/'
- - integrations
- !Ref ApiIntegration
- CloudWatch Alarms for Anomalous Behavior:
import aws_cdk.aws_cloudwatch as cloudwatch
import aws_cdk.aws_cloudwatch_actions as actions
import aws_cdk.aws_sns as sns
## Alarm for excessive 403 errors (potential unauthorized access attempts)
alarm = cloudwatch.Alarm(self, "UnauthorizedAccessAlarm",
metric=cloudwatch.Metric(
namespace="AWS/ApiGateway",
metric_name="4XXError",
dimensions_map={"ApiId": api.api_id},
statistic="Sum",
period=cdk.Duration.minutes(5)
),
threshold=50,
evaluation_periods=2,
comparison_operator=cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD
)
topic = sns.Topic(self, "AlertTopic")
alarm.add_alarm_action(actions.SnsAction(topic))
Example 2: Zero-Trust for Multi-Account AWS Organization
Scenario: Enterprise with separate AWS accounts for dev, staging, and production.
Implementation:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLeavingOrganization",
"Effect": "Deny",
"Action": "organizations:LeaveOrganization",
"Resource": "*"
},
{
"Sid": "RequireMFAForSensitiveActions",
"Effect": "Deny",
"Action": [
"iam:DeleteUser",
"iam:DeleteRole",
"ec2:TerminateInstances",
"rds:DeleteDBInstance"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
},
{
"Sid": "RestrictRegions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"us-east-1",
"us-west-2"
]
},
"ForAllValues:StringNotLike": {
"aws:PrincipalOrgPaths": "o-*/r-*/ou-*/"
}
}
}
]
}
Cross-Account Access with Conditions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "unique-external-id-12345"
},
"IpAddress": {
"aws:SourceIp": ["203.0.113.0/24"]
},
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
π‘ Best Practice: Cross-account roles should always require an external ID, MFA, and source IP restrictions.
Example 3: Enforcing Zero-Trust with AWS Network Firewall
Scenario: Block outbound traffic to known malicious domains and allow only approved destinations.
Resources:
NetworkFirewall:
Type: AWS::NetworkFirewall::Firewall
Properties:
FirewallName: ZeroTrustFirewall
VpcId: !Ref VPC
SubnetMappings:
- SubnetId: !Ref FirewallSubnetA
- SubnetId: !Ref FirewallSubnetB
FirewallPolicyArn: !Ref FirewallPolicy
FirewallPolicy:
Type: AWS::NetworkFirewall::FirewallPolicy
Properties:
FirewallPolicyName: ZeroTrustPolicy
FirewallPolicy:
StatelessDefaultActions:
- aws:forward_to_sfe
StatelessFragmentDefaultActions:
- aws:forward_to_sfe
StatefulRuleGroupReferences:
- ResourceArn: !Ref DomainAllowListRuleGroup
- ResourceArn: !Ref ThreatIntelRuleGroup
DomainAllowListRuleGroup:
Type: AWS::NetworkFirewall::RuleGroup
Properties:
RuleGroupName: AllowedDomains
Type: STATEFUL
Capacity: 100
RuleGroup:
RulesSource:
RulesSourceList:
TargetTypes:
- HTTP_HOST
- TLS_SNI
Targets:
- ".amazonaws.com"
- ".example.com"
- "api.github.com"
GeneratedRulesType: ALLOWLIST
ThreatIntelRuleGroup:
Type: AWS::NetworkFirewall::RuleGroup
Properties:
RuleGroupName: BlockMaliciousDomains
Type: STATEFUL
Capacity: 100
RuleGroup:
RulesSource:
RulesSourceList:
TargetTypes:
- HTTP_HOST
- TLS_SNI
Targets:
- ".malicious-domain.com"
- "phishing-site.net"
GeneratedRulesType: DENYLIST
Network Firewall Logs (CloudWatch):
import boto3
import json
logs_client = boto3.client('logs')
response = logs_client.filter_log_events(
logGroupName='/aws/networkfirewall/alert',
filterPattern='{ $.event_type = "alert" }',
limit=10
)
for event in response['events']:
log_data = json.loads(event['message'])
print(f"Alert: {log_data['alert']['signature']}")
print(f"Source: {log_data['src_ip']}:{log_data['src_port']}")
print(f"Destination: {log_data['dest_ip']}:{log_data['dest_port']}")
print(f"Action: {log_data['event_type']}")
print("---")
Example 4: Zero-Trust with AWS Verified Access
AWS Verified Access (released 2022) provides secure access to applications without VPN.
## Create Verified Access instance
aws ec2 create-verified-access-instance \
--description "Zero-Trust access for internal apps"
## Create Verified Access trust provider (Okta integration)
aws ec2 create-verified-access-trust-provider \
--policy-reference-name OktaProvider \
--trust-provider-type user \
--user-trust-provider-type oidc \
--oidc-options Issuer="https://example.okta.com",\
AuthorizationEndpoint="https://example.okta.com/oauth2/v1/authorize",\
TokenEndpoint="https://example.okta.com/oauth2/v1/token",\
ClientId="abc123",\
ClientSecret="secret456"
## Create Verified Access endpoint
aws ec2 create-verified-access-endpoint \
--verified-access-group-id vag-0123456789abcdef0 \
--endpoint-type network-interface \
--attachment-type vpc \
--domain-certificate-arn arn:aws:acm:us-east-1:123456789012:certificate/abc-123 \
--application-domain app.internal.example.com \
--endpoint-domain-prefix myapp \
--network-interface-options NetworkInterfaceId=eni-0abcd1234,\
Protocol=https,\
Port=443 \
--policy-document file://policy.json
Verified Access Policy:
{
"Version": "1.0",
"Statement": [
{
"Sid": "AllowAuthenticatedUsers",
"Effect": "Allow",
"Principal": "*",
"Action": "verified-access:Connect",
"Resource": "*",
"Condition": {
"StringEquals": {
"verified-access:user-email-verified": "true",
"verified-access:device-posture-compliant": "true"
},
"StringLike": {
"verified-access:user-email": "*@example.com"
}
}
}
]
}
π‘ Use Case: Employees can access internal applications from any device, but only if:
- They authenticate via Okta (MFA enforced)
- Their email is verified
- Their device passes posture checks (antivirus updated, disk encrypted, etc.)
- Their email domain matches company domain
Common Mistakes to Avoid β οΈ
1. Over-Reliance on Network Controls
β Wrong:
## Security group that trusts the entire VPC
app_sg.add_ingress_rule(
ec2.Peer.ipv4("10.0.0.0/16"), # Entire VPC!
ec2.Port.all_traffic()
)
β Right:
## Security group that trusts only specific source security groups
app_sg.add_ingress_rule(
ec2.Peer.security_group_id(alb_sg.security_group_id),
ec2.Port.tcp(8080)
)
2. Using Long-Lived Credentials
β Wrong:
## Hardcoded credentials in code
import boto3
s3_client = boto3.client(
's3',
aws_access_key_id='AKIAIOSFODNN7EXAMPLE',
aws_secret_access_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
)
β Right:
## Use IAM roles for EC2/ECS/Lambda
import boto3
## Automatically uses instance profile credentials
s3_client = boto3.client('s3')
## OR use temporary credentials from STS
sts_client = boto3.client('sts')
response = sts_client.assume_role(
RoleArn='arn:aws:iam::123456789012:role/MyRole',
RoleSessionName='session1',
DurationSeconds=3600
)
3. Granting * Permissions
β Wrong:
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
β Right:
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-specific-bucket/my-prefix/*"
}
4. Not Encrypting Data in Transit
β Wrong:
import requests
## HTTP (unencrypted)
response = requests.get('http://api.example.com/data')
β Right:
import requests
## HTTPS (encrypted)
response = requests.get('https://api.example.com/data', verify=True)
5. Ignoring CloudTrail Logs
β Wrong: CloudTrail enabled but logs never reviewed.
β Right:
import boto3
from datetime import datetime, timedelta
cloudtrail = boto3.client('cloudtrail')
## Review failed login attempts daily
response = cloudtrail.lookup_events(
LookupAttributes=[
{'AttributeKey': 'EventName', 'AttributeValue': 'ConsoleLogin'}
],
StartTime=datetime.now() - timedelta(days=1),
EndTime=datetime.now()
)
failed_logins = [
event for event in response['Events']
if 'errorCode' in event.get('CloudTrailEvent', '{}')
]
if len(failed_logins) > 10:
# Alert security team
print(f"Alert: {len(failed_logins)} failed console logins in last 24h")
6. Not Using MFA for Privileged Access
β Wrong: Admin users without MFA.
β Right:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllExceptListedIfNoMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ListMFADevices",
"iam:ListUsers",
"iam:GetUser"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
Key Takeaways π―
π Zero-Trust Security Quick Reference
| Principle | AWS Implementation | Key Service |
|---|---|---|
| Never Trust, Always Verify | Authenticate every request regardless of source | IAM, Cognito, STS |
| Least Privilege | Grant minimum necessary permissions for minimum time | IAM Policies, SCPs |
| Micro-Segmentation | Isolate workloads with fine-grained network controls | Security Groups, NACLs |
| Encrypt Everything | Protect data at rest and in transit | KMS, ACM, SSL/TLS |
| Continuous Monitoring | Log all activity and detect anomalies | CloudTrail, GuardDuty |
| Assume Breach | Design systems to limit blast radius | Detective, Security Hub |
π§ Memory Device: NELMA-C
- Never Trust
- Encrypt
- Least Privilege
- Micro-Segment
- Assume Breach
- Continuous Monitoring
Implementation Checklist:
- β Enable MFA for all users (especially privileged accounts)
- β Use IAM roles instead of access keys wherever possible
- β
Implement fine-grained security groups (no
0.0.0.0/0for databases) - β Enable CloudTrail in all regions and protect logs
- β Activate GuardDuty for threat detection
- β Encrypt all S3 buckets, EBS volumes, and RDS instances
- β Use VPC endpoints for AWS service access
- β Review IAM Access Analyzer findings regularly
- β Set up CloudWatch alarms for suspicious activity
- β Conduct regular access reviews and remove unused permissions
π Further Study
- AWS Well-Architected Framework - Security Pillar: https://docs.aws.amazon.com/wellarchitected/latest/security-pillar/welcome.html
- AWS Zero Trust Whitepaper: https://aws.amazon.com/security/zero-trust/
- NIST Zero Trust Architecture (SP 800-207): https://csrc.nist.gov/publications/detail/sp/800-207/final
π Next Steps: Practice implementing these patterns in your own AWS environment. Start smallβsecure one application with Zero-Trust principles, then expand organization-wide.