AWS Gateway VPC endpoint S3 with CDK

AWS Gateway VPC endpoints allow us to setup private access to the s3 buckets we control and restrict access.

What do we need? CDK. see on how to set it up.

A Vpc with subnets that need access to s3.

// vpcendpoint-stack.ts
const vpc = ec2.Vpc.fromLookup(this, 'Vpc', {
      isDefault: true,
    });

A bucket with a unique name where we'll store our objects.

// vpcendpoint-stack.ts
const bucket = new s3.Bucket(this, 'VpceBucket', {
        bucketName: `my-endpoint-bucket`,
    });

A Gateway Vpc Endpoint to provide private access to the bucket

// vpcendpoint-stack.ts
const vpce = new ec2.GatewayVpcEndpoint(this, 'S3Vpce', {
        service:  ec2.GatewayVpcEndpointAwsService.S3,
        vpc,
    });

Is this secure We can lock it down further. Note: be careful about this next part because you can easily lock yourself out with resource policies.

First we'll lock down the vpc endpoint to only point to the bucket we've created.

// vpcendpoint-stack.ts

// allow get object and put object only to that bucket
    const strictPolicy = true;

    // you can allow all actions if that's what you want
    let actions = ['*'];
    if(strictPolicy){ 
      actions = [
        's3:GetObject',
        's3:PutObject',
      ]
    }
    // you can allow all resources if you don't want to limit the bucket
    let resources = ['*'];
    if(strictPolicy){ 
      resources = [
        `${bucket.bucketArn}`,
        `${bucket.bucketArn}/*`,
      ]
    }

    // I'm not going to lock down the principal here as we haven't included any. You could lock it down to ec2.amazonaws.com if you only want ec2 to have access to s3. Explicit deny would be better.

    const allowAccessToS3 = new iam.PolicyStatement({
      actions,
      effect: iam.Effect.ALLOW,
      principals: [new iam.AnyPrincipal()],
      resources,
    });
    // attach the policy statement to the vpce
    vpce.addToPolicy(allowAccessToS3);

Check that everything is working in your vpc.

Now to lock down the bucket access. This will limit access to only the VPC Endpoint as it's an Explicit Deny.

// vpcendpoint-stack.ts
const denyAccessToNotVpce = new iam.PolicyStatement({
      actions: ['s3:*'],
      effect: iam.Effect.DENY,
      principals: [new iam.AnyPrincipal()],
      resources: ['*'],
      conditions: {
        StringNotEquals: {
          "aws:sourceVpce": `${vpce.vpcEndpointId}`
        }
      }
    });
    bucket.addToResourcePolicy(
        denyAccessToNotVpce
    );

Finally check your access.

Links There are some limitations so please read the limitations Resource Policies details for S3