7.43 兩個網路之間的連線安全:可達範圍、連線方向與流入的資料、被入侵端改不到的限制、應用層認證、監控主機的位置、金鑰與控制平面、異地備份的寫入憑證與連線紀錄
本章處理兩個網路之間的連線怎麼設計與評估:地端主機與雲端主機、或兩個雲端業者的主機,以 VPN 或存取金鑰接起來之後,各自對另一端暴露了什麼、限制要放在哪裡。範圍從決定要把兩個網路接起來那一刻開始。防火牆的寫法以 Linux 主機、Docker 使用 iptables 後端為例,其他平台要查對應的轉送與連線狀態比對機制。文中 WireGuard、Tailscale、Prometheus、Docker、物件儲存、restic 與 rsync 的行為依各自的官方文件寫成,跨主機的限制效果沒有實機驗證。
本章的情境與範圍:地端監控與異地備份
本章用兩個情境推導。地端監控:監控主機放在地端(家裡或辦公室),經由 VPN 監看雲端的服務主機,這是 小型服務的兩到三台主機配置 的配置。監控主機上跑三個程式:Prometheus 定時向服務主機上的 exporter(把主機或服務的狀態轉成指標的程式)讀取指標並評估告警規則;Alertmanager 接收 Prometheus 交來的告警,決定送到哪個通知管道;blackbox_exporter 從外面對網址或連接埠發請求,回報對方有沒有回應。服務主機上另有一個心跳監看程式(Dead Man’s Switch(心跳監看):約定時限內沒收到心跳就通知的程式),監控主機的心跳來自 Watchdog,一條永遠成立的告警規則,Alertmanager 每隔固定時間把 Watchdog 這則告警送到心跳監看程式;Prometheus 的規則評估、Alertmanager 的路由與送出任何一段停掉,心跳就中斷。異地備份:雲端服務主機把備份送到另一個業者的物件儲存,兩邊之間沒有 VPN,只有一把寫入用的存取金鑰。兩個情境分別代表兩種接法:地端監控靠網路上的可達性,異地備份靠一把存取憑證(credential,這裡指存取金鑰這類證明身分的祕密,不是 TLS 憑證)。
相鄰的主題各有專篇。Tailscale 與自建 WireGuard 之間的選擇(省事,或不依賴第三方的協調伺服器)在 Tailscale 深入 的〈取捨與邊界〉,Tailscale 的位址模型與中繼在同一篇的前半。同一個雲端業者內的私有網路切分(VPC、subnet)與 security group 在 網路地基 — VPC、subnet 分層與 security group 設計,從網際網路進來的對外入口在 7.3 入口治理與伺服器防護。存取金鑰這類機器憑證要用哪一種機制在 7.34 機器憑證的機制選型,跨平台的工作負載身分在 7.10 Workload Identity 與聯邦信任邊界。
VPN 提供的保證與邊界模型
VPN 在兩個網路之間建立一條加密的隧道,提供三件事:封包在網際網路上傳送時被加密、兩端各自確認對方持有約定的金鑰、兩端各拿到一個在隧道裡固定的位址。WireGuard 以兩端事先交換的公鑰確認對方;Tailscale 建在 WireGuard 之上,由它營運的協調伺服器(coordination server)分發金鑰與位址。
三件事都發生在網路層,回答的是「這個封包是不是從持有那把金鑰的機器送來的」,不涵蓋「這台機器可以使用哪些服務」。VPN 早期的用法把兩個問題合成一個:接進來就算在內網,內網裡的服務彼此信任,這種做法稱為邊界模型(perimeter security)。服務搬上雲端、使用者在遠端工作之後,內網與外網這條線已經不對應任何實體,7.3 入口治理與伺服器防護 描述過這種錯位的後果:一個只需要看一台機器日誌的人,接進來之後連得到整個內網。業界把相反的原則稱為 Zero Trust(零信任):每一次連線各自通過身分與授權,網路上的位置不構成信任的理由。
兩三台主機的小型服務不需要整套導入零信任的基礎設施,本章借用的是它的問法,用來評估每一條跨網路的連線:發起的是哪一台機器、以什麼身分、連到哪一個服務。這三件事都對得上工作需要的連線,才保留那條連線;其餘連得到的位址與連接埠都要收回,這是 Least Privilege 在網路層的形態。
連線清單上各台的可達範圍與假設入侵
可達範圍(reachability)是一台機器經由這條連線能主動連到的位址與連接埠。隧道建立之後的預設是雙向的:地端連得到雲端,雲端也連得到地端。Tailscale 新建的 tailnet(同一個 Tailscale 帳號底下互相連通的裝置網路)預設讓所有裝置互通(Tailscale 的存取控制文件)。WireGuard 兩端連得到對方在隧道裡的位址;雲端還連得到地端背後的區網要三個條件同時成立:雲端那一側把地端的區網網段設成經由隧道送出、地端主機轉送封包、區網裝置的回應回得到隧道(通常靠地端做位址轉換)。
雙向的預設讓任何一台被入侵的機器都連得到別台。攻擊者拿下一台之後經由隧道往別台走,就是 Lateral Movement(橫向移動):以一台已經拿下的機器為起點,連到原本從外面連不到的機器。所以評估時,連線清單上的每一台機器(下一段定義)都要各假設一次被入侵,包括由人操作的那幾列的裝置,業界稱這個做法為 assume breach(假設已被入侵)。本章把正在被假設入侵的那一台稱為被入侵端。
各台被入侵的機率通常不同,入侵機率較高的那一台本章稱為較不可信的一端。它決定兩件事:先查哪一台,以及一個設計選擇拿某一台的暴露換另一台的暴露時,要保護的是哪一台(見〈地端監控情境需要的連線、發起方向與流入的資料〉一節的讀取方向)。清單上有多台時依入侵機率排序,最高的那一台先查;兩台的入侵機率相當時,兩台互為較不可信的一端,先後沒有差別。入侵的入口有兩類:對網際網路提供服務的程式(雲端服務主機上應用程式的漏洞、外洩的 SSH 金鑰),以及日常上網、收信、安裝軟體的裝置,連同和這類裝置在同一個區網裡的主機。雲端服務主機屬於前一類;管理者的筆電屬於後一類;地端的監控主機若是專用機、不對網際網路開任何連接埠,被入侵的機率較低,但它若兼作日常電腦、或和家人的筆電、NAS、印表機在同一個區網裡,後一類入口就在它旁邊。雲端被入侵時,攻擊者往地端走,再下一步是地端區網裡的筆電、NAS 與印表機,這些裝置從來沒有按面對攻擊者的標準設定過;地端或管理者的筆電被入侵時,攻擊者往雲端走。
Tailscale 的 tailnet 另有一種擴大可達範圍的方式。同一個帳號底下常常還有個人筆電與手機,tailnet 裡所有裝置預設互通時,任何一台個人裝置被入侵都連得到雲端主機的 exporter 與 SSH;反過來,雲端主機被入侵時也連得到那些個人裝置。
評估可達範圍的做法是寫出一張連線清單,每一列是一條需要的連線:發起的機器、目的機器、連接埠、由程式還是由人操作,以及這條連線的回應由哪一台產生。由人操作的連線(管理者的筆電連 SSH、看 Grafana)也是清單的一列,那台裝置上存著哪些存取憑證要一起記下,因為它被假設入侵時那些存取憑證就是攻擊者的工具(見〈限制的設置位置〉一節)。目前實際的可達範圍要從各台的設定(防火牆規則、WireGuard 的設定、Tailscale 的存取規則)讀出來,再從每一台實際連一次確認;實際觀察到的連線(見〈連線本身的紀錄〉一節)也是列清單時的輸入。清單上沒有、實際卻連得到的每一條,都是被入侵時攻擊者多拿到的可達範圍。
地端監控情境需要的連線、發起方向與流入的資料
地端監控情境的連線清單如下,機器之間的連線全部由地端發起:
| 發起端 | 目的地 | 用途 | 回應由誰產生 |
|---|---|---|---|
| 監控主機的 Prometheus | 服務主機上各 exporter 的連接埠(例如 node_exporter 的 9100) | 讀取指標 | 服務主機 |
| 監控主機的 Alertmanager | 服務主機上心跳監看程式的心跳網址(ping URL) | 送出 Watchdog 這則告警當心跳 | 服務主機 |
| 監控主機的 blackbox_exporter | 服務主機上心跳監看程式的 HTTP 連接埠 | 確認心跳監看程式本身還在運作 | 服務主機 |
| 管理者的裝置(人操作) | 監控主機的 Grafana 與 SSH、服務主機的 SSH | 看儀表板、管理 | 監控主機、服務主機 |
被假設入侵的是哪一台,那一台產生的資料就是另一台的不可信輸入:服務主機被入侵時是表上前三列的回應,監控主機被入侵時是它送往服務主機的請求,以及它回給管理者裝置的 Grafana 頁面與 SSH 工作階段的輸出(後者的一種形態見〈監控主機在信任關係裡的位置〉一節的 agent forwarding),管理者的裝置被入侵時是它發出的每一個管理動作。後兩種的危害集中在請求帶著的權限上,處置見〈限制的設置位置〉一節;本節處理服務主機被入侵時的回應。
隧道本身也由地端建立。用 WireGuard、地端在 NAT 後面時,地端的設定裡寫給雲端 peer 的區段設 PersistentKeepalive,由地端定時送出封包,維持 NAT 的對應;雲端主機在業者的防火牆開放 WireGuard 的 UDP 連接埠給它。管理者的筆電要經由 VPN 連進來時,在 WireGuard 下它自己要是一個 peer:每一台要讓它連的機器在設定裡各有一段寫給它,AllowedIPs 只寫它的位址。筆電與地端都在 NAT 後面時兩者無法直接握手,這時不要讓雲端主機替它們中轉:中轉要把筆電的位址寫進地端給雲端 peer 的 AllowedIPs,被入侵的雲端主機就能冒用那個位址,走進替管理者開的例外。可行的做法是地端在路由器上開一個 UDP 連接埠給筆電,或改用 Tailscale。筆電的隧道介面同樣套用只放行回應的規則,它不需要任何被連入的連線。用 Tailscale 時,隧道由 Tailscale 經 NAT 穿越建立,各台都不必自己開連接埠,筆電也是 tailnet 裡的一台裝置。
機器之間的連線裡,服務主機沒有任何一條需要主動連到監控主機,本章把這個性質稱為地端單向發起。它讓監控主機的隧道介面可以套用只放行回應的規則:依連線追蹤(conntrack,核心記錄每條連線狀態的表)的狀態,接受屬於自己發起的連線的封包(狀態為 ESTABLISHED、RELATED),另外只放行連線清單上由人操作那幾列(管理者裝置在隧道內的位址連到 Grafana 與 SSH 的連接埠),其餘由隧道進來的新連線一律丟棄。監控主機跑 Docker 時這條規則要寫在兩個地方,兩個都保留:INPUT 鏈上的那一條管主機本身的程式(例如 SSH),而 Docker 發佈的連接埠在位址轉換之後走轉送路徑、不經過 INPUT 鏈(Docker 的封包過濾文件),所以以 0.0.0.0 發佈的 Alertmanager、Prometheus 與 Grafana 要靠 Docker 留給使用者、排在它自己的規則之前的 DOCKER-USER 鏈裡的對應規則來擋;那裡的封包已經轉成容器的位址與連接埠,人員操作列的例外要以連線追蹤記下的原始目的連接埠比對(-m conntrack --ctorigdstport,見 Docker 的 iptables 說明),照抄 INPUT 鏈的連接埠條件,在發佈的連接埠與容器內的連接埠不同時會把管理者擋在外面。DOCKER-USER 裡用 iptables 指令加的規則在重開機之後就不在;firewalld 主機用 iptables 後端、或用 nftables 後端而有 direct 設定時,firewall-cmd --reload 也會清掉它,ufw 主機上可以寫進 /etc/ufw/after.rules 讓它在開機時載入。實測與各種寫法在重新載入、重開機之後的結果見 CDN 後面的源站主機防火牆:只放行 CDN 來源的位置與套用時機、Docker 發佈連接埠的封包路徑、出站 DNS 的限制與地理封鎖 的〈Docker 發佈的連接埠:封包路徑與限制的寫法〉。更簡單的做法是這些容器的連接埠只發佈在 127.0.0.1,管理者經由 SSH 通道看 Grafana。發佈在區網位址上會把它們交給區網裡的每一台裝置,家人的筆電與 NAS 都連得到 Alertmanager;監控主機區網那一側的介面同樣只放行清單上那台管理裝置。
雲端那一側同樣要收:服務主機的隧道介面只放行來自監控主機、往 exporter 與心跳監看程式那幾個連接埠的連線,以及連線清單上管理者裝置到 SSH 的那一列。服務主機的資料庫與其他服務多半也是 Docker 發佈的容器,同樣要在 DOCKER-USER 鏈擋,或只發佈在 127.0.0.1。監控主機被入侵時,這幾條規則決定攻擊者經由隧道連不連得到服務主機的 SSH 與資料庫,成本只是幾條規則。
只放行回應的規則管的是誰能開啟連線,管不到流進來的資料。表上「回應由誰產生」寫服務主機的三列,回應都由被入侵時的服務主機決定。Prometheus 讀取 exporter、blackbox_exporter 的 HTTP 探測、Alertmanager 送出告警時,預設都會跟隨 HTTP 轉址(follow_redirects 預設為 true)。被入侵的服務主機回一個轉址,指向 http://192.168.1.10/ 這類區網位址,地端的程式就會自己對區網裝置發出請求;這條連線由地端發起,只放行回應的規則擋不到它。這是 SSRF(伺服器替攻擊者發出請求)經由轉址的一種,攻擊者讀不到那個請求得到的回應,危害落在區網裡收到請求就執行動作的裝置管理介面。處置是三處都把 follow_redirects 設成 false:Prometheus 的讀取設定(scrape config)、blackbox_exporter 的 HTTP 探測模組、Alertmanager 送往心跳監看程式的那一個通知設定。轉址之外還有兩條同類的路徑:讀取對象寫成主機名稱、而服務主機上存著能改那個 DNS 區域的 API token 時,攻擊者把名稱指到區網位址;讀取對象清單由服務主機提供時,攻擊者改清單。所以讀取對象寫成隧道內的位址,對象清單寫在監控主機自己的設定檔裡。
回應的大小與內容是另一種流入的資料,屬於 Unrestricted Resource Consumption 這一類。Prometheus 對單次讀取的樣本數(一次讀取帶回的時間序列筆數)、每筆的標籤數與標籤長度、回應大小預設都不設上限(sample_limit、label_limit、label_name_length_limit、label_value_length_limit、body_size_limit 預設為 0,可以寫在讀取設定或全域設定裡,見 Prometheus 的設定文件),一份刻意灌大的回應可以耗盡監控主機的記憶體。上限依平常一次讀取的量加上餘裕來定;超過上限時那一次讀取失敗,那個讀取對象在監控上看起來與讀不到相同。單次的上限擋不住每次換一組標籤值、讓時間序列總數一路累積的做法,所以標籤數與標籤長度也要設。被入侵主機回報的指標本身也不可信,它回報一切正常,不代表那台主機的狀態正常。
地端單向發起來自兩個選擇,換掉任何一個都要重新評估。
讀取方向:監控主機上的 Prometheus 主動向各 exporter 讀取指標。改成各主機以 remote write 把指標推送到監控主機(兩者的取捨見 多台主機的指標收集 的〈指標回到中央的架構:中央直接讀取與各主機推送〉)時,服務主機不必再開放 exporter 的連接埠,換來的是監控主機要接受一種由雲端發起的連線:只放行接收端點那一個連接埠,接收端點另外要有自己的認證。流進來的資料也換了形態,不可信的是雲端送來的請求本身;被入侵的服務主機持有接收端點的認證,認證擋不住它。Prometheus 自己的接收端沒有限制單次請求大小或時間序列數的設定,要在它前面放一層能限制請求大小的反向代理,或換用有這類上限設定的接收端。兩個方向哪個比較好,取決於要保護的是哪一台:要保護的是地端時,讀取讓地端維持單向發起;要保護的是服務主機、而要關閉的正是 exporter 那一組連接埠時,推送讓服務主機少開一組連接埠。
心跳監看程式的位置:心跳監看程式放在服務主機上、由監控主機送心跳過去。反過來把它放在地端、由服務主機送心跳,同樣要在地端接受一種由雲端發起的連線。放在服務主機上也有代價:服務主機被入侵時,看守監控主機的程式與它存著的通知存取憑證都在攻擊者手上,所以它的通知管道要與其他告警分開。
監控主機改放在另一個雲端業者的 VPS 時,連線清單與地端監控相同,差別在兩台都對網際網路提供服務、入口都在網際網路那一側,兩台互為較不可信的一端,兩台的隧道介面都只放行清單上的連線。
限制的設置位置:被入侵端改得到與改不到的限制
被入侵端的攻擊者拿到 root 時,那台機器上的一切設定都在他手上:防火牆規則、WireGuard 的設定檔、Tailscale 的用戶端設定,以及存在那台機器上或那台機器取得得到的每一把存取憑證。所以收窄可達範圍的限制要依被入侵端能不能改寫它分成兩種。被入侵端改得到的限制:設定存放在被入侵端上,或被入侵端有能改寫它的存取憑證或寫入路徑。被入侵端改不到的限制:設定不在被入侵端上,而且被入侵端沒有任何能改寫它的存取憑證或寫入路徑,例如存放在另一台機器上、或存放在控制平面(control plane,下發設定與政策的那一層,例如 Tailscale 的協調伺服器)上而被入侵端沒有那裡的寫入權限。要防的是「被入侵端往別台走」時,只有被入侵端改不到的限制在入侵發生之後仍然成立。
判斷時先看設定存放在哪裡,再逐一列出被入侵端的存取憑證與寫入路徑,問每一項能改寫哪些限制。常見的寫入路徑有這幾種:存在被入侵端上、能改 ACL 的 Tailscale API 金鑰或 OAuth client(用 IaC 管理 tailnet、或自動產生認證金鑰時會放在主機上);雲端業者的 API token,它改得了業者的防火牆與 security group,常見的存放理由是自動化部署、DNS 驗證、快照,以及監控主機上 Prometheus 的雲端服務探索(例如依業者 API 列出主機的那一類設定,它要一把業者的 token);雲端主機經由實例中繼資料服務(instance metadata service)取得的實例角色,它不在磁碟上,逐一列檔案時找不到;能推送到部署來源(存放另一台設定的 git repo)的金鑰;被入侵端本身是 Tailnet Lock 的簽署節點,或自架的協調伺服器架在被入侵端上;Tailscale policy 裡的自動核准設定(autoApprovers)讓帶某個 tag 的裝置宣告的子網路由自動生效,帶那個 tag 的被入侵端因此改得了別台的路由。有這些寫入路徑時,限制雖然存放在別處,仍屬於被入侵端改得到的限制。
由人操作的裝置被假設入侵時,它存著的存取憑證就是它的寫入路徑,而且通常是最寬的那一條:管理者的筆電存著兩台主機的 SSH 金鑰、登得進去之後取得得到 root,兩台主機上的每一條限制對它都是改得到的限制,網路上的收窄全部不相干,攻擊者走的是清單上本來就允許的管理連線。這台裝置的寫入路徑不只 SSH 金鑰:瀏覽器裡登入著的雲端業者主控台(網頁主控台、救援模式、業者防火牆)與物件儲存帳號的主控台,都繞過主機上的每一條限制。這一種的處置不在網路層,而真正切斷它的只有一項:管理只從一台不拿來日常上網、不收信、不裝其他軟體的專用裝置做。其餘幾項只縮小範圍:金鑰放在需要觸碰才簽章的硬體金鑰裡(取捨見 7.39 使用者持有型憑證),擋得住管理者沒在操作時攻擊者自己發起的新登入,擋不住沿用已開啟的 SSH 連線與工作階段;sudo 要求再驗證一次,密碼在被入侵的裝置上輸入時擋不住;每台主機各用一把金鑰,防的是其他途徑造成的單把外洩,兩把都在同一台筆電上時沒有幫助。
以下以地端監控情境、被入侵端是雲端主機為例。WireGuard 的 AllowedIPs 同時承擔兩個角色(WireGuard 官方說明 的 Cryptokey Routing 一節)。每一個 peer(WireGuard 設定裡代表一個對端的區段,含對端的公鑰)各有一份 AllowedIPs:送出封包時它是路由表,目的位址落在哪個 peer 的 AllowedIPs 裡,WireGuard 就以那個 peer 的金鑰加密封包、送給它;收到封包時它是存取清單,解密之後,封包在隧道內的來源位址不在送出那個 peer 的 AllowedIPs 裡,WireGuard 就丟棄它。由這兩個角色推出三件事,前提都是雲端主機沒有能改寫地端設定的寫入路徑:
- 地端設定裡寫給雲端 peer 的 AllowedIPs 是被入侵端改不到的限制。 只寫雲端主機在隧道裡的那一個位址(IPv4 寫
/32,IPv6 寫/128),雲端送來的封包在隧道內就只能以這個位址為來源;攻擊者改雲端自己的設定繞不過,因為檢查發生在地端。 - 雲端設定裡寫給地端 peer 的 AllowedIPs 是被入侵端改得到的限制。 攻擊者把地端的區網網段加進去,雲端就會把往那個網段的封包送進隧道。這些封包到了地端會不會被轉送進區網,由地端的防火牆決定:轉送路徑上丟棄從隧道介面進來、要往區網去的封包,攻擊者改了雲端這一側也到不了區網。只靠「地端的監控主機不開 IP 轉送」不夠可靠:監控主機跑 Docker 時,Docker 啟動時就會開啟 IP 轉送,同時把轉送封包的預設政策設成丟棄。這個預設政策擋得住,但它是預設,任何一條排在前面的放行規則都會蓋過它,例如 WireGuard 設定檔在介面啟動時執行的指令(wg-quick 的
PostUp)裡加了一條「從隧道介面進來的轉送一律放行」。所以丟棄的規則也寫在DOCKER-USER鏈裡,不依賴預設政策。 - 地端隧道介面的防火牆規則存放在地端,是被入侵端改不到的限制。 只放行回應的規則就屬於這一種。
Tailscale 的存取控制規則(ACL)由每一台裝置對連進來的連線執行,規則由協調伺服器分發,執行時不經過協調伺服器(Tailscale 的存取控制文件)。雲端主機上的攻擊者改不到地端裝置收到的規則,所以 ACL 屬於被入侵端改不到的限制,前提同樣是雲端主機上沒有能改 ACL 的 API 金鑰。規則是單向的:允許監控主機連到服務主機,不等於允許服務主機連回監控主機。反方向的假設(地端或管理者的筆電被入侵)結果不同:管理者在那台筆電上登入著 Tailscale 的管理介面時,ACL 就由那台筆電改得到(見〈WireGuard 與 Tailscale 的金鑰與控制平面〉一節)。
tailnet 的預設政策本身就是一條「所有裝置都能連到所有裝置」的放行規則,在它旁邊再加允許規則收窄不了任何連線,所以收窄是把這一條替換成只允許清單上的連線。用 tag(Tailscale 替伺服器這類非個人裝置分組的標籤)把伺服器與個人裝置分開,是把連線清單寫成規則的方式:規則寫成「監控主機的 tag 可以連到服務主機的 tag 的哪些連接埠」,個人裝置只出現在清單上由人操作的那幾列,例如管理者的筆電連得到兩台主機的 SSH 與監控主機的 Grafana,其餘連不到。人員列的來源寫那台管理裝置的 Tailscale 位址(或在 policy 裡替它取的別名),不寫使用者:以使用者為來源時,規則涵蓋那個使用者的全部裝置,手機與其他筆電也會一起拿到 SSH(Tailscale 的存取控制文件)。
Tailscale 常被描述成零信任網路,而所有裝置預設互通的 tailnet 行為接近邊界模型,收窄到清單上的連線之後才符合零信任的問法。
VPN 之內的應用層認證:第一道與第二道防線的條件
VPN 確認的是封包來自持有金鑰的機器,VPN 裡的服務本身多半沒有認證:exporter 預設沒有認證,連得到連接埠就讀得到主機的全部指標;心跳監看程式的心跳網址只要知道就能送出心跳或失敗;Prometheus 與 Alertmanager 的 HTTP 介面沒有權限分級,連得到 Alertmanager 就能經由它的 API 建立靜默(silence,讓符合條件的告警在一段時間內不送出)。隧道本身不做認證、隧道之後要疊一層認證的原則,與對外隧道入口(服務主機主動連出到業者、由業者對外提供網址的那種入口,例如 Cloudflare Tunnel)相同,見 5.10 Outbound Tunnel 入口與生命週期 的〈認證必須疊在 tunnel 之後〉。
每個服務要不要再加一層認證,逐個服務看收窄之後連得到它的有哪些機器,這是 Defense in Depth 的判斷:哪一層實際擋在前面。連得到它的只剩清單上那一台機器,而且收窄靠的是被入侵端改不到的限制時,應用層認證是第二道防線:限制設錯時(例如 AllowedIPs 寫成整個網段而不是 /32、或 ACL 加了規則卻沒有替換預設的全部放行),多出來那些連得到它的機器要過的就是這一道。代價是每個 exporter 各自的 TLS 與認證設定,做法見 多台主機的指標收集 的〈exporter 的部署位置與連接埠〉的末段。
連得到它的機器裡有個人裝置、或可達範圍收窄不了時,應用層認證是第一道防線:那些機器任何一台被入侵,網路層都會放行它發出的連線,擋在服務前面的只剩應用層的認證。同一個 tailnet 裡兩種可以並存:exporter 只有監控主機連得到,認證是第二道;Grafana 管理者的筆電也連得到,認證是第一道。
監控主機在信任關係裡的位置
監控主機為了工作,要連得到每一台被監控的主機,也存著通知管道的祕密(推播的網址、心跳網址、寄信的帳號)與 Grafana 的資料來源設定。它被入侵時,攻擊者同時拿到通往每一台主機的可達範圍,以及讓告警消失的能力,例如在 Alertmanager 建立靜默、改掉通知路由。
讓告警消失這件事要分故障與入侵兩種情形看。監控主機故障、Prometheus 或 Alertmanager 停掉時,Watchdog 這則告警不再送出,心跳中斷,心跳監看程式因此會通知。監控主機被入侵時不同:攻擊者手上有監控主機存的心跳網址,可以停掉 Prometheus 與 Alertmanager 之後自己定時送心跳,也可以只靜默特定的告警、讓 Watchdog 照常送出,兩種做法下心跳監看都看不出異狀。
這時還能發出通知的,是不經過監控主機、通知也不用監控主機上任何存取憑證的觀察者,也就是 Out-of-Band Signal:第三方的外部探測直接對服務的公開網址發請求(外部探測的位置與成立條件見 4.28 單台主機的監控盲區與失效域以外的觀察者 的〈外部探測:使用者看到的結果〉),雲端業者自己的主機告警,以及使用者回報。成立的前提是這些觀察者的通知不經過任何一台被假設入侵的機器存著的帳號、網址或已登入的工作階段:外部探測的告警若寄到監控主機也存著密碼的那個信箱、或管理者筆電上一直登入著的那個信箱,攻擊者在那裡設一條過濾規則就能把告警刪掉。這類觀察者擋得住的是服務中斷沒人知道,偵測不到靜默本身,也偵測不到不影響可用性的入侵。
所以把本章的可達範圍問法套到監控主機自己身上:通往監控主機的路徑有哪幾條,每一條在別台被入侵時還擋不擋得住。Grafana 這一條,不對網際網路開放,經由 VPN 或 SSH 通道看(做法見 Grafana 的對外存取);儀表板必須給客戶看時,把對外的儀表板放在另一台不存通知祕密、也連不到各主機的機器上,資料由監控主機推過去(remote write 或定時匯出),讓監控主機仍是發起的那一端,這條連線也進連線清單;那台對外的機器入侵機率最高,它回給推送的回應是監控主機的不可信輸入,這條推送的 follow_redirects 同樣設成 false。管理用的 SSH 這一條,只走 VPN、只從清單上那台管理裝置來,並使用與服務主機不同的金鑰,登入服務主機的私鑰(包括部署流程持有的那一把)外洩時,登入不了監控主機。從服務主機轉送過來的 SSH agent 這一條:SSH agent 是管理者本機上持有私鑰、替 ssh 簽章的程式,agent forwarding 讓連上去的遠端主機借用它,所以連到服務主機時不開 agent forwarding,否則服務主機上的 root 可以借用轉送過來的 agent 登入監控主機。
WireGuard 與 Tailscale 的金鑰與控制平面
自建 WireGuard 的信任錨(trust anchor,信任關係最終追溯到的那一方)是每台機器上的 peer 設定,以及能改寫那些設定的人與部署流程:一台機器接受誰,由它自己設定裡列的公鑰決定。WireGuard 的金鑰沒有到期日,金鑰的分發也明確不在 WireGuard 的範圍內(官方說明寫的是 key distribution 不屬於 WireGuard 處理的問題)。撤銷一台機器的方法是在每一台列著它的機器上把它的 peer 從設定裡刪掉,只刪一台時那把金鑰在其他台仍然有效;輪替是產生新的金鑰對、每一台一起換掉。沒有人做這兩件事時,一把外洩的私鑰永遠有效。所以每一把金鑰要有紀錄:放在哪台機器上、什麼時候產生、在什麼條件下停用,登記的欄位見 7.32 機器憑證的配發。金鑰沒有到期日,回收只能靠登記時寫下的停用條件:機器退役或疑似被入侵時,在每一台列著它的機器上刪掉它的 peer。這是機器憑證生命週期的一個實例,治理見 7.6 秘密管理與機器憑證治理。
Tailscale 把金鑰分發交給協調伺服器,信任錨因此換成 tailnet 的管理帳號與 Tailscale 營運的協調伺服器。自架協調伺服器(例如開源的 Headscale)時,信任錨是那台自架的伺服器,而它架在哪一台決定了 ACL 屬於哪一種限制:架在雲端服務主機上時,雲端被入侵就改得到 ACL。
管理帳號被盜時,攻擊者可以把自己的裝置加進 tailnet、把機器分享出去、改寫 policy 檔(ACL、Tailscale SSH 的規則、自動核准子網路由的設定都寫在裡面)、改 DNS 設定,〈限制的設置位置〉一節裡由 ACL 承擔的被入侵端改不到的限制,全部由這個帳號改得到。Tailscale 多半經由 Google、GitHub 這類外部帳號登入,這個帳號的登入因子設在那個身分提供者上,要用攻擊者拿不走的因子,例如 passkey 或安全金鑰(取捨見 7.39 使用者持有型憑證)。登入因子擋不住已經登入的工作階段:管理者平常在哪一台裝置上登入管理介面與身分提供者,那台裝置也算進信任錨,它被入侵時 ACL 就由它改得到。裝置核准(device approval)讓新裝置要經管理者核准才能連線,它擋得住用外洩的使用者帳號或預先產生的認證金鑰(auth key,讓伺服器免互動加入 tailnet 的金鑰)加入的裝置,擋不了管理帳號本身被盜,因為核准的人就是管理帳號。
協調伺服器負責把每台裝置的公鑰發給其他裝置,它被入侵或作惡時,可以把不屬於這個 tailnet 的節點發給其他裝置。Tailscale 的 Tailnet Lock 讓新節點的金鑰必須帶有 tailnet 內受信任裝置(簽署節點)的簽章,其他裝置才接受它(Tailnet Lock 文件)。這一項同時約束協調伺服器與被盜的管理帳號:兩者都無法單方面加入節點,而 ACL 仍由管理帳號改得到。簽署節點與預先簽署過的認證金鑰都掌握「誰能加入 tailnet」這一條限制,所以簽署節點要放在一台三個條件都成立的裝置上:連線清單上沒有任何一列連得到它、不拿來日常上網、自己不對區網或網際網路提供任何服務也不和日常裝置同在一個區網,例如一台平常關機、只在簽署時開機的裝置。兩台主機都在連線清單上,所以都不適合;NAS 這類沒有出現在清單上、卻開著檔案分享服務的裝置也不適合。預先簽署的認證金鑰也不放在服務主機上。完全不依賴第三方協調伺服器的做法是自架協調伺服器或改用自建 WireGuard,代價是金鑰分發與撤銷回到自己手上。
節點金鑰(node key)的到期:新建 tailnet 的節點金鑰預設 180 天到期,管理者可以把期限調短;到期之後那台裝置的連線兩個方向都中斷,直到重新認證(Tailscale 的金鑰到期文件)。裝置第一次以 tag 認證時,金鑰到期預設就是關閉的;管理者也可以為了避免伺服器在無人值守時斷線,在管理介面逐台關掉到期。兩種情形下那台的金鑰都是永久有效,與 WireGuard 相同,所以用 tag 管理伺服器的 tailnet,每一台 tagged 裝置除非另外開啟了到期,都要當成永久金鑰記進金鑰紀錄,撤銷的方式是在管理介面移除那台裝置。到期造成的斷線,在監控上看起來與 VPN 斷線相同,判讀見 小型服務的兩到三台主機配置 的〈監控主機與服務主機之間的連線與連線中斷的誤判〉。
協調伺服器停擺時,已經在 tailnet 裡的裝置照常互通,直到某一台的金鑰到期;新裝置加入不了,ACL 改不了,也撤銷不了任何一台的金鑰(Tailscale 的協調伺服器停擺說明)。撤銷不了是安全面的代價:停擺期間發現某一台被入侵,只能在那台機器或其他台的防火牆上擋,等不到管理介面。可用性那一面,協調伺服器是監控主機與服務主機共用的依賴,要列進兩台共用的失效域(failure domain,同一個原因會讓它們一起停掉的範圍)。
雲端對雲端與異地備份:沒有共用私網時的接法
兩個雲端業者之間預設沒有共用的私有網路。一台主機需要連到另一個業者主機上的服務時,做法與地端監控相同:各台之間建 VPN,寫出連線清單,照清單收窄可達範圍,清單上每一台各假設一次被入侵,每一條限制都要有一條被入侵端改不到的限制管住同一條連線。
異地備份情境不需要兩個網路之間互通。服務主機只要連得到業者的公開 API、把檔案寫進另一個業者的物件儲存,靠的是一把存取金鑰。這時攻擊者的目標從網路移到存取憑證:服務主機被入侵時,攻擊者拿到的就是那把存取金鑰,它的權限決定備份還在不在,這是橫向移動經由存取憑證而不經由網路的那一種。小型服務的兩到三台主機配置 的配置把備份放到另一個業者或帳號,防的是帳號停權、主機故障,以及資料所在帳號的存取憑證外洩;寫入備份的存取金鑰仍放在服務主機上,要防它外洩之後備份被刪或被覆寫,要從下面的做法裡選至少一種,目標是讓服務主機上的存取憑證刪不掉也改不了既有的備份。其中只有 compliance 模式的物件鎖定做到連持有帳號完整權限的人也刪不掉,那一種才是 WORM Storage(不可變儲存);其餘幾種擋的是服務主機上那把存取憑證,擋不了帳號本身的完整權限。
存取金鑰只給寫入權限:權限只允許上傳,不允許刪除。上傳權限在 S3 這類物件儲存裡本身就包含覆寫同名物件,攻擊者用垃圾內容覆寫既有的備份,效果等同刪除;所以這一種要搭配版本保留,或以 bucket 的政策強制只能寫入還不存在的物件名稱(S3 的 conditional write)。另外要先確認備份工具在這組權限下跑得動:restic 每次執行都會在儲存庫的 locks/ 下建立鎖定檔(restic 的設計說明),只給上傳權限時要在那組權限下實際跑一次備份確認。業者的權限模型做不到「只能上傳、不能刪除」這個粒度時,這一種不成立,改用物件的版本保留或鎖定。
物件的版本保留或鎖定:物件儲存開啟版本保留(versioning)時,覆寫與刪除只會產生新版本,舊版本仍在,可是持有完整權限的金鑰能把舊版本一起刪掉,舊版本到期的生命週期規則也會在設定的天數之後自動刪掉它們,攻擊者只要等那個天數過去。業者提供物件鎖定(object lock,S3 用的名稱)時,要看鎖定的模式:S3 的 compliance 模式在保留期間內連 root 帳號也刪不掉;governance 模式下,持有繞過權限(s3:BypassGovernanceRetention)的金鑰仍刪得掉(S3 Object Lock 文件)。防存取金鑰外洩要用 compliance 模式,或確認那把金鑰沒有繞過權限;保留期間要長過從入侵發生到被發現所需的時間,否則攻擊者等鎖定到期再刪。
改由備份端拉取:備份主機定期連到服務主機取資料,服務主機上沒有任何碰得到備份的存取憑證。代價是方向反過來:這條連線要進連線清單,備份主機持有連到服務主機的權限,它的保護要比照〈監控主機在信任關係裡的位置〉一節的監控主機。拉取用的 SSH 金鑰在服務主機的 authorized_keys 裡以 command= 指定一支只對備份路徑做唯讀傳送的程式(例如 rsync 附的 rrsync 以唯讀模式執行),再加 restrict 關掉轉送與終端機,這把金鑰不論對方要求什麼都只執行那支程式,否則備份主機拿到的是服務主機的 shell。拉回來的資料對備份主機是不可信的輸入,被入侵的服務主機能利用拉取工具本身的漏洞:rsync 3.3.0 以下的版本,被入侵的伺服器端可以讓用戶端把檔案寫到目的目錄之外(CERT VU#952657,2025 年 1 月公布)。所以備份主機上的拉取以只寫得到備份目錄的非特權帳號執行、rsync 用修正之後的版本,並限制備份目的地的空間。
以 append-only 伺服器接收推送:restic(一個做加密增量備份的工具)的備份伺服器 rest-server 以 --append-only 模式執行時只接受新增備份,拒絕刪除與修改既有的備份(rest-server 的說明);服務主機仍然主動送出備份,而它手上的權限碰不到舊的備份。代價是目的地從業者的物件儲存換成一台自己營運的主機,那台主機的可達範圍與認證要照本章的方法再評估一次。append-only 擋的是刪除與覆寫,不擋讀取:備份的內容由 restic 自己加密,加密用的密碼外洩之後還解得開哪些備份、什麼時候要換掉主金鑰,在 7.45 加密備份的密碼、key 檔與主金鑰。
不論選哪一種,有兩件事相同。服務主機上的權限刪不掉任何一份備份,所以舊備份的清除(restic 的 forget 與 prune 這類動作)要由另一台持有完整存取權的機器執行,否則儲存只增不減;持有完整存取權的那一台本身是一條刪除備份的寫入路徑,同樣進「每一台各假設一次」,它被入侵時只有 compliance 模式的鎖定還擋得住,所以它的位置比照簽署節點挑選,不放在監控主機或服務主機上。被入侵的服務主機仍可以交出被竄改或已加密的新資料,這些做法擋的是刪除與修改既有的備份,所以舊的備份要保留多份,還原前要驗證。這把存取金鑰的機制選型與輪替見 7.34 機器憑證的機制選型 與 7.6 秘密管理與機器憑證治理;備份被讀走那一面的收斂(備份加密、備份存取憑證的日常權限只剩寫入與驗證)在 7.4 資料保護與遮罩治理。兩邊都是大型雲端、能以工作負載身分聯邦取代長期存取金鑰時,見 7.10 Workload Identity 與聯邦信任邊界。
連線本身的紀錄
紀錄有兩個用途:列連線清單時用來觀察實際有哪些連線,清單定案之後用來比對有沒有偏離、限制有沒有被試探、設定有沒有被改。紀錄同樣要套用假設入侵:被入侵端上的紀錄由攻擊者控制,要看別台的。
WireGuard 的握手紀錄:WireGuard 本身不記錄連線。在被入侵端以外的每一台執行 wg show,輸出會列出每個 peer 最後一次握手的時間,以及對端目前的公開位址與連接埠(endpoint)。endpoint 是封包在網際網路上的來源,與隧道內的來源位址是兩件事,AllowedIPs 不限制 endpoint。兩種輸出要查:一個應該已經退役、卻仍留在設定裡而且仍有握手的 peer,代表退役沒有做完、那把私鑰仍在某台機器上使用;一個 peer 的 endpoint 出現在預期之外的網段,代表那把私鑰可能正在另一台機器上使用。兩種的處置都是在每一台列著它的機器上刪掉那個 peer。地端在家用網路時公開位址會隨網路業者變動,判讀時比對的是業者的網段,不是單一位址;地端在電信商的 CGNAT(多個用戶共用公開位址的位址轉換)後面時,這項比對排除得了其他業者,排除不了同一個業者的其他用戶。wg show 是一次性的輸出,要接上告警就定時執行它,或用把它轉成指標的 exporter。
Tailscale 的設定變更與連線:新裝置加入、機器分享與 ACL 修改都記在 Tailscale 的設定稽核紀錄(configuration audit log)裡,這份紀錄本身不發通知,要變成通知得另外接 webhook 或串流到集中的日誌系統。ACL 擋下的連線在 Tailscale 的程式裡就被丟掉,不會到主機的防火牆,所以用 Tailscale 時主機防火牆的丟棄紀錄是空的,空的不代表沒有人試;裝置之間的連線要看連線流量紀錄(network flow logs),它屬於付費方案、預設關閉。
各台隧道介面的丟棄紀錄:用 WireGuard 時,各台隧道介面上只放行清單連線的規則會丟棄清單以外的新連線。地端那一側丟棄的新連線代表雲端有程式在試著往回連;服務主機那一側丟棄的、來自監控主機往 SSH 或資料庫的新連線,代表監控主機被拿下之後攻擊者在往雲端走。正常運作時這類丟棄只有零星的遲到封包(連線追蹤表裡那條連線的項目已經逾時之後才到的關閉封包,被判為 INVALID);把 INVALID 的封包與 NEW 的新連線分開記錄,清單以外的新連線出現才是訊號。監控改成推送之後,推送本身就是清單上的新連線,比對的對象仍是清單以外的那些。
物件儲存的存取紀錄:靠存取憑證連接的異地備份,紀錄在業者那一側。S3 這類物件儲存的存取紀錄(S3 的 server access log 或 CloudTrail 的資料事件)記得下每一次覆寫既有物件的上傳與每一次被拒絕的刪除,這兩種在正常的備份流程裡都不該出現。
這幾項訊號要接到有人看的告警,訊號的取捨與誤報成本見 7.13 偵測覆蓋率與訊號治理。
評估一條跨網路連線時各項判斷的依賴
各項判斷以兩張清單為基準。連線清單的每一列是一條需要的連線,寫發起的機器、目的機器、連接埠、由程式還是由人操作,以及回應由哪一台產生;由人操作的那幾列另外記下那台裝置上存著哪些存取憑證。流入清單記的是不經過連線清單上任何一列、經由第三方到達另一台的資料與設定:DNS 業者那裡的紀錄、git repo 裡的設定與讀取對象清單、映像登錄處的容器映像。被假設入侵的是哪一台,流入清單就列那一台寫得到的那些,所以每一台各有一份。部署來源在兩處都會出現:它是限制的寫入路徑(〈限制的設置位置〉),也是流入的資料,兩處指的是同一項。實際觀察到的連線(〈連線本身的紀錄〉)是列清單時的輸入,清單定案之後紀錄改用來比對偏離。
收窄可達範圍依賴連線清單與實際範圍的比對,清單上每一台各收一次,因為每一台都要各假設一次被入侵;較不可信的一端決定先查哪一台,以及一個設計選擇拿某一台的暴露換另一台的暴露時要保護哪一台。收窄用的每一條限制,接著問被入侵端能不能改寫它:先看設定存放在哪裡,再逐一列出被入侵端的存取憑證與寫入路徑。被入侵端改得到的限制在入侵之後不再成立,所以每一條都要在別台或控制平面上有一條被入侵端改不到的限制管住同一條連線。被假設入侵的是由人操作的裝置時,它的存取憑證是最寬的寫入路徑,判斷轉到那台裝置與它的金鑰怎麼保護。
哪些資料要當成不可信的輸入,由被假設入侵的是哪一台決定:那一台產生的回應、請求與檔案,以及它寫得到的流入清單項目。讀取時是回應(關掉轉址、限制樣本數、標籤與回應大小),推送時是請求本身(接收端前面限制單次請求的大小與時間序列數),拉取備份時是拉回來的檔案(非特權帳號、修正後的拉取工具、限制目的地的空間);流入清單上的每一項改由另一台自己持有或自己解析:讀取對象寫在監控主機自己的設定檔裡、寫成隧道內的位址而不經過 DNS、部署來源的寫入權不放在被入侵端上。要不要在服務前面加應用層認證,逐個服務看收窄之後連得到它的機器:其中有個人裝置、或收窄不了時,認證是第一道防線。
信任錨與撤銷方式依用的是哪一種 VPN 而定:自建 WireGuard 要的是每一把金鑰的位置與停用條件;Tailscale 要的是管理帳號的登入因子、管理者平常在哪一台裝置上登入、有沒有開 Tailnet Lock、簽署節點在哪裡、哪些 tagged 裝置的金鑰不會到期;自架協調伺服器要的是那台伺服器架在哪一台上。異地備份依做法而定:只給寫入權限與版本保留或鎖定的做法,判斷落在那把存取金鑰能做的每一件事(刪不刪得掉、覆寫不覆寫得了既有的備份、鎖定是不是 compliance 模式、舊版本會不會被生命週期規則刪掉);拉取的做法,那條連線進連線清單,判斷落在 command= 與 restrict 的限制、拉取帳號的權限與備份主機的保護;append-only 伺服器的做法,那台伺服器照本章的方法再評估一次。
失敗推演:tailnet 預設互通時的橫向移動,與只給上傳權限的備份被覆寫
以下是依本章的機制推演的兩種形態。
一個人把服務放在雲端 VPS,監控主機放在家裡,用 Tailscale 把兩台接起來;為了方便,筆電與家裡的 NAS 也裝了 Tailscale,tailnet 維持所有裝置預設互通。監控運作正常,exporter 的讀取、心跳與外部探測都沒有異狀。
雲端 VPS 上的應用程式有一個檔案上傳的漏洞,攻擊者以這個漏洞取得了 shell。tailnet 裡每一台裝置的位址都在 Tailscale 的 100.x.y.z 網段裡,所有裝置預設互通時每一台裝置也看得到其他裝置的名稱,攻擊者不必掃描就找到 NAS 的檔案分享服務;NAS 在家裡從來沒有面對過攻擊者,管理密碼是出廠時設定的那一組。
監控在整個過程中沒有發出任何告警,因為它量的是服務可不可用,而服務一直可用。攻擊者往回連的每一條連線,在 tailnet 的預設政策下都是被允許的連線,tailnet 這一層沒有留下可以告警的紀錄(連線流量紀錄屬於付費方案、預設關閉);NAS 自己的登入紀錄有記下那次登入,只是沒有人在看。發現的時間點是 NAS 上的檔案被加密、出現勒索訊息的那一天。
發現之後的代價由預設互通決定。tailnet 裡每一台裝置都要當成可能被碰過:筆電與監控主機要查,雲端 VPS 要重建,每一台的 Tailscale 金鑰與存放在它們上面的存取憑證都要重發。NAS 的資料救不救得回來,取決於有沒有一份不在 tailnet 裡、NAS 碰不到的備份。
讓這條路徑成立的是兩件事同時存在:tailnet 裡沒有任何被入侵端改不到的限制(政策維持預設的全部放行、NAS 上也沒有防火牆),以及個人裝置與伺服器在同一個 tailnet、而 ACL 沒有把它們分開。任何一件不成立,攻擊者都到不了 NAS:ACL 只允許清單上的連線時,雲端主機連不到 tailnet 裡的其他裝置;只在 NAS 上設防火牆時,NAS 仍在裝置清單裡,但連不進它的檔案分享服務;個人裝置放在另一個 tailnet 時,雲端主機看不到也連不到它們。
另一種形態的後果更不直觀:防護做了,而它擋的不是那一種攻擊。一個人照「存取金鑰只給寫入權限」設定異地備份,金鑰有上傳與列出物件的權限(備份工具要列出既有的物件),沒有刪除權限,物件儲存沒有開版本保留,因為只能上傳的金鑰看起來刪不掉任何一份備份。服務主機被入侵之後,攻擊者用同一把金鑰列出既有的物件名稱,把每一份重新上傳一次,內容換成垃圾;每一次上傳都是權限允許的動作,物件儲存這一側沒有任何被拒絕的請求,存取紀錄裡記下了那些覆寫,只是沒有人在看。沒有人在還原之前打開過舊備份,所以要等到需要還原的那一天才發現:那段期間的每一份備份都已經被覆寫,而覆寫之前的內容不存在任何地方。
常見風險邊界:可達範圍、限制位置、流入的資料、金鑰紀錄與備份寫入憑證
- 列不出連線清單時,可達範圍沒有被決定過,它等於 VPN 的預設,而預設通常是所有裝置互通。
- 只假設雲端被入侵、地端與管理者的裝置沒有各假設一次時,監控主機兼作日常電腦或和家用裝置同在一個區網的配置下,地端被入侵就連得到雲端主機上每一個聽在隧道位址的連接埠。
- 管理者的筆電存著兩台主機的 SSH 金鑰、又拿來日常上網時,它被入侵就等於兩台主機的每一條限制都被改寫,網路上的收窄全部不相干。
- 收窄可達範圍的限制全是被入侵端改得到的限制時,被入侵端被拿下就等於沒有限制;被入侵端存著或取得得到能改 ACL、改業者防火牆或推送部署設定的存取憑證時,存放在別處的限制也在其中。
- 任一台跑 Docker、只放行回應的規則只寫在 INPUT 鏈時,以
0.0.0.0發佈的容器連接埠仍收得到由隧道進來的新連線,攻擊者連得到 Alertmanager 就能建立靜默、連得到資料庫就能讀寫。 - 只放行回應的規則與雲端那一側的限制沒有替清單上由人操作的那幾列開例外時,管理者經由 VPN 連不進自己的主機,最常見的補救是把整條規則拿掉。
- 個人裝置與伺服器在同一個 tailnet、ACL 仍是預設的全部放行時,任何一台個人裝置被入侵都連得到伺服器,反過來也一樣。
- 地端讀取雲端時跟隨轉址、讀取對象寫成雲端改得到的主機名稱、或對象清單由雲端提供時,被入侵的雲端主機能讓地端的程式對區網發出請求。
- 地端讀取雲端時不限制樣本數、標籤與回應大小,一份刻意灌大的回應、或一路累積的時間序列,可以耗盡監控主機的記憶體。
- 監控改成由各主機推送、或心跳監看程式搬到地端時,地端不再是單向發起,只放行回應的規則與它的評估要重做,推送的請求本身也成了不可信的輸入。
- 監控主機被入侵時,心跳監看看不出靜默與偽造的心跳;還送得出服務中斷告警的觀察者,通知若寄到被入侵的機器存著存取憑證或登入著的信箱或推播頻道,同樣會被攔下。
- WireGuard 的金鑰沒有紀錄、或 Tailscale 的伺服器以 tag 認證或關掉金鑰到期而沒有記下時,退役與疑似被入侵的機器不會有人去撤銷,它們的金鑰一直有效。
- Tailscale 的管理帳號只靠密碼登入、或管理者在會被入侵的日常電腦上保持登入時,所有 ACL 的限制都由那一組密碼或那一台電腦決定;又沒有 Tailnet Lock、或簽署節點放在連線清單上的機器時,加入裝置的權力也一樣。
- 異地備份的存取金鑰刪得掉或覆寫得了既有的備份、又沒有 compliance 模式的物件鎖定時,服務主機被入侵就等於備份可以被毀掉;只開版本保留時,舊版本到期的生命週期規則也會替攻擊者完成刪除。
- 拉取備份的工具以 root 執行、版本又停在已公布漏洞之前時,被入侵的服務主機能經由拉取工具寫進備份主機的任意位置。
- 監控主機對網際網路開放 Grafana 或其他連接埠時,連得到每一台主機、存著通知管道祕密的那一台多了一個入口。
延伸閱讀:監控的多主機配置、Tailscale 的運作、機器憑證、備份權限與入口防護
- 兩到三台主機時監控主機放哪裡、經 VPN 讀取與連線中斷的誤判、兩台互相監看:小型服務的兩到三台主機配置
- exporter 綁定在哪個位址、
EXPORTER_BIND_ADDR、exporter 的 TLS 與認證、讀取與推送的取捨:多台主機的指標收集 - Tailscale 的 tailnet 位址模型、直連與 DERP 中繼、依賴第三方協調伺服器的代價:Tailscale 深入
- 從網際網路進來的對外入口,以及 VPN 接進來之後觸及範圍過大的形態:7.3 入口治理與伺服器防護
- 存取金鑰這類機器憑證的登記、機制與輪替:7.32 機器憑證的配發、7.34 機器憑證的機制選型、7.6 秘密管理與機器憑證治理
- 管理者裝置上的金鑰改用需要觸碰才簽章的硬體金鑰:7.39 使用者持有型憑證
- 備份被讀走那一面的權限與加密:7.4 資料保護與遮罩治理;物件鎖定的兩種模式與版本保留的差別:WORM Storage(不可變儲存)
- 兩個大型雲端之間以工作負載身分取代長期金鑰:7.10 Workload Identity 與聯邦信任邊界
- 外部探測的位置與成立條件(本章用它在監控主機被入侵、告警被靜默時,仍送得出服務中斷的告警):4.28 單台主機的監控盲區與失效域以外的觀察者