VPC Flow logs with CDK (Part 2)

Now that we have some VPC flow logs lets get into the different destinations.

Based on the current documentation CloudWatch could have an additional delay of 5 minutes and S3 could have an additional delay of 10 minutes (based on the aggregation interval). Searching CloudWatch Flow logs is easier because you will be able to query the logs in the CloudWatch Console. Whereas S3 you can store the logs and place lifecycle policies if you need to place them in cheaper storage options like S3 Glacier.

S3 Flow Logs Note: the logs are not encrypted so you should consider placing an encryption key on them

// my-app-stack.ts
createS3FlowLogs(vpc: ec2.IVpc, props: cdk.StackProps | undefined) {

    const bucket = new s3.Bucket(this, 'Bucket', {
      bucketName: 'my-vpc-flow-logs-bucket'
    });
    const keyPrefix = 'flow-logs';
    const flowLogs = new ec2.FlowLog(this, 's3flowLog', {
      resourceType: ec2.FlowLogResourceType.fromVpc(vpc),
      destination: ec2.FlowLogDestination.toS3(bucket, keyPrefix),
      trafficType:ec2.FlowLogTrafficType.ALL,
      flowLogName: 'my-vpc-flow-logs',
    });

    return {flowLogs, bucket, keyPrefix};
  }

Restricting put actions

We should lock down the access to these logs by restricting who can put in logs .

import * as iam from "@aws-cdk/aws-iam";
...
restrictS3FlowLogActions(bucket:s3.IBucket, keyPrefix: string, props: cdk.StackProps) {
    const allowPut = new iam.PolicyStatement({
        sid: "AWSLogDeliveryWrite",
        effect: iam.Effect.ALLOW,
        principals: [new iam.ServicePrincipal("delivery.logs.amazonaws.com")],
        actions:[ "s3:PutObject"],
        resources: [`arn:aws:s3:::${bucket.bucketName}/${keyPrefix}/AWSLogs/${props.env!.account}/*`],
        conditions: {"StringEquals": {"s3:x-amz-acl": "bucket-owner-full-control"}}
    });
    const allowAclCheck = new iam.PolicyStatement( {
      sid: "AWSLogDeliveryAclCheck",
      effect: iam.Effect.ALLOW,
      principals: [new iam.ServicePrincipal("delivery.logs.amazonaws.com")],
      actions: ["s3:GetBucketAcl"],
      resources: [`arn:aws:s3:::${bucket.bucketName}`]
    });
    bucket.addToResourcePolicy(allowPut);
    bucket.addToResourcePolicy(allowAclCheck);
  }

Restricting Encryption

We should encrypt the logs so the actions are restricted. Note: resource policies can easily lock you out if you're not careful so please check who needs access to read the logs.

createS3FlowLogsEncryptionKey() {
    const encryptionKey = new kms.Key(this, 'BucketKey', {});

    const allowKeyOperations = new iam.PolicyStatement({
      sid: "Allow VPC Flow Logs to use the key",
      effect: iam.Effect.ALLOW,
      principals: [new iam.ServicePrincipal("delivery.logs.amazonaws.com")],
      actions:[ "kms:Encrypt",
      "kms:Decrypt",
      "kms:ReEncrypt*",
      "kms:GenerateDataKey*",
      "kms:DescribeKey"
      ],
      resources: [`*`],
    });

    encryptionKey.addToResourcePolicy(allowKeyOperations);

    return { encryptionKey };
  }
...
createS3FlowLogs(vpc: ec2.IVpc, props: cdk.StackProps | undefined) {
    const bucket = new s3.Bucket(this, 'Bucket', {
      bucketName: 'my-vpc-flow-logs-bucket',
      encryptionKey,
    });