Aws-cdk: aws-cloudfront needs love

Created on 15 Aug 2018  路  5Comments  路  Source: aws/aws-cdk

We should redesign the API for the aws-cloudfront construct library. There's a lot we can do in order to make it friendlier, less error-prone and less flat and declarative. At the moment, it's basically "leaking" the low level API provided by CloudFormation.

Furthermore, it would be awesome if one could use Assets to point to a local directory that includes the web distribution content and have the toolkit do the work of uploading it to S3 and all that.

@aws-cdaws-cloudfront efforlarge feature-request

Most helpful comment

For reference, this is what the current API looks like just to setup a simple SPA/PWA:

const bucket = new s3.Bucket(this, 'WebsiteBucket', {
    bucketName: 'pmaddox-website-bucket',
    versioned: true,
});

const originId = new cloudfront.cloudformation.CloudFrontOriginAccessIdentityResource(this, 'OriginAccessIdentity', {
    cloudFrontOriginAccessIdentityConfig: {
        comment: 'A comment to associate with this CloudFront origin access identity',
    }
});

const cert = acm.Certificate.import(this, 'ExistingCertificate', {
    certificateArn: new acm.CertificateArn('arn:aws:acm:us-east-1:123456789012:certificate/7d3591e4-de7f-45cf-f8f5-7cc3d1732930'),
});

const distribution = new cloudfront.CloudFrontWebDistribution(this, 'WebsiteDistribution', {
    aliasConfiguration: {
        names: ['my-website.com', 'www.my-website.com'],
        acmCertRef: cert.certificateArn,
    },
    originConfigs: [{
        behaviors: [{
            isDefaultBehavior: true,
        }],
        s3OriginSource: {
            originAccessIdentity: originId,
            s3BucketSource: bucket,
        },
    }]
})

The new API should improve the linking of S3 buckets to CloudFront distributions, and abstract away the need to explicitly create a CloudFrontOriginAccessIdentityResource.

It would be really nice if we could tie this in with #605 to handle certificate generation/validation too.

Furthermore, it would be awesome if one could use Assets to point to a local directory that includes the web distribution content and have the toolkit do the work of uploading it to S3 and all that.

馃憤

All 5 comments

Internally, maybe take a look at BONESConstructs - it's got a mildly less bad wrapper around this. I can port some of that out if you find it useful

For reference, this is what the current API looks like just to setup a simple SPA/PWA:

const bucket = new s3.Bucket(this, 'WebsiteBucket', {
    bucketName: 'pmaddox-website-bucket',
    versioned: true,
});

const originId = new cloudfront.cloudformation.CloudFrontOriginAccessIdentityResource(this, 'OriginAccessIdentity', {
    cloudFrontOriginAccessIdentityConfig: {
        comment: 'A comment to associate with this CloudFront origin access identity',
    }
});

const cert = acm.Certificate.import(this, 'ExistingCertificate', {
    certificateArn: new acm.CertificateArn('arn:aws:acm:us-east-1:123456789012:certificate/7d3591e4-de7f-45cf-f8f5-7cc3d1732930'),
});

const distribution = new cloudfront.CloudFrontWebDistribution(this, 'WebsiteDistribution', {
    aliasConfiguration: {
        names: ['my-website.com', 'www.my-website.com'],
        acmCertRef: cert.certificateArn,
    },
    originConfigs: [{
        behaviors: [{
            isDefaultBehavior: true,
        }],
        s3OriginSource: {
            originAccessIdentity: originId,
            s3BucketSource: bucket,
        },
    }]
})

The new API should improve the linking of S3 buckets to CloudFront distributions, and abstract away the need to explicitly create a CloudFrontOriginAccessIdentityResource.

It would be really nice if we could tie this in with #605 to handle certificate generation/validation too.

Furthermore, it would be awesome if one could use Assets to point to a local directory that includes the web distribution content and have the toolkit do the work of uploading it to S3 and all that.

馃憤

At a minimum I would recommend making the Cloudfront construct aware of other constructs such as:

  • elb.LoadBalancer
  • elbv2.ApplicationLoadBalancer
  • elbv2.NetworkLoadBalancer
  • apiGateway.LambdaRestApi
  • ecs.LoadBalancedFargateService (add the LB created by this construct)
  • ecs.LoadBalancedEc2Service (add the LB created by this construct)
  • ecs.FargateService and ecs.Ec2Service (lookup the attached LB)
  • s3.Bucket

CloudFront construct should be aware of how to get the domain name / address and potentially even the port from each construct and auto configure the origin details

I imagine an interface like:

const dist = new cloudfront.CloudFrontWebDistribution(this, 'WebsiteDistribution');

const ecsOrigin = dist.addOrigin(this, {
   target: myEcsServiceConstruct,
   port: 3000
});

const apiOrigin = dist.addOrigin(this, {
   target: myApiGatewayConstruct
});

dist.addBehavior(this, {
   path: '*',
   origin: ecsOrigin
   default: true
});

dist.addBehavior(this, {
   path: 'api*',
   origin: apiOrigin
   default: true
});

Hi @eladb, @PaulMaddox, @mindstorms6, @nathanpeck

I'm trying to add policy statements to my bucket, but it fails with the message Invalid principal in policy.
Any hint on how to reference the OID arn correctly?

    const originAccessIdentity = new cloudfront.CfnCloudFrontOriginAccessIdentity(
      this,
      'PublicSiteOAI',
      {
        cloudFrontOriginAccessIdentityConfig: {
          comment: 'OAI for adac-public-site-bucket'
        }
      }
    );

    const bucket = new s3.Bucket(this, 'Bucket', {
      blockPublicAccess: s3.BlockPublicAccess.BlockAll,
      bucketName: 'public-site-bucket'
    });

    const distribution = new cloudfront.CloudFrontWebDistribution(
      this,
      'Cloudfront',
      {
        comment: 'Public Site Cloudfront',
        originConfigs: [
          {
            behaviors: [{ isDefaultBehavior: true }],
            s3OriginSource: {
              originAccessIdentity,
              s3BucketSource: bucket
            }
          }
        ]
      }
    );

    const listBucketPolicy = new iam.PolicyStatement()
      .addAction('s3:ListBucket')
      .allow()
      .addResource(`arn:aws:s3:::${distribution.domainName}`)
      .addAwsPrincipal(originAccessIdentity.cloudFrontOriginAccessIdentityId);
    listBucketPolicy.sid = 'bucket_policy_site_root';
    bucket.addToResourcePolicy(listBucketPolicy);

    const getObjectPolicy = new iam.PolicyStatement()
      .addAction('s3:GetObject')
      .allow()
      .addResource(`arn:aws:s3:::${distribution.domainName}/*`)
      .addAwsPrincipal(originAccessIdentity.cloudFrontOriginAccessIdentityId);
    getObjectPolicy.sid = 'bucket_policy_site_all';
    bucket.addToResourcePolicy(getObjectPolicy);

The "love" this module needs was designed in this RFC (https://github.com/aws/aws-cdk-rfcs/issues/171) and implementation of the initial "Developer Preview" version is being tracked via this milestone: https://github.com/aws/aws-cdk/milestone/5.

There is also the overall tracking issue #6490 where high-level feature work can be tracked.

Closing this issue out in favor of the above.

Was this page helpful?
0 / 5 - 0 ratings