AWS: How to configure Apache on EC2 as a reverse proxy for S3

Ingkwan
Ingkwan’s Knowledge Hub
5 min readJul 26, 2019

--

ลองทำ Reverse Proxy จาก EC2 แบบง่ายๆไปหา S3 โดยในส่วนของ Path ที่เรียกนั้นจะต้องสามารถทำ Dynamic Mapping ได้เช่นกัน

อย่างเช่น ถ้าเราเรียก /get/* เข้ามาใน EC2 โดย * เป็นชื่อ Path ของไฟล์ใน S3 เราจะให้ไป Request วิ่งไปตาม Object URL ใน S3 ตาม Path นั้นๆ

http://your_ec2_hostname:8888/get/test.json
---> https://your_bucket.s3-ap-southeast-1.amazonaws.com/test.json
http://your_ec2_hostname:8888/get/nooo.json
---> https://your_bucket.s3-ap-southeast-1.amazonaws.com/nooo.json

สำหรับการสร้าง Instance ของ EC2 และ S3 Bucket ตรงนี้จะขอข้ามไป มาดูกันว่าสิ่งที่ต้องเตรียมให้พร้อมก่อนมีอะไรบ้าง ในตัวอย่าง EC2 เราจะใช้ OS เป็น Red Hat Enterprise Linux 8 ค่ะ

Prerequisites

  1. EC2
    - เพิ่ม Inbound Port ดังนี้ HTTP 80, TCP 8888 (8888 เป็น Custom Port ที่เราจะใช้ในการเข้าถึง Resource ของ S3)
    - มี Access สำหรับ SSH
  2. S3
    - สร้าง Bucket (สมมติว่าชื่อ your_bucket)
    - Upload ไฟล์สำหรับทดสอบ
    - ในส่วนของ Permission ให้เลือกเป็น Block all public access เท่านั้น

Let’s get started!

อันดับแรกเราจะสร้าง IAM Role ขึ้นมาอันนึงสำหรับ EC2 ก่อน โดยกำหนด Policy การเข้าถึง S3 ให้เป็นแบบ Read Only

หลังจากนั้นก็ใส่ชื่อ Role name เป็นอันจบ ถัดมาเราจะทำการเพิ่ม IAM Role นี้ไปใน EC2 Instance ของเราผ่านเมนู Actions -> Instance Settings -> Attach/Replace IAM Role ในหน้า Console และเลือกตามชื่อ Role name ที่เราได้ตั้งไว้ก่อนหน้า จากนั้นกด Apply

SSH เข้าไปที่ EC2 เพื่อติดตั้ง AWS CLI (AWS Command Line Interface) ซึ่งเป็น Tool ตัวหนึ่งที่ใช้ในการจัดการ AWS Service ต่างๆของเรา

$ sudo su
$ yum install python3
$ curl -O https://bootstrap.pypa.io/get-pip.py
$ python3 get-pip.py --user
$ cd ~

Set PATH เพื่อรันคำสั่ง Python โดยการเติมคำสั่งด้านล่างในไฟล์ .bashrc
export PATH=~/.local/bin:$PATH

$ source .bashrc

จากนั้นลง AWS CLI ผ่าน pip3

$ pip3 install awscli -upgrade -user

พอได้แล้วให้ทดสอบการ Access Bucket ใน S3 โดยคำสั่ง aws s3 ls จะเป็นการ List ข้อมูล Resource ใน Bucket ที่เราต้องการ ซึ่งถ้ายังไม่สร้าง IAM Role ผูกกับ EC2 จะไม่สามารถใช้จัดการ S3 ผ่าน AWS CLI ได้

$ aws s3 ls your_bucket
2019-07-26 08:58:13 22 nooo.json
2019-07-26 07:24:14 18 test.json

แต่พอลอง cURL หาไฟล์ที่ Upload ไว้จะได้ Error กลับมาว่า Access Denied

$ curl https://your_bucket.xxx.amazonaws.com/test.jsonAccess Denied

แล้วแบบนี้เราจะทำยังไงเพื่อให้สามารถยิง HTTP Request ผ่านเข้าไปที่ Public URL ของ S3 ได้กันล่ะ?

คำตอบคือเราจะใช้วิธีกำหนดว่าจะยอมให้ VPC (Virtual Private Cloud) ไหนสามารถเข้าถึง S3 Bucket ที่ต้องการได้บ้าง

อ่านเพิ่มเติมเกี่ยวกับ Amazon VPC ที่นี่นะ
https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html

ในตัวอย่างเราจะใช้ที่เป็น Default VPC ที่มาตอนสร้าง EC2 Instance ซึ่งดูได้จากหน้า EC2 Console แล้วดูในส่วน Description จะเห็นว่ามี VPC ID อยู่

เข้ามาที่ S3 Bucket ของเรา และแก้ไข Bucket Policy เพื่อให้ Allow เฉพาะ VPC ที่ต้องการ

{
"Version": "2012-10-17",
"Id": "Policy1415115909153",
"Statement": [
{
"Sid": "Access-to-specific-VPC-only",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::your_bucket",
"arn:aws:s3:::your_bucket/*"
],
"Condition": {
"StringEquals": {
"aws:sourceVpc": "vpc-xxxxxxxx"
}
}
}
]
}

ไปที่หน้า VPC Dashboard และสร้าง VPC Endpoint

เลือก Service Name เป็น com.amazonaws.ap-southeast-1.s3 (ปรับตาม Region ที่เราใช้)

เลือก VPC ที่เป็นของ EC2 และกด Check ตรง Route Table

กด Create Endpoint

กลับมาที่หน้า Terminal และลอง cURL ใหม่อีกครั้ง เราจะได้ Response กลับมาแล้ว

$ curl https://yourbucket.xxx.amazonaws.com/test.json{"message":"test"}

ถัดมาเราจะ Install Apache ดังนี้

$ yum install httpd

ใช้คำสั่ง chkconfig เพื่อให้ Service ของเรา Start ตอน Boot ทุกครั้ง และทำการ Start Apache ขึ้นมา

$ chkconfig httpd on
$ service httpd start

ทดสอบว่า Apache Server เราใช้ได้หรือไม่ โดยสร้างไฟล์ index.html แล้วใส่ไว้ใน /var/www/html จากนั้น Access ด้วย Public DNS ของ EC2 ตามด้วย /index.html

ลง semanage (SELinux Policy Management Tool) เพื่อใช้ในการจัดการ Port

$ yum provides semanage
$ yum install policycoreutils-python-utils

เมื่อลง policycoreutils-python-utils เสร็จแล้วเราจะเพิ่ม TCP Port 8888 เข้าไป

$ semanage port -a -t http_port_t -p tcp 8888

ให้ตรวจสอบว่า Port ได้ถูกเพิ่มเข้าไปแล้ว

$ semanage port -l | grep -w http_port_t

ลง mod_ssl และ ทำการ Allow Apache ให้สร้าง Network Connection ได้

$ yum install mod_ssl
$ /usr/sbin/setsebool -P httpd_can_network_connect 1

ทำการแก้ไข Apache Config ในไฟล์ httpd.conf เพื่อเพิ่มการทำ Reverse Proxy

$ cd /etc/httpd/conf
$ vi httpd.conf

เพิ่ม Listen Port 8888 โดยใช้ Hostname เป็o Public DNS ของ EC2

เพิ่ม VirtualHost สำหรับ Port 8888 และเราจะใช้ RewriteRule ในการทำ Dynamic Mapping เวลามี HTTP Request เรียกเข้ามาที่ EC2

<VirtualHost xxx.ap-southeast-1.compute.amazonaws.com:8888>        RewriteEngine On
RewriteRule ^/get/(.*)$ https://your_bucket.s3-ap-southeast-1.amazonaws.com/$1? [P,L]
</VirtualHost>

ทดสอบโดยเรียกเข้ามาที่ EC2 ที่ Port 8888

แต่จะเห็นว่าถ้าเรียกตรงๆเข้ามาที่ S3 จาก Public ก็จะได้ Access Denied กลับไป

สมมติว่าถ้าเรามี DEV Environment หลายอันเราก็สามารถสร้าง VirtualHost สำหรับแต่ละ DEV ได้โดยแยกตาม Port ไป ไม่จำเป็นต้องลง Apache ใน Server หลายๆเครื่อง

จากทั้งหมดที่กล่าวมาเป็นการ Setup เบื้องต้นให้เราสามารถใช้งานตามโจทย์ที่กำหนดได้โดยมีการทำ Access Control ในระดับหนึ่ง ถ้าหากใครอยากให้ Secure มากกว่านี้ก็สามารถ Custom Policy ตามที่ต้องการได้เช่นกันค่ะ ヽ(・∀・)ノ

--

--