作者彙整: dada

關於「dada」

I'm dada

使用 SSH 配合憑證來遠端複製檔案 (scp)

以下整理 UNIX 系統上面使用 SSH 配合憑證來遠端複製檔案

假設有一台主機叫做 X,多台要被複製檔案的機器是 A, B, C。理論上這種情況下 X 的安全等級應該要高於 A, B, C,不過這並不一定


安全等級的差異牽涉到要由哪台機器去信任哪一台機器

以 A, B, C 去信任 X 為例,作法如下:

在 X 上面用某個帳號產生一組 Private/Public Key,然後把 Public Key 發佈給 A, B, C,要求 A, B, C 去信任這一個 Public Key


更進一步,還能限制這個 Public Key 只能作某項動作…

以下是詳細的作法


[步驟一] 產生 Public/Private Key

先在 X 上面開設一個帳號,例如 backup (或者使用現有的任何一個帳號也可以) 然後使用 ssh-keygen -t dsa 命令產生一組 Private/Public Key,內定會在 .ssh/ 目錄下產生兩個檔案: id_dsa id_dsa.pub (不要設定 passphrase)

由於之後會限制一組 Key 只能作特定一件工作,因此我們再執行一次 ssh-keygen -t dsa 產生另一組 Private/Public Key

記得把 Key 儲存成不同的檔名以供辨識,例如我們可以把 .ssh 目錄下的 Key 更名成:

id_cmd1 id_cmd1.pub => 用來執行命令1

id_cmd2 id_cmd2.pub => 用來執行命令2

[步驟二] 設定信任關係

接下來,我們就可以把 id_cmd1.pub 及 id_cmd2.pub 的內容複製到 A, B, C 上面了

首先在 A 上面,建立特定一個帳號,例如 backup,然後執行 vipw (FreeBSD),把 password 欄位置換成 * 星號:


backup:*:1010:50::0:0:backup user:/home/backup:/bin/sh


這樣的話,這個帳號雖然擁有 shell,但也不能隨意用 password 來登入了,只能從 local 用 su – backup 或從遠端用 ssh public key 來進入使用

然後把 id_cmd1.pub 及 id_cmd2.pub 合成一個檔案,放在/home/backup/.ssh/authorized_keys 中:


ssh-dss AAAAB3NzaC1kc3MAAACBAPWP8FS0iatXx3z7o/alB1pI8a…. backup@X
ssh-dss AAAAB3NzaC1kc3MAAACBALW8J12p4Jebc5sAPDhiokTy2…. backup@X


這樣寫,代表 A 上面的 backup 這個帳號信任這組 public/private key,任何人持有該相對應的 private key,都可以 ssh 進入 backup 在 A 上面的帳號

既然可以 ssh,當然也可以自由使用 scp 來複製檔案了,而且使用任何一組 Key 都可以進行沒有限制的作業,


例如從 X 上面可以用 ssh 登入 A:

ssh -i /home/backup/.ssh/id_cmd1 backup@A

ssh -i /home/backup/.ssh/id_cmd2 backup@A


[步驟三] 限制只允許特定動作

由於 ssh 的權限太大,而我們只是要複製檔案 (scp) 而已,因此我們可以再作一些限制。

改寫 /home/backup/.ssh/authorized_keys,在每個 key 開頭加上特定指令,例如

command=”scp -f /tmp/backup.tgz”,no-port-forwarding,no-pty ssh-dss AAAAB3NzaC1kc3MAAACBAPWP8FS…. backup@X
command=”scp -t /tmp/info.tgz”,no-port-forwarding,no-pty ssh-dss AAAAB3NzaC1kc3MAAACBALW8J12p4J…. backup@X

上面 scp -f 代表 copy 的來源, scp -t 代表 copy 的目的地,目的地也可以是一個目錄,但是要再加上 -d 選項

這樣的話,不管對方下了什麼指令,A 都只會執行前面 command 內的指令,所以…. X 只能對 A 進行下列兩種工作,而且都要指定正確的 Key 才能完成:

scp -i /home/backup/.ssh/id_cmd1 backup@A:/tmp/backup.tgz backup-A.tgz

scp -i /home/backup/.ssh/id_cmd2 data.tgz backup@A:/tmp/info.tgz

上面 scp -i 就是指定該動作要使用的身份,後面接上相對應的 private key 即可


事實上,由於每個 key 只會被對方的機器允許作特定的事情,因此遠方的目錄及檔案名稱甚至可以省略,例如:

scp -i /home/backup/.ssh/id_cmd1 backup@A: backup-A.tgz

scp -i /home/backup/.ssh/id_cmd2 data.tgz backup@A:

測試沒有問題後,把 authorized_keys 同樣複製一份到 B, C 上面就大功告成了

備註: 如果您要大量複製、備份檔案,請參考另外一篇「使用 SSH 配合憑證來遠端備份檔案 (rsync)

Replication of MySQL database

MySQL database 自 3.23.15 版以後就支援 Replication 功能,使用 Replication 可以拿來當備援及作流量分散

其實設定十分簡單,整理設定方法說明如下:

假設 Master 是 A (192.168.100.1) , Slave 是 B (192.168.100.2) ,要複製的 database 為 hello

[步驟一] A 機器上面..

首先編輯 /etc/my.cnf,加入下列幾行

[mysqld]
server-id=1
log-bin

binlog-do-db=hello

log-bin 是告訴 MySQL server 把 Binary Log 機制啟動,把對 hello 這個 DB 的所有更動 LOG 紀錄下來,然後才有辦法讓 Slave 過來同步

接下來重新啟動 MySQL server

[步驟二]

使用 phpMyAdmin 連接到 A,增加一個連線帳號,要擁有 replication 的權限,記得要設定正確的來源位址 (假設是帳號: replication 密碼: simba)

[步驟三]

把 A 機器的 /home/mysql/ (或是 /var/db/) tar 下來,並於 B 機器上面回存,

這個步驟是要讓一開始 B 擁有和 A 相同的資料,後續的複製工作才有辦法進行

[步驟四]

B 機器上面..

編輯 /etc/my.cnf,加入下列幾行

[mysqld]
master-host=192.168.100.1
master-user=replication
master-password=simba
master-port=3306
server-id=2
master-connect-retry=60
replicate-do-db=hello
log-slave-updates

[步驟五]

重新啟動 B 上面的 MySQL database

[步驟六]

測試在 A 上面的 hello database 內建立一個 table,然後去 B 看看是否有相同的 table 出現

HINT: 若有多個 DB 要做 Replication 的話,分別指定多行 binlog-do-db replicate-do-db 即可

讓 FreeBSD 下的 PHP DBA extension 能支援 ‘dbm’ handler

讓 FreeBSD 下的 PHP DBA extension 能支援 ‘dbm’ handler

在 FreeBSD 上面開發了一些程式,使用到 DBOPEN(3) 這個函數來處理一些 hash..

原本 PHP 有支援 DBM extension 可以讀取這些 db,不過新版的 PHP 已經不支援 DBM extension 了,改用 DBA extension 配合 ‘dbm’ handler 來存取這些 db

然而在 FreeBSD 下,使用 ports 去安裝的新版 PHP,其中的 DBA extension 卻無法支援 ‘dbm’ handler..

當然,如果可以的話改用 ‘db4’ handler 可能是比較好的,不過由於歷史因素難解.. 所以就只好自己跳下去改程式,讓 PHP 在安裝時能夠利用 DBOPEN(3) 來提供 ‘dbm’ handler

DBM 事實上只是一個 API,其所產生的 db 檔案格式在各種系統下可能不相容,而且利用不同方式提供的 DBM handler 所產生的 db 檔案格式也可能不一樣..

這個 patch 我有回送給 PHP 開發小組,據說 PHP 5.1 已經恢復支援 DBM handler 了,不過我還沒空去測試

有了這個 patch,你就可以使用 PHP 來存取 FreeBSD 的一些系統 db 檔案了,例如 /etc/mail/aliases.db

$id = dba_open("/etc/mail/aliases.db", "r", "dbm");
$root_alias = dba_fetch( "root\0", $id );

另外,這個 patch 使用 HASH(3) 當作內部的資料格式,因此如果用 C 寫程式,記得第四個參數要使用 DB_HASH ,例如:

db = dbopen("/tmp/test.db", O_RDWR, 0644, DB_HASH, NULL);

其他詳細資訊請參考: http://www.csie.nctu.edu.tw/~cdsheen/codings/freebsd-phpdbm-patch.php