לקוח מחייג לשרת OpenVPN על VM של Compute Engine, חלון המצב אומר מחובר, ופינג למארח בתוך ה-VPC עדיין לא מגיע לשום מקום. האינסטינקט הוא להוסיף עוד שורת push, וזה אף פעם לא מתקן. Compute Engine מחליט לאן הולכים הפקטים לפי טבלת ה-routes שלו ולפי הכתובות שממשק ה-VM באמת מחזיק, ולכן pool של מנהרה שה-VM לא מחזיק בו הוא pool שאליו אף אחד לא מספק.

עקבו אחרי הפקט שנכשל ולא אחרי קובץ התצורה, והחלקים החסרים יופיעו לפי הסדר.

התחילו מהפקט שמת

ה-SYN עוזב את הלקוח, נכנס למנהרה ומגיע ל-VM כפקט עטוף ליעד בתוך ה-VPC. OpenVPN מפרק את העטיפה ומנסה להעביר אותו דרך eth0, ושם ה-fabric שואל שאלה אחת לפני כל דבר אחר: האם ה-instance הזה מחזיק בכתובת היעד. pool של מנהרה שנגזר מה-subnet של מישהו אחר נכשל בשאלה הזו, והפקט נזרק לפני שנבדק route כלשהו או כלל firewall.

כך שלכיוון מהלקוח אל ה-VPC יש שתי דרישות נפרדות, ואף אחת מהן אינה הוראת push. ה-VM זקוק לטווח alias שמכסה את pool המנהרה, וזה מה שהופך אותו לבעלים החוקי של הכתובות האלה. ה-VPC זקוק ל-route שממנה את ה-VM כ-next hop לכל prefix מוגן. אם אחד מהם חסר הפקט מת במקום אחר, בעוד הלקוח רואה את אותה שתיקה.

קראו את התקלה בסדר הזה, כי מצד הלקוח שתי התנאים נראים זהים. מנהרה שמדווחת מחובר כששום דבר לא עונה היא סימן לבעיית טופולוגיה, לא לצופן גרוע.

האם ה-instance מחזיק ב-pool המנהרה

תנו ל-VM טווח משני בתוך ה-subnet שלו עצמו, ואז תנו ל-OpenVPN לחלק כתובות בדיוק מהטווח הזה. ב-instance שכתובתו הראשית היא 10.156.0.10/20, alias מסוג /28 שומר על ה-pool נפרד מהכתובות שכבר מוחזקות בידי instance-ים אחרים:

gcloud compute instances network-interfaces update openvpn-vm \
  --zone=europe-west1-b \
  --aliases=eth0:10.156.1.0/28

הוראת server חייבת אז לתאר את אותו בלוק. הכתובת הראשונה שלו הופכת ל-gateway של המנהרה, והכתובות הנותרות מחולקות ללקוחות. כאן שני מספרים מתארים בלוק אחד, רשת ומסכה, וזו התחביר של pool ש-OpenVPN עדיין מצפה לו.

server 10.156.1.0 255.255.255.240

ודאו שהכתובת באמת הגיעה לממשק ולא רק לתצורת OpenVPN. ה-fabric מעביר את מה שה-NIC מדווח, לא את מה שה-daemon מאמין. פקודה אחת מכריעה את זה:

ip -4 addr show dev eth0

כתובת משנית שלעולם לא מגיעה ל-eth0, או pool שחופף ל-subnet אחר, מופיעה מאוחר יותר כאובדן מנות לסירוגין ולא כשגיאת אתחול. ה-daemon עולה, לקוחות מתחברים, ורק חלק מהיעדים מתנהגים לא נכון. שמרו על טווח alias קטן כדי שה-pool יהיה קל לזיהוי בטבלת routes. לעולם אל תגזרו אותו מ-subnet ש-instance אחר כבר משתמש בו.

תנו ל-traffic החוזר next hop

תשובה ממארח ב-VPC ממוענת לכתובת לקוח ב-pool המנהרה, שאינה שייכת לשום subnet שה-VPC מכיר. בלי route ל-pool הזה, התשובה נעצרת ב-hop הראשון שאין לו התאמה, והבקשה עשויה בהחלט להצליח בקצה השני.

gcloud compute routes create openvpn-return \
  --network=prod-vpc \
  --destination-range=192.168.127.0/24 \
  --next-hop-instance=openvpn-vm \
  --next-hop-instance-zone=europe-west1-b \
  --priority=800

אותו route נדרש לכל prefix שנמצא מאחורי לקוח ולא בתוך ה-VPC. לאותם prefix-ים נדרש גם רשומת iroute בקובץ ה-ccd של אותו לקוח. הרשומה הזו היא הנהלת חשבונות בצד השרת: היא אומרת לשרת איזה לקוח מחזיק ב-prefix, והיא לא מתקינה דבר על הלקוח עצמו.

שמרו את רשימת ה-push לצד הלקוח של השיחה, כי היא רק מוסיפה routes למכונה המתחברת. שורת push ל-subnet ב-VPC ו-route של VPC חזרה ל-pool הם שני חצאים של אותו נתיב, וכל חצי לבדו מייצר מנהרה שנושאת בקשות אבל לא תשובות.

חומות אש, העברה וה-hops שביניהם

ה-firewall של ה-VPC מעריך את הפקט המפורק, ולכן כלל ingress חייב לאפשר את pool המנהרה ואת כל prefix אתר שמגיע ל-VM בדרך הזו. עמדת default-deny נכשלת כאן בשקט: הפקט נזרק אחרי הפירוק, וה-log של OpenVPN מראה הפעלה בריאה.

בכל מארח Linux שמעביר ולא מסיים, בדקו ש-net.ipv4.ip_forward מופעל. כלל הבעלות חל גם שם: מכונה שמעבירה עבור subnet שאינו שלה זורקת את הפקט בדיוק כפי שה-VM היה עושה. קראו את הערך לפני שאתם מאשימים את המנהרה.

כשנכשל בדיוק prefix אחד

כשל חלקי הוא המקרה הקל ביותר לקריאה, כי כל השאר בנתיב כבר הוכח. התחילו מרשימת ה-routes וקראו את טווח היעד וה-next hop של הרשומה שאמורה לכסות את ה-prefix, ואז קראו את תיאור ה-instance והשוו את טווח ה-alias שלו ל-pool שהשרת מחלק.

gcloud compute routes list --filter=destination-range~10.164.0.0
 gcloud compute instances describe openvpn-vm --format=get(networkInterfaces[0].aliasIpRanges)

route חסר מתגלה כהיעדר next hop ל-prefix, בעוד alias חסר מתגלה כפקט שנזרק בממשק; מצד הלקוח השניים נראים דומים ובשני הפלטים האלה הם שונים לחלוטין. אם שניהם קיימים, החשוד שנותר הוא ה-ccd iroute של הלקוח שתובע את ה-prefix.

רשמו את ארבעת הערכים ליד המנהרה: טווח alias, ה-pool של השרת, ה-prefix-ים שנדחפו, ה-routes של VPC. alias מיושן שובר כל כתובת ב-pool, route מיושן שובר כיוון אחד, push חסר מסתיר את ה-prefix מהלקוח, ו-iroute שגוי שולח את ה-prefix ל-peer הלא נכון. האדם הבא שיוסיף subnet צריך את כל הארבעה במקום אחד, והפתק זול יותר מהערב.

מאמרים קשורים