如果您使用 Linux,那麼您就已經可以使用那些創建定制備份解決方案的極其強大的工具。本文中的方案,可以讓您使用幾乎每個 Linux 發行版本都附帶的開放源代碼工具來執行從簡單的到更高級而且安全的網絡備份。
簡單備份
本文按照一步一步的方法來進行講述,只要您遵循那些基本的步驟,此方法會是非常直觀的。
在研究更高級的分布式備份解決方案之前,讓我們首先來看一個簡單而強大的存檔機制。讓我們來分析一個名為 arc 的方便的腳本,它可以讓我們在 Linux shell 提示符中創建備份快照。
#!/bin/sh tar czvf $1.$(date +%Y%m%d%-H%M%S).tgz $1 exit $?
清單 1. arc shell 腳本 arc 腳本接收一個單獨的文件或目錄名作為參數,創建一個壓縮的存檔文件,同時將當前日期嵌入到生成的存檔文件的名字之中。例如,如果您有一個名為 beoserver 的目錄,您可以調用 arc 腳本,將 beoserver 目錄名傳遞給它以創建一個壓縮的存檔文件,如: beoserver.20040321-014844.tgz
使用 date 命令是為了嵌入一個日期和時間戳以幫助您組織存檔文件。日期的格式是年、月、日、小時、分、秒 —— 雖然秒域的使用有一些多余。查看 data 命令的手冊( man date)來了解其他選項。另外,在清單 1 中,我們向 tar 傳遞了 -v(verbose)選項。這就使得 tar 顯示出它正在存檔的文件。如果您喜歡靜默地進行備份,那麼刪除這個 -v 選項。
$ ls arc beoserver $ ./arc beoserver beoserver/ beoserver/bookl.dat beoserver/beoserver_ab_off beoserver/beoserver_ab_on $ ls arc beoserver beoserver.20040321-014844.tgz
清單 2. 存檔 beoserver 目錄 高級備份
這個簡單備份是實用的;不過,它仍然包含一個人工備份的過程。行業最佳經驗通常建議將數據備份到多個媒體上,並備份到分開的不同地理位置。中心思想是避免依賴於任何一個單獨的存儲媒體或單獨的位置。
在下一個例子中我們將應對這一挑戰,我們將分析一個如圖 1 所示的假想的分布式網絡,它展示了對兩台遠程服務器和一台離線存儲服務器的系統管理。
圖 1. 分布式網絡
服務器" #1 和 #2 上的備份文件將安全地傳輸到離線存儲服務器上,而且整個分布式備份過程將在沒有人工干涉的情況下定期進行。我們將使用一組標准的工具(開放安全 shell 工具套件(OpenSSH)的一部分),以及磁帶存檔器(tar)和 cron 任務調度服務。我們的全部計劃是,使用 cron 進行調度,使用 shell 程序和 tar 應用程序完成備份過程,使用 OpenSSH 安全 shell(ssh)加密進行遠程訪問、認證、安全 shell 拷貝(scp)以自動完成文件傳輸。要獲得另外的資料請務必查看每個工具的手冊。 使用公鑰/私鑰進行安全的遠程訪問
在數字安全的上下文中,密鑰(key)指的是用來加密或解密其他數據片斷的一個數據片斷。公鑰私鑰模式的有趣之處在於,使用公鑰加密的數據,只有用相應的私鑰才可以解密。您可以自由地發布一個公鑰,這樣別人就可以對發送給您的消息進行加密。公鑰/私鑰模式徹底改變了數字安全的原因之一是,發送者和接收者不必再共享一個通用的密碼。除了其他方面的貢獻,公鑰/私鑰加密使用電子商務和其他安全傳輸成為可能。在本文中,我們將創建並使用公鑰和私鑰來創建一個非常安全的分布式備份解決方案。
要進行備份過程的每台機器都必須運行 OpenSSH 安全 shell 服務(sshd),同時讓 22 端口可以通過任何內部防火牆被訪問。如果您訪問遠程的服務器,那麼很有可能您正在使用安全 shell。
我們的目標將是,不需要人工提供密碼就可以安全地訪問機器。一些人認為最簡單的辦法是設置無密碼的訪問:不要這樣做。這樣做不安全。不用那樣,本文中我們將使用的方法可能會占用您大約一個小時的時間,建立起一個與使用“無密碼”帳號同樣方便的系統 —— 不過它是公認非常安全的。
讓我們首先確保 OpenSSH 已經安裝,接下來查看它的版本號。完成本文時,最新的發行的 OpenSSH 是 2004 年 2 月 24 日發布的版本 3.8。您應該考慮使用一個較新的而且穩定的發布版本,至少所用的版本應該要比版本 2.x 新。訪問 OpenSSH Security 網頁以獲得關於特定舊版本的缺陷的細節(請參閱本文後面的 參考資料 中的鏈接)。到目前為止,OpenSSH 是非常穩定的,而且已經證明不存在其他 SSH 工具所報告的很多缺陷。
在 shell 提示符中,輸入 ssh 並給出重要的 V 選項來檢查版本號:
$ ssh -V OpenSSH_3.5p1, SSH protocols 1.5/2.0, OpenSSL 0x0090701f
如果 ssh 返回的版本號大於 2.x,則機器處於相對良好的狀態。無論如何,建議您所有的軟件都使用最新的穩定版本,這對於安全相關的軟件來說尤其重要。
我們的第一個步驟是,使用將會有特權訪問服務器 1 和 2 的帳號登錄到離線存儲服務器機器(見圖 1)。
$ ssh [email protected]
登錄到離線存儲服務器以後,使用 ssh-keygen 程序並給出 -t dsa 選項來創建一個公鑰/密鑰對。 -t 選項是必須的,用來指定我們要生成的密鑰類型。我們將使用數字簽名算法(Digital Signature Algorithm,DSA),它讓我們可以使用更新的 SSH2 協議。參閱 ssh-keygen 手冊以獲得更多細節。
在 ssh-keygen 執行的過程中,在詢問您口令(passphrase)之前,將提示您輸入 ssh 密鑰存儲的位置。當詢問在何處存儲密鑰時只需要按下回車鍵,然後 ssh-keygen 程序將創建一個名為 .ssh 的隱藏目錄(如果原來不存在),以及兩個文件,一個公鑰文件和一個私鑰文件。
ssh-keygen 的一個有趣特性是,當提示輸入一個口令時,它讓您可以只是簡單地按下回車鍵。如果您沒有給出口令,那麼 ssh-keygen 將生成沒有加密的密鑰!如您所想,這不是個好主意。當要求輸入口令時,確保輸入一個足夠長的字符消息,最好包含混合字符而不僅僅是一個簡單的密碼字符串。
[offsite]:$ ssh-keygen -t dsa Generating public/private dsa key pair. Enter file in which to save the key (/home/accountname/.ssh/id_dsa): Enter passphrase (empty for no passphrase): (enter passphrase) Enter same passphrase again: (enter passphrase) Your identification has been saved in /home/accountname/.ssh/id_dsa. Your public key has been saved in /home/accountname/.ssh/id_dsa.pub. The key fingerprint is: 7e:5e:b2:f2:d4:54:58:6a:fa:6b:52:9c:da:a8:53:1b accountname@offsite
清單 3. 永遠選擇好的口令 由於 ssh-keygen 生成的 .ssh 目錄是一個隱藏的“dot”目錄,所以要給 ls 命令傳入一個 -a 選項來查看新創建的目錄:
[offsite]$ ls -a . .. .bash_logout .bash_profile .bashrc .emacs .gtkrc .ssh
進入隱藏的 .ssh 目錄並列出其內容:
[offsite]$ cd .ssh [offsite]$ ls -lrt id_dsa id_dsa.pub
現在,在隱藏的 .ssh 目錄中,我們已經擁有了一個私鑰(id_dsa)和一個公鑰(id_dsa.pub)。您可以使用 vi 或 emacs 等文本編輯工具或者簡單地使用 less 或 cat 命令來分析每個密鑰文件的內容。您將看到由混合字符構成的內容已經經過了 base64 編碼。
然後,我們需要將公鑰拷貝並安裝到服務器 1 和 2 上。不要使用 ftp。更合理的是,使用安全拷貝程序來將公鑰傳送到每一台遠程機器上。
[offsite]$ scp .ssh/id_dsa.pub [email protected]:offsite.pub [email protected]'s password: (enter password, not new passphrase!) id_dsa.pub 100% |*****************************| 614 00:00 [offsite]$ scp .ssh/id_dsa.pub [email protected]:offsite.pub [email protected]'s password: (enter password, not new passphrase!) id_dsa.pub 100% |*****************************| 614 00:00
清單 4. 將公鑰安裝到遠程服務器上 在安裝完新的公鑰後,我們就可以使用創建私鑰和公鑰時指定的口令來登錄到每一台機器。現在,登錄到每台機器,並將 offsite.pub 文件的內容附加到一個名為 authorized_keys 的文件中,這個文件存儲在每台遠程機器的 .ssh 目錄下。我們可以使用一個文本編輯器或者簡單地使用 cat 命令來將 offsite.pub 文件的內容附加到 authorized_keys 文件:
[offsite]$ ssh [email protected] [email protected]'s password: (enter password, not new passphrase!) [server1]$ cat offsite.pub >> ./ssh/authorized_keys
清單 5. 將 offsite.pub 添加到已授權密鑰列表 接下來的步驟是考慮一些額外的安全性。首先,我們修改 .ssh 的訪問權限,以使得只有所有者有讀、寫和執行的權限。然後,我們確保 authorized_keys 文件只能由所有者來訪問。最後,將先前上傳的 offsite.pub 密鑰文件刪除,因為再也不需要它了。確保設置適當的訪問權限很重要,因為 OpenSSH 服務器可能會拒絕使用具有不安全訪問權限的密鑰。
[server1]$ chmod 700 .ssh [server1]$ chmod 600 ./ssh/authorized_keys [server1]$ rm offsite.pub [server1]$ exit
清單 6. 使用 chmod 修改權限 在服務器 2 上完成同樣的步驟後,我們就可以返回到離線存儲機器上來測試新的口令類型的訪問。在離線服務器上您可以輸入下面的內容:
[offsite]$ ssh -v [email protected] 在檢驗您的帳號現在可以使用新的口令而不是原來的密碼來訪問遠程的服務器時,使用 -v 或 verbose 標記選項來顯示調試信息。調試輸出除了能讓您在一個高的層面上觀察到認證過程是如何工作的之外,還可以顯示出您可以以其他方式無法得到的重要信息。在以後的連接中您可能並不需要指定 -v 標記;但是在測試連接時它相當有用。
使用 ssh-agent 自動化機器訪問
ssh-agent 程序如同一個看門人,它根據需要安全地提供對安全密鑰的訪問。ssh-agent 啟動後,它就會在後台運行,並且可以由 ssh 和 scp 程序等其他 OpenSSH 應用程序所使用。這就使得 ssh 程序可以請求一個已經解密了的密鑰,而不是在每次需要時向您詢問私鑰的安全口令。
讓我們來仔細研究一下 ssh -agent。ssh-agent 運行時它會輸出 shell 命令:
[offsite]$ ssh-agent SSH_AUTH_SOCK=/tmp/ssh-XX1O24LS/agent.14179; export SSH_AUTH_SOCK; SSH_AGENT_PID=14180; export SSH_AGENT_PID; echo Agent pid 14180;
清單 7. ssh-agent 應用 我們可以使用 shell 的 eval 命令來讓 shell 執行 ssh-agent 顯示的輸出命令:
[offsite]$ eval `ssh-agent` Agent pid 14198
eval 命令告訴 shell 去評價(執行)ssh-agent 程序生成的命令。確保您指定的是反引號(`)而不是單引號!執行後,eval `ssh-agent` 語句將返回代理的進程標識符。在幕後,SSH_AUTH_SOCK 和 SSH_AGENT_PID shell 變量已經被導出而可以使用。您可以將它們顯示在 shell 控制台中來查看它們的值:
[offsite]$ echo $SSH_AUTH_SOCK /tmp/ssh-XX7bhIwq/agent.14197
$SSH_AUTH_SOCK (SSH Authentication Socket 的縮寫)是一個本地套接字的位置,應用程序可以通過它來與 ssh-agent 通信。將 eval `ssh-agent` 語句加入到您的 ~/.bash_profile 文件以確保 SSH_AUTH_SOCK 和 SSH_AGENT_PID 始終被注冊。
ssh-agent 現在就已經成為一個後台進程,可以用 top 和 ps 命令查看得到。
現在我們就已經可以使用 ssh-agent 共享我們的口令。為此,我們必須使用一個名為 ssh-add 的程序,這個程序將我們的口令添加(發送)到運行著的 ssh-agent 程序。
[offsite]$ ssh-add Enter passphrase for /home/accountname/.ssh/id_dsa: (enter passphrase) Identity added: /home/accountname/.ssh/id_dsa (/home/accountname/.ssh/id_dsa)
清單 8. 用於免口令登錄的 ssh-add 現在,當我們訪問 server1 時,不會再被提示輸入口令:
[offsite]$ ssh [email protected] [server1]$ exit
如果您還不相信,那麼嘗試去掉(kill -9)ssh-agent 進程,然後重新連接 server1。這一次,您將注意到,server1 將會詢問存儲在 .ssh 目錄下 id_dsa 中的私鑰的口令:
[offsite]$ kill -9 $SSH_AGENT_PID [offsite]$ ssh [email protected] Enter passphrase for key '/home/accountname/.ssh/id_dsa': 使用 keychain 簡化密鑰訪問
到現在為止,我們已經了解了幾個 OpenSSH 程序(ssh、scp、ssh-agent 和 ssh-add),而且我們已經創建並安裝了私鑰和公鑰來啟用一個安全而且自動的登錄過程。您可能已經意識到,大部分設置工作只需要進行一次。例如,創建密鑰、安裝密鑰、通過 .bash_profile 執行 ssh-agent 的過程在每台機器只需要進行一次。那真是好消息。
不太理想的消息是,我們每次登錄到離線的機器上時,都必須調用 ssh-add,而且,ssh-agent 與我們將要用來自動化備份工作的 cron 調度進程並不直接兼容。cron 進程不能與 ssh-agent 通信的原因是,cron 作業是作為 cron 的子進程來執行,這樣它們就不會繼承 $SSH_AUTH_SOCK shell 變量。
幸運的是,有一個解決方案不但可以消除 ssh-agent 和 ssh-add 的局限,而且可以讓我們使用 cron 來自動進行各種需要對其他機器進行安全地無密碼訪問的過程。在他 2001 年發表的三篇 developerWorks 系列文章中,即 OpenSSH key management(參閱 參考資料 以獲得鏈接),Daniel Robbins 介紹了一個名為 keychain 的 shell 腳本,它是 ssh-add 和 ssh-agent 的一個前端,簡化了整個無密碼的過程。隨著時間的過去,keychain 腳本已經經歷了很多改進,現在由 Aron Griffis 維護,其最新的 2.3.2-1 發布版本公布於 2004 年 6 月 17 日。
keychain shell 腳本太長以致於無法在本文中列出,因為精心編寫的腳本中包括了很多錯誤檢測、豐富的文檔以及非常多的跨平台代碼。不過,keychain 可以自項目的 Web 站點上方便地下載得到(參閱 參考資料 以獲得鏈接)。
下載並安裝了 keychain 後,使用它就很簡單了。只需要登錄到每台機器並將下面兩行添加到每個 .bash_profile 文件:
keychain id_dsa . ~/.keychain/$HOSTNAME-sh
在您第一次重新登錄到每台機器時,keychain 將向您詢問口令。不過,除非機器被重新啟動,否則,以後再登錄時,keychain 將不會再要求您重新輸入口令。最好的是,cron 任務現在可以使用 OpenSSH 命令來安全地訪問遠程的機器,而不需要交互地使用口令。更好的安全和更容易的使用,現在我們已經兼得。
KeyChain 2.3.2; http://www.gentoo.org/projects/keychain Copyright 2002-2004 Gentoo Technologies, Inc.; Distributed under the GPL * Initializing /home/accountname/.keychain/localhost.localdomain-sh file... * Initializing /home/accountname/.keychain/localhost.localdomain-csh file... * Starting ssh-agent * Adding 1 key(s)... Enter passphrase for /home/accountname/.ssh/id_dsa: (enter passphrase)
清單 9. 在每台機器上初始化 腳本化備份過程
我們的下一個任務是創建執行必要的備份過程的 shell 腳本。目標是執行服務器 1 和 2 的完全數據庫備份。在我們的例子中,每個服務器都運行著 MySQL 數據庫服務器,我們使用 mysqldump 命令行工具來將一些數據庫表導出到一個 SQL 輸入文件中。
#!/bin/sh # change into the backup_agent directory where data files are stored. cd /home/backup_agent # use mysqldump utility to export the sites database tables mysqldump -u sitedb -pG0oDP@sswrd --add-drop-table sitedb --tables tbl_ccode tbl_machine tbl_session tbl_stats > userdb.sql # compress and archive tar czf userdb.tgz userdb.sql
清單 10. 服務器 1 的 dbbackup.sh shell 腳本 在服務器 2 上,我們將設置一個類似的腳本來備份站點數據庫中給出的獨有表單。每個腳本都通過下面的步驟標記為可執行的:
[server1]:$ chmod +x dbbackup.sh
在服務器 1 和 2 上設置了 dbbackup.sh 後,我們返回到離線的數據服務器,在那裡我們將創建一個 shell 腳本來調用各個遠程 dbbackup.sh 腳本並隨後傳輸壓縮的(.tgz)數據文件。
#!/bin/sh # use ssh to remotely execute the dbbackup.sh script on server 1 /usr/bin/ssh [email protected] "/home/backup_agent/dbbackup.sh" # use scp to securely copy the newly archived userdb.tgz file # from server 1. Note the use of the date command to timestamp # the file on the offsite data server. /usr/bin/scp [email protected]:/home/backup_agent/userdb.tgz /home/backups/userdb-$(date +%Y%m%d-%H%M%S).tgz # execute dbbackup.sh on server 2 /usr/bin/ssh [email protected] "/home/backup_agent/dbbackup.sh" # use scp to transfer transdb.tgz to offsite server. /usr/bin/scp [email protected]:/home/backup_agent/transdb.tgz /home/backups/transdb-$(date +%Y%m%d-%H%M%S).tgz
清單 11. 用在離線的數據服務器上的 backup_remote_servers.sh shell 腳本 backup_remote_servers.sh shell 腳本使用 ssh 命令來執行遠程服務器上的腳本。由於我們已經設置的無密碼的訪問,ssh 命令可以通過離線的服務器在服務器 1 和 2 上遠程地執行命令。感謝 keychain,整個認證過程現在可以自動完成。 調度
我們的下一個步驟,也是最後一個步驟,是調度 backup_remote_servers.sh shell 腳本在離線的數據存儲服務器上的執行。我們將向 cron 調度服務器中添加兩個條目,以要求每天執行備份腳本兩次,3:34 執行一次,8:34 再執行一次。在離線的服務器上使用 edit(-e)選項調用 crontab 程序。
[offsite]:$ crontab -e
crontab 調用 VISUAL 或 EDITOR shell 環境變量所指定的默認的編輯器。然後,輸入兩個條目並保存和關閉文件。
34 3 * * * /home/backups/remote_db_backup.sh 34 20 * * * /home/backups/remote_db_backup.sh
清單 12. 離線的服務器上的 Crontab 條目 一個 crontab 行包括兩個主要部分,時間表部分和後面的命令部分。時間表分為多個域,用來指定一個命令應該何時執行:
+---- minute | +----- hour | | +------ day of the month | | | +------ month | | | | +---- day of the week | | | | | +-- command to execute | | | | | | 34 3 * * * /home/backups/remote_db_backup.sh
清單 13. Crontab 格式 檢驗您的備份
您應該對備份進行例行地檢查,以確保程序正確進行。自動程序可以使煩瑣的工作得到避免,但是永遠不能因此而懶惰。如果您的數據值得備份,那麼它也值得您時常進行抽樣檢查。
考慮添加一個 cron 作業來提醒您自己至少每個月對備份進行一次檢查。另外,經常修改安全密鑰也是一個好主意,同樣您也可以調度一個 cron 作業來提醒您做這件事。
另外的安全防范
要獲得更高的安全性,可以考慮在每台機器上安裝並配置一個入侵檢測系統(ntrusion Detection System,IDS),比如 Snort。可以預見,當入侵正在發生或者近期發生過時,IDS 將會通知您。IDS 到位後,您將可以添加其他層次上的安全,比如對您的備份進行數字簽名和加密。
GNU Privacy Guard(GnuPG)、OpenSSL 和 ncrypt 等流行的開放源代碼工具可以支持通過 shell 腳本對存檔文件進行加密,不過不建議在沒有 IDS 提供的額外層次保護的情況下這樣做(參閱 參考資料 以獲得關於 Snort 的更多信息)。
結束語
本文向您展示了如何讓您的腳本在遠程服務器執行以及如何執行安全自動的文件傳輸。我希望您能由此得到靈感而開始考慮保護您自己的重要數據,並使用 OpenSSH 和 Snort 等開放源代碼工具來構建新的解決方案。