Docker UFW फायरवॉल का बायपास करतो व उपाय काय
Docker कंटेनर पोर्ट iptables नियमांनी प्रकाशित करतो जे UFW च्या नियमांना वगळतात, म्हणून डिनाय केलेला पोर्टही इंटरनेटला प्रतिसाद देतो. यंत्रणा आणि काम करणारे उपाय येथे पाहा.
Docker UFW चा बायपास का करतो
Docker UFW चा बायपास करतो कारण प्रकाशित केलेले कंटेनर पोर्ट UFW ज्या फायरवॉल नियमांवर नियंत्रण ठेवतो, त्यातून कधीच जात नाहीत. तुम्ही docker run -p 8080:80 चालवल्यावर, Docker कर्नेलच्या nat टेबलमधील PREROUTING चेनमध्ये एक DNAT (destination network address translation) नियम लिहितो. कर्नेलने ठरवण्यापूर्वी तो नियम प्रत्येक पॅकेटचे गंतव्य कंटेनरच्या खाजगी पत्त्यात बदलतो. बदललेला पॅकेट नंतर FORWARD चेनद्वारे कंटेनरमध्ये पाठवला जातो, ज्यावर Docker चे नियंत्रण असते. UFW चे नियम INPUT चेनमध्ये असतात, आणि पॅकेट कधीच त्यात प्रवेश करत नाही. त्यामुळे ufw status डिफॉल्ट डिनाय दर्शवतो, sudo ufw deny 8080 यशस्वी असल्याचे कळवतो, आणि पोर्ट 8080 अजूनही संपूर्ण इंटरनेटला प्रतिसाद देत राहतो.
हे Docker चा दोष नाही, आणि UFW खराब झालेले नाही. दोन्ही साधने समान कर्नेल फायरवॉल प्रोग्राम करतात. Docker चे नियम फक्त पॅकेटच्या मार्गावरील एका आधीच्या टप्प्यावर कार्य करतात, त्यामुळे UFW ला कधीच विचारले जात नाही. हे मार्गदर्शक बायपास प्रदर्शित करते, यंत्रणा स्पष्ट करते, आणि नंतर काम करणाऱ्या दोन उपायांवर चर्चा करते: 127.0.0.1 वर पोर्ट प्रकाशित करणे, आणि DOCKER-USER चेनमध्ये फिल्टर करणे. जर UFW तुमच्यासाठी नवीन असेल, तर ते आधी UFW फायरवॉल मूलभूत मार्गदर्शक सह सेट करा, कारण डिफॉल्ट-डिनाय फायरवॉल सर्व्हरवरील इतर सर्व गोष्टींसाठी अजूनही योग्य पाया आहे.
आपल्या सर्व्हरवर बायपास पहा
UFW सक्रिय असलेल्या आणि येणाऱ्या ट्रॅफिकसाठी डिफॉल्ट डिनाय धोरण लागू असलेल्या VPS वरून सुरुवात करा. प्रकाशित पोर्टसह एक वेब कंटेनर चालवा:
sudo ufw status verbose
docker run -d --name web -p 8080:80 nginx:1.29-alpineufw status verbose हे Default: deny (incoming), allow (outgoing) दर्शवते आणि पोर्ट 8080 साठी कोणताही नियम नाही. फायरवॉलच्या अहवालानुसार, हा पोर्ट बंद आहे. आता दुसऱ्या मशीनवरून तपासणी करा, सर्व्हरवरून नाही:
curl -I http://your-vps-ip:8080/HTTP/1.1 200 OKकंटेनर प्रतिसाद देते. एक स्पष्ट डिनाय नियम जोडा आणि पुन्हा तपासणी करा:
sudo ufw deny 8080/tcpपोर्ट अजूनही प्रतिसाद देतो, कारण डिनाय नियम अशा चेनमध्ये आहे जेथे पॅकेट कधीच जात नाही. UFW अपयशी ठरले नाही. त्याचा सल्लाही घेतला गेला नाही. समस्या इतकी चांगली लपवली जाते कारण याचेच कारण आहे: कोठेही कोणतीही त्रुटी छापली जात नाही, डिप्लॉय यशस्वी होते, आणि फायरवॉल स्टेटस आउटपुट नेमका एका निरोगी, लॉकडाउन सर्व्हरसारखा दिसतो.
यंत्रणा: PREROUTING हे INPUT आधी चालते
कर्नल येणाऱ्या पॅकेटची प्रक्रिया एका निश्चित क्रमाने करते, आणि हा प्रश्न त्याच क्रमात दडला आहे.
PREROUTINGप्रथम चालते. येथील नियम पॅकेटचे गंतव्य बदलू शकतात, आणि प्रकाशित पोर्टसाठी Docker चा नियम तेच करतो.- त्यानंतर राउटिंग निर्णय येतो. होस्टला स्वतःला पाठवलेले पॅकेट
INPUTचेनवर जाते. इतर कोणत्याही मशीनला पाठवलेले पॅकेटFORWARDचेनवर जाते. - UFW चे नियम
INPUTमध्ये आहेत. Docker चे नियमFORWARDमध्ये आहेत.
तुम्ही नुकताच सुरू केलेल्या कंटेनरसाठी Docker चा नियम पाहा:
sudo iptables -t nat -L DOCKER -nChain DOCKER (2 references)
target prot opt source destination
RETURN 0 -- 0.0.0.0/0 0.0.0.0/0
DNAT 6 -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80DNAT ही ओळ संपूर्ण कथा आहे. पोर्ट 8080 साठी येणाऱ्या कोणत्याही पॅकेटचे गंतव्य बदलून 172.17.0.2:80 केले जाते, जे Docker च्या खाजगी ब्रिज नेटवर्कवरील कंटेनरचा पत्ता आहे. गंतव्य बदलल्यानंतर पॅकेट होस्टला पाठवलेले राहत नाही, म्हणून राउटिंग निर्णय त्याला FORWARD मार्गावर पाठवतो, जिथे Docker ने आपल्या स्वतःच्या नेटवर्कमधील ट्रॅफिक स्वीकारणारे नियम आधीच जोडले आहेत. तुमचा deny 8080/tcp नियम INPUT मध्ये अशा पॅकेटसाठी थांबून असतो जे कधीच येत नाही.
Ubuntu 24.04 वर iptables हा आदेश nftables वरील एक फ्रंट एंड आहे, परंतु चेनचा क्रम आणि परिणाम तुल्यकारी आहेत. UFW आणि Docker दोन्ही त्याच कर्नल पॅकेट पाइपलाईनमध्ये लिहितात, आणि Docker चे प्रवेश बिंदू आधीचा आहे.
दैनंदिन उपाय: 127.0.0.1 वर पोर्ट प्रकाशित करा
बहुतांश कंटेनर मूळतःच सार्वजनिक करण्याची गरज नसते. डेटाबेस, रिव्हर्स प्रॉक्सीमागील ॲप सर्व्हर, ॲडमिन पॅनेल, मेट्रिक्स एंडपॉईंट: यापैकी कोणतेही थेट इंटरनेटवर प्रतिसाद देऊ नये. त्यांना लूपबॅक ॲड्रेसवर प्रकाशित करा:
docker run -d --name web -p 127.0.0.1:8080:80 nginx:1.29-alpineकिंवा Compose फाईलमध्ये:
services:
web:
image: nginx:1.29-alpine
ports:
- "127.0.0.1:8080:80"हे कार्य करते कारण Docker चे DNAT नियम आता फक्त 127.0.0.1 ला निर्देश केलेले पॅकेट्सशी जुळतात. इंटरनेटवरून येणारे पॅकेट कधीच योग्यरित्या हे गंतव्य धारण करू शकत नाही, म्हणून कर्नल कोणताही फायरवॉल नियम चालू होण्यापूर्वीच ते पॅकेट टाकून देते. पोर्ट होस्टवरून पोहोचण्यायोग्य आहे, आणि दुसऱ्या कोणत्याही मार्गातून नाही. बाइंडिंग तपासा:
sudo ss -tlnp | grep 8080आउटपुटमध्ये तुम्हाला 127.0.0.1:8080 हवे आहे, 0.0.0.0:8080 किंवा [::]:8080 नाही. त्यानंतर दुसऱ्या मशीनवरून curl http://your-vps-ip:8080/ नकारले गेले आहे याची खात्री करा.
इंटरनेटसमोर यायचे असलेल्या सेवांसाठी, एक रिव्हर्स प्रॉक्सी चालवा जो पोर्ट 80 आणि 443 वर नियंत्रण ठेवतो आणि होस्टनेमनुसार मार्ग दर्शवतो, आणि दुसरे काहीही प्रकाशित करू नका. Traefik रिव्हर्स प्रॉक्सी मार्गदर्शक हीच रचना तयार करते, आणि VPS वर Nextcloud सारखा स्वतःच्या होस्टवर ठेवलेला ॲप त्या प्रॉक्सीव्यतिरिक्त अन्य कोणत्याही मार्गातून पोहोचण्यायोग्य राहत नाही. ports: नोंदी कशा घोषित केल्या जातात आणि Compose वर्कफ्लोचा बाकीचा भाग, याबद्दलचे स्पष्टीकरण Docker Compose मूलभूत मार्गदर्शक मध्ये दिले आहे.
प्रत्येक आंतरिक कंटेनर लूपबॅकवर असल्यामुळे, UFW पुन्हा त्याचे नियमित काम करू लागते: होस्ट स्वतः ज्या पोर्ट्सवर सेवा देतो त्यांचे रक्षण करणे. तो नियम संच येथे तयार करा, त्यानंतर कमांड्स क्रमानुसार चालवा:
वास्तविक फिल्टरिंग: DOCKER-USER चेन
कधीकधी कंटेनर पोर्ट नेटवर्कवर प्रकाशित ठेऊन त्यावर निर्बंध घालावे लागतात. उदाहरणार्थ, डेटाबेस रेप्लिका पोर्ट ज्याला फक्त एका कार्यालयाचा पत्ता गाठू शकतो. ह्यासाठी Docker मध्ये DOCKER-USER चेन उपलब्ध आहे. कोणत्याही कंटेनरकडे जाणारा प्रत्येक पॅकेट Docker च्या स्वतःच्या स्वीकृती नियमांपूर्वी DOCKER-USER मधून जातो. Docker त्यात कधीच नियम लिहित नाही. ही चेन तुमच्यासाठी आहे. डिमन रीस्टार्ट झाल्यावरही Docker तिच्या सामग्रीस हात लावत नाही.
कमांडपूर्वी एक सूचना: पॅकेट DOCKER-USER पर्यंत पोहोचेपर्यंत DNAT रीराईट आधीच पूर्ण झालेला असतो. पॅकेटचा गंतव्य पोर्ट कंटेनर पोर्ट (आमच्या उदाहरणात 80) असतो, प्रकाशित पोर्ट (8080) नाही. म्हणून --dport 8080 जुळणारा नियम कशाशीही जुळत नाही. विश्वसनीय मार्ग म्हणजे क्लायंटने सुरुवातीला ज्या पोर्टवर संपर्क शोधला त्याची जुळवारी करणे. हा पोर्ट कर्नलचा कनेक्शन ट्रॅकर लक्षात ठेवतो:
sudo iptables -I DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 8080 --ctdir ORIGINAL ! -s 10.0.0.10 -j DROPहे असे वाचा: eth0 वर आलेले आणि ज्या कनेक्शनचा मूळ गंतव्य पोर्ट 8080 होता असे पॅकेट्ससाठी, 10.0.0.10 वरून न आलेले सर्व पॅकेट टाकून द्या. --ctdir ORIGINAL जुळवारी नियमाला क्लायंट-ते-कंटेनर दिशेपुरता मर्यादित करते. त्यामुळे प्रत्युत्तर पॅकेट्स चुकून सापडत नाहीत. eth0 याऐवजी तुमचा सार्वजनिक इंटरफेस वापरा. ip route | grep default हे त्याचे नाव दर्शवते. हे आधीच्याप्रमाणेच तपासा: परवानगी असलेल्या पत्त्यावरून curl यशस्वी होते. अन्य कोणत्याही ठिकाणाहून कनेक्शन टाइमआउट होते.
iptables कमांडने जोडलेले नियम रीबूट झाल्यावर गायब होतात. UFW आधीच हा फायरवॉल व्यवस्थापित करत असल्याने, ते टिकवून ठेवण्यासाठी योग्य ठिकाण /etc/ufw/after.rules आहे. फाईलच्या शेवटी एक ब्लॉक जोडा:
*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 8080 --ctdir ORIGINAL ! -s 10.0.0.10 -j DROP
COMMITनंतर sudo ufw reload चालवा. UFW प्रत्येक रीलोड आणि प्रत्येक बूटवर ती फाईल पुन्हा लागू करते. त्यामुळे तुमचे कंटेनर फिल्टरिंग आता तुमच्या इतर फायरवॉलसोबतच एकाच ठिकाणी आहे. ते रीबूट आणि Docker अपग्रेड दोन्ही टिकवून ठेवते.
Docker चे iptables इंटिग्रेशन बंद करू नये असे का
या समस्येची जुनी उत्तरे /etc/docker/daemon.json मध्ये { "iptables": false } सेट करण्याचा सल्ला देतात. तसे करू नका. Docker चे फायरवॉल नियम पोर्ट प्रकाशित करण्यापेक्षा खूप जास्त काम करतात. मास्करेड नियमामुळे कंटेनरला होस्टच्या पत्त्याद्वारे बाह्य इंटरनेट वापरण्याची परवानगी मिळते. त्यामुळे इंटिग्रेशन बंद असल्यास, कंटेनर इमेज डाउनलोड करू शकत नाहीत, पॅकेज मिररपर्यंत पोहोचू शकत नाहीत किंवा कोणताही बाह्य API (application programming interface) कॉल करू शकत नाहीत. DNAT नियमांमुळेच -p काम करते, त्यामुळे प्रकाशित पोर्ट पूर्णपणे काम करणे बंद होतात. वेगळे Compose नेटवर्क वेगळे ठेवणारे आयसोलेशन नियमही गायब होतात. तुम्ही कंटेनर नेटवर्किंग तोडून बायपास फिक्स कराल आणि ते सर्व नियम तुम्हाला स्वतः लिहावे आणि जोपासावे लागतील. Docker चे स्वतःचे दस्तऐवज ही सेटिंग अशा व्यक्तींसाठी आहे असे सांगते ज्यांना हेच करायचे आहे. DOCKER-USER चेन अगदी यासाठीच अस्तित्वात आहे की कुणालाही हा स्विच वापरायची गरज नाही.
त्याच समस्येचा IPv6 बाजू
प्रथम तपासा की प्रकाशित पोर्ट IPv6 वर कसा दिसते:
sudo ss -tlnp | grep 8080Docker Engine 27 पासून, Docker डीफॉल्टरित्या ip6tables व्यवस्थापित करते. IPv6 सक्षम असलेल्या Docker नेटवर्कवर, प्रकाशित पोर्टला IPv6 टेबलमध्ये समान DNAT वागणूक मिळते. त्यामुळे तेथेही तीच बायपास अस्तित्वात आहे आणि तीच उपाय लागू होतो: ip6tables मध्ये DOCKER-USER चेन देखील अस्तित्वात आहे, त्यामुळे तुमच्या नियमाचे रूप sudo ip6tables -I DOCKER-USER ... सह दुसऱ्या बाजूस लावा आणि बाहेरून तुमच्या सर्व्हरच्या सार्वजनिक IPv6 पत्त्यावर curl सह चाचणी करा, उदाहरणार्थ curl -6 http://[2001:db8:2a::1]:8080/.
IPv6 नसलेल्या नेटवर्कवर, IPv6 क्लायंटची हाताळणी त्याऐवजी docker-proxy करते, जो एक सामान्य युझर-स्पेस प्रक्रिया आहे जी [::]:8080 वर ऐकते आणि ट्रॅफिकला IPv4 द्वारे कंटेनरमध्ये पाठवते. होस्ट प्रक्रियेकडील ट्रॅफिक INPUT मधून जातो, त्यामुळे UFW त्या मार्गावर फिल्टर लावू शकते, परंतु फक्त तेव्हाच जेव्हा UFW एकूणच IPv6 व्यवस्थापित करत असेल. ते करत आहे की नाही, आणि VPS वर IPv6 अंतर कसे निर्माण होते, हा UFW आणि IPv6 मार्गदर्शक याचा विषय आहे.
लूपबॅकवर प्रकाशित केल्याने संपूर्ण प्रश्न टळतो: -p 127.0.0.1:8080:80 फक्त IPv4 लूपबॅकशी बांधते, त्यामुळे कोणताही IPv6 लिसनर नसतो आणि बाहेरून कोणत्याही स्टॅकवर पोहोचण्यासाठी काहीही नसते.
काम करणारी रचना
- प्रत्येक आंतरिक पोर्ट
127.0.0.1वर प्रकाशित करा, जेणेकरून ती सुरुवातीपासूनच कधीच उघडी पडणार नाहीत. - सार्वजनिक बाजू 80 आणि 443 पोर्ट वापरणाऱ्या एका रिव्हर्स प्रॉक्सीला द्या.
- होस्टसाठी UFW डिफॉल्ट डिनाय ठेवा, फक्त SSH आणि प्रॉक्सी पोर्टना परवानगी द्या.
- खरोखर सार्वजनिक असलेले कंटेनर पोर्ट
DOCKER-USERमध्ये फिल्टर करा, मूळ गंतव्य पोर्टवर जुळवून घ्या, आणि/etc/ufw/after.rulesमध्ये जतन करा. - Docker चे iptables इंटिग्रेशन चालू ठेवा.
एकदा सेटअप केल्यावर, हे आश्चर्य टळते: ufw status होस्टचे वर्णन करते, आणि DOCKER-USER कंटेनरचे वर्णन करते. काहीही नकळत प्रकाशित होत नाही, आणि तुम्ही टाईप करणारा पुढचा docker run -p तुम्हाला नेमके तेच उघडे करतो जे तुम्हाला हवे आहे.
FAQ
UFW पोर्ट ब्लॉक करत असताना मी माझ्या Docker कंटेनरपर्यंत पोहोचू शकतो कसा?
कारण Docker हा पोर्ट PREROUTING चेनमध्ये एक DNAT नियमासह प्रकाशित करतो. हा नियम कोणताही फिल्टरिंग होण्यापूर्वीच पॅकेटचे गंतव्य कंटेनरच्या पत्त्यात बदलतो. त्यानंतर पॅकेट FORWARD मार्गावरून जातो. UFW चे नियम INPUT मध्ये असतात, जी अशी चेन आहे ज्यामध्ये हा पॅकेट कधीच प्रवेश करत नाही. फायरवॉलला कधीच संपर्क केला जात नाही, म्हणून प्रकाशित कंटेनर पोर्टवर त्याच्या नकारात्मक नियमांचा कोणताही परिणाम होत नाही.
मी UFW ला Docker चे प्रकाशित पोर्ट ब्लॉक करण्यासाठी कसे सांगू?
UFW त्या करू शकत नाही, कारण त्याचे नियम चुकीच्या चेनमध्ये आहेत. एकतर पोर्ट उघडे करणे थांबवा, त्यास 127.0.0.1:8080:80 म्हणून प्रकाशित करून जेणेकरून फक्त होस्ट त्यापर्यंत पोहोचू शकेल, किंवा conntrack मार्फत मूळ गंतव्य पोर्टशी जुळणाऱ्या iptables नियमासह DOCKER-USER चेनमध्ये फिल्टर करा. तो नियम /etc/ufw/after.rules मध्ये टिकवून ठेवा जेणेकरून तो रीबूट आणि ufw reload नंतरही टिकून राहील.
मी Docker च्या daemon.json मध्ये "iptables": false सेट केले पाहिजे का?
नाही. हे सेटिंग Docker चे सर्व फायरवॉल आणि NAT नियम काढून टाकते, ज्यामुळे बायपासपेक्षा खूपच जास्त गोष्टी खराब होतात. masquerade नियम गेल्यामुळे कंटेनरना आउटबाउंड इंटरनेट ऍक्सेस मिळत नाही, आणि DNAT नियम गेल्यामुळे प्रकाशित पोर्ट काम करणे थांबतात. त्याऐवजी लूपबॅक प्रकाशन आणि DOCKER-USER चेन वापरा; हे कंटेनर नेटवर्किंग खराब न करता दिसण्याची समस्या ठीक करतात.
Docker IPv6 वरही UFW ला बायपास करते का?
Docker Engine 27 आणि नंतरच्या आवृत्त्यांमध्ये, ip6tables व्यवस्थापन डिफॉल्टनुसार चालू असते. त्यामुळे IPv6-सक्षम Docker नेटवर्कवर प्रकाशित केलेला पोर्ट IPv4 प्रमाणेच UFW भोवती बदलला जातो, आणि त्याला ip6tables सह प्रतिबिंबित केलेल्या समान DOCKER-USER नियमाची आवश्यकता असते. IPv6 नसलेल्या नेटवर्कवर, docker-proxy प्रक्रिया [::] वर ऐकते आणि ती ट्रॅफिक खरंच INPUT मधून जाते, जिथे UFW ते फिल्टर करू शकते जर UFW IPv6 व्यवस्थापित करत असेल. 127.0.0.1 वर प्रकाशित केल्याने दोन्ही प्रकरणे टळतात, कारण IPv6 वर काहीच ऐकत नाही.