ลดความยุ่งยากในการใช้คลาวด์ พูดคุยกับเจ้าหน้าที่

ตั้งค่า Firewall ด้วย nftables บน Ubuntu และ Debian
Home ตั้งค่า Firewall ด้วย nftables บน Ubuntu และ Debian

ตั้งค่า Firewall ด้วย nftables บน Ubuntu และ Debian

nftables คือระบบ Firewall ที่มาแทน iptables ในเคอร์เนล Linux รุ่นใหม่ ทั้ง Ubuntu 22.04 ขึ้นไปและ Debian 11 ขึ้นไปใช้ nftables เป็นค่าเริ่มต้นแล้ว แม้คำสั่ง iptables จะยังพิมพ์ได้อยู่ แต่เบื้องหลังก็ถูกแปลไปเป็น nftables ให้อีกที

ข้อดีของการเขียนกฎด้วย nftables ตรง ๆ คือไวยากรณ์อ่านง่ายกว่า รวมกฎ IPv4 และ IPv6 ไว้ในชุดเดียวกันได้ และดูกฎทั้งหมดได้ในคำสั่งเดียว คู่มือนี้เขียนกฎชุดพื้นฐานสำหรับเซิร์ฟเวอร์ที่เปิดสู่อินเทอร์เน็ต ตั้งแต่ศูนย์จนถึงบันทึกให้อยู่ถาวร

สิ่งที่ต้องเตรียม

  • Ubuntu 22.04/24.04 หรือ Debian 11/12 และสิทธิ์ sudo
  • ช่องทางสำรองเข้าเครื่องกรณีถูกตัดขาดจาก SSH เช่น Console ผ่านหน้าเว็บของผู้ให้บริการ
  • รายการพอร์ตที่ต้องเปิดจริง เช่น 22 (SSH), 80 และ 443 (เว็บ)

หากเครื่องใช้ UFW อยู่แล้ว ให้เลือกอย่างใดอย่างหนึ่ง อย่าใช้พร้อมกัน เพราะกฎจะทับซ้อนกันจนไล่ปัญหาไม่ออก ปิด UFW ก่อนด้วย sudo ufw disable

ขั้นตอนที่ 1: ติดตั้งและดูสถานะปัจจุบัน

sudo apt update
sudo apt install -y nftables
sudo systemctl enable --now nftables

ดูกฎที่มีอยู่ตอนนี้ทั้งหมด ถ้าเพิ่งติดตั้งจะยังว่างเปล่าหรือมีเพียงโครงว่าง

sudo nft list ruleset

ขั้นตอนที่ 2: ทำความเข้าใจโครงสร้าง table, chain และ rule

nftables จัดกฎเป็นสามชั้น เข้าใจสามคำนี้แล้วที่เหลือจะง่ายขึ้นมาก

  • table คือกล่องใหญ่ที่รวมกฎของตระกูลโพรโทคอลหนึ่ง ๆ ใช้ inet เพื่อคุมทั้ง IPv4 และ IPv6 พร้อมกัน
  • chain คือจุดที่แพ็กเก็ตวิ่งผ่าน เช่น input สำหรับแพ็กเก็ตที่เข้ามาหาเครื่องนี้ forward สำหรับที่วิ่งผ่านไปเครื่องอื่น และ output สำหรับที่ออกจากเครื่อง
  • rule คือเงื่อนไขและการกระทำ เช่น "ถ้าปลายทางเป็นพอร์ต 443 ให้ accept"

ขั้นตอนที่ 3: เขียนไฟล์กฎ

วิธีที่ดูแลง่ายที่สุดคือเขียนกฎทั้งชุดลงไฟล์เดียว แล้วโหลดทีเดียว เปิดไฟล์

sudo nano /etc/nftables.conf

แทนที่เนื้อหาทั้งหมดด้วยชุดนี้ แล้วค่อยปรับพอร์ตให้ตรงกับงานจริงของคุณ

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;

    # อนุญาตการเชื่อมต่อที่สร้างไว้แล้ว ต้องมาเป็นกฎแรกเสมอ
    ct state established,related accept
    ct state invalid drop

    # loopback ภายในเครื่อง
    iif lo accept

    # ping (ใช้ตรวจสอบเครื่องจากภายนอก)
    ip protocol icmp accept
    ip6 nexthdr ipv6-icmp accept

    # SSH
    tcp dport 22 accept

    # เว็บ
    tcp dport { 80, 443 } accept
  }

  chain forward {
    type filter hook forward priority 0; policy drop;
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}

จุดสำคัญคือ policy drop ใน chain input หมายความว่าอะไรที่ไม่มีกฎอนุญาตไว้จะถูกทิ้งทั้งหมด นี่คือแนวทางที่ถูกต้องสำหรับเซิร์ฟเวอร์ที่เปิดสู่อินเทอร์เน็ต และเป็นเหตุผลที่กฎ tcp dport 22 accept ต้องมีก่อนโหลด ไม่เช่นนั้นคุณจะหลุดจาก SSH ทันที

ขั้นตอนที่ 4: ทดสอบก่อนใช้จริง

ตรวจไวยากรณ์ก่อน โดยยังไม่โหลดเข้าเคอร์เนล

sudo nft -c -f /etc/nftables.conf

ถ้าไม่มีข้อความใดแสดงขึ้นมาแปลว่าไวยากรณ์ถูกต้อง ต่อไปตั้งตัวช่วยกันล็อกตัวเองออก โดยสั่งให้ระบบล้างกฎทิ้งอัตโนมัติในอีก 5 นาที หากคุณยังเชื่อมต่อได้ตามปกติค่อยยกเลิกคำสั่งนี้

sudo sh -c 'sleep 300 && nft flush ruleset' &
echo $!

จดเลข Process ID ที่ได้ไว้ แล้วค่อยโหลดกฎจริง

sudo nft -f /etc/nftables.conf

เปิด Terminal อีกหน้าต่างหนึ่งแล้วลอง SSH เข้าเครื่องใหม่ ถ้าเข้าได้แปลว่ากฎถูกต้อง ให้ยกเลิกตัวช่วยด้วย sudo kill <PID>

ขั้นตอนที่ 5: บันทึกให้อยู่ถาวรหลังรีบูต

บน Ubuntu และ Debian เซอร์วิส nftables จะอ่าน /etc/nftables.conf ตอนบูตอยู่แล้ว เพียงเปิดใช้งานเซอร์วิสไว้

sudo systemctl enable nftables
sudo systemctl restart nftables
sudo systemctl status nftables --no-pager

หากคุณเพิ่มกฎชั่วคราวด้วยคำสั่ง nft add rule กฎนั้นจะหายเมื่อรีบูต ถ้าพอใจแล้วให้เขียนกลับเข้าไฟล์ด้วย

sudo sh -c 'nft list ruleset > /etc/nftables.conf'

ขั้นตอนที่ 6: กฎที่ใช้บ่อยเพิ่มเติม

จำกัด SSH ให้เข้าได้เฉพาะ IP ของออฟฟิศ

tcp dport 22 ip saddr { 203.0.113.10, 198.51.100.0/24 } accept

ใส่แทนบรรทัด tcp dport 22 accept เดิม ระวังให้แน่ใจว่า IP ที่ใส่คือ IP ขาออกจริงของคุณ ตรวจได้จากคำสั่ง curl -s ifconfig.me บนเครื่องที่ใช้อยู่

จำกัดจำนวนการเชื่อมต่อใหม่ต่อวินาที

tcp dport 22 ct state new limit rate 10/minute accept

ช่วยลดแรงของบอตที่ไล่เดารหัสผ่าน ใช้ร่วมกับ Fail2ban ได้

บันทึก Log แพ็กเก็ตที่ถูกทิ้ง

เพิ่มบรรทัดนี้ไว้ท้ายสุดของ chain input ก่อนปิดปีกกา

limit rate 5/minute log prefix "nft-drop: " level info

ดู Log ได้ด้วย sudo journalctl -k | grep nft-drop ใส่ limit rate ไว้ด้วยเสมอ ไม่อย่างนั้นไฟล์ Log จะโตจนดิสก์เต็ม

ขั้นตอนที่ 7: ดูและแก้กฎที่ใช้งานอยู่

ดูกฎพร้อมหมายเลขบรรทัด (handle) ซึ่งใช้อ้างอิงตอนลบ

sudo nft -a list ruleset

ลบกฎหนึ่งข้อด้วยหมายเลข handle ที่เห็น

sudo nft delete rule inet filter input handle 12

เพิ่มกฎชั่วคราวเพื่อทดสอบ

sudo nft add rule inet filter input tcp dport 8080 accept

ปัญหาที่พบบ่อย

โหลดกฎแล้ว SSH หลุดทันที

เกือบทุกครั้งเกิดจากลืมกฎ ct state established,related accept หรือลืมเปิดพอร์ต SSH เข้าเครื่องผ่าน Console แล้วรัน sudo nft flush ruleset เพื่อล้างกฎทั้งหมดก่อน จากนั้นแก้ไฟล์ให้ถูกแล้วค่อยโหลดใหม่

เปิดพอร์ตแล้วแต่ยังเข้าไม่ได้

ตรวจสองอย่าง หนึ่งคือโปรแกรมฟังอยู่ที่ IP ภายนอกจริงไม่ใช่เฉพาะ 127.0.0.1 ดูด้วย sudo ss -tlnp สองคือผู้ให้บริการอาจมี Firewall อีกชั้นอยู่นอกเครื่อง ต้องเปิดพอร์ตที่ชั้นนั้นด้วย

กฎหายหลังรีบูต

กฎที่เพิ่มด้วย nft add rule อยู่แค่ในหน่วยความจำ ต้องเขียนลง /etc/nftables.conf และเปิดเซอร์วิส nftables ไว้

Docker เปิดพอร์ตทะลุ Firewall

Docker เขียนกฎของตัวเองลง chain ที่ทำงานก่อน input การ publish พอร์ตด้วย -p 8080:80 จึงเปิดสู่อินเทอร์เน็ตแม้ nftables จะไม่ได้อนุญาต แก้โดย bind เฉพาะเครื่องด้วย -p 127.0.0.1:8080:80 แล้วให้ Nginx เป็นตัวรับจากภายนอกแทน

หากตั้งค่าแล้วยังเข้าถึงบริการไม่ได้ ติดต่อทีมซัพพอร์ต THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/

ผู้ให้บริการคลาวด์ไทย
เพื่อธุรกิจของคนไทย

"มุ่งมั่น" และ "มั่นคง"
พร้อมรับมือทุกการเติบโต
Trust Cloud
คลาว์ที่ปลอดภัย
คือรากฐานที่มั่นคง
cloud security