huaweicloud-oidc-sdk-nodejs:基于 Node.js 与 OIDC 的华为云免密接入项目

用于 GitHub/GitCode Actions 中免 AK/SK 调用华为云 APIG 或上传 OBS。该 Node.js SDK 基于 OIDC 经华为云 STS 换取短期临时凭证,支持缓存刷新、APIG 签名和 OBS 接入。【此简介由AI生成】

分支1Tags4
当前项目代码仓暂无内容

@openlibing/huaweicloud-oidc-client

openlibing 平台对接华为云的 SDK(npm 包):基于 CI 流水线 OIDC(GitHub Actions / GitCode Actions)→ 华为云 STS 免密换取临时凭证,全程零 AK/SK 密钥。

简介

问题

CI 流水线(GitHub Actions / GitCode Actions)调用华为云服务(APIG 接口、OBS 上传等)时,传统做法是把永久 AK/SK 配置成仓库 secret:

  • 永久密钥长期有效,一旦泄露即可被任意冒用,泄露面还会随仓库协作者、CI 日志等扩散;
  • 轮换依赖人工,密钥管理成本高;
  • 密钥权限往往大于流水线实际所需,难以满足最小权限与审计要求。

解决方案

基于 OIDC 联邦认证免密换证,仓库中不存放任何密钥:

CI 流水线 OIDC ID Token(GitHub Actions / GitCode Actions,签发方式一致)
  → 华为云 STS AssumeAgencyWithOIDC 换临时凭证
    → OBS 上传(临时凭证 + esdk-obs-nodejs)
    → APIG 调用(V11-HMAC-SHA256 签名 + X-Security-Token)
  1. 流水线声明 id-token: write 权限,运行时向平台申请短期 OIDC ID Token;
  2. SDK 携带令牌调用华为云 STS AssumeAgencyWithOIDC,换取临时 AK/SK/SecurityToken(默认 1 小时有效,SDK 自动缓存、临期刷新、并发去重);
  3. 用临时凭证访问目标服务:调用 APIG 时 SDK 自动完成 V11-HMAC-SHA256 签名并携带 X-Security-Token;上传 OBS 时将临时凭证注入 esdk-obs-nodejs 客户端。

华为云 IAM 侧通过「身份提供商 + 信任委托」限定可换证的令牌来源(iss / aud / sub 逐项校验),只有指定仓库的流水线能换取凭证;IAM 侧配置见下方「华为云侧配置」。

快速开始

最常见的使用场景:在 GitCode Actions / GitHub Actions 流水线的本地自定义插件(Action)中引入 SDK,免 AK/SK 调用 APIG 接口或上传文件到 OBS。两类流水线的接入方式完全一致(OIDC Token 获取方式相同),完整可运行示例见仓库自带的 .gitcode/actions/test-apig-action/.gitcode/actions/test-obs-action/,对应的使用方 workflow 见 test-action-workflow.yml

1. 插件声明依赖

在插件目录的 package.json 中引入 SDK;OBS 上传场景还需引入 esdk-obs-nodejs(固定 3.26.2,后续版本存在构造后立即上传的竞态问题),仅调用 APIG 时无需引入。要求 Node 18+(SDK HTTP 层基于内置 fetch):

{
  "dependencies": {
    "@openlibing/huaweicloud-oidc-client": "^0.0.6",
    "esdk-obs-nodejs": "3.26.2"
  }
}

2. 初始化配置

SDK 内置 openlibing 平台(GitCode Actions)的华为云账号配置,不调用 configure() 也能直接开箱即用。内置默认值即以下代码注释中标注的值:

const { configure } = require("@openlibing/huaweicloud-oidc-client");

// 例:接入其他华为云账号 / GitHub 平台流水线时,按需覆盖对应字段
// (未传字段保持内置默认值;全部可覆盖字段见「核心 API」的配置项说明)
configure({
  accountId: "4d29a984c4fe4e6eb5d404a853d0084e", // 默认:openlibing 华为云账号 ID
  audience: "huawei-cloud-service", // 默认:申请 OIDC ID Token 的 audience,需与身份提供商注册的客户端 ID 一致
  agencyName: "gitcode-actions", // 默认:IAM 信任委托名称
  oidcProviderName: "GitCodeActions", // 默认:华为云侧 OIDC 提供商(GitHub 平台接入时覆盖为 'GitHubActions')
  region: "cn-southwest-2", // 默认:STS 端点区域,换证走任一支持的 region 均可(按网络可达性与速度选择);callApig 默认还以它作 APIG 签名区域(可 opts.region 覆盖)
  durationSeconds: 3600, // 默认:临时凭证有效期(秒)
  refreshBufferSeconds: 300, // 默认:提前刷新缓冲(秒),避免凭证在边界过期
  debug: false, // 默认:调试日志开关,开启后额外打印请求/响应详情(敏感字段自动脱敏)
});

自定义配置:接入其他华为云账号(或 GitHub 平台流水线)时,按需覆盖对应字段,未传字段保持默认值。以接入自有账号为例,字段需与 IAM 侧注册一致(见「华为云侧配置」):

// 例:接入自己的华为云账号
configure({
  accountId: "<华为云账号ID>",
  oidcProviderName: "GitHubActions", // 或 'GitCodeActions',取决于流水线平台
  agencyName: "my-agency",
  audience: "my-audience",
  region: "cn-north-4",
});

3. 场景一:调用 APIG 接口

插件代码中引入 SDK,callApig 一行完成 OIDC 免密换证 + V11 签名 + 请求发送:

const core = require("@actions/core");
const { callApig, configure } = require("@openlibing/huaweicloud-oidc-client");

configure({ debug: false }); // 可选:开启后额外打印请求/响应详情(敏感字段自动脱敏)

const res = await callApig(
  "GET",
  "https://{apig-instance-id}.apic.cn-southwest-2.huaweicloudapis.com/version",
);
// => { status, headers, data }

if (res.status >= 200 && res.status < 300) {
  core.info(`调用成功: ${JSON.stringify(res.data)}`);
} else {
  core.setFailed(`调用失败 (HTTP ${res.status}): ${JSON.stringify(res.data)}`);
}

4. 场景二:上传文件到 OBS

getCredentials() 换取临时凭证后,交给 OBS SDK 客户端执行上传:

const ObsClient = require("esdk-obs-nodejs");
const {
  getCredentials,
  configure,
} = require("@openlibing/huaweicloud-oidc-client");

const { region } = configure({ debug: false });
const cred = await getCredentials();
// => { accessKeyId, secretAccessKey, securityToken, expiresAt, expiresIn }

const client = new ObsClient({
  access_key_id: cred.accessKeyId,
  secret_access_key: cred.secretAccessKey,
  security_token: cred.securityToken,
  server: `https://obs.${region}.myhuaweicloud.com`,
});

const result = await client.putObject({
  Bucket: "your-bucket-name",
  Key: "path/to/object.csv",
  SourceFile: "./local-file.csv",
});
await client.close();

5. workflow 声明 OIDC 权限并使用插件

流水线必须声明 id-token: write 权限,否则插件无法向平台申请 OIDC ID Token。完整 workflow 示例(含手动触发与两个场景的插件调用):

name: Deploy via OIDC

on:
  workflow_dispatch:
    inputs:
      debug:
        description: "开启 SDK 调试定位日志"
        type: boolean
        required: false
        default: false
  push:
    branches:
      - main

permissions:
  repository: read
  id-token: write # 必须声明此权限,否则无法申请 OIDC ID Token

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: checkout

      - name: Call APIG via OIDC
        uses: ./.gitcode/actions/my-apig-action
        with:
          debug: ${{ inputs.debug }} # 可选:开启 SDK 调试日志

      - name: Upload to OBS via OIDC
        uses: ./.gitcode/actions/my-obs-action
        with:
          file-path: ./dist/app.zip
          debug: ${{ inputs.debug }}

提示:流水线 runner 不会为本地插件执行 npm install,插件需用 ncc build 将依赖(含 SDK)构建为自包含产物并提交 dist/,构建方式参考两个测试插件。

华为云侧配置

SDK 接入前需在华为云 IAM 侧完成联邦认证配置(按流水线平台分别注册),共三步:创建 OIDC 身份提供商 → 创建信任委托并配置信任策略 → 为委托授予身份策略。

创建 OIDC 身份提供商

在 IAM 控制台「身份提供商」中按流水线平台分别创建 OIDC 类型身份提供商:

平台 提供商名称 颁发者 URL 客户端 ID(audience)
GitCode Actions GitCodeActions https://actions-results.atomgit.com huawei-cloud-service
GitHub Actions GitHubActions https://token.actions.githubusercontent.com huawei-cloud-service
  • 提供商 URN 格式:iam::<华为云账号ID>:oidcProvider:<提供商名称>
  • 客户端 ID 必须与 SDK 申请 OIDC ID Token 时使用的 audience 一致(内置默认 huawei-cloud-service)。

创建信任委托

在 IAM「委托」中创建信任委托(名称如 gitcode-actions),信任主体选择上一步创建的 OIDC 身份提供商。委托 URN 为 iam::<华为云账号ID>:agency:gitcode-actions

信任策略通过 Condition 限定可换取凭证的令牌来源,仅允许来自指定仓库的令牌通过。oidc:sub 建议使用 StringMatch 运算符(区分大小写,支持 *? 通配符,比 StringEquals 精确匹配更灵活)。以下为 GitCode Actions 平台示例(GitHub 平台将 Federated 的提供商 URN 与 oidc:iss 替换为 GitHub 侧对应值):

{
  "Version": "5.0",
  "Statement": [
    {
      "Action": ["sts:agencies:assumeWithOIDC"],
      "Effect": "Allow",
      "Principal": {
        "Federated": ["iam::<华为云账号ID>:oidcProvider:GitCodeActions"]
      },
      "Condition": {
        "StringEquals": {
          "oidc:iss": ["https://actions-results.atomgit.com"],
          "oidc:aud": ["huawei-cloud-service"]
        },
        "StringMatch": {
          "oidc:sub": ["repo:<组织>/<仓库>:ref:refs/heads/main"]
        }
      }
    }
  ]
}

oidc:sub 的取值格式(标识哪个仓库的哪条分支在换证,匹配区分大小写,组织名/仓库名/分支名的大小写必须与平台完全一致):

  • GitCode Actionsrepo:<组织>/<仓库>:ref:refs/heads/<分支>,与 GitHub 名称格式一致;实际取值以流水线签发的令牌为准,可从调试日志读取。
  • GitHub Actions 有两种格式,同时存在且无法相互转换:
    • 名称格式(存量仓库沿用):repo:<组织>/<仓库>:ref:refs/heads/<分支>
    • 不可变 ID 格式(2026-07-15 起新建、重命名或转移的仓库使用,名称后追加 @<组织ID> / @<仓库ID>):repo:<组织>@<组织ID>/<仓库>@<仓库ID>:ref:refs/heads/<分支>
    • 兼容两类仓库时,把两种格式同时放入 oidc:sub 数组即可(StringEquals / StringMatch 均按「请求值与任意一个条件值匹配」判定)。

通配符放宽范围StringMatch 支持 * 匹配任意多字符、? 匹配单字符):

"StringMatch": {
  "oidc:sub": [
    "repo:<组织>/<仓库>:*",        // 放行该仓库的所有分支
    "repo:<组织>/*:*"              // 放行该组织内所有仓库的所有分支
  ]
}
  • oidc:issoidc:aud 是必选条件键,缺少任一会导致创建或修改信任委托时校验失败;oidc:sub 强烈建议配置,用于在共享身份提供商场景下防范「混淆代理」攻击(限定只有指定仓库的流水线能换证),未限定 oidc:sub 时任何仓库的流水线都可能换证。
  • 信任策略元素与条件运算符的完整定义见华为云《身份策略 JSON 元素参考》(StringMatch 推荐使用、StringLike 已标注不推荐);GitHub 平台以 oidc:sub 限定组织/仓库/分支的说明见《创建 OIDC 身份提供商的信任委托》。

为委托授予身份策略

  • 调用 APIG:IAM 自定义身份策略不支持控制可调用的 APIG 接口范围,无需额外配置身份策略——默认即可调用全部以 IAM 认证的 APIG 接口。前提是 APIG 接口的安全认证方式需配置为 IAM 认证。建议为流水线调用新增接口,不要直接修改存量接口的认证方式,避免影响现有业务。
  • 上传 OBS:需在 IAM「策略」中配置自定义身份策略并按最小权限授予。示例(允许读写 openlibing-gitcode-action 桶内所有对象):
{
  "Version": "5.0",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["obs:object:PutObject", "obs:object:GetObject"],
      "Resource": ["obs:*:*:object:openlibing-gitcode-action/*"]
    }
  ]
}

关键配置项对照

配置项 示例值 说明
华为云账号 ID <华为云账号ID> configure({ accountId }) 必须使用真实账号 ID
OIDC 身份提供商 GitCodeActions / GitHubActions configure({ oidcProviderName }) 需与 IAM 侧注册名一致
OIDC 客户端 ID(audience) huawei-cloud-service configure({ audience }) 需与 IAM 侧注册的客户端 ID 一致
IAM 信任委托 gitcode-actions configure({ agencyName }) 需与 IAM 侧委托名一致
区域 cn-southwest-2 configure({ region }) 影响 STS 端点与 APIG 签名 scope

排错时优先核对三处一致性:SDK 配置与华为云侧命名(身份提供商、委托、audience)、区域(APIG 域名、STS、OBS)、签名头完整性(含 X-Security-Token)。开启 configure({ debug: true }) 后,Token 的 iss/aud/azp/sub 声明会在调试日志中打印,可与华为云信任策略逐项比对;换证失败时这些声明也会以 error 级自动补打,无需手动开启。

npm 包构建与发布

npm test          # 运行 SDK 测试
npm run build     # npm pack,产出 openlibing-huaweicloud-oidc-client-x.y.z.tgz(仅含 src/)
npm publish --access public   # 发布到 npm(scoped 包需显式 public)

发布流水线见 .gitcode/workflows/deploy.yml,打 tag 或手动触发即可发布(依赖仓库 secret NPM_TOKEN)。

项目介绍

用于 GitHub/GitCode Actions 中免 AK/SK 调用华为云 APIG 或上传 OBS。该 Node.js SDK 基于 OIDC 经华为云 STS 换取短期临时凭证,支持缓存刷新、APIG 签名和 OBS 接入。【此简介由AI生成】

定制我的领域