แนะนำ Origin Access Control (OAC) ฟังก์ชันใหม่ของ CloudFront วิธีใหม่ที่ใช้ควบคุม Access ในการเชื่อมต่อไปยัง S3

นี่เป็นบทความที่ดัดแปลงเนื้อหามาจากบทความภาษาญี่ปุ่นของ Classmethod, Inc. ในหัวข้อ [NEW] CloudFrontからS3への新たなアクセス制御方法としてOrigin Access Control (OAC)が発表されました! หากผู้อ่านสนใจอ่านเนื้อหาต้นฉบับสามารถอ่านได้ที่ลิ้งค์ "บทความต้นฉบับ" ด้านล่าง เนื้อหาในบทความนี้การอธิบายบางอย่างจะถูกปรับให้เข้าใจง่ายขึ้นทำให้แตกต่างจากต้นฉบับในบางจุด
2022.09.30

สวัสดีครับ ชิมิซึครับ ในวันที่ 26 ที่ผ่านมาได้มีการอัพเดทเพิ่มฟังก์ชัน Origin Access Control (OAC) ให้กับ Amazon CloudFront ซึ่งเป็น CDN Service ของ AWS เข้ามาครับ
ซึ่งเป็นวิธีใหม่ในการควบคุมการ Access จาก CloudFront ไปยัง Amazon S3 ที่เป็น Object Storage Service ครับ
ที่ผ่านมาเราใช้ฟังก์ชัน Origin Access Identity (OAI) กันมา แต่ก็มีข้อจำกัดต่างๆเช่นไม่รับรองรับ SSE-KMS ของฝั่ง S3 เกิดขึ้นในช่วงที่ผ่านมา
จึงได้เกิดเป็น OAC ที่เป็นฟังก์ชันที่สามารถรองรับฟังก์ชันต่างๆที่ในเมื่อก่อนไม่สามารถทำได้และสามารถกำหนด Policy ให้ละเอียดขึ้นได้

ด้วยการอัพเดทครั้งนี้ทำให้ได้มีการเปลี่ยนเนื้อหาใน CloudFront Developer Guide ให้วิธีการควบคุมแบบเก่า OAI กลายเป็นวิธีที่ "legacy, not recommended" ไปแล้วครับ
แต่ก็ไม่ใช่ว่าเราจะไม่สามารถใช้ OAI ในการควบคุม Access ในการเชื่อมต่อไปยัง S3 ไปเลย เรายังสามารถใช้ได้เหมือนเดิม แต่ OAC ที่อัพเดทเข้ามาเป็นวิธีที่สามารถจัดการปัญหาต่างๆได้ดีกว่า AWS จึงแนะนำให้ใช้ฝั่งนี้มากกว่าเท่านั้นครับ

โดยบทความนี้จะเขียนเกี่ยวกับข้อจำกัดของ OAI, สิ่งที่ OAC สามารถทำได้และรวบรวมวิธีการใช้ OAC อย่างง่ายๆมาให้ท่านผู้อ่านได้ฟังกันครับ

ข้อจำกัดของ OAI และสิ่งถูกอัพเดทใน OAC

เราจะมาคุยกันก่อนเกี่ยวกับข้อจำกัดของ OAI (Origin Access Identity) กันก่อนครับ
ในการใช้ CloudFront โดยให้ S3 เป็น Origin เราจะสามารถควบคุมการ Access ไปยัง S3 ได้ครับ

ดูรูปภาพใน S3 ผ่าน CloudFront ด้วย OAI | DevelopersIO

การทำงานของ OAI นั้นในด้านของ CloudFront นั้นจะกำหนด Origin ที่จะใช้เป็น OAI ส่วนด้านของ S3 จะตั้งค่า Bucket Policy เพื่ออนุญาตให้ OAI สามารถเข้ามาเขียนหรืออ่านข้อมูลได้
ด้วยการใช้ OAI จะทำให้เราสามารถเชื่อมต่อ S3 Bucket ได้โดยไม่ต้องผ่าน Public Access จะเป็นการอนุญาตแค่การ Access จาก CloudFront เท่านั้น
แต่ในกรณีที่ S3 Bucket ที่เปิดใช้งานการเข้ารหัสไฟล์ด้วย AWS Key Management Service (AWS KMS) หรือกรณีที่ใช้ SSE-KMS นั้น OAI จะไม่สามารถใช้งานได้เพราะไม่รองรับฟังก์ชันเหล่านี้

และนอกจากนั้นการ PUT Request ในการอัพโหลด Object ไปยัง S3 ใน Region ที่ซัพพอร์ตแค่ AWS Signature Version 4 (SigV4) จำเป็นต้องเพิ่ม Header x-amz-content-sha256 และ มีข้อจำกัดที่ว่าไม่ Support POST Request ด้วย

ส่วนฟังก์ชันใหม่ OAC (Origin Access Control) นั้นมีการซัพพอร์ตข้อจำกัด 2 อย่างนี้
ทำให้สามารถ ดาวน์โหลด และ อัพโหลด S3 ที่มีการเข้ารหัสด้วย SSE-KMS ได้ และสามารถส่ง PUT และ POST Request ไปยัง S3 Bucket ในทุก Region ได้ด้วยแล้วครับ(ต่อให้ซัพพอร์ตแค่ AWS Signature Version 4 (SigV4) ก็ตาม)

ส่วนด้วน Security ก็ถูกอัพเกรดให้รองรับ Short-term credentials แล ะcredential rotation ที่บ่อยขึ้น ทำให้สามารถป้องกันThe confused deputy problemได้ดีขึ้น

ลองใช้ OAC ดู

กรณีที่ต้องการควบคุม Access ของ S3 แบบง่ายๆ

งั้นเรามาลองใช้ฟังก์ชัน OAC(Origin Access Control) ที่เป็นฟังก์ชันใหม่สำหรับการใช้ควบคุมการเชื่อมต่อไปยัง S3 กันครับ
ก่อนอื่นเราจะมาลองใช้วิธีแบบง่ายกันก่อน ที่เป็นเคสที่จะส่ง GET Access ไปยัง S3 Origin ครับ
ซึ่งตัว OAI (Origin Access Identity) ก็สามารถที่จะใช้งานได้
และวิธีใช้ของ OAC ก็ไม่ได้แตกต่างจาก OAI มากนัก

ก่อนอื่นให้เราทำการสร้าง S3 Bucket แล้วเลือก ACLs disabled, เปิดการใช้งาน Block Public Access และไม่มีการเข้ารหัส(Disable encrypion) ครับ



ต่อจากนั้น ในฝั่ง CloudFront เราจะสร้าง Distribution ที่เลือก S3 Bucket เป็น Origin ครับ
ในการตั้งค่า Origin ในหัวข้อ Origin access เราจะเลือก Origin access control settings ครับ
กดปุ่มCreate control settingsเพื่อสร้าง OAC ใหม่ครับ


ใช้ OAC ที่สร้างขึ้น แล้วสร้าง CloudFront Distribution ขึ้นครับ

ภาพด้านล่างเป็นหน้าหลังจากสร้างเสร็จแล้วครับ เราถูกได้รับแจ้งให้ไปอัพเดท Policy ของฝั่ง S3 Bucket ครับ
ในตรงนี้ ถ้าเราทำการคลิกที่[Copy policy] Policy จะถูก Copy ลงใน Clipboard ครับ และลิ้งค์ [Go to S3 bucket permissions to update policy] จะส่งเราไปยังหน้าต่าง Edit Policy ของ S3 Bucket ที่เราเลือกเป็น Origin ไว้

ในหมวด Permissions ของหน้าต่าง S3 Bucket ให้เรากด [Edit] เพื่อเปลี่ยน Bucket policy ครับ
เนื่อหาข้างในให้เราใช้จากที่ Copy จาก Clipboard เมื่อกี้ได้เลยครับ


ด้านล่างเป็นเนื่อหาจริงๆใน Bucket policy ครับ
Service Principal ของ CloudFront จะเป็น cloudfront.amazonaws.com ซึ่งมีความแตกต่างจาก OAI นิดหน่อยครับ

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::cloudfront-origin-access-control-test/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1XXXXXXXXXXD4"
                }
            }
        }
    ]
}

และเพื่อเป็นการเปรียบเทียบ ด้านล่างนี้จะเป็น Bucket Policy ของ OAI ครับ (อ้างอิงจาก Restricting access to an Amazon S3 origin - Amazon CloudFront)
และลิ้งค์ด้านบนนี้ก็ได้เขียนเกี่ยวกับ วิธีย้ายจาก OAI ไปเป็น OAC ด้วยครับ

{
    "Version": "2012-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EH1HDMB1FH2TC"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
        }
    ]
}

สำหรับการตั้งค่า OAC ถือว่าเสร็จเพียงแค่นี้ครับ ลองเข้าไปยังไฟล์ cloudfront-origin-access-control-test.html ซึ่งเป็นไฟล์ที่ใส่ลงไปใน S3 Bucket เมื่อกี้ดู ปรากฎว่าสามารถเข้าใช้งานจากทาง CloudFront ได้อย่างปกติ ไม่มีปัญหาอะไรครับ หรือก็คือ เราเห็นได้ว่าการเชื่อมต่อจาก CloudFront ไปยัง S3 ได้ถูกใช้ OAC แล้ว (การเชื่อมต่อโดยตรงไปยัง S3 จะถูก Block เพราะไม่ได้รับอนุญาตตามที่เขียนใน Bucket Policy)

กรณีที่ต้องการ Access ไปยัง S3 ที่ถูกเข้ารหัส SSE-KMS

เราได้เรู้เกี่ยวกับพื้นฐานการใช้ OAC กันไปแล้ว ในหัวข้อนี้เราจะมาดูข้อดีอย่างหนึ่งของ OAC ที่รองรับ SSE-KMS กันครับ

ก่อนอื่นให้เราสร้าง S3 Bucket ที่มีการเข้ารหัส SSE-KMS กัน
โดยเราจะเริ่มจากการสร้าง KMS CMK โดยในการตั้งค่าให้เราสร้าง CMK ครับ


ต่อไปให้เราสร้าง S3 Bucket แล้วเลือก ปิดการใช้งาน ACL และเปิดการใช้งาน Block Public Access
ส่วนการตั้งค่าการเข้ารหัสให้เราเลือก SSE-KMS ส่วน KMS Key ให้เลือกที่เราสร้างขึ้นมาเมื่อกี้ครับ



แล้วก็ให้เราสร้าง CloudFront Distribution แล้วให้เลือก Origin เป็น S3 Bucket ที่สร้างขึ้นที่มีการเปิดใช้งาน SSE-KMS
ในการตั้งค่า Origin ในหัวข้อ Origin access เราจะเลือก Origin access control settings ครับ

หลังจากสร้าง CloudFront Distribution แล้ว ให้เราทำการอัพเดท Bucket policy ใน S3 Bucket ที่เป็น Origin เหมือนกับเมื่อกี้

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::cloudfront-origin-access-control-sse-kms-test/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1XXXXXXXXXXP1"
                }
            }
        }
    ]
}

ในกรณีที่ S3 Bucket มีการใช้การเข้ารหัส SSE-KMS เราจำเป็นต้องอัพเดทการควบคุมของฝั่ง KMS CMK ด้วยครับ
เราจำเป็นต้องเพิ่ม Key policy ของ CMK เพิ่มขึ้นตามด้านล่างนี้ครับ

        {
            "Sid": "AllowCloudFrontServicePrincipalSSE-KMS",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root",
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": [
                "kms:Decrypt",
                "kms:Encrypt",
                "kms:GenerateDataKey*"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1XXXXXXXXXXP1"
                }
            }
        }

และท้ายสุด ใน Key Policy จะกลายเป็นเช่นนี้ครับ

{
    "Version": "2012-10-17",
    "Id": "key-consolepolicy-3",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "AllowCloudFrontServicePrincipalSSE-KMS",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root",
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": [
                "kms:Decrypt",
                "kms:Encrypt",
                "kms:GenerateDataKey*"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1XXXXXXXXXXP1"
                }
            }
        }
    ]
}

เราได้ทำการ 3 อย่างต่อไปนี้กันแล้ว (1)การใช้ OAC ในการตั้งค่า Origin ฝั่ง CloudFront (2)ปรับแต่ง S3 Bucket Policy ให้อนุญาตให้CloudFront Distribution ที่ใช้ OAC ให้สามารถอ่าน Object ที่อยู่ด้านใน S3 Bucket (3)เพิ่มการอนุญาตให้ CloudFront Distribution ที่ใช้ OAC อยู่ใน Key policy ของ KMS
หลังจากการตั้งค่าเหล่านี้เสร็จแล้ว ให้เราลองใช้ การเชื่อมต่อผ่าน CloudFront เพื่อ Access ไปยัง Object ที่ถูกอัพโหลดขึ้นใน S3 Bucket ดูกันครับ
โดยผมได้ลอง Access ไปยังcloudfront-origin-access-control-sse-kms-test.htmlที่เป็นไฟล์ที่ถูกอัพโหลดขึ้นใน S3 Bucket ปรากฎว่าเข้าใช้งานได้ปกติไม่เจอปัญหาอะไรครับ

สรุป

เราได้คุยกับไปแล้วกับข่าวอัพเดทใหม่ที่ว่ากันด้วย Origin Access Control (OAC) ฟังก์ชันใหม่ของ CloudFront วิธีใหม่ที่ใช้ควบคุม Access ในการเชื่อมต่อไปยัง S3 ซึ่งมีความแตกต่างกับ Origin Access Identity (OAI) ที่เป็นฟังก์ชั่นเดิมอยู่ดังนี้

  • รองรับ S3 Bucket ที่ใช้ SSE-KMS ในการเข้ารหัส
  • รองรับ Dynamic request(POST, PUT) ไปยัง S3 ทุก Region รวมที่ซัพพอร์ตแค่ SigV4 ด้วย
  • จะมีการรองรับให้ใช้งานได้ในทุก AWS Region ในกาารอัพเดทหลัง เดือน 12 ปี 2022
  • มีการเพิ่มระบบรักษาความปลอดภัย

ส่วนฟังก์ชัน OAI นั้นยังสามารถใช้งานได้ปกติ (แต่หลังจาก Region ที่จะเปิดหลังจาก เดือน 12 ปี 2022 จะซัพพอร์ตแค่ OAC เท่านั้น) แต่ Origin Access Control (OAC) มีการอัพเดทเรื่องระบบรักษาความปลอดภัยเข้ามา เพราะฉนั้นหากต้องการควบคุม Access ในจาก CloudFront เชื่อมต่อไปยัง S3 ผมแนะนำว่าเราควรที่จะใช้ OAC (origin Access Control) กัน

บทความต้นฉบับ

[NEW] CloudFrontからS3への新たなアクセス制御方法としてOrigin Access Control (OAC)が発表されました! | DevelopersIO

บทความที่เกี่ยวข้อง