GitHub Actions + 阿里云 OSS:OIDC 免密同步构建产物

发布时间:2026/6/30 5:42:05
GitHub Actions + 阿里云 OSS:OIDC 免密同步构建产物 装包同步到阿里云 OSS后续官网可以提供国内镜像链接。全程使用 OIDC 免密认证不存长期 AccessKey。过程中遇到不少问题带着 claude code 折腾了几个小时才整好。下边是详细的过程记录。顺带说一句 Molio 在 github 上开源了有兴趣的同学可以去看看。实施过程中还修了一个附带问题electron-builder 的--publish always会把 beta/rc 预发布 tag 也发到 GitHub Releases而我们的 OSS 同步没有区分预发布和正式版导致latest.json被 beta 版本覆盖官网下载链接指向了测试版。方案流程GitHub Actions (tag push) → smoke-test → build (发布到 GitHub Releases) → upload-oss ├── 始终上传安装包到 OSS含 prerelease └── 仅正式版更新 latest.json认证链路GitHub OIDC Token → 阿里云 STS AssumeRoleWithOIDC → 临时 AK/SK/Token → ossutil 上传前置配置阿里云侧一次性创建 OSS Bucketmolio-releases公共读、标准存储创建 OIDC Provider信任 GitHub ActionsAudience 设为sts.aliyuncs.com创建 RAM RoleGitHubActions-OSSUpload信任策略限定repo:zhuzhaoyun/Molio:*附加最小权限策略仅允许操作molio-releasesbucketGitHub 侧配置 4 个 Repository Variables非 Secrets开源项目可审计ALIYUN_ROLE_ARN、ALIYUN_OIDC_PROVIDER_ARN、OSS_BUCKET、OSS_ENDPOINT。Pre-release 处理版本号含-即为预发布如1.0.0-beta.1不含则为正式版如1.0.0。预发布版本上传到 OSS 但不更新latest.json方便内部测试的同时不把测试版推给普通用户。Tag 格式类型OSS 上传更新 latest.jsonv1.0.0正式版✅✅v1.0.0-beta.1预发布✅❌v1.0.0-rc.2预发布✅❌踩坑记录凭空捏造的 GitHub Action我凭记忆写了aliyun/configure-credentialsv3和aliyun/ossutil-actionv1CI 报 repository not found。这两个 action 在 Marketplace 上不存在。aliyun CLI 下载链接失效改用安装 aliyun CLI 的方案https://aliyuncli.alicdn.com/aliyun_cli_latest_linux_amd64.tar.gz返回 404。curl 调 STS API 缺少签名放弃 CLI 后用 curl 直调 STS API。OIDC Token 获取成功但 STS 返回MissingTimestamp。阿里云 STS API 要求 HMAC-SHA1 请求签名包含 Timestamp、Nonce 等参数curl 手动拼 URL 无法完成签名。测试 tag 不匹配 workflow trigger推送v0.3.11-test后 release workflow 没触发。release.yml的 trigger 配置为tags: [v*.*.*]-test后缀不匹配三段式版本号 glob。临时改为tags: [v*]验证通过后恢复。Pre-release 覆盖了 latest.json推送v0.3.8-beta.1后latest.json被更新为 beta 版本号。正式版用户通过 auto-update 不会收到 beta但新用户从官网下载到的是测试版。最终方案前三个问题的解法相同放弃第三方 action 和 aliyun CLI改用原生工具链。curl获取 OIDC TokenPython SDK 调用 STSossutil 上传。零外部依赖不受 action 下架或链接失效影响。STS 签名问题靠阿里云官方 Python SDKalibabacloud_sts20150401解决。SDK 自动处理签名、Timestamp、Nonce并且原生支持 OIDC bearer tokenfrom alibabacloud_sts20150401.client import Client from alibabacloud_tea_openapi import models as api_models config api_models.Config( credentialapi_models.CredentialConfig(bearer_tokenoidc_token), region_idcn-guangzhou, ) client Client(configconfig) resp client.assume_role_with_oidc(request)CredentialConfig(bearer_token...)是 OIDC 免密认证的标准用法不需要任何 AK/SK。Pre-release 区分在 upload-oss job 中用版本号判断- name: Upload to OSS and update latest.json shell: bash run: | VERSION${{ steps.version.outputs.version }} TAGv${VERSION} for file in ./release-assets/*; do filename$(basename $file) ossutil cp $file oss://${{ vars.OSS_BUCKET }}/releases/${TAG}/${filename} \ --endpoint${{ vars.OSS_ENDPOINT }} --update done if [[ $VERSION ! *-* ]]; then echo Stable release, updating latest.json cat /tmp/latest.json EOF {version:${VERSION},updatedAt:$(date -u %Y-%m-%dT%H:%M:%SZ)} EOF ossutil cp /tmp/latest.json oss://${{ vars.OSS_BUCKET }}/releases/latest.json \ --endpoint${{ vars.OSS_ENDPOINT }} --meta Cache-Control:no-cache else echo Pre-release (${VERSION}), skipping latest.json fi备忘要点说明先确认 action 存在再写不要凭记忆写 action 名称去 Marketplace 查阿里云 API 用官方 SDKcurl 手动签名不可行SDK 自动处理鉴权OIDC 认证走 bearer_tokenCredentialConfig(bearer_token...)无需 AK/SKARN 放 Variables 不放 Secrets开源项目可审计ARN 本身不是敏感信息信任策略限定 repooidc:sub: repo:owner/repo:*防止其他 repo 扮演你的角色workflow 顶层声明id-token: write否则拿不到 OIDC TokenPre-release 区分对待文件全量上传latest.json只指向正式版