S3 Bucket Public Access Block disabled manually
Re-enable S3 Public Access Block on the affected bucket and add a config rule to alert on future manual changes. The Terraform below restores the block and adds a preventive guardrail.
# Remediation for DRIFT-001 - S3 Public Access Blockresource "aws_s3_bucket_public_access_block" "customer_data" { bucket = "aegis-prod-customer-data" block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true}resource "aws_config_config_rule" "s3_public_access" { name = "s3-public-access-block-enabled" source { owner = "AWS" source_identifier = "S3_BUCKET_PUBLIC_ACCESS_BLOCKED" } scope { compliance_resource_types = ["AWS::S3::Bucket"] }}- 1.Run terraform plan to confirm only the public access block changes
- 2.Run terraform apply to restore block_public_access = true
- 3.Verify with: aws s3api get-public-access-block --bucket aegis-prod-customer-data
- 4.Confirm the aws_config_config_rule reports Compliant within 10 minutes
Security Group port 22 open to 0.0.0.0/0
Restore the restricted CIDR on the bastion security group and enable GuardDuty finding export so future SSH exposure is paged immediately.
# Remediation for DRIFT-002 - SSH open to the worldresource "aws_security_group_rule" "bastion_ssh_ingress" { type = "ingress" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["10.0.0.0/16"] security_group_id = "sg-0a9f2c1b" description = "SSH restricted to corporate CIDR - drift remediated"}resource "aws_cloudwatch_event_rule" "ssh_world_open" { name = "aegis-ssh-world-open-alert" description = "Triggers when any SG allows 0.0.0.0/0 on port 22" event_pattern = jsonencode({ "source" = ["aws.guardduty"] "detail-type" = ["GuardDuty Finding"] })}- 1.Run terraform plan - only the ingress rule CIDR will change
- 2.Run terraform apply
- 3.Verify: aws ec2 describe-security-groups --group-ids sg-0a9f2c1b
- 4.Confirm no active SSH sessions were dropped; reconnect via corporate VPN
RDS instance missing encryption at rest
Encryption at rest cannot be toggled on an existing RDS instance. The remediation creates an encrypted snapshot, restores a new encrypted instance, and updates the Terraform pointer. A blue/green cutover minimizes downtime.
# Remediation for DRIFT-03 - RDS encryption at restresource "aws_db_snapshot" "orders_unencrypted" { db_instance_identifier = "aegis-orders-db" db_snapshot_identifier = "orders-unencrypted-bridge"}resource "aws_db_snapshot" "orders_encrypted" { db_snapshot_identifier = "orders-encrypted-bridge" source_db_snapshot_identifier = aws_db_snapshot.orders_unencrypted.id kms_key_id = aws_kms_key.db.arn}resource "aws_db_instance" "orders_encrypted" { identifier = "aegis-orders-db-enc" snapshot_identifier = aws_db_snapshot.orders_encrypted.id storage_encrypted = true kms_key_id = aws_kms_key.db.arn instance_class = "db.r6g.large" multi_az = true backup_retention_period = 7 deletion_protection = true skip_final_snapshot = false final_snapshot_identifier = "orders-encrypted-final"}- 1.Run terraform plan - confirm snapshot and new instance resources are added
- 2.Run terraform apply during the approved maintenance window
- 3.Run the application cutover to point at aegis-orders-db-enc
- 4.Verify encryption: aws rds describe-db-instances --db-instance-identifier aegis-orders-db-enc
- 5.Decommission the unencrypted source instance after validation
IAM role granted wildcard s3:* on production account
Remove the over-privileged inline policy and restore the scoped-down policy from Terraform state. Add an IAM Access Analyzer finding archive to prevent the same drift recurring.
# Remediation for DRIFT-004 - IAM wildcard s3:*resource "aws_iam_role_policy" "data_pipeline_s3_read" { name = "DataPipelineS3ReadScoped" role = aws_iam_role.data_pipeline.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = ["s3:GetObject"] Resource = "arn:aws:s3:::aegis-raw-events/*" }, { Effect = "Deny" Action = ["s3:DeleteBucket", "s3:PutBucketPolicy"] Resource = "*" } ] })}- 1.Run terraform plan - only the inline policy is replaced
- 2.Run terraform apply
- 3.Verify: aws iam get-role-policy --role-name AegisDataPipelineRole --policy-name DataPipelineS3ReadScoped
- 4.Confirm the data pipeline still reads from aegis-raw-events with no permission errors
GCP firewall rule allows RDP from 0.0.0.0/0 on port 3389
Delete the temporary GCP firewall rule that is not tracked in Terraform. Import the intended management subnet rule into Terraform state so future drift is detected.
# Remediation for DRIFT-005 - GCP RDP open to the worldresource "google_compute_firewall" "allow_rdp_temp" { name = "allow-rdp-temp" network = "projects/aegis-prod/global/networks/aegis-vpc"}resource "google_compute_firewall" "allow_rdp_iap" { name = "allow-rdp-iap-only" network = "projects/aegis-prod/global/networks/aegis-vpc" allow { protocol = "tcp" ports = ["3389"] } source_ranges = ["35.235.240.0/20"] target_tags = ["management"]}- 1.Run terraform plan - confirm allow-rdp-temp is destroyed and allow-rdp-iap-only is created
- 2.Run terraform apply
- 3.Verify: gcloud compute firewall-rules describe allow-rdp-iap-only
- 4.Confirm engineers use IAP tunnel (gcloud compute start-iap-tunnel) for RDP
CloudTrail logging disabled on management bucket
Re-enable CloudTrail logging and add a CloudWatch alarm that pages on-call if logging is ever disabled again. The Terraform below restores enable_logging and wires the alarm.
# Remediation for DRIFT-006 - CloudTrail logging disabledresource "aws_cloudtrail" "management_trail" { name = "aegis-management-trail" s3_bucket_name = aws_s3_bucket.aegis_audit_logs.id enable_logging = true is_multi_region_trail = true include_global_service_events = true kms_key_id = aws_kms_key.audit.arn log_file_validation_enabled = true}resource "aws_cloudwatch_log_metric_filter" "trail_disabled" { name = "CloudTrailLoggingDisabled" log_group_name = aws_cloudwatch_log_group.audit_alerts.name pattern = "{ ($.eventSource = cloudtrail.amazonaws.com) && ($.eventName = StopLogging) }" metric_transformation { name = "TrailLoggingDisabled" namespace = "Aegis/Compliance" value = "1" }}- 1.Run terraform plan - confirm enable_logging flips to true and alarm is added
- 2.Run terraform apply
- 3.Verify: aws cloudtrail get-trail-status --name aegis-management-trail
- 4.Trigger a test event and confirm the on-call SNS topic receives the alarm