การเปิด API บนอินเทอร์เน็ตโดยตรงทำให้ endpoint สามารถถูกเรียกจากแหล่งต่าง ๆ ได้ หาก API เป็นระบบภายในองค์กร, Admin API, Partner API หรือ API ที่ต้องการให้เฉพาะ Server บางเครื่องเข้าถึง การใช้ IP Allowlisting เป็นอีกชั้นหนึ่งของการควบคุมการเข้าถึงที่มีประโยชน์มาก

Workshop นี้จะทดลองสร้าง API และใช้ Nginx เป็น Reverse Proxy เพื่ออนุญาตเฉพาะ IP Address ที่กำหนดเท่านั้น


#วัตถุประสงค์

หลังจบ Workshop ผู้อ่านจะสามารถ

  • อธิบายหลักการของ IP Allowlisting ได้
  • จำกัดการเข้าถึง API ด้วย IP Address ได้
  • ตั้งค่า Nginx ด้วย allow และ deny
  • อนุญาตหลาย IP และเครือข่ายแบบ CIDR ได้
  • ทดสอบ API ด้วย curl
  • เข้าใจปัญหา Client IP เมื่อระบบอยู่หลัง Proxy หรือ Load Balancer
  • ประยุกต์ใช้ร่วมกับ Docker และระบบ Production ได้

#1. IP Allowlisting คืออะไร

IP Allowlisting คือการกำหนดรายการ IP Address ที่ได้รับอนุญาตให้เข้าถึง Resource เช่น API

ตัวอย่างเช่น เรามี API

https://api.example.com/api/private

และต้องการให้เฉพาะเครื่องที่มี Public IP

203.0.113.10

เรียก API ได้

แนวคิดจะเป็นดังนี้

203.0.113.10
      |
      | Allowed
      v
+-------------+
|    Nginx    |
| IP Allowlist|
+-------------+
      |
      v
+-------------+
|     API     |
+-------------+

ส่วน Client อื่น

198.51.100.20
      |
      | Denied
      v
+-------------+
|    Nginx    |
+-------------+
      |
      X
403 Forbidden

IP ที่ใช้ในตัวอย่างเป็น IP สำหรับเอกสาร ควรเปลี่ยนเป็น Public IP จริงของระบบที่ต้องการอนุญาต


#2. เหมาะกับระบบแบบใด

IP Allowlisting เหมาะกับระบบ เช่น

  • Internal API
  • Partner API
  • B2B API
  • Admin API
  • Webhook Endpoint ที่ทราบ Source IP
  • Database Administration API
  • Monitoring API
  • CI/CD Server
  • API ที่เรียกจาก Server-to-Server

ตัวอย่างเช่น

Partner Server
      |
      | Static Public IP
      v
API Gateway
      |
      v
Private API

#3. Architecture ของ Workshop

ใน Workshop นี้จะใช้ Architecture ดังนี้

Client
  |
  | HTTP Request
  v
+------------------+
|      Nginx       |
| Reverse Proxy    |
| IP Allowlisting  |
+------------------+
         |
         v
+------------------+
|    REST API      |
|   Port 3000      |
+------------------+

Nginx จะทำหน้าที่

  1. รับ Request
  2. ตรวจสอบ Source IP
  3. อนุญาตเฉพาะ IP ที่กำหนด
  4. Forward Request ไปยัง API

#4. เตรียมเครื่องมือ

ตัวอย่างนี้สามารถทำบน Ubuntu Server หรือ Linux Server ที่มี

  • Node.js
  • npm
  • Nginx
  • curl

ตรวจสอบ Node.js

node --version

ตรวจสอบ npm

npm --version

ตรวจสอบ Nginx

nginx -v

#5. สร้าง REST API ตัวอย่าง

สร้าง Project

mkdir ip-allowlist-api
cd ip-allowlist-api

สร้าง package.json

npm init -y

ติดตั้ง Express

npm install express

สร้างไฟล์

server.js

ใส่โค้ด

const express = require("express");

const app = express();

app.get("/api/public", (req, res) => {
    res.json({
        message: "Public API"
    });
});

app.get("/api/private", (req, res) => {
    res.json({
        message: "Private API",
        status: "Access granted"
    });
});

app.listen(3000, "127.0.0.1", () => {
    console.log("API running on http://127.0.0.1:3000");
});

รัน API

node server.js

ทดสอบ

curl http://127.0.0.1:3000/api/public

ผลลัพธ์

{
  "message": "Public API"
}

ทดสอบ Private API

curl http://127.0.0.1:3000/api/private

#6. ติดตั้ง Nginx

Ubuntu/Debian

sudo apt update
sudo apt install nginx -y

ตรวจสอบสถานะ

sudo systemctl status nginx

เปิดใช้งาน

sudo systemctl enable --now nginx

#7. ตั้งค่า Nginx เป็น Reverse Proxy

สร้างไฟล์

sudo nano /etc/nginx/sites-available/api

กำหนดค่า

server {

    listen 80;

    server_name api.example.com;

    location /api/ {

        proxy_pass http://127.0.0.1:3000;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

เปิด Site

sudo ln -s /etc/nginx/sites-available/api /etc/nginx/sites-enabled/api

ตรวจสอบ Configuration

sudo nginx -t

Reload

sudo systemctl reload nginx

#8. จำกัด API ด้วย IP Address

สมมติว่าอนุญาต IP

203.0.113.10

แก้ Configuration

location /api/private {

    allow 203.0.113.10;

    deny all;

    proxy_pass http://127.0.0.1:3000;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

คำสั่ง

allow 203.0.113.10;

หมายถึงอนุญาต IP ดังกล่าว

ส่วน

deny all;

หมายถึงปฏิเสธ IP อื่นทั้งหมด


#9. อนุญาตหลาย IP

ตัวอย่าง

location /api/private {

    allow 203.0.113.10;
    allow 203.0.113.20;
    allow 203.0.113.30;

    deny all;

    proxy_pass http://127.0.0.1:3000;
}

Architecture

203.0.113.10 ----+
                 |
203.0.113.20 ----+----> Nginx ----> API
                 |
203.0.113.30 ----+

IP อื่น

198.51.100.20
       |
       X
403 Forbidden

#10. อนุญาตเป็น Network ด้วย CIDR

ถ้าต้องการอนุญาตทั้ง Network

203.0.113.0/24

สามารถกำหนด

allow 203.0.113.0/24;
deny all;

ตัวอย่าง

location /api/private {

    allow 203.0.113.0/24;

    deny all;

    proxy_pass http://127.0.0.1:3000;
}

ดังนั้น IP ในช่วง Network ดังกล่าวจะได้รับอนุญาตตาม CIDR


#11. อนุญาต localhost

สำหรับ Development อาจอนุญาต

allow 127.0.0.1;
allow ::1;

ตัวอย่าง

location /api/private {

    allow 127.0.0.1;
    allow ::1;
    allow 203.0.113.10;

    deny all;

    proxy_pass http://127.0.0.1:3000;
}

#12. ตรวจสอบ Configuration

ทุกครั้งที่แก้ Nginx ควรตรวจสอบ

sudo nginx -t

หากถูกต้องจะพบข้อความลักษณะ

syntax is ok
test is successful

จากนั้น

sudo systemctl reload nginx

#13. ทดสอบ API

จาก Client ที่ได้รับอนุญาต

curl -i http://api.example.com/api/private

ควรได้

HTTP/1.1 200 OK

พร้อม Response เช่น

{
  "message": "Private API",
  "status": "Access granted"
}

#14. ทดสอบจาก IP ที่ไม่ได้รับอนุญาต

curl -i http://api.example.com/api/private

จะได้

HTTP/1.1 403 Forbidden

แสดงว่า Nginx ปฏิเสธ Request ก่อนที่จะส่งไปยัง Application


#15. Public API และ Private API

เราสามารถกำหนดให้บาง API เป็น Public

location /api/public {

    proxy_pass http://127.0.0.1:3000;
}

และบาง API เป็น Private

location /api/private {

    allow 203.0.113.10;
    deny all;

    proxy_pass http://127.0.0.1:3000;
}

Architecture

                    +--> /api/public
                    |      Everyone
Internet --> Nginx -+
                    |
                    +--> /api/private
                           |
                           +--> IP Allowlist

#16. ใช้กับ Docker

สมมติ API ทำงานใน Container ชื่อ

api

และใช้ Docker Compose

services:

  api:
    build: .
    expose:
      - "3000"

  nginx:
    image: nginx:alpine

    ports:
      - "80:80"

    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro

    depends_on:
      - api

ไฟล์

nginx.conf

ตัวอย่าง

server {

    listen 80;

    location /api/public {

        proxy_pass http://api:3000;
    }

    location /api/private {

        allow 203.0.113.10;
        deny all;

        proxy_pass http://api:3000;
    }
}

รัน

docker compose up -d

ตรวจสอบ

docker compose ps

#17. IP Allowlisting ที่ Application Layer

นอกจาก Nginx แล้ว สามารถตรวจสอบ IP ใน Application ได้เช่นกัน

ตัวอย่าง Express Middleware

const allowedIps = new Set([
    "203.0.113.10",
    "203.0.113.20"
]);

function ipAllowlist(req, res, next) {

    const clientIp = req.ip;

    if (!allowedIps.has(clientIp)) {

        return res.status(403).json({
            error: "Forbidden",
            message: "IP address is not allowed"
        });
    }

    next();
}

นำไปใช้

app.get(
    "/api/admin",
    ipAllowlist,
    (req, res) => {

        res.json({
            message: "Admin API"
        });

    }
);

#18. ปัญหาเมื่ออยู่หลัง Reverse Proxy

ระบบ Production มักมี Architecture

Client
   |
   v
Cloudflare
   |
   v
Load Balancer
   |
   v
Nginx
   |
   v
Application

Application อาจเห็น IP ของ Proxy แทน Client

ตัวอย่าง

10.0.0.5

แทนที่จะเห็น

203.0.113.10

จึงต้องจัดการ Trusted Proxy อย่างถูกต้อง


#19. X-Forwarded-For

Proxy มักส่ง Header

X-Forwarded-For

ตัวอย่าง

X-Forwarded-For: 203.0.113.10

Nginx สามารถส่งต่อด้วย

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

และ

proxy_set_header X-Real-IP $remote_addr;

แต่ไม่ควรเชื่อ X-Forwarded-For จาก Client ทุกเครื่องโดยตรง เพราะ Header สามารถถูกปลอมได้


#20. Trusted Proxy

ควรกำหนดว่า Proxy ใดเป็น Trusted Proxy เท่านั้น

ตัวอย่าง Architecture

Internet
   |
   v
Trusted Load Balancer
   |
   v
Nginx
   |
   v
API

จากนั้น Application จึงใช้ Client IP ที่ได้รับผ่าน Trusted Proxy


#21. Static IP สำคัญอย่างไร

IP Allowlisting เหมาะกับ Client ที่มี

Static Public IP

ตัวอย่าง

Office Network
      |
      v
NAT Gateway
203.0.113.10
      |
      v
Internet
      |
      v
Private API

ทุกเครื่องในองค์กรออก Internet ผ่าน Public IP เดียวกัน ทำให้สามารถ Allowlist IP ของ NAT Gateway ได้


#22. Dynamic IP

ถ้า Client ใช้

  • Home Internet
  • Mobile Network
  • Dynamic Public IP

Public IP อาจเปลี่ยนได้

ทำให้

IP Allowlist

ไม่เหมาะสมหรือจำเป็นต้องแก้ Configuration บ่อย

ในกรณีดังกล่าวควรพิจารณา

  • VPN
  • OAuth 2.0
  • JWT
  • API Key
  • mTLS
  • Zero Trust Network Access

#23. Firewall Layer

ถ้าระบบมี Dedicated API Server สามารถจำกัด IP ที่ Firewall ได้ด้วย

แนวคิด

Internet
   |
   v
Firewall
   |
   | allow 203.0.113.10
   |
   v
Nginx
   |
   v
API

ข้อดีคือ Request ที่ไม่ได้รับอนุญาตถูกบล็อกก่อนถึง Web Server


#24. API Gateway

ระบบ Microservices อาจใช้

Client
   |
   v
API Gateway
   |
   +-- IP Restriction
   +-- Authentication
   +-- Rate Limiting
   +-- Logging
   |
   v
Microservices

ตัวอย่าง API Gateway เช่น

  • Kong Gateway
  • AWS API Gateway
  • Google Cloud API Gateway
  • Azure API Management

#25. ตัวอย่าง Kong API Gateway

Kong มี IP Restriction Plugin

ตัวอย่าง Declarative Configuration

_format_version: "3.0"

plugins:

  - name: ip-restriction

    config:

      allow:
        - 203.0.113.10
        - 203.0.113.20
        - 198.51.100.0/24

แนวคิด

Client
   |
   v
Kong Gateway
   |
   +-- IP Restriction
   |
   v
Backend API

#26. Defense in Depth

ไม่ควรใช้ IP Allowlisting เป็น Security Mechanism เพียงอย่างเดียว

ระบบ Production ควรมีหลายชั้น

Internet
   |
   v
Firewall / WAF
   |
   | IP Allowlist
   v
API Gateway
   |
   | Rate Limiting
   v
Authentication
   |
   | OAuth2 / JWT / API Key / mTLS
   v
Application
   |
   | Authorization
   v
Database

เรียกว่า

Defense in Depth


#27. ตัวอย่าง Production Configuration

ตัวอย่าง Nginx

server {

    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;

    location /api/public {

        proxy_pass http://127.0.0.1:3000;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api/private {

        allow 203.0.113.10;
        allow 203.0.113.20;
        allow 198.51.100.0/24;

        deny all;

        proxy_pass http://127.0.0.1:3000;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

#28. Workshop Challenge

ทดลองปรับระบบให้มี API

/api/public
/api/partner
/api/admin

โดยกำหนด Policy

API Access
/api/public ทุก IP
/api/partner Partner Network
/api/admin Admin IP เท่านั้น

ตัวอย่าง

location /api/public {

    proxy_pass http://127.0.0.1:3000;
}

location /api/partner {

    allow 198.51.100.0/24;
    deny all;

    proxy_pass http://127.0.0.1:3000;
}

location /api/admin {

    allow 203.0.113.10;
    deny all;

    proxy_pass http://127.0.0.1:3000;
}

#29. Checklist ก่อนนำขึ้น Production

ตรวจสอบว่า

  • [ ] ใช้ HTTPS
  • [ ] Client มี Static Public IP
  • [ ] ใช้ CIDR ที่แคบที่สุดเท่าที่จำเป็น
  • [ ] มี deny all
  • [ ] Backend port ไม่เปิดตรงสู่ Internet โดยไม่จำเป็น
  • [ ] กำหนด Trusted Proxy ถูกต้อง
  • [ ] ไม่เชื่อ X-Forwarded-For จากทุกแหล่ง
  • [ ] มี Authentication
  • [ ] มี Authorization
  • [ ] มี Rate Limiting
  • [ ] มี Logging และ Monitoring
  • [ ] มีขั้นตอนอัปเดต Allowlist เมื่อ Partner IP เปลี่ยน
  • [ ] ทดสอบทั้ง Allowed IP และ Denied IP

#30. สรุป

การจำกัด API ด้วย IP Allowlisting เป็นวิธีที่เรียบง่ายและมีประสิทธิภาพสำหรับ API ที่รู้จักต้นทางแน่นอน โดยเฉพาะ Server-to-Server, Internal API และ Partner API

สำหรับระบบขนาดเล็กสามารถเริ่มจาก Nginx

location /api/private {

    allow 203.0.113.10;

    deny all;

    proxy_pass http://127.0.0.1:3000;
}

แต่สำหรับ Production ควรออกแบบเป็นหลายชั้น

Firewall / WAF
       |
       v
IP Allowlisting
       |
       v
API Gateway
       |
       v
Authentication
       |
       v
Authorization
       |
       v
Application API

หลักสำคัญคือ IP Allowlisting เป็นส่วนเสริมของ API Security ไม่ใช่สิ่งทดแทน Authentication และ Authorization