# Migrating CloudFront OAI to OAC using CloudFormation

## 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.

%[https://aws.amazon.com/jp/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!

%[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}
```

**After**

```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.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663746850244/IDxEAq0v9.png align="left")

## 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.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663756931310/R7-Jqm-Oy.png align="left")

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

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663760156996/Es-UXXUyL.png align="left")

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

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663760434371/ZZE_cdyEy.png align="left")

The S3 bucket policy is also updated as expected.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663760594959/Y5P_stKfL.png align="left")

Also, access from the browser seems to be okay.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663760678612/CSIBmQzTY.png align="left")

I hope this will be of help to someone else.
