Programmable Packet Filtering with Magic Firewall

Cloudflare ปกป้องบริการจากการโจมตีที่ซับซ้อนทุกวัน สำหรับผู้ใช้ Magic Transit นั้น การป้องกัน DDoS จะตรวจจับและลดการโจมตี ในขณะที่ Magic Firewall อนุญาตให้มีการตั้งกฎระดับแพ็กเก็ตในแบบที่ต้องการ ทำให้ลูกค้าสามารถเลิกใช้งานอุปกรณ์ฮาร์ดแวร์ไฟร์วอลล์และปิดกั้นการรับส่งข้อมูลที่เป็นอันตรายภายในเครือข่ายของ Cloudflare บริษัทยังคงพัฒนาประเภทของการโจมตีและความซับซ้อนของการโจมตีต่อไป เช่นที่แสดงให้เห็นจาก DDoS และ Reflection การ โจมตีผให้บริการ VoIP ที่เล็งเป้าไปที่โปรโตคอล เช่น Session Initiation Protocol (SIP) การต่อสู้กับการโจมตีเหล่านี้จำเป็นต้องผลักดันขีดจำกัดของการกรองแพ็กเก็ตให้มากกว่าที่ไฟร์วอลล์แบบเดิมจะสามารถทำได้ โดยเราได้นำเทคโนโลยีที่ดีที่สุดมารวมเข้าด้วยกันในรูปแบบใหม่เพื่อเปลี่ยน Magic Firewall ให้กลายเป็นไฟร์วอลล์ที่ตั้งค่าโปรแกรมได้อย่างรวดเร็วและเต็มรูปแบบ ซึ่งสามารถต้านทานการโจมตีที่ซับซ้อนที่สุดได้

กำแพงเวทย์มนตร์แห่งไฟ

Magic Firewall เป็นไฟร์วอลล์แพ็กเก็ตไร้สัญชาติแบบกระจายที่สร้างขึ้นบน Linux nftables ไฟร์วอลล์นี้ทำงานบนทุกเซิร์ฟเวอร์ ในศูนย์ข้อมูล Cloudflare ทุกแห่งทั่วโลก หากจะให้การแยกตัวและความยืดหยุ่น กฎ nftables ของลูกค้าแต่ละรายจะได้รับการกำหนดค่าภายในเนมสเปซเครือข่าย Linux ของตนเอง

This diagram shows how packets are processed by Magic Firewall on a Cloudflare server.

ไดอะแกรมนี้แสดงอายุของแพ็กเก็ตตัวอย่างเมื่อใช้ Magic Transit ซึ่งมี Magic Firewall ในตัว อันดับแรก แพ็กเก็ตจะเข้าสู่เซิร์ฟเวอร์และการป้องกัน DDoS จะถูกนำมาใช้ ซึ่งจะลดการโจมตีให้เร็วที่สุด หลังจากนั้น แพ็กเก็ตจะถูกส่งไปยังเนมสเปซเครือข่ายเฉพาะลูกค้า ซึ่งใช้กฎ nftables กับแพ็กเก็ต แล้วแพ็กเก็ตก็จะถูกส่งกลับไปยังต้นทางผ่าน GRE tunnel โดยผู้ใช้ Magic Firewall สามารถสร้างคำสั่งไฟร์วอลล์จาก API เดียวด้วยซินแท็กซ์ Wirefilter ที่ยืดหยุ่น นอกจากนี้ กฎยังสามารถกำหนดค่าได้ผ่านแดชบอร์ด Cloudflare โดยใช้องค์ประกอบการลากและวาง UI ที่ใช้งานได้ง่าย

Magic Firewall ให้ซินแท็กซ์ที่ทรงพลังมากสำหรับการจับคู่กับพารามิเตอร์แพ็กเก็ตต่าง ๆ แต่ยังจำกัดเฉพาะการจับคู่ที่ให้โดย nftables แม้ว่าสิ่งนี้จะมากเกินพอสำหรับกรณีการใช้งานจำนวนมาก แต่ก็ไม่ได้ให้ความยืดหยุ่นเพียงพอเมื่อต้องแยกวิเคราะห์แพ็กเก็ตขั้นสูงและจับคู่เนื้อหาที่เราต้องการ เราต้องการพลังมากกว่าเดิม

สวัสดี eBPF ขอเชิญพบกับ Nftables!

เมื่อต้องการเพิ่มพลังให้กับความต้องการเครือข่าย Linux ของคุณ Extended Berkeley Packet Filter (eBPF) เป็นตัวเลือกที่เป็นธรรมชาติ เพราะด้วย eBPF คุณสามารถแทรกโปรแกรมประมวลผลแพ็กเก็ตที่รันในเคอร์เนล ให้ความยืดหยุ่นของกระบวนทัศน์การเขียนโปรแกรมที่คุ้นเคยด้วยความเร็วของการดำเนินการในเคอร์เนล ทั้งนี้ Cloudflare ชื่นชอบ eBPF  และเทคโนโลยีนี้ได้รับการเปลี่ยนแปลงเมื่อเปิดใช้งานผลิตภัณฑ์มากมายของเรา เราต้องการหาวิธีใช้ eBPF ให้ได้อย่างเป็นธรรมชาติเพื่อขยายการใช้งาน nftables ใน Magic Firewall ซึ่งจะทำให้เราสามารถจับคู่ได้โดยใช้โปรแกรม eBPF ภายในตารางและโซ่เป็นกฎ การทำเช่นนี้เหมือนกับว่าเรามีเค้กเป็นของเราเอง และกินเองด้วยโดยการรักษาโครงสร้างพื้นฐานและโค้ดที่มีอยู่ของเราไว้ และขยายออกไปมากขึ้นอีก

หาก nftables สามารถใช้ประโยชน์จาก eBPF ได้จริง เรื่องนี้จะสั้นกว่านี้มาก เพราะงั้น เราต้องทำภารกิจกันต่อไป การที่เรารู้ว่า iptables ทำงานร่วมกับ eBPF คือจุดเริ่มต้นของภารกิจดังกล่าว ตัวอย่างเช่น เราสามารถใช้ iptables และโปรแกรม eBPF ที่ปักหมุดไว้เพื่อวางแพ็กเก็ตด้วยคำสั่งต่อไปนี้:

iptables -A INPUT -m bpf --object-pinned /sys/fs/bpf/match -j DROP

เงื่อนงำนี้ช่วยให้เราอยู่บนเส้นทางที่ถูกต้อง Iptables ใช้ส่วนขยาย xt_bpf เพื่อจับคู่ในโปรแกรม eBPF ส่วนขยายนี้ใช้ประเภทโปรแกรม BPF_PROG_TYPE_SOCKET_FILTER eBPF ซึ่งช่วยให้เราโหลดข้อมูลแพ็กเก็ตจากซ็อกเก็ตบัฟเฟอร์และส่งคืนค่าตามรหัสของเรา

เรารู้ว่า iptables สามารถใช้ eBPF ได้ แล้วทำไมไม่ลองใช้ดูล่ะ ปัจจุบัน Magic Firewall ใช้ประโยชน์จาก nftables ซึ่งเป็นตัวเลือกที่ยอดเยี่ยมกับเคสการใช้งานของเราเพราะซินแท็กซ์มีความยืดหยุ่นและอินเทอร์เฟซก็เป็นแบบตั้งโปรแกรมได้ ดังนั้น เราจำเป็นต้องหาวิธีใช้ส่วนขยาย xt_bpf กับ nftables

แผนผังนี้ช่วยอธิบายความสัมพันธ์ระหว่าง iptables, nftables และเคอร์เนล ทั้งนี้ nftables API สามารถใช้ได้กับทั้งโปรแกรม iptables และ nft userspace และสามารถกำหนดค่าการจับคู่ xtables ทั้งสอง (รวมถึง xt_bpf) และการจับคู่ nftables ปกติ

ซึ่งหมายความว่าเมื่อมีการเรียก API ที่ถูกต้อง (ข้อความ netlink/netfilter) เราสามารถฝังการจับคู่ xt_bpf ภายในกฎ nftables หากจะดำเนินการนี้ เราต้องเข้าใจว่าข้อความ netfilter ใดที่เราต้องส่ง ซึ่งเมื่อใช้เครื่องมือต่าง ๆ เช่น strace, Wireshark และโดยเฉพาะอย่างยิ่งการใช้ source เราจะสามารถสร้างข้อความที่สามารถผนวกกฎ eBPF ให้กับตารางและเชนได้

NFTA_RULE_TABLE table
NFTA_RULE_CHAIN chain
NFTA_RULE_EXPRESSIONS | NFTA_MATCH_NAME
	NFTA_LIST_ELEM | NLA_F_NESTED
	NFTA_EXPR_NAME "match"
		NLA_F_NESTED | NFTA_EXPR_DATA
		NFTA_MATCH_NAME "bpf"
		NFTA_MATCH_REV 1
		NFTA_MATCH_INFO ebpf_bytes	

โครงสร้างของข้อความ netlink/netfilter เพื่อเพิ่มการจับคู่ eBPF ควรมีลักษณะเหมือนตัวอย่างด้านบน ซึ่งแน่นอนว่าข้อความนี้จำเป็นต้องฝังอย่างถูกต้องและรวมขั้นตอนที่มีเงื่อนไข เช่น verdict เมื่อมีคำที่ตรงกัน ขั้นตอนถัดไปคือการถอดรหัสรูปแบบของ "ebpf_bytes" ตามที่แสดงในตัวอย่างด้านล่าง

 struct xt_bpf_info_v1 {
	__u16 mode;
	__u16 bpf_program_num_elem;
	__s32 fd;
	union {
		struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR];
		char path[XT_BPF_PATH_MAX];
	};
};

ดูรูปแบบไบต์ได้จากคำจำกัดความของส่วนหัวเคอร์เนลของ struct xt_bpf_info_v1 ตัวอย่างโค้ดด้านบนแสดงส่วนที่เกี่ยวข้องของโครงสร้าง

โมดูล xt_bpf รองรับทั้ง bytecodes ดิบและเส้นทางไปยังโปรแกรม ebpf ที่ปักหมุดไว้ โหมดต่อมาคือเทคนิคที่เราใช้ในการรวมโปรแกรม ebpf กับ nftables

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

แค่เพิ่ม eBPF

ตอนนี้ เราต้องสร้างโปรแกรม eBPF และโหลดลงในตาราง nftables และเชนที่มีอยู่ การเริ่มใช้ eBPF อาจสร้างความกังวลเล็กน้อย เราต้องการใช้โปรแกรมประเภทใด เราจะคอมไพล์และโหลดโปรแกรม eBPF ได้อย่างไร เราเริ่มกระบวนการนี้โดยทำการสำรวจและวิจัย

ขั้นแรก เราสร้างโปรแกรมตัวอย่างเพื่อทดลองใช้เองก่อน

SEC("socket")
int filter(struct __sk_buff *skb) {
  /* get header */
  struct iphdr iph;
  if (bpf_skb_load_bytes(skb, 0, &iph, sizeof(iph))) {
    return BPF_DROP;
  }

  /* read last 5 bytes in payload of udp */
  __u16 pkt_len = bswap_16(iph.tot_len);
  char data[5];
  if (bpf_skb_load_bytes(skb, pkt_len - sizeof(data), &data, sizeof(data))) {
    return BPF_DROP;
  }

  /* only packets with the magic word at the end of the payload are allowed */
  const char SECRET_TOKEN[5] = "xyzzy";
  for (int i = 0; i < sizeof(SECRET_TOKEN); i++) {
    if (SECRET_TOKEN[i] != data[i]) {
      return BPF_DROP;
    }
  }

  return BPF_OK;
}

ข้อความที่ตัดตอนมาเป็นตัวอย่างของโปรแกรม eBPF ที่ยอมรับเฉพาะแพ็กเก็ตที่มีแมจิคสตริงต่อท้ายเพย์โหลด ซึ่งต้องตรวจสอบความยาวรวมของแพ็กเก็ตเพื่อค้นหาตำแหน่งที่จะเริ่มต้นการค้นหา กล่าวให้ชัดคือ ตัวอย่างนี้ละเว้นการตรวจสอบข้อผิดพลาดและส่วนหัว

เมื่อเรามีโปรแกรมแล้ว ขั้นตอนต่อไปคือการผสานโปรแกรมเข้ากับเครื่องมือของเรา เราลองใช้เทคโนโลยีสองสามอย่างเพื่อโหลดโปรแกรม เช่น BCC, libbpf และเรายังสร้างตัวโหลดแบบกำหนดเองอีกด้วย ท้ายที่สุด เราจะได้ใช้ไลบรารี ebpf ของ cilium เนื่องจากเราใช้ Golang สำหรับโปรแกรมควบคุมระนาบของเรา และไลบรารีทำให้ง่ายต่อการสร้าง ฝัง และโหลดโปรแกรม eBPF

# nft list ruleset
table ip mfw {
	chain input {
		#match bpf pinned /sys/fs/bpf/mfw/match drop
	}
}

เมื่อคอมไพล์และปักหมุดโปรแกรมแล้ว เราก็ใช้คำสั่ง netlink เพื่อเพิ่มรายการที่ตรงกันลงใน nftables การแสดงรายการชุดกฎแสดงว่ามีรายการที่ตรงกัน ซึ่งเหลือเชื่อมาก! ขณะนี้ เราสามารถปรับใช้โปรแกรม C แบบกำหนดเองเพื่อให้การจับคู่ขั้นสูงภายในชุดกฎของ Magic Firewall!

Magic เพิ่มเติม

เมื่อเพิ่ม eBPF ในชุดเครื่องมือของเรา ทำให้ Magic Firewall เป็นวิธีที่ยืดหยุ่นและมีประสิทธิภาพยิ่งขึ้นไปอีก ในการปกป้องเครือข่ายของคุณจากผู้ไม่หวังดี ตอนนี้เราสามารถพิจารณารายละเอียดของแพ็กเก็ตและใช้ตรรกะการจับคู่ที่ซับซ้อนกว่าที่ nftables เท่านั้นที่ทำได้ และเนื่องจากไฟร์วอลล์ของเราทำงานเป็นซอฟต์แวร์บนเซิร์ฟเวอร์ Cloudflare ทั้งหมด เราจึงสามารถทำซ้ำและอัปเดตคุณสมบัติต่าง ๆ ได้อย่างรวดเร็ว

ผลลัพธ์หนึ่งของโครงการนี้คือการป้องกัน SIP ซึ่งขณะนี้อยู่ในรุ่นเบต้า นั่นเป็นเพียงจุดเริ่มต้นเท่านั้น เรากำลังสำรวจการใช้ eBPF เพื่อตรวจสอบความถูกต้องของโปรโตคอล การจับคู่ช่องข้อมูลขั้นสูง การดูเพย์โหลด และการสนับสนุนแม้แต่ชุดของรายการ IP ที่ใหญ่ขึ้น

เรายินดีรับความช่วยเหลือของคุณที่นี่เช่นกัน! หากคุณมีกรณีการใช้งานและแนวคิดอื่น ๆ โปรดพูดคุยกับทีมดูแลลูกค้าของเรา หากคุณพบว่าเทคโนโลยีนี้น่าสนใจ มาร่วมทีมกับเรา!

หารือกันบน Twitter หารือกันบน Hacker News หารือกันบน Reddit

CIO Week Magic Firewall Magic Transit Security VoIP

ติดตามบน Twitter

Chris J Arges |@ChrisArges

Cloudflare |Cloudflare