本文也发布在我的博客上,最新修订内容可随时参考:使用GPG签名部署Github Pages
这周忙着迁移博客,偶然了解到GitHub存在提交伪造的风险,出于安全考虑给仓库添加了GPG签名。但在使用Hugo部署时,遇到了关于GPG签名能否在部署流程中生效的问题,好在最终解决了。
如果你还不了解GPG,可先阅读GPG入门指南。
如何使用GPG签名部署并验证Github Pages
主流部署方式有两种:
- 直接将所有源文件推送到GitHub,通过官方Action完成构建部署。
- 将博客源文件与构建产物分离,源文件存放在私有仓库,通过Workflow自动构建并推送到公开的静态资源仓库。
为确保更高安全性,我选择了第二种方式,利用GitHub Pages的Workflow结合actions-gh-pages
行动部署Hugo。但该行动作者明确表示不打算添加GPG签名功能,因此需要手动解决签名问题。
导入GPG密钥
首先在GitHub上找到一个导入GPG密钥的Workflow行动,参考文档后我的配置如下:
- name: 导入GPG密钥 # 将GPG密钥导入到GitHub Action环境
uses: crazy-max/ghaction-import-gpg@v6 # 行动仓库:https://github.com/crazy-max/ghaction-import-gpg
with: # 使用子密钥进行提交签名(若用主密钥,可参考行动文档)
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} # GPG子私钥(加密存储的Secret)
passphrase: ${{ secrets.PASSPHRASE }} # 子密钥的密码短语
git_user_signingkey: true # 配置Git使用签名密钥
git_commit_gpgsign: true # 强制提交时使用GPG签名
fingerprint: ${{ secrets.FINGERPRINT }} # 所用子公钥的指纹(不带空格)
注意:若仅使用GPG主私钥,无需指定fingerprint
;但为安全起见,我生成了专门用于签名的子密钥,此时必须填写子公钥的指纹**(不带空格)**,否则会报错67108933 Not implemented <GPG Agent>
。我已在相关Issue中补充了该注意事项。
别忘了在仓库的「 Secrets」中配置对应的密钥和密码变量。
自定义部署行动
由于官方行动不支持GPG签名,需克隆项目并修改代码。核心是在提交命令中添加-S
选项以启用GPG签名。我在提交记录中找到提交逻辑,添加了-S
参数。
需注意:官方行动不保留分支代码,每次发布后会删除修改,因此必须自行发布自定义版本。在项目根目录运行./release.sh
生成新版本,之后即可在Workflow中引用。我的部署配置如下:
- name: 部署到Web
uses: timerring/actions-gh-pages@v5.0.0 # 基于官方行动修改的自定义版本(可直接使用)
with:
personal_token: ${{ secrets.PERSONAL_TOKEN }} # GitHub Action的个人令牌
external_repository: your_username/your_repository # 目标仓库(格式:用户名/仓库名)
publish_branch: main # 部署目标分支
publish_dir: ./public # 构建产物目录(Hugo默认输出路径)
user_name: ${{ secrets.USER_NAME }} # 提交者姓名(需与GPG密钥UID一致)
user_email: ${{ secrets.USER_EMAIL }} # 提交者邮箱(必须是GitHub验证过的邮箱)
commit_message: ${{ github.event.head_commit.message }} # 继承原始提交信息
关键细节:
- 邮箱必须为GitHub验证过的地址:若使用默认值
${process.env.GITHUB_ACTOR}@users.noreply.github.com
,会导致邮箱与GPG密钥中的UID不匹配(2017年后创建的账号实际邮箱为ID+USERNAME@users.noreply.github.com
),最终签名显示unverified
。即使在密钥中添加该UID,未经验证的邮箱仍无法通过GitHub校验。
部署完成后,向源仓库(如blogsource
)推送代码,Workflow会自动构建并推送到目标仓库(如blog
),所有提交均会附带GPG签名并显示verified
!
验证效果可参考我的仓库提交记录。
附录:完整Workflow示例
如需复用我的Hugo部署方案,可直接使用自定义行动timerring/actions-gh-pages,并按以下YAML配置Workflow(注意替换secrets
和仓库名):
name: 博客部署
on:
push:
branches:
- main # 监听主分支推送
workflow_dispatch: # 支持手动触发
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 拉取代码
uses: actions/checkout@v3
with:
submodules: true # 包含子模块(如主题)
fetch-depth: 0 # 获取完整提交历史
ref: main # 拉取主分支代码
- name: 安装Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: "0.108.0" # 指定Hugo版本
extended: true # 启用扩展版本(支持SCSS等)
- name: 构建网站
run: hugo --minify # 生成压缩后的静态文件
- name: 导入GPG密钥
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.PASSPHRASE }}
git_user_signingkey: true
git_commit_gpgsign: true
fingerprint: ${{ secrets.FINGERPRINT }}
- name: 部署到GitHub Pages
uses: timerring/actions-gh-pages@v5.0.0
with:
personal_token: ${{ secrets.PERSONAL_TOKEN }}
external_repository: timerring/blog # 目标仓库:你的用户名/仓库名
publish_branch: main # 部署到主分支
publish_dir: ./public # 构建产物目录
user_name: "GitHub Action" # 提交者姓名(任意,但需与GPG密钥UID兼容)
user_email: ${{ secrets.USER_EMAIL }} # 必须为GitHub验证邮箱
commit_message: "[skip ci] ${{ github.event.head_commit.message }}"
通过以上配置,即可在GitHub Pages部署流程中实现GPG签名验证,确保代码提交的真实性和完整性。