'Get 403 Error when trying to use CloudFront OAI for S3 bucket access

I have a S3 bucket which hosts my react website. I banned public access to the bucket, and configured an OAI to access the S3 bucket.

I can see that I have granted the OAI with IAM policy in the S3 bucket permission, and also the OAI ID matches:

{
   "Effect":"Allow",
   "Principal":{
      "AWS":"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2M5555555"
   },
   "Action":"s3:GetObject",
   "Resource":"arn:aws:s3:::dummywebsite.com-12345-us-east-1/*"
}

However, I still get 403 permission error from the cloudfront url. Any idea what may cause this?

Context

Here is my CDK code:

   // Amazon S3 bucket to host the store  website artifact
    const websiteBucket = new S3.Bucket(this, "dummywebsite", {
      bucketName: `${props.websiteDomain}-${props.env.account}-${props.env.region}`,
      websiteIndexDocument: "index.html",
      websiteErrorDocument: "error.html",
      removalPolicy: CDK.RemovalPolicy.DESTROY,
      autoDeleteObjects: true,

      accessControl: S3.BucketAccessControl.PRIVATE,
      encryption: S3.BucketEncryption.S3_MANAGED,
      publicReadAccess: false,
      blockPublicAccess: S3.BlockPublicAccess.BLOCK_ALL,
    });

    const hostedZone = Route53.HostedZone.fromLookup(this, "HostedZoneId", {
      domainName: props.websiteDomain,
    });

    const certificateManagerCertificate = new ACM.Certificate(
      this,
      "CertificateManagerCertificate",
      {
        domainName: props.websiteDomain,
        validation: ACM.CertificateValidation.fromDns(hostedZone),
      }
    );

    // Create a special CloudFront user called an origin access identity (OAI)
    // and associate it with the CloudFront distribution.
    const cloudFrontOAI = new CloudFront.OriginAccessIdentity(
      this,
      "dummyWebsiteOriginAccessIdentityID"
    );
    const cloudfrontUserAccessPolicy = new IAM.PolicyStatement();
    cloudfrontUserAccessPolicy.addActions("s3:GetObject");
    cloudfrontUserAccessPolicy.addPrincipals(cloudFrontOAI.grantPrincipal);
    cloudfrontUserAccessPolicy.addResources(websiteBucket.arnForObjects("*"));
    websiteBucket.addToResourcePolicy(cloudfrontUserAccessPolicy);

    const cloudFrontDistribution = new CloudFront.Distribution(
      this,
      "CloudFrontDistribution",
      {
        domainNames: [props.websiteDomain],
        defaultBehavior: {
          origin: new CloudFrontOrigins.S3Origin(websiteBucket, {
            // CloudFront can use the OAI to access the files in the S3 bucket and serve them to users.
            // Users can’t use a direct URL to the S3 bucket to access a file there.
            originAccessIdentity: cloudFrontOAI,
          }),
          compress: true,
          allowedMethods: CloudFront.AllowedMethods.ALLOW_GET_HEAD,
          cachedMethods: CloudFront.CachedMethods.CACHE_GET_HEAD,
          viewerProtocolPolicy:
            CloudFront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
          cachePolicy: CloudFront.CachePolicy.CACHING_OPTIMIZED,
        },
        errorResponses: [
          {
            httpStatus: 403,
            responsePagePath: "/index.html",
            responseHttpStatus: 200,
            ttl: CDK.Duration.minutes(0),
          },
          {
            httpStatus: 404,
            responsePagePath: "/index.html",
            responseHttpStatus: 200,
            ttl: CDK.Duration.minutes(0),
          },
        ],
        priceClass: CloudFront.PriceClass.PRICE_CLASS_ALL,
        enabled: true,
        certificate: certificateManagerCertificate,
        minimumProtocolVersion: CloudFront.SecurityPolicyProtocol.TLS_V1_2_2021,
        httpVersion: CloudFront.HttpVersion.HTTP2,
        defaultRootObject: "index.html",
        enableIpv6: true,
      }
    );

    new Route53.ARecord(this, "Route53RecordSet", {
      recordName: props.websiteDomain,
      zone: hostedZone,
      target: Route53.RecordTarget.fromAlias(
        new Route53Targets.CloudFrontTarget(cloudFrontDistribution)
      ),
    });


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source