Migrating CloudFront OAI to OAC using CloudFormation
Tags: aws, cloudfront, cloudformation
Published: 2022-09-21 12:20:13

## Goals of this post
Describes the CloudFormation template modifications required to migrate CloudFront's Origin access identity (OAI) to Origin Access Control (OAC).

OAC is a new access control method for setting S3 buckets as origins in CloudFront.

{% embed https://aws.amazon.com/blogs/networking-and-content-delivery/amazon-cloudfront-introduces-origin-access-control-oac/ %}

Previously we had used Origin Access Identity (OAI) to restrict access to origin S3 buckets to CloudFront only.

OAI is currently treated as Legacy. Migration from OAI to OAC is recommended to support security best practices and new regions.

## Sample Template
See my GitHub repository!

{% embed https://github.com/hayao-k/CFn-sample-cloudfront-oac %}

## Examples of modifications
Migrating existing CloudFormation templates from OAI to OAC requires, as a minimum, the following modifications.

* Creating an OAC
* Modifying the bucket policy
* Modifying Distribution Origin

### Creating an OAC
Create an `AWS::CloudFront::OriginAccessControl`. Description of the OriginAccessControlConfig is an optional field.

```yaml
Resources:
  CloudFrontOriginAccessControl:
    Type: AWS::CloudFront::OriginAccessControl
    Properties: 
      OriginAccessControlConfig:
        Description: Default Origin Access Control
        Name: !Ref AWS::StackName
        OriginAccessControlOriginType: s3
        SigningBehavior: always
        SigningProtocol: sigv4
```

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html

Delete `AWS::CloudFront::CloudFrontOriginAccessIdentity` as it will no longer be required after migration.

### Modifying the bucket policy
In the following example, the policy for OAI has been removed, but it is a recommended migration procedure to include both OAI and OAC policies. This will prevent CloudFront from losing access to S3 buckets during migration to OAC. Please take action as necessary.

**Before**

```yaml
 # S3 bucket policy to allow access from CloudFront OAI
  AssetsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AssetsBucket
      PolicyDocument:
        Statement:
        - Action: s3:GetObject
          Effect: Allow
          Resource: !Sub ${AssetsBucket.Arn}/*
          Principal:
            AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}
```

**After**

```yaml
# S3 bucket policy to allow access from CloudFront OAC
  AssetsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AssetsBucket
      PolicyDocument:
        Statement:
        - Action: s3:GetObject
          Effect: Allow
          Resource: !Sub ${AssetsBucket.Arn}/*
          Principal:
            Service: cloudfront.amazonaws.com
          Condition:
            StringEquals:
              AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}
```

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

### Modifying Distribution Origin
OAI sets S3OriginConfig for Distribution Origin, but OAC requires OriginAccessControlId to be specified.

**Before**

```yaml
  AssetsDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
        - Id: S3Origin
          DomainName: !GetAtt AssetsBucket.DomainName
          S3OriginConfig:
            OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}
```

**Afeter**

```yaml
  AssetsDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
        - Id: S3Origin
          DomainName: !GetAtt AssetsBucket.DomainName
          S3OriginConfig:
            OriginAccessIdentity: ''
          OriginAccessControlId: !GetAtt CloudFrontOriginAccessControl.Id
```

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origin.html

**Note:** As of September 2022, an empty OriginAccessIdentity must be specified in S3OriginConfig.

Deleting S3OriginConfig will result in the following error when updating the stack.

```
Resource handler returned message: "Invalid request provided: Exactly one of CustomOriginConfig and S3OriginConfig must be specified"
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0fx7bsjn597p5t5bswb8.png)

## Examples of actual migration
Now let's update the existing CloudFormation stack using the [modified template](https://github.com/hayao-k/CFn-sample-cloudfront-oac/blob/main/CloudFront-S3-OAC.yaml). Update the stack to ensure that the change set is as expected.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c24xq7ql1f36eku9g0rp.png)

As described before, removing the bucket policy for OAI and migrating to OAC will result in Access Denied during distribution updates.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zeeutnmjoe8brhzcsr48.png)

After updating the distribution, the S3 bucket access settings can be seen to have been updated to OAC.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/na4tu2ut3fndln4b3i5u.png)

The S3 bucket policy is also updated as expected.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4mjy2tgtj07k4zznmbwn.png)

Access from the browser seems to be okay.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pz4zqtovr0ckzgj4ch1z.png)

I hope this will be of help to someone else.