延長或縮短 GPG 金鑰的過期時間 (Expiration Time)

筆者在 2018 年的時候開了第一個真的有在長期使用的 GPG 金鑰。

因為年少輕狂不懂事,當時特別把 primary key 設定成永遠不會過期。 但演算法可能在未來被發現漏洞,電腦的運算能力也會越來越好, 一把不會過期的 GPG 金鑰是先天上不合理的存在。 考量到此問題,筆者後來又再修正了該金鑰的過期時間, 以及整理這篇筆記…

GPG Key 可以延展過期時間?

我想這應該是熟悉 X.509 憑證生態系的人最為驚訝的一件事情了。

我發現幾位公司主管並不知道這件事情,也促使我在經過一段時間後回來整理這篇文章。 事實上,GPG key 不只是可以延展過期時間,這也是一般推薦的最佳慣例。

People think that they don’t want their keys to expire, but you actually do. Why? Because you can always extend your expiration date, even after it has expired!

See: OpenPGP Best Practices - riseup.net

使用者應該設一個較短的有效時間,並在後續有需要時延展過期時間。

GPG key 可以自己修改金鑰的過期時間,是因為 GPG key 和 X.509 憑證有著本質上的區別。

GPG key 的產生是透過 primary key 的 self-signature, 而 X.509 憑證的簽署是由公正的第三方 CA 進行。

X.509 憑證的過期時間是 CA 幫你簽署憑證時決定,自然無法隨意修改, 大家也很習慣這件事情,但 GPG key 就不一樣了。 GPG key 的有效時間是透過 key 的 self-signature 內所記載的時間決定。 只要 primary (private) key 沒有遺失,持有者隨時可以重新自簽並修改時間。

只要認知到兩者本質上的差異,可以修改過期時間這件事情也就很好理解了。

他人如何認定過期時間?

既然 GPG key 可以隨時重簽修改過期時間,那對他人來說, 該如何判定某把 key 究竟什麼時候過期呢?

規則很簡單

The latest self-signature takes precedence

See: Key Management

若是透過 gpg tool 修改過期時間,舊的 self-signature 會被刪掉。 因為只有一個 self-signature,修改完之後,只要重新把 key export 給他人, 他人就可以知道新的過期時間。

若不是透過信賴管道直接把新簽的 key 給他人,而是透過 GPG key server, 狀況會有點不一樣。

基於安全考量,GPG key server 是不允許部分或完全刪除 key 的,MIT 名下的 key server 還特別寫了一篇 FAQ 來說明這件事。 對於一把已存在的 key,使用者只能推新的 sub key 或新的 signature 上去。

因此,他人透過 key server 取得 key 時,也會拿到多個 signature。 好在 signature 本身也有時戳,根據上述 “後者為準” 的規則,他人就可以知道 正確的過期時間是何時。

有興趣的可以查看筆者的 GPG key 來確認這個行為

1
2
3
4
5
6
7
8
gpg --keyserver keys.gnupg.net --recv-keys C9756E05
# Get key from key server

gpg --export C9756E05 | gpg --list-packets
# One signature has "key expires after ..." while another doesn't

gpg -k C9756E05
# Validate that the key indeed expires at some time

或是可以直接去 GnuPG 官方的 key server 查看: Search results for ‘0xc728b2bdc9756e05’

結語

翻閱文件研究的過程,慢慢感受到到 GPG 這個扣除 X.509 之外唯一成熟的 PKI 生態系,究竟有多麼偉大。同時也看到很多值得細讀的 guideline 文件。

若有時間,真的該來好好吸收整理。

保護存在檔案系統上的 Docker 登入密碼

在企業內部的工作環境中,常會碰到需要存取 private registry 上的 image 的狀況。 以 Docker 的工作流程來說,一般要透過執行 docker login 來存取 private registry。 不過,若事先毛設定好 docker credential helper,執行 docker login 會導致 我們的密碼 / API token 直接以明文的方式寫在檔案系統上。

這篇筆記說明如何在 Linux 環境下安裝與設定 docker credential helper

Installation

至 docker/docker-credential-helpers 的 GitHub release 頁面下載最新版本的 docker-credential-secretservice

1
curl -L https://github.com/docker/docker-credential-helpers/releases/download/v0.6.3/docker-credential-secretservice-v0.6.3-amd64.tar.gz >secretservice.tar.gz

解壓縮並把執行檔放到任意一個 PATH 資料夾內。

1
2
3
tar -zxv -f secretservice.tar.gz
chmod +x docker-credential-secretservice
mv docker-credential-secretservice ~/.local/bin

Configuration

為了讓 docker 工具知道我們要用 credential helper,需要調整家目錄下的設定檔。

在設定檔 ~/.docker/config.json 內加入 credsStore 設定。

1
$EDITOR ~/.docker/config.json
1
2
3
{
"credsStore": "secretservice"
}

註: 此資料夾和 JSON 檔案可能不存在。若沒有自己創一個即可。

註: 根據文件,此欄位的值與是 helper binary 的後綴對齊,因為 Linux 環境使用的 binary 是 docker-credential-secretservice 所以需要填入的值爲 secretservice

Usage

如果已經有登入過某 registry,需要手動登出。

1
docker logout registry.example.com

(重新) 登入該 registry。

1
docker login registry.example.com

檢視 ~/.docker/config.json 並確認對應的身分紀錄是空白的。

1
2
3
4
5
{
"auths": {
"registry.example.com": {}
}
}

若有安裝 Seahorse 程式的話,此時可以看到 secret 被放在 Login keyring 中。

如果設定錯誤的話,登入資訊會以編碼過的方式呈現在該紀錄中。

1
2
3
4
5
6
7
{
"auths": {
"registry.example.com": {
"auth": "c3R...zE2"
}
}
}

Future Reading

在 macOS 上架設 Apache 與 PHP-FPM

工作上因為一些特殊需求,需要在 macOS 環境下架設 Apache + PHP-FPM 的使用環境。好在 macOS 本來就有預裝 Apache 以及 PHP-FPM,並提供 Apache 的 launchd 設定檔,要在 macOS 上架設這個服務並不困難。

本文介紹如何以最低限度的設定,在 macOS 上跑 Apache + PHP-FPM。以筆記的方式呈現,不會有太多的講解。

Notes

  • 筆者是在 macOS 10.14 與 10.15 上測試此流程
  • macOS 系統上,/etc 是一個 symblic link 連至 /private/etc/var, /tmp 也有相同行為。

設定與啟用 PHP-FPM

複製並修改 PHP-FPM 設定檔

系統內有會自帶 PHP-FPM 的 default 設定檔,將其複製一份出來,並修改內容。

1
2
$ sudo cp /etc/php-fpm.conf.default /etc/php-fpm.conf
$ sudo cp /etc/php-fpm.d/www.conf.default /etc/php-fpm.d/www.conf

將執行身分從 nobody 修改為 _www (與 Apache httpd一致)。

1
$ sudo vim /etc/php-fpm.d/www.conf
1
2
3
4
5
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = _www
group = _www

修改 error_log,調整 log file 的路徑。

1
$ sudo vim /etc/php-fpm.conf
1
2
3
4
5
6
; Error log file
; If it's set to "syslog", log is sent to syslogd instead of being written
; into a local file.
; Note: the default prefix is /usr/var
; Default Value: log/php-fpm.log
error_log = /var/log/php-fpm.log

新增 PHP-FPM 的 launchd 設定檔並啟用

創一個 launchd daemon 設定檔給 PHP-FPM 使用, 此舉目的為讓 PHP-FPM daemon 可以在 macOS 開機時自己啟用。

建議將設定檔放在 /Library/LaunchDaemons 下,參照 launchd 的文件, 此位置是供第三方軟體擺放 daemon 設定使用。

1
$ sudo vim /Library/LaunchDaemons/com.example.php-fpm.plist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<true/>
<key>Label</key>
<string>com.example.php-fpm</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/php-fpm</string>
<string>--nodaemonize</string>
</array>
<key>OnDemand</key>
<false/>
</dict>
</plist>

做好設定檔之後,用 launchctl 指令 load 此設定檔,並下參數告訴 macOS 之後此 daemon 要在開機時預設啟用。

1
$ sudo launchctl load -w /Library/LaunchDaemons/com.example.php-fpm.plist

上述指令執行完後, launchd 會把 PHP-FPM daemon 叫起。

1
2
3
4
$ ps aux | grep php
_www 515 0.0 0.0 4297608 648 ?? S 6:18PM 0:00.00 /usr/sbin/php-fpm
_www 514 0.0 0.0 4305800 628 ?? S 6:18PM 0:00.00 /usr/sbin/php-fpm
root 513 0.0 0.0 4305800 784 ?? Ss 6:18PM 0:00.00 /usr/sbin/php-fpm

設定並啟用 Apache Web Server

修改設定檔,讓 Apache 使用 proxy_moduleproxy_fcgi_module, 並確認 php7_module 沒被啟用。

需要本文的讀者應該不至於把 Apache PHP module 與 PHP-FPM 搞混.. XD

1
$ sudo vim /etc/apache2/httpd.conf
1
2
3
LoadModule proxy_module libexec/apache2/mod_proxy.so
LoadModule proxy_fcgi_module libexec/apache2/mod_proxy_fcgi.so
# LoadModule php7_module libexec/apache2/libphp7.so

<Directory "/Library/WebServer/Documents"> 或其他需要的地方內, 加入 PHP 的 handler,指向 PHP-FPM 預設提供服務的 socket。

1
2
3
4
5
6
7
<Directory "/Library/WebServer/Documents">
... 上略
<FilesMatch \.php$>
SetHandler "proxy:fcgi://localhost:9000/"
</FilesMatch>
</Directory>

Apache 的 daemon config 本來就存在於系統目錄內,但 Disable 的值被設為 true, 用下述 command 將 Apache daemon load 進 launchd 內,並讓 launchd 記錄此 daemon 應被啟用。

1
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist

與 PHP-FPM 相同,此指令下去之後,launchd 就會把 Apache 拉起。

此時可去 http://localhost/ 確認,如果看到大大的標題寫著

It works!

即代表 Apache 有順利執行。

確認 PHP-FPM 運作正常

丟一個 phpinfo 到 web server 的預設根目錄下。

1
$ sudo vim /Library/WebServer/Documents/phpinfo.php
1
2
3
<?php
phpinfo();
?>

之後連上 http://localhost/phpinfo.php ,看到 Server APIFPM/FastCGI 即可。 :D