2010年三月,ssh證書認證悄然地包含到了OpenSSH5.4中。到了2014年,很多人對ssh證書依舊相當模糊,既沒有得到廣泛的理解,也沒有得到廣泛的使用。對于這樣一個問題,我們可能會認為它實施起來要不是很難,就是很復雜。實際上這樣做既不難,也不復雜,只是它沒有得到較好的文檔化的描述。?
本文的目標是以一種實際的方式向各位展示使用和管理ssh證書認證有多容易,無論是較小的還是較大的環境。
本文的創建用于解答筆者日常中遇到的一些ssh證書認證的問題,當然還增添了在學習過程中發現的一些東西。本文內容中也許會有點小差錯,某些特性也沒有提到,歡迎各位指正。
本文假設你已經了解:
基本的Unix/Linux服務器管理
SSH管理,包括但不限于:
a) 密鑰生成
b) SSH公鑰認證
c) 使用SSH代理
d) 使用口令加密密鑰
基本的安全概念如:
不要直接以root身份登陸
證書是已有的ssh公鑰認證系統的擴展,可被應用于任何已有的公鑰和私鑰對,也可以用于任何當前ssh支持的認證方法。
盡管(SSH證書認證)基于公鑰認證,它同時也被設計來簡化多臺服務器之間密鑰管理的復雜性。證書免除了對已知主機和經授權用戶文件的需要,如果實現合理的話,只許更少的人力便能復制全部功能。
由于證書認證是公鑰加密的一個擴展,它可以與OPenSSH支持的任意密鑰類型和密鑰大小的ssh2協同使用。這意味著如果你當前的OpenSSH支持的話,RSA、DSA、EC都能使用。方便起見,本文將使用默認的RSA-1024。
Tips:有些較老的操作系統雖然使用OpenSSH5.4或更高的版本,但是還是不支持EC。
常規的公鑰認證和證書認證之間有幾點較大的不同,最大的不同就是證書驗證上。
SSH證書相比其他證書格式如x509、SSL中使用的PEM更為簡單
a) 沒有證書鏈,只有一個CA
b) 沒有可疑的的商業簽名授權(authority)
c) 除了CA簽名外沒有可信模式
操作 | 公鑰認證 | 證書認證 |
---|---|---|
認證未知主機 | 初始登陸時詢問用戶是否接受主機秘鑰 | 驗證CA簽發的主機證書 |
認證已知主機 | 將密鑰和用戶的已知主機文件對比 | 驗證CA簽發的主機證書 |
替換已知主機的密鑰 | a) 入口必須從用戶的已知主機文件中刪除 b) 用戶登錄時會被問及是否接受新的主機秘鑰 | 驗證CA簽發的主機證書 |
撤銷密鑰/證書 | [email protected] | [email protected] |
a) 用戶可以認證之前沒有登入過的主機
b) 無需再分發或管理已知的已知主機文件(例:puppet)
c) 可以無需用戶干預實現服務器替換及密鑰再生成
d) 除非什么地方出錯了,用戶在工作場合再也不會收到接受服務器密鑰的提示
e) 通過搜索未簽名的主機密鑰可以發現不一致的主機
操作 | 公鑰認證 | 證書認證 |
---|---|---|
認證 | 用戶的公鑰來自每個服務器主機用戶經授權的密鑰文件 | 檢查用戶證書是否由CA簽名 |
過期密鑰/證書 | 不做強制 | 過期時間由管理員在簽名時設置 |
登錄用戶名 | 服務器上的目標用戶的公鑰置于每個用戶目錄下的authorized_keys文件中 | 用戶名可在簽名時添加到證書中,也可由每個服務器上的AuthorizedPrinciples文件控制 |
限制(端口轉發、強制命令等) | 可以在authorized_keys文件中(可被用戶編輯),可在每個服務器sshd_config的匹配用戶/組塊中 | 可在簽名時加入證書中,可在每個服務器sshd_config的匹配用戶/組塊中,可在每個服務器”經授權的規則”中添加 |
撤銷密鑰/證書 | 可添加到每個服務器的RevokedKeys文件中或從服務器上每個受影響的authorized_keys文件移除 | 每個服務器上將證書添加到”RevokedKeys”文件中 |
替換用戶的證書 | 服務器上authorized_keys文件必須可被編輯 | 將舊證書添加到服務器上已撤銷的密鑰文件或簽名新的證書 |
使用證書認證的好處
a) 證書過期時間可由管理員在簽名時設置,強制實施輪轉策略
b) 無需跨越多臺主機管理已授權的證書
c) 不用擔心惡意用戶編輯或添加內容到未管理的經授權文件
d) 在簽名時更容易限制某些用戶的權限
e) 無需從已授權密鑰文件中移除已吊銷的密鑰
f) 證書簽名時可以限制用戶使用指定的用戶名
實現ssh證書認證要比SSL證書容易得多,最難的地方是決定簽名用戶和服務器是使用單個CA密鑰還是使用兩個CA密鑰——服務器和用戶各一個
我們推薦使用兩個獨立的密鑰用于簽名的用戶和服務器,以便讓不同的角色來管理每一個功能:例如,一個系統管理員可以登錄服務器密鑰,而安全管理員可以登錄該用戶的密鑰。
下面的例子中服務器和用戶使用各自的證書授權
激活服務器授權僅需4個步驟
在你的證書授權服務器上運行下列命令:
#!bash
~ $ # Lets start with good organization
~ $ mkdir -p ssh_cert_authorita/server_ca
~ $ cd ysh_cert_authority/server_ca/
~/ssh_cert_authority/server_ca $ # Now lets generate our server certificate authority keypair
~/ssh_cert_authority/server_ca $ ssh-keygen -f server_ca -C "companyname_server_ca"
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
wour identification has been saved in server_ca.
Your public key has been saved in server_ca.pub.
The key fingerprint is:
21:f6:9f:5d:ec:75:2e:df:c0:6b:5e:9d:5b:97:d8:19 "companyname_server_ca"
~/ssh_cert_authority/server_ca $ # The resulting files
~/ssh_cert_authority/server_ca $ ls -l
total 8
-rw------- 1 username username 1675 Aug 16 14:12 server_ca
-rw-r--r-- 1 username username 409 Aug 16 14:12 server_ca.pub
Tips:強烈建議不僅使用密碼,還要使用強密碼。任何用這個密鑰簽名的人都能添加受信任的服務器訪問到你的網絡。
既然證書認證是公鑰認證的一個擴展,你可以使用已有的
/etc/ssh/ssh_host*key.pub
ssh主機密鑰。舉例來說,任何類型的ssh主機密鑰都可以。
在你的證書授權服務器上運行如下命令:
#!bash
~/ssh_cert_authority/server_ca $ # 為拷貝主機密鑰和證書留個地方
~/ssh_cert_authority/server_ca $ mkdir -p host_certs
~/ssh_cert_authority/server_ca $ cd host_certs
~/ssh_cert_authority/server_ca/host_certs $ # 從主機下載主機密鑰
~/ssh_cert_authority/server_ca/host_certs $ scp -rp example.host.net:/etc/ssh/ssh_host_rsa_key.pub example.host.net.pub
ssh_host_rsa_key.pub 100% 396 0.4KB/s 00:00
~/ssh_cert_authority/server_ca/host_certs $ # 簽名主機密鑰
~/ssh_cert_authority/server_ca/host_certs $ ssh-keygen -s ../server_ca -I example.host.net -h -n example.host.net,96.126.102.173,2600:3c01::f03c:91ff:fe69:87a2 example.host.net.pub
Signed host key example.host.net-cert.pub: id "example.host.net" serial 0 for example.host.net,123.45.67.89,2600:dead:beef:cafe:::87a2 valid forever
~/ssh_cert_authority/server_ca/host_certs $ # 結果文件
~/ssh_cert_authority/server_ca/host_certs $ ls -l
total 8
-rw-r--r-- 1 username username 1430 Aug 16 14:19 example.host.net-cert.pub
-rw-r--r-- 1 username username 396 Jul 14 20:19 example.host.net.pub
~/ssh_cert_authority/server_ca/host_certs $ # 將證書考回服務器
~/ssh_cert_authority/server_ca/host_certs $ scp -rp example.host.net-cert.pub [email protected]:/etc/ssh/ssh_host_rsa_key-cert.pub
example.host.net-cert.pub 100% 1430 1.4KB/s 00:00
Tips:
保留CA的所有公鑰及證書,如果你需要撤銷它們,最好復制一份
創建服務器證書時,注意 –l 、–h、 –n 選項的用法
1) -n 選項只能指向相關的主機名、IP地址,空格、通配符或任意名字會導致可互換的服務器證書
2) -l 選項可以是用于標識這個證書的任意文本,而且你沒必要使用和上面同樣的格式
3) -h 選項標明證書為主機證書
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
保存/etc/ssh/sshd_config保存完畢后,重啟sshd
復制server_ca.pub
中的文本,進入你的~/.ssh/known_hosts
(或/etc/ssh/known_hosts
)文件,參考:
#!bash
@cert-authority *.host.net,123.45.67.* ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVifNRc+EN4b9g/ygWRCIvV1qw0aR33qzkutIA6C3MzHidaXe6tO4Q35YqrP2UUhOdcl2g8nO7BNSSHkjrFyEnyNqkpgHYcDzUdpE6XGS6rNcjrmLajf1CRvUBvFD0ceu//z6HL1dpE347AHSZbFxHT6NdhscdEd/Bd5c1aVyS+dUdiGX4U9YdgTN2lM8zQy5rJo+siFyHmtqXh1ZVBBC+VBF6ZPzMkxvkJmAp4eWCQJOZLIybcNZlyuXrs1bXV0X0ZIIL2j/gYC2gJPO1FUTKRcqzo/fQ/m6hAhxMMpTTgI92FiE/QOfOk5+MmgfTOqsF0us2TJ5mrSIE9o/3DQsj "companyname_server_ca"
Tips:
a) 刪除 known_host 中與”example.host.net”相關的host
b) 該文件的格式遵循標準的known_hosts格式,但要注意通配符匹配整個域和IP地址范圍。
#!bash
~ $ ssh -v [email protected]
...
debug1: Server host key: RSA-CERT 39:aa:3f:bb:eb:24:11:93:15:b1:63:2f:de:ad:be:ef
debug1: Host 'example.host.net' is known and matches the RSA-CERT host certificate.
...
用戶認證不會比服務器認證更難
在你的證書授權服務器上運行下列命令:
#!bash
~ $ # Lets start with good organization
~ $ mkdir -p ssh_cert_authority/user_ca
~ $ cd ssh_cert_authority/user_ca
~/ssh_cert_authority/user_ca $ # 生成我們的服務器證書授權密鑰對
~/ssh_cert_authority/user_ca $ ssh-keygen -f user_ca -C "companyname_user_ca"
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in user_ca.
Your public key has been saved in user_ca.pub.
The key fingerprint is:
90:67:8a:ed:b6:53:0a:bd:06:f0:71:ce:fb:89:b9:3e "companyname_user_ca"
~/ssh_cert_authority/user_ca $ # 結果文件
~/ssh_cert_authority/user_ca $ ls -l
total 8
-rw------- 1 username username 1679 Aug 16 18:14 user_ca
-rw-r--r-- 1 username username 407 Aug 16 18:14 user_ca.pub
~/ssh_cert_authority/user_ca $ # 把user_ca.pub復制到服務器上
~/ssh_cert_authority/user_ca $ scp -rp user_ca.pub [email protected]:/etc/ssh
user_ca.pub 100% 407 0.4KB/s 00:00
Tips:強烈建議不僅使用密碼,還要使用強密碼。任何用這個密鑰簽名的人都能訪問你網絡中所有服務器上的任意用戶。
讓一個用戶創建一個ssh公鑰集,并獲得他們公鑰的拷貝
恢復用戶公共SSH密鑰的拷貝,執行如下命令:
#!bash
~/ssh_cert_authority/user_ca $ # 我們需要一個地方存放簽名的證書
~/ssh_cert_authority/user_ca $ mkdir -p user_certs
~/ssh_cert_authority/user_ca $ cd user_certs/
~/ssh_cert_authority/user_ca/user_certs $ # 以使用公鑰為例
~/ssh_cert_authority/user_ca/user_certs $ cp ~/.ssh/id_rsa.pub username.pub
~/ssh_cert_authority/user_ca/user_certs $ # Sign the key
~/ssh_cert_authority/user_ca/user_certs $ ssh-keygen -s ../user_ca -I user_full_name -n root,loginname username.pub
Signed user key username-cert.pub: id "user_full_name" serial 0 for root,loginname valid forever
~/ssh_cert_authority/user_ca/user_certs $ # 結果文件
~/ssh_cert_authority/user_ca/user_certs $ ls -l
total 8
-rw-r--r-- 1 username username 1525 Aug 16 22:01 username-cert.pub
-rw------- 1 username username 411 Aug 16 22:00 username.pub
~/ssh_cert_authority/user_ca/user_certs $ # 復制證書到用戶的~/.ssh/文件夾下
~/ssh_cert_authority/user_ca/user_certs $ cp username-cert.pub ~/.ssh/id_rsa-cert.pub
Tips:
保留CA的所有公鑰和證書,如果你需要撤銷它們,最好復制一份
當創建服務器證書時,你不能否認–l、–n 選項的使用
a) -n 選項只能指向相關的登陸用戶名,空格、通配符名字會允許任何有效用戶賬戶的登錄,除非在服務端有其他的嚴格限制。在本例中,用戶名使用root和loginname
b) -l 選項可以是用于標識這個證書任意文本,而且你沒必要使用和上面一樣的格式
在你想激活證書認證的每臺服務器上將如下代碼添加至/etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/user_ca.pub
保存sshd_config文件,重啟sshd
從服務上所有的經授權密鑰文件中刪除用戶公鑰
運行如下命令:
#!bash
~ $ ssh -v [email protected]
...
debug1: identity file /home/username/.ssh/id_rsa-cert type 4
debug1: Offering RSA-CERT public key: /home/username/.ssh/id_rsa
debug1: Server accepts key: pkalg [email protected] blen 1101
...
另外,如果你開啟了調試記錄,你會看到如下日志:
#!bash
Jul 18 23:22:03 localhost sshd[9603]: debug1: list_hostkey_types: ssh-rsa,[email protected] [preauth]
Jul 18 23:22:03 localhost sshd[9603]: Accepted certificate ID "user_username" signed by RSA CA d2:c0:6c:08:2b:e4:b4:f2:cd:56:22:66:de:ad:be:ef via /etc/ssh/user_ca.pub
上述步驟是證書認證的基礎,接下來我們會涵蓋一些更細節的特性。
授予訪問你的服務器很棒,但是你必須要有權利撤銷這種訪問
下面的方法同樣適用于公鑰認證,目前它們是撤銷ssh證書的唯一方式
啟用用戶取消功能,將如下代碼添加至你服務器的/etc/ssh/sshd_config
:
#!bash
RevokedKeys /etc/ssh/ssh_revoked_keys
然后輸入如下命令:
#!bash
~ $ # 如果文件不存在且對sshd不可讀,**all** 用戶將沒有訪問權限
~ $ sudo touch /etc/ssh/ssh_revoked_keys
~ $ sudo chmod 644 /etc/ssh/ssh_revoked_keys.
一旦完成,重啟sshd
當需要從服務器撤銷用戶訪問權限時,簡單地添加其公鑰或證書到/etc/ssh/ssh_revoked_keys
中。文件格式同authorized_keys密鑰類似,一個密鑰或證書占一行
#!bash
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDL8HShSFKdY3Tox9U+gUotTFlRedPxI5zSrU6KiZEXA8i+37BtB0yp502q3Dx1MmXBF8Pqa+xEQ9DOgtragDwX0V7ieOjvRSB83w2Orj9cdMj8U6WluU2T+QlD2JtVmOp0Skg4k3AENIN9J0rmnxvmuCZa2G5f+6DGp/pW5kk9FfNv1xaAOgy3yfExD2w5cEHZfztajbTuCE6z9aNxU96ZHvXdV6Z8M3xkkea6IUU3XCyg+lB/qSq+KoBoByzwZSJ6BfA7x63okq57K6XsPp4GuVukq0OmDk9ZLpqmeC8esWhniA+2DwmjdaFa1k9K/bpCy4mVLhqTgwkU9u8rxaCd [email protected]
[email protected] [email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected]rI+pD9mv7qLU3h22JvQUKnuWNvdJJuQATZ [email protected]
Tips:
a) 這阻斷了系統范圍公鑰和證書的使用
b) 公鑰更為理想化,因為它們更小,除了會阻斷證書認證還會阻斷公鑰
c) 這里證書同樣能工作良好,但是如果它在authorized_keys文件中它不會阻斷公鑰
Jul 19 00:27:26 localhost sshd[11546]: error: WARNING: authentication attempt with a revoked RSA-CERT key 6d:59:82:70:2b:93:dc:57:a6:c6:1f:64:de:ad:be:ef
服務器密鑰得從用戶的已知主機文件中撤銷,或者在/etc/ssh/known_hosts
使用:
#!bash
@revoked * ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc9wlKYUzWZcfvPOa0L+h6Wbb/k9yJgXbnqa3VF+ucdwmBSiT3zBMAjqjFMnN3MuI4oig3SqkIXKPWn0QgFoV4d3G4opzs/OdZ6WLyxLwYQBggUQDg4QhKuHDltIR/BMxYlhB20ngmkaiBiK+Q4ThFRpW7FElOsuZ3rgJq559PgkFeFMY06oyzUMaSshFM84U/1zrVL4BgdnZBcJn018psem5kSkd0Gxm+ao1TuEnMGeArVMFiG9Hq1o2E+QGp1euE4YYQtR533fyZ8BSTE9ThLkmTXgU31dn1irFatBrBENm7TnIVmNT410NqV5J9zDME4NAnuEVwNWtq65rZkgut [email protected]
Tips:
a) 通配符會阻止主機密鑰被任何主機使用
b) 上面的情況中,公鑰和證書都能工作,不過公鑰更小且更有效
c) 當和個別已知主機入口一起工作時,簡單地刪除一個入口并不會阻止密鑰被再次使用
示例:
#!bash
~ $ ssh example.host.net
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REVOKED HOST KEY DETECTED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
The RSA host key for example.host.net is marked as revoked.
This could mean that a stolen key is being used to impersonate this host.
RSA host key for example.host.net was revoked and you have requested strict checking.
Host key verification failed.
簽名一個證書時,管理員可以直接實行證書控制,在沒有重簽名的情況下證書不能被改變
大多數組織使用密碼過期策略,許多情況下需求密碼和證書過期,遺憾的是目前僅有特設方法執行ssh密鑰輪換。
使用證書,一個過期日期在簽名時會加載到證書中,可以使用ssh時間格式-V選項完成
#!bash
~/ssh_cert_authority/user_ca/user_certs $ # Expiration in 52 weeks
~/ssh_cert_authority/user_ca/user_certs $ ssh-keygen -s ../user_ca -I user_full_name -n root,loginname -V +52w username.pub
~/ssh_cert_authority/user_ca/user_certs $ # Expiration in 180 days
~/ssh_cert_authority/user_ca/user_certs $ ssh-keygen -s ../user_ca -I user_full_name -n root,loginname -V +180d username.pub
正如簽名提到的,可以使用-n選項強制使用證書中的登錄名和服務器名
對用戶來說,這限制了用戶在遠程服務器上指定的登錄名,一般來說,這應該是一個單用戶名,但是在一些環境中可能需要多個用戶名
下面的例子允許單個證書上的多個登錄名:
#!bash
~/ssh_cert_authority/user_ca/user_certs $ ssh-keygen -s ../user_ca -I user_full_name -n loginname,anothername,thirdname username.pub
對于用戶證書
對用戶證書而言,簽名時可以直接構建好幾個選項到證書中。一般來說,這些選項運用于/etc/sshd_config或經授權的密鑰文件中,這些選項是:
a) clear:假設沒有默認選項
b) force-command=(command):強制遠程命令執行
c) 默認許可的:代理轉發/無代理轉發
d) 默認許可的:端口轉發/無端口轉發
e) 默認許可的:pty/無pty
f) 默認許可的:permit-user-rc/no-user-rc
g) 默認許可的:x11轉發/無x11轉發
h) 源地址=(地址列表):限制源地址,這些地址中的證書為有效
示例:
#!bash
~/ssh_cert_authority/user_ca/user_certs $ ssh-keygen -s ../user_ca -I user_full_name -n login \
-O clear \ # Clear all default options, including forwarding of all kinds
-O force-command=/some/specific/command \ # force execution of a specific command
-O source-address=10.22.72.0/24 \ # limit logins from specific source addresses
username.pub
上面的例子限制了只能在特定的服務器上自動化批處理,不允許pty,轉發,并強制特定的命令
隨著OpenSSH6.x的發布,證書的更新導致和OpenSSH 5.x之間存在兼容性問題
OpenSSH6.x生成的證書在OpenSSH 5.x上需要使用選項”-t v00”才能運行,例如:
#!bash
$ ssh-keygen -t v00 -s ca_key -I key_id host_key.pub
OpenSSH 6.x似乎向后兼容OpenSSH 5.x生成的證書
除了OpenSSH,如果有的話,僅有少數客戶端支持基于認證的證書
盡管大多數常見或不常見的操作系統都運行OpenSSH,也還是有使用其他客戶端的。舉例來說,Windows上非常流行的Putty,它至今都不支持證書認證。許多使用ssh的商業應用不支持證書認證,例如Rapid7的Nexpose
因此,如果可以的話,有些環境可能會比較難以強制實行只基于認證的證書
集中化的密鑰管理簡化了認證管理流程,不幸的是這同時也簡化了攻擊面,攻擊者只許獲得CA密鑰的管理就能獲得對全網的訪問
因此,CA密鑰的管理必須處于高安全等級,如果可能的話,將它們存儲在網絡無法訪問的地方,并千萬千萬確保它們被加密了
本文根據收集來的OpenSSH手冊信息進行組織,它們可能會更詳盡而且內容以后也會比本文更新
sshd_config – OpenSSH SSH daemon configuration file
ssh-keygen – authentication key generation, management and conversion
原文:Using OpenSSH Certificate Authentication