一種跳板機的實現思路
vivo 網際網路運維團隊- Yang Lei
本文介紹了一種跳板機實現思路,闡述了基本原理,並講解了特點和相對優勢。
一、 跳板機思路簡介
本文所描述的跳板機(下文稱為“jmp”)支援:
-
Linux伺服器
-
Windows伺服器
-
其他終端(MySQL終端、Redis終端、網路裝置終端 等等)
有別於市面上常見的jumpserver方案,使用本文所搭建的跳板機將不會儲存任何Linux伺服器的賬號、密碼、金鑰等資訊,杜絕了資訊洩露的可能。本文最大的特點是 藉助Linux的PAM機制,通過修改Linux伺服器系統層配置,部分接管了Linux系統的身份認證能力 ,關於這一點,下文將詳細描述。
二、背景知識
2.1 Linux 的 PAM 機制
PAM(Pluggable Authentication Modules)機制,是一種廣泛應用於當代Unix、Linux發行版的系統層身份認證框架。通過提供一系列動態連結庫和兩套程式設計介面(Service Programming Interface 和 Application Programming Interface),將系統提供的服務與該服務的認證方式分離,從而使得可以根據需要靈活地給不同的服務配置不同的認證方式而無需更改服務程式。
2.2 PAM 的核心能力
功能 |
應用程式API |
服務模組SPI |
認證管理 |
pam_authenticate |
pam_sm_authenticate |
pam_setcred |
pam_sm_setcred |
|
賬號管理 |
pam_acc_mgmt |
pam_sm_acc_mgmt |
會話管理 |
pam_open_session |
pam_sm_open_session |
pam_close_session |
pam_sm_close_session |
|
口令管理 |
pam_chauthok |
pam_sm_chauthok |
2.3 PAM 模組型別
-
auth
用來對使用者的身份進行識別,如:提示使用者輸入密碼,或判斷使用者是否為root等。
-
account
對帳號的各項屬性進行檢查,如:是否允許登入,是否達到最大使用者數,或是root使用者是否允許在這個終端登入等。
-
session
這個模組用來定義使用者登入前的,及使用者退出後所要進行的操作,如:登入連線資訊、使用者資料的開啟與關閉、掛載檔案系統等。
-
password
使用使用者資訊來更新,如:修改使用者密碼。
2.4 常見 PAM 模組
-
pam_unix.so模組
【auth】提示使用者輸入密碼,並與/etc/shadow檔案相比對,匹配返回0(PAM_SUCCESS)。
【account】檢查使用者的賬號資訊(包括是否過期等),帳號可用時,返回0。
【password】修改使用者的密碼,將使用者輸入的密碼,作為使用者的新密碼更新shadow檔案。
-
pam_cracklib.so模組
這個模組可以插入到一個程式的密碼棧中,用於檢查密碼的強度。
-
pam_loginuid.so模組
用來設定已通過認證的程序的uid,以使程式通過正常的稽核。
-
pam_securetty.so模組
如果使用者要以root登入時,則登入的tty必須在/etc/securetty中之前。
-
pam_rootok.so模組
pam_rootok模組用來認證使用者id是否為0,為0返回PAM_SUCCESS。
-
pam_console.so模組
當用戶登入到終端時,改變終端檔案檔案的許可權.在使用者登出後,再將它們修改回來。
-
pam_permit.so模組
該模組任何時候都返回成功。
-
pam_env.so模組
pam_env允許設定環境變數;預設下若沒有指定檔案,將依據/etc/security/pam_env.conf進行環境變數的設定
-
pam_xauth.so模組
pam_xauth用來在使用者之間轉發xauth-key。
-
pam_stack.so模組
pam_stack可以呼叫另一個服務;即多個服務可以包含到一個設定中,當需要修改時只修改一個檔案就可以了。
-
pam_warn.so模組
pam_warn用來記錄服務、終端使用者、遠端使用者和遠端主機的資訊到系統日誌,模組總是返回PAM_IGNORE、指不希望影響到認證處理。
三、跳板機系統架構
3.1 微服務和高可用設計
3.1.1 微服務設計
整個跳板機系統可拆分為5個服務,和1個元件。
① jmp-api 服務
-
監聽8080埠,提供http介面能力
-
認證某個賬號是否存在且正常
-
認證某個賬號對某臺伺服器是否有登入許可權
-
認證某個賬號對某臺伺服器是否有sudo許可權
-
資料拉取:賬號、主機、危險命令庫等
-
是jmp訪問資料庫的唯一入口
② jmp-ssh 服務
-
監聽2200埠,提供ssh代理能力
-
可直接訪問Linux伺服器、其他終端
③ jmp-socket 服務
-
監聽8080埠,提供websocket/socket.io連線能力
-
通過ssh協議轉發socket.io的流量到jmp-ssh
-
支援網頁終端的連線和訪問
④ jmp-rdp 服務
-
監聽8080埠,提供socket.io連線能力
-
實現rdp代理,以便於操作Windows伺服器
-
支援基於網頁的遠端桌面服務
⑤ jmp-sftp 服務
-
提供檔案上傳下載能力,支援在jmp中通過sftp命令,支援任意sftp客戶端連線
-
訪問S3,以便存取檔案
⑥ jmp-agent 元件
-
部署在每臺Linux伺服器中
-
jmp-agent常駐程序
定時從jmp-api拉取服務和許可權資訊,快取到本地檔案
根據需要檢測檔案改動,確保配置檔案不被惡意修改
-
jmp專用pam模組
提供jmp.so動態庫,為pam模組
安裝指令碼釋放配置檔案,修改/etc/pam.d/xxx檔案,生效jmp的pam模組
接管身份識別和許可權認證,呼叫jmp-api介面以完成鑑權
3.1.2 高可用設計
jmp中任何一個服務都是無狀態的,因而支援異地多機房部署
http協議的服務(jmp-api、jmp-socket、jmp-rdp),通過Nginx配置路由,且配置自動負載均衡策略。
非http的服務(jmp-ssh、jmp-sftp),通過4層負載均衡(lvs、vgw)實現高可用。
自動降級策略
危險命令識別能力存在耗時久的可能性,因此當發現識別危險命令的介面超時,則自動忽略危險命令識別。
身份認證介面超時的情況下,則使用jmp-agent本地快取的身份資訊,如獲取不到本地快取,則使用配置項的預設策略(全部通過或者全部拒絕)。
jmp-agent元件的高可用
由於jmp-agent部署在業務伺服器上,所處環境可能隨時發生變化,因此必須具備較強的適應性(磁碟空間不足、inode滿、記憶體不足、網路不穩定、域名解析異常等等)。
針對磁碟空間或inode不足,jmp-agent可能無法使用本地檔案快取,因此此時選擇降級,忽略快取。
針對網路不穩定問題,jmp-agent選擇增加同jmp-api、jmp-ssh的通訊超時,同時可降級鑑權,確保操作不受影響。
針對解析異常問題,jmp-agent無法通過域名同服務互動,此時使用內建的固定ip同服務互動。
3.2 跳板機各子服務互動圖
從圖中可見,作為核心服務的jmp-ssh承載了ssh流量的代理轉發,將來自使用者ssh客戶端、jmp-socket服務的ssh流量轉發到目標伺服器上,並將來自目標伺服器的返回結果送達回ssh客戶端、jmp-socket服務。因此,可在jmp-ssh服務上識別來自使用者的危險命令,在送達目標伺服器之前就給出告警或者直接攔截,避免惡意操作或者誤操作給業務造成影響。
圖中的jmp-api作為同資料庫和快取直接互動的服務,在整個系統中承擔資料介面和管理端的角色,接受來自全量伺服器中jmp-agent元件的使用者身份鑑別和許可權校驗請求,是整個系統中的控制中樞。
jmp-api也同時提供的許可權設定能力,通過與流程系統對接,可方便的為人員/部門申請機器/服務/專案的登入許可權或root許可權,此外,jmp-api也對登入許可權和root許可權的可申請人做出限制,針對不同專案/服務,對許可權有效時間做出限制,嚴格控制權限粒度。
由於同一個專案/服務往往由同一個組的人維護,因此jmp-api內建了預設的許可權策略,可允許專案/服務的負責人對專案/服務直接擁有登入許可權,而無需申請;僅支援對應專案/服務的運維負責人預設擁有root許可權,其他所有人如果希望獲取root許可權,則必須經過申請,由對應服務的運維負責人審批。
圖中的jmp-agent是部署在每一臺Linux伺服器上的,通過在Linux上修改/etc/pam.d/sshd、/etc/
pam.d/remote、/etc/pam.d/sudo等等檔案,讓 jmp.so (屬於jmp-agent.rpm或jmp-agent.deb的一部分)接管ssh服務、sudo程式等關鍵系統程式的身份識別、許可權認證。從而使得在不增加/etc/passwd、/etc/shadow內容的前提下實現了在任意一臺伺服器上識別出所有人員身份的能力。
圖中的jmp-rdp僅作為Windows伺服器的rdp代理服務,並提供基於web的遠端桌面能力。
圖中的jmp-socket則提供基於web的Linux伺服器操作終端,從而讓使用者不使用ssh客戶端也能夠方便地登入伺服器。
四、核心設計思路
4.1 登入跳板機
-
使用者使用ssh客戶端登入到jmp-ssh服務,與jmp-ssh服務互動。
-
jmp-ssh服務獲得ssh會話建立過程中的賬號、加密後密碼、二次認證資訊。
-
jmp-ssh服務訪問jmp-api服務,提交賬號、加密後密碼、二次認證資訊,以便知曉該使用者是否有登入jmp的許可權。
4.2 登入目標伺服器
-
僅當用戶已經登入到jmp-ssh或者已經通過了jmp-socket的前端身份認證時方可登入目標伺服器。
-
使用者在jmp-ssh提供的偽終端下輸入ssh xxxx(xxxx為目標伺服器的主機名或者IP地址)。
-
jmp-ssh通過ssh連線到目標伺服器,自動攜帶使用者名稱資訊,嘗試建立會話。
-
由於目標伺服器上的jmp-agent接管了sshd的身份識別和許可權認證,因此jmp.so獲取ssh會話建立過程中的使用者名稱,將使用者名稱和本機IP地址資訊加密,呼叫jmp-api介面進行許可權認證。
-
jmp-api根據內建的策略,以及查詢授權表,斷定該使用者對該機器是否有登入許可權。
-
jmp-agent得到鑑權結果,對有許可權的,則ssh會話建立成功,否則會話建立失敗。
-
jmp-ssh獲得會話建立結果和原因,返回給使用者ssh終端。
4.3 命令互動
-
僅當用戶已經登入到某臺機器時,才可命令互動。
-
當用戶在ssh客戶端上敲入字元,傳遞到jmp-ssh,jmp-ssh判斷語句是否結束。
-
當語句結束,則jmp-ssh根據該機器的危險命令規則,匹配使用者輸入的語句,決定告警、攔截、通過。
-
jmp-ssh將通過的語句或需要告警的語句傳遞到目標伺服器,目標伺服器執行並返回結果。
4.4 切換使用者 / 特權賬號
-
僅當用戶已經登入到某臺機器時,才可能觸發切換使用者的行為。
-
當用戶在ssh客戶端執行sudo xxxx、su、id等等命令時,jmp-ssh透傳命令到目標伺服器上。
-
目標伺服器上的sshd程序執行sudo xxxx、su、id等等命令,由於目標伺服器上已經被jmp-agent接管了身份失敗和許可權認證,因此由jmp.so獲取登入使用者名稱、當前使用者名稱、本機地址資訊、目標使用者名稱資訊,調jmp-api的介面進行sudo許可權認證。
-
jmp-api判斷該使用者是否擁有對該機器切換到xx賬號的許可權(如是否有root許可權)。
-
sudo、su、id等程序通過jmp.so獲得了鑑權結果,決定是否切換使用者。
4.5 使用網頁互動
-
僅針對使用者已經通過網頁完成了登入(如sso)的情況。
-
使用者通過網頁訪問jmp-socket服務。
-
jmp-socket服務獲取使用者名稱資訊、網頁登入sso資訊,提交給jmp-api,生成一個臨時登入憑證。
-
jmp-socket訪問jmp-ssh,提交臨時登入憑證。
-
jmp-ssh發起登入的二次認證,等待使用者完成二次認證。
-
jmp-socket在使用者完成二次認證後,承擔了ssh客戶端的角色,與jmp-ssh互動。
4.6 危險命令攔截
-
jmp-ssh在使用者已經登入到目標伺服器後,在該會話內,載入目標機器對應服務的危險命令規則,初始化正則匹配邏輯。
-
jmp-ssh在使用者輸入語句結束後,根據該機器的危險命令規則,匹配使用者輸入的語句。
-
jmp-ssh根據危險命令規則匹配後策略,決定對該輸入做如下處理:告警、攔截、通過。
-
對於通過的,jmp-ssh傳遞命令到目標伺服器。
-
對於告警的,jmp-ssh傳遞命令到目標伺服器,但是向用戶、使用者的直屬領導、jmp系統管理員傳送危險命令告警。
-
對於攔截的,jmp-ssh拒絕傳遞命令,同時向用戶、使用者的直屬領導、jmp系統管理員傳送危險命令告警。
4.7 非Linux伺服器的跳板機
-
Windows伺服器
對於Windows伺服器,使用jmp-rdp服務,將rdp協議資料轉成由socket.io承載的應用資料(依賴Apache Guacamole),並通過web頁面的Canvas展示實時影象並接受鍵盤滑鼠事件。
-
MySQL終端和Redis終端
僅支援部署在Linux伺服器上的MySQL和Redis。
在伺服器上通過mysql.sock,使jmp-agent連線到本地MySQL服務,jmp-agent轉發標準輸入和標準輸出到jmp-ssh。
在伺服器上通過redis.sock,使jmp-agent連線到本地Redis服務,jmp-agent轉發標準輸入和標準輸出jmp-ssh。
該方法理論上支援任意可通過unixsocket連線的服務。
-
網路裝置管理終端
對於網路終端,則jmp-ssh讀取jmp-api介面,獲取對應網路裝置的連線資訊(協議型別、賬號資訊等),實現連線和操作。
五、許可權規則和審批鏈路設計
5.1 預設擁有的許可權
無需申請,即可擁有的許可權。
授權的主體 |
許可權的目標 |
許可權的型別 |
服務負責人 |
服務的線上主機 |
登入許可權 |
服務的線下主機 |
登入許可權+ROOT許可權 |
|
專案負責人 |
專案的線上主機 |
登入許可權 |
專案的線下主機 |
登入許可權+ROOT許可權 |
|
服務的運維 |
服務的線上主機 |
登入許可權+ROOT許可權 |
服務的線下主機 |
||
專案的運維 |
專案的線上主機 |
登入許可權+ROOT許可權 |
專案的線下主機 |
5.2 許可權申請的審批鏈路
-
如果沒有預設許可權,但是需要登入機器,或者需要使用ROOT許可權,則需要申請。
-
如果為組織申請許可權,則該組織(部門)下所有成員均有鎖申請的許可權。
這裡明確了申請流程的審批鏈路:
六、這種實現思路的優點
6.1 操作方便,體驗較好
通過該思路所建設的跳板機系統,操作上比較方便,即支援了ssh、又相容了rdp,同時提供了網頁端操作入口,體驗較好。同時,由於採用微服務架構,服務間耦合較小,比較容易做到高可用,從而很少出現卡頓、延時等現象,整體穩定性可靠,體驗上有保證。
6.2 安全可靠,容易審計
本文的最大特點就是在目標伺服器上使用了pam機制,通過jmp.so接管多個服務的身份識別和許可權認證,從而做到了 在不修改標準命令的基礎上,統一接管許可權,統一管控。 並且做到了在登入到目標機器上後,可以進一步ssh到其他伺服器,所有的互動過程全程記錄,所有的操作命令都會被記錄下來。
由於通過該思路所實現的跳板機 直接將使用者名稱作為目標伺服器ssh會話的登入名 ,所以在系統內部所記錄的日誌裡也是直接的使用者名稱,而不是如jumpserver等方案的統一賬號,這種方式下,更容易定位到操作軌跡的真實執行人,一目瞭然。
危險命令攔截功能,更是可以很大程度上避免惡意操作或者破壞性強的誤操作,為業務穩定性增加一層保障。
6.3 服務間職責明確
由於採用了微服務架構,可以做到每個服務的橫向擴充套件,從而做到了通過擴容服務的方式管控更多的機器。服務間職責明確,可根據需要裁減jmp-rdp、jmp-socket、jmp-sftp,也可以根據需要增加新的服務,適配性較好。
七、總結與展望
隨著伺服器規模的擴大,如何管理這些伺服器成為一個越來越重要的問題。針對伺服器的登入訪問,本文介紹了跳板機的一種實現思路,並描述了該思路的優點和獨特之處。通過該思路可以一定程度上構建簡單、易用且高可用的跳板機,從而解決伺服器登入問題。如果讀者對這個實現思路感興趣,或者有任何疑問,歡迎與我們溝通。我們也非常願意與各位一起學習,研究技術。
- HttpClient 在vivo內銷瀏覽器的高併發實踐優化
- electron 應用開發優秀實踐
- Kotlin協程解析系列(上):協程排程與掛起
- Redis 定長佇列的探索和實踐
- 從RabbitMQ平滑遷移到RocketMQ技術實戰
- 基於微前端qiankun的多頁籤快取方案實踐
- 推薦系統-協同過濾在Spark中的實現
- 伺服器記憶體故障預測居然可以這樣做!
- 工作流引擎在vivo營銷自動化中的應用實踐 | 引擎篇03
- vivo官網APP全機型UI適配方案
- RocketMQ之消費者啟動與消費流程
- vivo官網APP全機型UI適配方案
- 工作流引擎在vivo營銷自動化中的應用實踐 | 引擎篇03
- RocketMQ之消費者啟動與消費流程
- CSS Houdini:用瀏覽器引擎實現高階CSS效果
- 初探 Redis 客戶端 Lettuce:真香!
- Lepton 無失真壓縮原理及效能分析
- 從0到1建設智慧灰度資料體系:以vivo遊戲中心為例
- Lepton 無失真壓縮原理及效能分析
- 從0到1建設智慧灰度資料體系:以vivo遊戲中心為例