第一次在 FreeBSD 監獄中將 TinyDNS 作為服務安裝 - 怎麼做?
我目前正在使用 FreeBSD 11.2(可能會在一段時間內遷移到 12)。我需要一個小型的僅權威 DNS 伺服器(無需查找或記憶體,在 10 個域和 10 個查詢/小時以下,幾乎沒有記錄更改)。
我可能會選擇, 其中的
TinyDNS
一部分djbdns
,它以安全著稱,而且看起來很小,可以滿足我的需要。安全的部分原因是它會暴露在網際網路上,儘管在 IP/埠過濾器和非常低的速率、速率限制器(
pf
用於此)之後。但出於這個原因,我確實想特別注意守護程序的設置方式,以避免明顯的漏洞。我的意思是諸如所需的使用者和組、啟動/停止腳本、jail/chrooting 以及最小化/禁用/拒絕攻擊者可能轉向的主要非必要訪問/功能等方面。(我應該提一下,我可以在測試系統上“通常”安裝 tinydns,並創建所需的
.conf
文件,因此純粹是如何以安全的方式執行它,這是缺失的)我在設置軟體以執行 chrooted/jailed 或查看 chrooted/jailed 包以獲取適當的安全實踐方面沒有經驗,這也是我第一次嘗試做這樣的事情,儘管我選擇了特定的DNS 伺服器包專門為其明顯的設置簡單性。
忽略該
.conf
文件,“配方”會是什麼樣子,將 TinyDNS 設置為作為服務正確執行,並在理想情況下最小化對“其他對守護程序不是必需但對攻擊者有幫助的東西”的訪問?
這是相當長的,所以對於那些懶得讀完的人來說,這是一個非常簡短的版本:
echo "testjail { }" >> /etc/jail.conf mkdir -p /usr/local/jails/testjail bsdinstall jail /usr/local/jails/testjail service jail start testjail pkg -j testjail install -y nginx sysrc -j testjail "nginx_enable"=YES service -j testjail nginx start
我通常會將這個問題評為“過於寬泛”,並直接將人們推薦給FreeBSD 手冊。但我自己發現那部分寫得相當糟糕而且令人困惑。一切都在那裡——但事情比看起來要容易得多!我只是希望他們更多地關注概念而不是列出命令。你可能會喜歡閱讀監獄——高價值但糟糕的虛擬化
相反,我要做的是謙虛地概述我個人所做的事情以及我遇到的絆腳石。我的失敗可能不是你的,但因為我曾經和你處於同樣的境地,我希望我的旅程能有所幫助。你對 FreeBSD 的整體理解越好,越容易越獄。
什麼是監獄?
許多描述掩蓋了監獄的重要部分。它極大地有助於理解核心的作用。它“執行”程式碼並跟踪 PID(程序 ID)和 UID(使用者 ID)。這是許多 Unix 使用者的常識。FreeBSD 核心隨後添加了 JID(監獄 ID)的概念。然後核心能夠將程序劃分為監獄。這實際上意味著 FreeBSD 核心能夠“虛擬化”系統而無需任何成本。您仍然只有一個核心,但可以擁有多個系統。這是我理解這個概念的關鍵。
如果您執行“沒有”監獄的香草盒。那麼所有程序都屬於 JID 0。當您開始使用監獄時,我們將其稱為“監獄主機”。
考慮到這一點,我下一步是了解與 FreeBSD 實際工作方式的聯繫。如果您來自 Linux 背景,您可能知道 Linux “只是”核心。構成系統的原因是隨發行版提供的使用者空間(Ubuntu、Debian、Slackware 等)。FreeBSD 是核心和使用者空間的組合。它是完整的作業系統(作業系統)。
所以第 12 章的一個非常粗略的總結。FreeBSD 引導過程是:
您可能知道 FreeBSD 是多麼模組化,並且您可以用OpenRC之類的東西替換 rc 系統,但我們暫時忽略它以保持簡單。
然後,當您啟動(引導)一個 jail 時,核心會使用一個新的 JID(即 1)進行初始化。然後這裡的所有東西都被限制在監獄 1 中。init 需要接觸的東西必須在 chroot 文件系統中。如果你想讓事情變得簡單,那就是完整的使用者空間。但是我們希望將監獄與主機系統分開,所以這是使用者空間的完整副本!
這些事物如何相互關聯的重要性不可低估。當您完全了解它時,您會注意到許多 FreeBSD 工具直接支持監獄。不僅僅是簡單的事情,
ps -J
但是bsdinstall
,freebsd-update
和pkg
!如果維護 FreeBSD 系統是您的第二天性,那麼監獄將是您的樂園!但對於我們大多數人來說,我們在通往涅槃的道路上處於中間位置,可能不得不與一些概念作鬥爭才能“正確”地完成它。
這裡
我是他的超級粉絲。它提供了一個清晰一致的觀點,即應該放置物品的位置。不幸的是,權力永遠不會決定監獄的預設位置是什麼。當您將它與許多使用不同位置的不同教程結合起來並混合使用各種術語作為“基本安裝”和“模板”時,事情會很快變得混亂!
手冊沒有討論這個,只是參考
/here/is/the/jail
。在最後一個範例中,他們使用/home/j
and/home/j/mroot
。我更喜歡將使用者目錄和僅使用者目錄保留在/home
.j
在我的書中,簡單地使用速記符號就像是一個很大的禁忌。我想說最常見和“正確”的位置是
/usr/local/jails
. 對於使用 ZFS 的人來說,一個強有力的競爭者是/jails
在這個位置,我會為我的監獄放置 chroot。我是這樣講的。從此以後的監獄將在這裡找到。
當我開始時,我發現這非常令人困惑。給我自由將它放在任何地方讓我更加不安全,因為我不明白後果。
為了增加這種混亂,許多教程使用“basejail”、“skeleton directory”、“templates”。這增加了監獄的真正含義,並將其與許多管理混為一談。
文件系統
我們並不真正關心我們使用的是什麼文件系統。它可以是 UFS 或 ZFS。為了監獄,我們只需要一個目錄來存放我們的 chroot。
使用 UFS 時要注意的重要一點是如何排列切片。初學者往往沒有考慮這麼多。哪個切片有足夠的空間來容納 chroot。這就是為什麼我特別不喜歡
/home
為此目的使用。也許您為此目的創建了一個切片,或者您只是在某個地方創建了一個目錄,然後再確定您是否有足夠的空間。如果您使用的是 ZFS,問題實際上是相同的。由於 ZFS 的結構方式,您可能會爭辯說創建一個新數據集比僅僅做
mkdir
. 但對於初學者來說,你不應該擔心。使用 ZFS 執行“mkdir”對您來說更好。這使事情變得更簡單,您可以在沒有 ZFS 的情況下繼續前進。下一個問題是許多教程也使用“basejail”,這是一個完整的香草系統,可以複製以創建新的監獄。然後,一些教程會告訴您進行 ZFS 複製而不是複制。很長一段時間,您將更新 basejail 並自然地對其進行快照。但是隨後您注意到您無法刪除任何具有它們複製的快照。所以在實際使用中我更喜歡使用zfs send/receive。
在我看來,教程應該只將 ZFS 作為附錄。ZFS 本身就是一個巨大的話題,應該這樣對待。當您對 jails 和 ZFS 都感到滿意時,您就可以心滿意足地結合起來並從中獲益。如果不是這樣,您最終會建造一座非常脆弱的塔,而在它們破裂時沒有任何修復能力。
胖/厚vs瘦
FreeBSD 手冊談到了“完整的”監獄和“服務”的監獄。大多數其他地方使用術語厚(胖/滿)和薄監獄。厚監獄和瘦監獄都是“完整的”虛擬化 FreeBSD 系統,FreeBSD 手冊將其稱為“完整的”監獄。然而,“服務”監獄更加難以捉摸
厚監獄是完整作業系統的副本。但那是多少脂肪?帶有 base/lib32/ports 的 FreeBSD 11.2 的重量為 1.4G,但對於監獄,“base”本身可能會使您保持在相對苗條的 512M(與 Windows 10 的 C:\Windows 的 20G 相比)。
一個瘦監獄是一個技巧,可以最大限度地減少“完整”監獄的磁碟使用。通過使用nullfs(回送文件系統子樹)來掛載只讀文件系統和幾個放置良好的符號連結來啟用讀/寫部分,您可以減少磁碟使用量。不幸的是,我手頭沒有任何數字。當您擁有磁碟結構後,您只需在啟動 jail 時添加
mount.fstab
到您的文件系統以掛載文件系統。jail.conf
我從FreeBSD Jails得到瞭如何做到這一點的想法。這教會了我如何在沒有任何 3rd 方實用程序的情況下處理監獄,並最終讓這些作品適合我。儘管有標題 - 這實際上是簡單的方法。然而,他們確實弄錯了一件事。您不應該執行 zfs 複製,而應該按照Unadulterated Jails, the Simple Way中的描述執行 zfs 發送/接收。兩者都可能從略過時的帶有 nullfs 的 Multiple FreeBSD Jails中找到了靈感。另一個有價值的來源是FreeBSD Thin Jails。最後一個更新的資源也涵蓋了 VNET(我們將回到那個!)是 How to configure a FreeBSD Jail with vnet and ZFS
以上通常被稱為瘦監獄,但可以通過其他方式完成。條條大路通羅馬,您自己決定如何在當地實施。
所有這些都將我們引向難以捉摸的“服務”監獄。在最鎖定的場景中只執行一項特定服務的監獄。只是實際的應用程序,只有一個薄層來支持它。它可以完成,但我還沒有看到很多工作。
典型的
jail.conf
將包含:exec.start = "/bin/sh /etc/rc"; # Start command exec.stop = "/bin/sh /etc/rc.shutdown"; # Stop command
這是確保 rc 系統在啟動/停止時執行監獄的原因。如果你有一個非常簡單的執行檔,你可以簡單地指向它。所以問題是:我的服務需要訪問多少作業系統?需要哪些共享庫,您是否執行腳本?
我知道沒有任何工作為您完成了這項工作。所以你從一個完整的監獄開始,然後刪除你的特定服務不需要的東西。許多命令行實用程序(例如
top
和 )可以安全刪除ps
,tail
因為它們通常不被守護程序使用。但是,如果您自己在監獄中進行調試,您可能會錯過它們。如果你直接啟動一個守護程序,exec.start
你不需要rc.subr
和朋友。如果你走這條路並開始瘋狂殺戮以確定在服務保持功能的同時可以從作業系統中刪除多少(以減少攻擊面),那麼你應該知道nanobsd。這可以幫助您根據需要定制安裝。
所以 - 絕對可行。但我知道沒有公共工作。大多數人都會選擇厚監獄或薄監獄,然後在那裡執行他們指定的服務。
依賴地獄
在做瘦監獄時,你需要非常小心地做所有正確的事情,否則事情會破裂。當您更新系統時,您需要記住更新所有不同的部分。您開始的基地監獄或來源。模板和實際的監獄。這是很多移動的輪子,使管理更加困難。可以做到,但您應該權衡努力與獎勵。磁碟空間非常便宜——因此您需要相當多的服務才能使其值得付出努力。
然後,我會建議使用帶有完整作業系統的簡單胖監獄。
如果您對 ZFS 非常滿意,那麼一定要瘋狂。但如果不是,那麼我強烈建議將 chroot 放在一個簡單的目錄中。當你覺得在監獄里工作很舒服時,你就可以開始添加奶油了。
關鍵是將監獄視為一個獨立的系統。如果您今天正確維護您的系統,您應該已經有使用的習慣,
freebsd-update fetch install
並且您會知道它會更新核心和使用者空間。在將監獄添加到混合中時,您只需要記住也更新它們:
freebsd-update -b /usr/local/jails/testjail install
如果您正在進行升級 - 還要記住監獄:
freebsd-update -b /usr/local/jails/testjail --currently-running 10.3-RELEASE -r 11.0-RELEASE upgrade
就像您保持包裹新鮮一樣
pkg upgrade pkg -j testjail upgrade
嗨,老兄!我只是想監禁一項服務!
好的!有了所有的警告購買者,讓我們在一個完全普通的系統上以簡單的方式完成這項工作。TinyDNS 是一個不好的例子,所以讓我們安裝nginx
- 在中創建一個贊恩監獄配置
/etc/jail.conf
- 允許監獄在啟動時啟動
- 添加監獄名稱“testjail”
- 為“testjail”chroot 添加目錄
- 將作業系統安裝到 chroot 中(僅選擇基礎。取消選擇
lib32
/ports
)- 啟動監獄
- 將
nginx
包添加到監獄。- 告訴監獄在啟動時啟動 nginx
- 立即啟動 nginx!
完畢!
1 和 2 僅用於為監獄做準備。每個新監獄 3 - 6 個。每項服務 7 - 9 個。
cat <<'EOF'>/etc/jail.conf # Global settings applied to all jails. host.hostname = "${name}.jail"; ip4 = inherit; ip6 = inherit; path = "/usr/local/jails/${name}"; exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.clean; mount.devfs; # Specific seetings can be applied for each jail: 'EOF' sysrc "jail_enable"=YES echo "testjail { }" >> /etc/jail.conf mkdir -p /usr/local/jails/testjail bsdinstall jail /usr/local/jails/testjail service jail start testjail pkg -j testjail install -y nginx sysrc -j testjail "nginx_enable"=YES service -j testjail nginx start
這就是我聲稱的做監獄和簡單管理的“正確”方式。有很多變化 - 最後一行可以替換為
service jail restart testjail
. 此時,我可以在我的入獄 nginx 實例上瀏覽網頁。一些 FreeBSD 的預設設置不適合監獄。所以也考慮設置這些:
sysrc -j testjail sendmail_enable="NONE" sysrc -j testjail sendmail_submit_enable="NO" sysrc -j testjail sendmail_outbound_enable="NO" sysrc -j testjail sendmail_msp_queue_enable="NO"
刪除監獄
要刪除監獄:
- 停止監獄
- 從“/etc/jail.conf”中刪除監獄名稱
- 重置標誌,以便您可以刪除文件
- 刪除文件
service jail stop testjail sed -i '' '/^testjail {/ d' /etc/jail.conf chflags -R noschg /usr/local/jails/testjail rm -rf /usr/local/jails/testjail
以上是為了表明使用手頭的工具管理監獄並不難,而第三部分不需要監獄管理工具。
嗨,老兄!我只是想監禁 TinyDNS!
您寫道您可以“通常”安裝 tinydns - 因此我將把它留給您。對於可能正在關注的其他人,他們可能會猜測它應該很簡單:
pkg -j testjail install djbdns
但是,無論是誰創建了這個包,都不足以為 tinydns 中的
/usr/local/etc/rc.d
. 然後,您需要弄清楚如何將其作為守護程序執行。您可以選擇使用替代服務管理,例如主管或簡單的 hack,將其添加到/etc/rc.local。或者為布朗尼點創建一個 rc 腳本並將其回饋給我們所有人享受!這將我們引向您真正需要知道的僅有的兩個特定的監獄命令:列出正在執行的監獄的jls和允許您在監獄內執行內容的jexec 。
root@test:~ # jls JID IP Address Hostname Path 3 testjail.jail /usr/local/jails/testjail
要以 root 身份獲取命令行,我們只需執行 root shell(記住那是 tcsh!)
root@test:~ # jexec testjail /bin/tcsh root@testjail:/ # tinydns tinydns: fatal: $IP not set root@testjail:/ # exit exit root@test:~ #
在那個 shell 中工作時,一切都在你的 jail/chroot 中。
他們不告訴你什麼!
到目前為止,我還沒有偏離大多數教程會告訴你的內容。在文件系統上浪費了大量時間之後,他們跳過了令人興奮的部分。今天,沒有網路訪問的電腦沒有太多樂趣。在上面的範例中,我們與主機共享網路堆棧。這意味著您不能在使用與監獄相同的埠的監獄主機上執行任何東西。在我的範例中,這是網路伺服器的埠 80。
另一方面,現在很容易設置防火牆。您只需將所有埠視為本地埠。如果您使用的是 IPv6,事情就輕而易舉了。但是我們中的大多數(全部?)仍然需要與 IPv4 鬥爭。IPv4 很簡單,但您可能沒有所需的地址,然後我們需要求助於某種 NAT。
如果您想真正了解網路,我們有虛擬網路介面VNET。它多年來已經成熟,但要使用它,您需要編譯一個支持 VIMAGE 的核心。這在FreeBSD 12.0及更高版本的通用核心中啟用。
使用 VNET 時,您有一個很好的虛擬介面,您可以在監獄內執行防火牆。
我目前不使用 VNET 作為監獄主機上的統一防火牆,這對我和我想要的來說已經足夠了。有了這個,我可以控制進出監獄的交通。這使得從監獄中破解東西變得更加困難。
在監獄主機上,我經常允許一些出站流量(http/ftp/nameresolution)。但是我的監獄中的所有交通我都會明確指定哪些埠可以雙向以及在監獄之間進行。
訣竅是將流量移動到另一個介面。本地環回介面
lo0
是一個很好的選擇。但為了更好地分離規則,最好將其複製為新的介面名稱lo1
。您可以設置它並在監獄主機中使用ifconfig
. 但是沒有必要,因為 jail 子系統會自動為您處理所有這些。為此,我們
/etc/jail.conf
現在看起來像這樣:# Global settings applied to all jails. host.hostname = "${name}.jail"; interface = "lo1"; path = "/usr/local/jails/${name}"; mount.fstab = "/usr/local/jails/${name}.fstab"; exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; exec.clean; mount.devfs; # Specific seetings can be applied for each jail: testjail { ip4.addr = 172.17.2.1; }
請注意如何
ip4/6 = inherit;
更改為interface="lo1"
. 另請注意mount.fstab
- 這就是我添加 nullfs 掛載的方式,但我現在不會進一步討論。然後我添加了要用於測試監獄的內部 IP。然後我們通過添加
lo1
來複製/etc/rc.conf
:sysrc "cloned_interfaces"="lo1"
您需要為此重新啟動。如果您想在不重新啟動的情況下立即試用,您需要自己創建介面:
ifconfig lo1 create ifconfig lo1 up
cloned_interfaces="lo1"
這與設置中的效果相同/etc/rc.conf
。您不需要為 IP 地址創建別名,因為這會在監獄啟動時自動處理。然而,這很無聊,因為交通無處可去。
為了讓流量繼續,我們需要設置防火牆並進行一些 NAT。我選擇的毒藥是pf。你有你的規則集
/etc/pf.conf
要從外部 NAT 到 http 的監獄 IP,請執行以下操作:
rdr pass inet proto tcp from any to (em0) port http -> 172.17.2.1 port http
如果無法連接到自己,許多服務不喜歡啟動。因此,我也為此添加了一條規則。
pass on lo1 proto tcp from 172.17.2.1 to 172.17.2.1 port http
僅當您希望外部人員連接時才需要 NAT 規則。當您開始擁有多個監獄時,您通常只希望一個監獄能夠連接到另一個監獄。
pass on lo1 proto tcp from 172.17.2.1 to 172.17.2.2 port 8180
通過這些簡單的防火牆設置,您可以在監獄和外部之間進行非常好的網路隔離。
概括
根據我自己的經驗,我建議通過以下途徑來了解如何使用監獄:
- 了解基本核心功能 - 什麼是程序
- 了解 chroot
- 了解啟動過程
- 建造一個胖監獄
- 與監獄合作。使用/更新
- 在這裡了解
- 建造一個薄監獄
- 與多個監獄一起工作
- 了解網路
- 設置網路
- 了解 ZFS
那是我的食譜。可能不是你所希望的:-)
如果您不想使用提供的工具處理棘手的問題,請查看一些 3rd 方工具:
從所有這些中,您可以看到您的問題相當廣泛,並且在很大程度上取決於您的首選設置。我相信我已經展示了一個行為良好的包裹的收據,
nginx
但也許你需要問一些其他問題:
- 我如何守護 tinydns?
- 如何以非特權使用者身份執行 tinydns?
- 如何編寫 rc 腳本
但後來我會把監獄部分排除在外。