mirror of
https://github.com/Sea-Haven-Industries/seahaven-org-baseline.git
synced 2026-09-30 09:13:17 +00:00
- H-1: 15 CIS Section 4 metric filters (4.1-4.15) on the CloudTrail log group, each alarming to a new SSE SNS topic seahaven-cis-alarms (email to adam). ALARM-only actions per Sea Haven preference. 4.16 = Security Hub (Day 1). - H-14: VPC flow logs (ALL traffic) on all 5 VPCs → hardened S3 bucket. Delivery bucket policy cross-reviewed; kept the AWS-required s3:x-amz-acl condition + logs:*:* source-ARN (cross-reviewer wrongly flagged these; verified against AWS flow-logs-s3-permissions docs), dropped the unneeded s3:ListBucket. - M-13: SES configuration set seahaven-email-events capturing bounce/complaint/ reject to CloudWatch for reputation visibility. L-4 (log retention) and L-5 (alarm action) applied via CLI, documented in README.
108 lines
3.7 KiB
TypeScript
108 lines
3.7 KiB
TypeScript
import * as cdk from "aws-cdk-lib";
|
|
import * as s3 from "aws-cdk-lib/aws-s3";
|
|
import * as iam from "aws-cdk-lib/aws-iam";
|
|
import * as ec2 from "aws-cdk-lib/aws-ec2";
|
|
import { Construct } from "constructs";
|
|
|
|
/**
|
|
* VPC flow logs for every VPC, delivered to a hardened S3 bucket (audit H-14,
|
|
* CIS 3.9/5.6). S3 destination (not CloudWatch Logs) for cost — query
|
|
* forensically via Athena. ALL traffic (accept + reject).
|
|
*
|
|
* S3 delivery needs no IAM role; instead the bucket policy grants the
|
|
* `delivery.logs.amazonaws.com` service principal write access, scoped to this
|
|
* account. That bucket policy is the Day 2 cross-review item.
|
|
*/
|
|
|
|
// All 5 VPCs in 328440206208 / us-east-1 (4 custom + default), audit Agent 7.
|
|
const VPC_IDS = [
|
|
"vpc-061d66990b6a4d1fb",
|
|
"vpc-0542a9e934b417d23",
|
|
"vpc-062d200c68bd4ca0e",
|
|
"vpc-0d3d4b67bd0cf8a68",
|
|
"vpc-02c10a89d66f6f9b8",
|
|
];
|
|
|
|
export class FlowLogs extends Construct {
|
|
constructor(scope: Construct, id: string) {
|
|
super(scope, id);
|
|
|
|
const stack = cdk.Stack.of(this);
|
|
|
|
const bucket = new s3.Bucket(this, "FlowLogsBucket", {
|
|
bucketName: `seahaven-vpc-flow-logs-${stack.account}`,
|
|
encryption: s3.BucketEncryption.S3_MANAGED,
|
|
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
|
|
enforceSSL: true,
|
|
versioned: false,
|
|
lifecycleRules: [
|
|
{
|
|
id: "transition-and-expire",
|
|
transitions: [
|
|
{
|
|
storageClass: s3.StorageClass.GLACIER,
|
|
transitionAfter: cdk.Duration.days(90),
|
|
},
|
|
],
|
|
expiration: cdk.Duration.days(365),
|
|
abortIncompleteMultipartUploadAfter: cdk.Duration.days(7),
|
|
},
|
|
],
|
|
removalPolicy: cdk.RemovalPolicy.RETAIN,
|
|
});
|
|
|
|
// Log-delivery service permissions (scoped to this account) — the standard
|
|
// VPC-flow-logs-to-S3 bucket policy.
|
|
bucket.addToResourcePolicy(
|
|
new iam.PolicyStatement({
|
|
sid: "AWSLogDeliveryWrite",
|
|
effect: iam.Effect.ALLOW,
|
|
principals: [new iam.ServicePrincipal("delivery.logs.amazonaws.com")],
|
|
actions: ["s3:PutObject"],
|
|
resources: [bucket.arnForObjects(`AWSLogs/${stack.account}/*`)],
|
|
conditions: {
|
|
StringEquals: {
|
|
"s3:x-amz-acl": "bucket-owner-full-control",
|
|
"aws:SourceAccount": stack.account,
|
|
},
|
|
ArnLike: {
|
|
"aws:SourceArn": `arn:${stack.partition}:logs:${stack.region}:${stack.account}:*`,
|
|
},
|
|
},
|
|
})
|
|
);
|
|
bucket.addToResourcePolicy(
|
|
new iam.PolicyStatement({
|
|
sid: "AWSLogDeliveryAclCheck",
|
|
effect: iam.Effect.ALLOW,
|
|
principals: [new iam.ServicePrincipal("delivery.logs.amazonaws.com")],
|
|
// AWS's documented flow-logs-to-S3 policy uses GetBucketAcl only
|
|
// (verified against flow-logs-s3-permissions.html); ListBucket is not
|
|
// needed and would be over-permissioned.
|
|
actions: ["s3:GetBucketAcl"],
|
|
resources: [bucket.bucketArn],
|
|
conditions: {
|
|
StringEquals: { "aws:SourceAccount": stack.account },
|
|
ArnLike: {
|
|
"aws:SourceArn": `arn:${stack.partition}:logs:${stack.region}:${stack.account}:*`,
|
|
},
|
|
},
|
|
})
|
|
);
|
|
|
|
VPC_IDS.forEach((vpcId, i) => {
|
|
const flowLog = new ec2.CfnFlowLog(this, `FlowLog${i}`, {
|
|
resourceId: vpcId,
|
|
resourceType: "VPC",
|
|
trafficType: "ALL",
|
|
logDestinationType: "s3",
|
|
logDestination: bucket.bucketArn,
|
|
maxAggregationInterval: 600,
|
|
tags: [{ key: "Name", value: `flow-log-${vpcId}` }],
|
|
});
|
|
flowLog.node.addDependency(bucket.policy!);
|
|
});
|
|
|
|
new cdk.CfnOutput(this, "FlowLogsBucketName", { value: bucket.bucketName });
|
|
}
|
|
}
|