ห้าม Compare Struct ใน Go

หลายเดือนก่อนทีมทำเรื่อง data encryption ใน Go ซึ่งเราจะมี struct EncryptedString ซึ่งเก็บ string แบบเข้ารหัสไว้แล้ว

ปัญหาก็คือเรากังวลว่า developer อาจจะคิดว่ามันใช้งานเหมือน string ปกติแล้วไป compare (encryptedA == encryptedB) ซึ่งมันอาจจะเท่าหรือไม่เท่ากันก็ได้ขึ้นอยู่กับ internal state ของ string ก็ต้องแจ้ง developer ไปว่าให้ใช้ Equal() เสมอ อย่าใช้ ==

บังเอิญช่วงนั้นผมเขียน Protobuf อยู่พอดีเลยไปเห็น google.golang.org/protobuf/internal/pragma ซึ่งผมว่ามันมีแต่ hack เทพๆ ที่อ่านแล้วฉลาดขึ้นเลย

DoNotCompare

Hyrum’s Law บอกว่าถ้ามีคนใช้ API มากพอ ต่อให้ไม่ได้บอกว่าใช้แบบนี้ได้ มันจะมีคนไปใช้ตามพฤติกรรมที่สังเกตได้เสมอ ซึ่งเราอาจจะเคยได้ยินว่าบางระบบอาจจะถึงกับต้อง emulate bug เพื่อให้มันใช้งานได้ เช่นใน StarCraft Remastered นั้น Blizzard ถึงกับต้องจำลอง buffer overflow เพราะ map เก่าๆ บางอันใช้

ในเคสของ Protobuf แปลว่าถ้าใช้ == กับ Protobuf message ได้แถม return ค่าถูกต้อง ก็คงจะมีคนใช้ == แน่นอน พอออก version ใหม่ที่เปลี่ยนโครงสร้างของ struct ก็พัง ทั้งๆ ที่ไม่เคยบอกว่าใช้ == ได้ ดังนั้น Go Protobuf เลยมี “pragma” หรือสูตรสำเร็จที่ฝังเข้าไปใน struct เพื่อทำให้พฤติกรรมต้องห้ามนั้นมี error หรือ warning เกิดขึ้นได้

ในบล็อคนี้ผมจะพาไล่ทั้ง 4 pragma ในแพคเกจขณะที่เขียนนี้ พร้อมทั้งเฉลยว่ามันทำได้อย่างไร อ่านแล้วผมแนะนำให้ลองคิดตามก่อนที่จะอ่านเฉลยครับ

โค้ด DoNotCompare มีอยู่ว่า

type DoNotCompare [0]func()

โดยเวลาใช้งานให้ฝังเข้าไปใน struct เช่น

type X struct {
    Value int

    DoNotCompare
}

เมื่อเรา compile จะได้ข้อความว่า

./prog.go:17:20: invalid operation: a == b (struct containing DoNotCompare cannot be compared)

เหตุผลที่เป็นอย่างนี้เพราะใน Go เราไม่สามารถเปรียบเทียบ function ได้

./prog.go:17:31: invalid operation: fmt.Println == fmt.Println (func can only be compared to nil)

การ compare struct นั้นมันจะ compare ทุก field ภายใน struct เมื่อเจอ field นี้ที่ type เป็น function ซึ่ง compare ไม่ได้แล้ว compiler จึงจะไม่ยอมให้ compile

ส่วน [0] ด้านหน้า ไว้เดี๋ยวจะเฉลยครับ…

DoNotCopy

ใน Go เราอาจจะมีการ pass by value ในบางครั้งซึ่งมันจะ copy object เข้าไปใน function เช่น

type X struct {
    Value string
}

func RecvX(v X) {
    v.Value = "changed"
}

func main() {
    x := X{value: "init"}
    RecvX(x)
    fmt.Println(x.Value)
}

ในกรณีนี้ เนื่องจาก RecvX ได้รับ X แบบ pass by value ทำให้ v เป็น copy ของ x ใน main เมื่อ print ออกมาจะได้ผลลัพท์ว่า “init” ไม่ใช่ “changed”

เพื่อป้องกันการใช้งานแบบ pass by value โค้ด DoNotCopy จึงมีดังนี้

type DoNotCopy [0]sync.Mutex

โค้ดนี้จะต่างกับ DoNotCompare คือสามารถ compile ผ่านได้ตามปกติ แต่ถ้ารัน go vet แล้วจะมี error ดังนี้

./prog.go:16:14: RecvX passes lock by value: play.X contains sync.Mutex

สำหรับคนที่เคยใช้งาน sync.Mutex แล้วน่าจะทราบดีว่าห้าม copy sync.Mutex เด็ดขาดเนื่องจากจะทำให้มี lock 2 ชุดแทนที่จะมีชุดเดียว ซึ่ง go vet จับให้อยู่แล้ว ดังนั้นการฝัง sync.Mutex เข้าไปใน struct ถึงแม้ไม่ได้ใช้ก็ทำให้ go vet ทำงาน

คำถามจากหัวเรื่องที่แล้วคือ แล้ว [0] คืออะไร? syntax นี้ผู้เริ่มต้น Go บางคนอาจจะเรียน บางคนอาจจะข้ามไปเลยเพราะไม่ค่อยได้ใช้ syntax นี้คือ fixed size array ใน Go เช่น [10]int คือ slice ที่มีสมาชิกเป็น int 10 ตัวไม่สามารถเพิ่มลดได้ (และมันเป็นคนละ type ไม่ใช่ slice ใช้แทนที่ slice ปกติไม่ได้)

เนื่องจากจำนวนสมาชิกเป็นค่าที่ทราบตั้งแต่ compile ทำให้ compiler สามารถจอง memory ให้สมาชิกทั้ง 10 ตัวได้ล่วงหน้า ในกรณีของ pragma 2 ตัวก่อนหน้านี้เราระบุเป็น [0] ก็คือไม่มีสมาชิก ทำให้ compiler ไม่จองพื้นที่สำหรับเก็บข้อมูลไว้เลย ทำให้ไม่มี overhead จากการใช้งาน

NoUnkeyedLiterals

ปัญหาถัดมาที่เจอคือมันจะมีคนมักง่าย แบบนี้…

type X struct {
    Value1 string
    Value2 int
}

func main() {
    X{"v", 1}
}

พอสร้าง struct โดยไม่ระบุชื่อ field ปัญหาที่ตามมาคือถ้าจะเพิ่ม field คนที่เพิ่มจะกรีดร้องเพราะต้องไล่ตามแก้ของเก่าให้หมด

โค้ด NoUnkeyedLiteral ง่ายๆ แค่

type NoUnkeyedLiterals struct{}

ใช่แล้ว มันคือ struct ง่ายๆ ไม่มีอะไรเลย เนื่องจากมันจะทำให้ struct มี 3 field (ไม่ใช้ 3 field) โค้ดด้านบนจึงจะเจอ

./prog.go:14:27: too few values in X{...}

ทำให้ไม่สามารถระบุแค่ 2 field ที่ใช้งานได้ ต้องระบุค่าของ NoUnkeyedLiteral ด้วย ก็คือต้องพิมพ์

X{"v", 1, NoUnkeyedLiteral{}}

ซึ่งก็ควรจะเอะใจได้แล้วนะว่าเค้าไม่ให้ทำแบบนี้ !!

DoNotImplement

Pragma ตัวสุดท้ายคือ DoNotImplement ซึ่งไม่อนุญาตให้แพคเกจอื่น implement interface นี้ เนื่องจากใน Go นั้น interface ไม่จำเป็นต้องประกาศ implement ขอแค่มี method ตรงกันเป็นอันใช้ได้ จึงไม่สามารถประกาศ interface เป็น private ได้

โค้ดของ DoNotImplement หน้าตาแบบนี้

type DoNotImplement interface{ ProtoInternal(DoNotImplement) }

โดยการใช้งานก็ให้ฝังเข้าไปใน Interface อื่น

type Printable interface {
    Print()

    DoNotImplement
}

ผมใช้เวลาหลายชั่วโมงพยายามทำความเข้าใจโค้ดนี้ ใคร declare ProtoInternal? แล้วมัน recursive มันช่วยยังไง?

ถ้าจัดรูปใหม่แล้ว มันจะเป็น

type DoNotImplement interface {
    ProtoInternal(value DoNotImplement)
}

ก็คือเป็น interface ที่มี 1 method ชื่อ ProtoInternal รับ argument 1 อย่างเป็น type ตัวเอง

แต่ เอ มันก็แก้ด้วยการเขียน implementation ง่ายๆ แบบนี้

func (x *X) ProtoInternal(value DoNotImplement) {}

หรือเปล่า….

ผมอ่าน docs อยู่ 2 ชั่วโมงก่อนจะไปสังเกตชื่อแพคเกจ google.golang.org/protobuf/internal/pragma

ใน Go แพคเกจจะไม่อนุญาตให้ import package ที่มี path internal มาจากแพคเกจอื่นๆ ดังนั้นถ้าจะ implement interface นี้ได้จริง ก็ต้อง import DoNotImplement มาใส่ใน argument ให้ได้ด้วย และเนื่องจากว่ามันเป็น internal จึงมีเฉพาะ package ที่ได้รับอนุญาตเท่านั้นจึงจะ import ได้

ทริคนี้ยังใช้ใน NoUnkeyedLiteral ในหัวข้อก่อนหน้าด้วย โดยถ้าจะดันทุรังใช้ X{"v", 1, NoUnkeyedLiteral{}} ก็จะเจอปัญหาเหมือนกันว่า import NoUnkeyedLiteral ไม่ได้

Genius

ทั้ง 4 ทริคนี้ผมว่าเป็นโค้ดที่เขียนได้ฉลาดมากๆ เหมือนเป็น puzzle และตอนอ่านผมก็คิดว่ามันลับสมองมากๆ ที่จะไล่ดูกลวิธีของผู้สร้างว่าเค้าวางกับดักโดยใช้แค่ Go standard tools ได้อย่างไร

ในทีมผมก็คุยกันแล้วว่าทริคลักษณะนี้อาจจะยังไม่อยากใช้เท่าไรนักเพราะภายในบริษัทอาจจะยังพอตกลงกันหรือตรวจกันใน code review ได้โดยไม่ต้องพึ่ง hack แต่ในระดับ protobuf ที่เป็น library ใช้กันแพร่หลายแล้วการบังคับทางเทคนิคนี้ก็เป็นเรื่องจำเป็นที่จะไม่ให้คนเขียนโค้ดแบบ genius เล่นท่าพิสดารที่อัพเกรดไม่ได้

On Firewall & VPN

ช่วงปีที่ผ่านมา evaluate firewall อยู่ หลักๆ ที่สนใจจะเป็นฟีเจอร์พวก VPN มากกว่าเพราะ AWS มันก็มี firewall อยู่แล้ว และพวก L7 firewall มันคือ security as a product ซึ่งไม่ได้ทำให้เกิด security (มันมีประโยชน์ถ้า security debt เยอะจนไม่ไหวแล้วและคุณอยากจะจ่ายดอกกู้นอกระบบ)

BeyondCorp

ที่ต้องใช้ VPN คือถึงโลกมันจะไป BeyondCorp กันแล้ว แต่เอาจริงๆ ecosystem ของ BeyondCorp มันห่วยมาก คือถ้าจะหวัง open source คิดว่ารอไปอีกนาน อาจจะต้องรอดู HashiCorp Boundary
แล้วพวก product พวกนี้เอามาลงเสร็จไม่ใช่จะเป็น BeyondCorp เลย เพราะ key สำคัญของ BeyondCorp คือ zero trust เอา auth มาปิดหน้าแต่ service ด้านหลังไม่ได้ auth ใคร port forward มาก็ปลอมเป็นใครก็ได้ แบบนี้ไม่ใช่ zero trust แต่คนน่าจะเข้าใจกันผิดเยอะว่าซื้อ product มา มี auth เรียบร้อยคือปลอดภัยตามแบบใหม่

ที่มันเป็นอย่างนี้เพราะไม่มี validator ที่ดีพอว่าคุณเป็น zero trust แล้วหรือยัง ไปซื้อ product มาตัว product เองมันก็ไม่ได้ require หรือ warn ว่าข้างหลังคุณต้องทำ mTLS นะ หรือ auth ท่าอื่นก็ว่ากันไป พวกนี้ดันไปอยู่ใน service mesh ซึ่งก็ยังไม่พร้อมใช้สักที แถมเรื่อง identity กับ service mesh ยังคิดว่าเป็นเรื่องอีกยาวไกลเพราะมันยังไม่ถึง MVP เลย

แต่จุดตายจริงๆ ของพวก Authenticating HTTPS proxy as a service ผมว่าคือพวก application ที่ไม่ใช่ HTTP ซึ่งไม่มีใครมีคำตอบดีๆ (ผมว่า LD_PRELOAD คือคำตอบ แต่ไม่มีใครทำ) ผมถาม Google กับ Cloudflare ไปว่า git push ssh ผ่าน solution ที่เค้าขายทำยังไง คำตอบก็คือต้องไปแก้ config บนเครื่องของ Git ให้มันเรียกผ่าน proxy เค้าซึ่งมันก็คือ VPN ดีๆ นี่แหละ แถมเอาออกมาได้ทีละ port

มันก็กลายเป็นปัญหาว่าโปรแกรมทุกตัวที่ไม่ใช่ HTTP เราก็ต้องไปหาวิธีก่อนถึงจะ deploy ได้ แล้วถ้าโปรแกรมมันไม่รองรับ proxy command เลยเช่น npm หรือ pypi จะทำยังไง ทาง vendor เองก็ไม่มี document เก็บไว้ว่าแอพแต่ละตัวใช้ยังไงบ้าง ถึงแม้จะบอกว่าภายในบริษัทของ vendor เองก็ใช้ product ตัวเองในการ develop อยู่แต่ก็ไม่ได้แชร์วิธีมาให้ลูกค้าด้วย

ทั้งหมดทั้งปวงเลยคิดว่าสำหรับ development team แล้ว BeyondCorp ยังไม่ใช่ solution ที่จะเวิร์คไปอีกสักพัก และถึงมันจะ work มันก็มีโอกาส footgun สูงมากๆ

พอเป็นแบบนี้แล้วผมก็เลยไม่มีทางเลือกนอกจากถอยกลับไป VPN ซึ่งพอไปค้นดูจริงๆ ก็พบว่าส่วนมากมันจะมาพ่วงกับ firewall แพงๆ

Next Gen Firewall

Keyword ของ firewall แพงๆ ตอนนี้คือ Next Gen Firewall ตอนแรกที่ผมเลือกทีมก็ยังลังเลอยู่ว่าทำไมผมต้องอยากซื้อ firewall แพงๆ ทั้งๆ ที่ใช้ OpenVPN ก็ได้ ไม่ว่าตัวฟรีหรือตัวเสียเงิน ผมก็อยากรู้เหมือนกันว่าทำไมคนยอมซื้อ firewall เป็นล้าน

ประเด็นสำคัญของ OpenVPN คือมันไม่ได้มากับ firewall แล้วผมก็ต้องไปนั่งเซต iptables อีกต่อหนึ่ง ซึ่งในเลเวลผมแล้วผมยัง prefer firewall gui มากกว่า config as code หรือ command line นะ

ทีนี้ก็ลองไปเลือกมาดูว่าเราจะใช้ใครดี

เจ้าแรกที่คิดถึงเลยคือ Pulse Secure เพราะที่บริษัทใช้อยู่แล้ว แต่พบว่ามันรัน 2 tunnel พร้อมกันไม่ได้ ก็เลยต้องแบน

ถัดมาก็ลองไปค้นดูว่าใครมี Linux client บ้าง ก็ได้ short list มาประมาณหนึ่งว่า

  • Citrix
  • Sophos
  • Barracuda
  • Fortigate
  • Palo Alto Networks

ซึ่งมันตัดตัวใหญ่ๆ ในตลาดไปเยอะเลย ทั้ง Checkpoint, Zscaler ต่างๆ

Citrix

ผมไม่ถนัดซื้อของประเภท contact us มากๆ คือ dev product ที่ขาย dev ตรงๆ มักจะมีราคาแล้ว tier แพงสุดถึงเป็น contact us แต่ product พวกนี้คือจะไม่มีราคาในหน้าเว็บเลย ซึ่งปกติผมจะตัดหมดไปดูเฉพาะเจ้าที่มีราคา แต่พอทุกเจ้าไม่มีราคาหมดก็เลยต้องยอมส่ง lead ไป

การส่ง lead ก็เป็นอีกอันนึงที่น่ารำคาญ คือมันแปลว่าช่วยติดต่อมาหน่อยจะซื้อของ แต่เอาเข้าจริงคิดว่าบริษัทหลายที่มักจะเก็บไปทำ remarketing หรือไม่ก็เก็บไว้ใน sales database แล้วมาขายเรื่อยๆ ซึ่งไม่ได้ consent ขนาดนั้น

Citrix เล่นตัวไม่คุยกับผมอยู่เดือนหนึ่งแล้วถึงส่งเซลมาคุย ก็เลยตัดจบ บาย

Sophos

ผมถือ vendor นึงอยู่ที่ผมจะดู ก็เลยลองคุยกับเซลดูว่าสนใจ bid project นี้มั้ย เค้าก็แนะนำ Sophos มาให้คุยดู

ปรากฏว่าจาก requirement ต่างๆ Sophos ยังไม่ตอบโจทย์ คือผมฟังแล้วรู้สึกว่าในมุม firewall ผมใช้ Mikrotik ที่บ้านยังดีกว่า แต่ Sophos จะไปเน้นเรื่อง internet security (เช่น antivirus) มากกว่าซึ่งก็ไม่ใช่แบรนด์ที่คนคิดถึงอยู่ดีถ้าจะซื้อของพวกนั้น

Barracuda

ผมส่ง lead ให้ Barracuda ก็สักพักติดต่อเข้ามาจากฮ่องกง แต่ผมถามก็บอกว่ามีตัวแทน local นะ

Barracuda เพิ่ง acquire Fyde เข้ามากลายเป็น Barracuda CloudGen Access ซึ่งผมว่าไอเดียมันโคตรดีเลยนะ แต่มันไม่ work

ไอเดียของ CGA คือมันไม่ใช่ VPN แต่มันคือ glorified SOCKS proxy โดยที่จะมี cloud ของ CGA เองเป็น directory service + authentication service

บน network ของเราเองเราจะต้องลง Envoy ที่เค้า customize มาแล้วและเปิด port ซึ่งมัน lightweight มากเพราะมาเป็น container ไม่ใช่ VM เหมือนกับ tranditional VPN

Magic ของ CGA อยู่ที่ client ซึ่งเท่าที่เห็นคือ UI มันเป็น webview ด้วยซ้ำ (ตามสไตล์ app สมัยใหม่) ด้านหลังมันจะ override DNS server บนเครื่องเรา พอมี DNS resolve บน CGA server จะ check ว่าเว็บนี้ IT admin allow หรือเปล่า และถ้ามันเป็น domain ที่ config ไว้ว่าต้องเข้าผ่าน VPN ตัว CGA client จะออก IP ใหม่ในวง 224.0.0.0/16 คืนให้

บน Application พอ connect ไปที่ 224.0.0.0/16 ที่ให้มาแล้ว CGA client ที่ listen อยู่บน IP นั้นจะ proxy กลับไปหา Envoy ตัวที่ directory บอก และเนื่องจาก Envoy มันเป็น L4 proxy มันเลยใช้กับ protocol ได้ทุกประเภท (ผมสงสัยมากว่าบน client ก็รัน Envoy หรือเปล่านะ มันอาจจะเป็น Envoy on client ตัวแรกที่ผมเห็นเลย)

ข้อดีของวิธีนี้คือมัน route by DNS ไม่ได้ route by subnet ทำให้ flexible กว่ามาก และถ้ามีหลาย site ที่ต้อง VPN ไปก็ไม่ต้องสลับไปสลับมา

ข้อเสียของวิธีนี้คือเนื่องจากมันเป็น proxy ทำให้ server ปลายทางไม่รู้ว่าใครเป็นคน connect เข้ามา เวลามีปัญหาดู access log ที่ service จะเห็นแต่ IP proxy ไม่รู้ว่าใคร (ต้องไปทำ audit log ให้หมด) และบน CGA server เองเนื่องจาก operate บน L4 ก็จะ log ให้แต่ว่าคนนี้เข้า service นี้แต่ถ้าเข้าพร้อมกันแล้วเอา log มาเทียบก็ยังไม่รู้ว่าใคร

ผมขอ Barracuda ลอง Firewall ธรรมดาๆ ต่อ แต่ดูท่าเซลจะพยายามดันตัวนี้ก็เลยตัดสินใจว่าไม่คุยต่อ

Fortigate

หลังจากเซลเค้าขาย Sophos ให้ไม่ได้ ก็เลยเลือก Fortigate เข้ามาคุย

ผมใช้ Fortigate แล้วก็ค่อนข้างประทับใจดี คือ UI มันลื่นไหล ใช้งานง่าย และดู modern ดี

แต่ในทางกลับกันฝั่ง VPN client (FortiClient) UI กลับดูโบราณเหมือนออกมาจากยุค 2010 ปลายๆ Windows XP อะไรแบบนั้น

ที่ไม่ชอบ Fortigate คือ product เค้าเยอะมีหลายตัว (FortiGate, FortiEMS, FortiClient, FortiAuthenticator) จนมันงงว่าต้องซื้ออะไรบ้าง และมันรู้สึกเหมือนซื้อเกมที่มันตัด content ไปทำ DLC เสียมากกว่า

สองคือ requirement ผมจะมีเรื่อง device check ต่างๆ ซึ่งมันไปอยู่ใน FortiEMS และ FortiEMS รันได้เฉพาะบน Windows Server เท่านั้น ซึ่งทีมไม่มีใครดู และเนื่องจาก FortiEMS มันวางตัวเป็น internet security ด้วยเลยขายแบบนับหัวซึ่งแพงมาก และถ้าไม่ซื้อ EMS แล้ว FortiClient ตัวที่ใช้จะโดนตัดฟีเจอร์ไปเยอะแถมมี nag ด้วยว่าต้องซื้อตัวแพง

คือขายของ enterprise แบบ EA ขายเกมนี่ไม่เอาอ่ะ

ในฝั่งของ product เองก็เจอบั๊กน่ารำคาญกับ SAML กับ LDAP คือ SAML มันบังคับเปิดใน embedded browser ซึ่ง Google เค้าจะแบนอยู่แล้ว และ login Google ค่อนข้างน่ารำคาญก็เลยไม่เอา

ส่วน LDAP ก็มีปัญหาว่ามัน fetch group แบบ lazy มากๆ คือ fetch เฉพาะ group ที่มีการใช้ใน firewall rule และ VPN access control มันเลยกลายเป็นว่าใช้ group ที่ไม่ได้ control สิทธิ์เข้าถึง VPN ใน firewall rule ไม่ได้

Palo Alto Network

สุดท้ายก็เลยเหลือแต่ Palo Alto…

ผมเกริ่นไว้นานมากว่าแล้ว firewall พวกนี้มันต่างกับ iptables ยังไง ประเด็นสำคัญของ NGFW คือวิธี match rule มันจะต่างกับ iptables ไปเลย (แต่ถ้าอยากเขียนแบบ iptables ก็ยังทำได้นะ) คือมันสามารถ match

  • Incoming/Outgoing zone (คือ group of interface)
  • Source/Destination IP address
  • Source user/group
  • Source computer settings
  • Application type
  • DNS name

ซึ่งมันทำให้เราทำ firewall rule ได้ล้ำมากๆ เพราะถ้าอยากจะแบ่งตาม user group โดยใช้ subnet เราอาจจะต้องแบ่งเช่น 10.1.0.0/16 = Dev, 10.2.0.0/16 = บัญชี, 10.3.0.0/16 = HR เป็นต้น แต่มันอาจจะมีกรณีที่ user หนึ่งอยู่หลาย group เช่น dev ที่เขียน ERP ต้องใช้งานระบบบัญชีด้วย มันก็จะทำให้ combination มันโตออกไปมากขึ้นเรื่อยๆ

แต่พอมัน match rule ตาม group ได้แล้วเราแจก 10.0.0.0/8 ได้เลยโดยไม่ต้องแบ่งแยกแผนก แต่ได้ access control ที่ละเอียดกว่าแบบแบ่ง subnet ซะอีก และมันเลยเป็นเหตุผลว่า firewall เลยเป็น VPN software ที่ดีด้วยเพราะข้อมูลการ login มันจะผูกกลับไปที่ firewall เอง (นอกจาก VPN client แล้ว Palo Alto ยังมีท่าที่ยิง log/API ให้มัน match แล้วรับรู้ว่า IP นี้ user อะไรอีกด้วย แต่เคสที่เห็นโหดๆ คือ clientless VPN ซึ่ง 1 source IP มีหลาย user มันก็ยังแยกได้ด้วย)

ในส่วนของ Match by computer settings ผมว่าเป็นข้อได้เปรียบของ closed source software หน่อยที่มันมีฟีเจอร์แบบ security by obscurity ได้ประมาณหนึ่ง โดยที่ตัว client มันจะเป็น spyware ให้เราดูดข้อมูล settings ของเครื่องส่งไปที่ firewall แล้วบน firewall match กับ rule บางอย่าง (ซึ่งแน่นอนในความเป็นจริง client fake report ได้ แต่ต้อง bypass client หรือไปแก้ source ที่มันอ่าน) ตัวอย่างเช่นถ้าเครื่องไม่ได้ลง Baidu Antivirus ไม่อนุญาตให้ใช้ VPN หรือไม่ให้ใช้บาง service เป็นต้น รวมถึง match serial number ของเครื่องเข้ากับ device inventory เพื่อเช็คว่าเป็นเครื่องบริษัทจริง

พวกนี้ถ้าเป็น open source ก็แก้ client แล้ว recompile ใหม่ ง่ายมาก แต่พอเป็น proprietary แล้วต้องทำ reverse engineering

ส่วนสุดท้ายคือ Application type และ URL คือการ match บน layer 7 โดย firewall จะเข้าใจ protocol บางตัวเช่น SSL SNI เพื่อ match กับ DNS name ที่กำหนด (โดยไม่ต้องทำ SSL interception) หรือเข้าใจ pattern ของ application โดยตรงถึงขนาดที่ว่าถ้ายอมทำ SSL interception แล้วสามารถเขียน rule แยกได้เลยว่าใช้ Slack คุยได้แต่ห้ามอัพไฟล์หรือ call

สำหรับ Palo Alto เอง client ทำออกมาได้ค่อนข้างดี อาจจะยกเว้น Linux ไว้หน่อยหนึ่งซึ่งถ้าเป็น distro ที่ support ก็รันได้ดีแต่เป็น distro ที่เก่าหน่อยคนอาจจะไม่ได้เอามาใช้เป็น desktop แล้ว ถ้าใ้ช distro ใหม่ๆ อาจจะต้องเล่นท่ายากพอสมควร

บนตัว Firewall เองผมยังไม่เจออะไรกวนใจนอกจาก UI ที่ค่อนข้างช้ามาก ก็ไม่แน่ใจว่ามันติดอะไรเหมือนกัน

เขียนมายาวแล้วเดี๋ยวจะไม่ได้ publish เอาเป็นว่าไว้ค่อยเล่าเรื่อง config