API Key

Fystack API key 使用 HMAC secret 或 Ed25519 客户端密钥对来签名请求。本页介绍如何为每种签名方案获取相应的密钥材料。有关签名本身的工作原理,请参阅 API 认证。

除快速测试外,建议优先使用 Client Key Pair(Ed25519)方案。HMAC secret 是你的应用必须持有的明文凭证,而 Ed25519 私钥可以保存在 HSM 或 AWS KMS 中,完全无需可导出,详见下文的客户端密钥对。


HMAC Secret

你无需自行生成密钥。在控制台创建 API key 时如果不注册公钥,Fystack 会为你生成 secret,并以十六进制编码字符串的形式仅显示一次。它比客户端密钥对更易于设置,但该 secret 是你的应用必须持有的明文凭证,条件允许时请优先使用下文的客户端密钥对。

请立即复制 api_secret 并妥善保存,创建后将无法再次获取。如果丢失,请删除该 key 并重新创建。

Using the SDK

import { FystackSDK, Environment } from '@fystack/sdk'

const sdk = new FystackSDK({
  credentials: {
    apiKey: 'YOUR_API_KEY',
    apiSecret: 'YOUR_API_SECRET'
  },
  workspaceId: 'YOUR_WORKSPACE_ID',
  environment: Environment.Production
})

客户端密钥对

使用 Ed25519 方案时,私钥永远不会离开你的进程,在控制台创建 API key 时只需向 Fystack 注册对应的 PEM 公钥。请使用适合你环境的工具生成密钥对,然后将公钥粘贴到控制台中。

Create API Key 对话框,已选择推荐的认证方式 Client Key Pair,使用 Ed25519 公钥且不存储任何 secret

在生产环境中,请在 AWS KMS 或本地 HSM 等有硬件支撑的存储中生成密钥,而不是生成 PEM 文件。这样私钥不可导出,永远不会出现在应用内存或磁盘中,即使主机被攻破也无法被窃取。为此请使用下文的 AwsKmsSigner,LocalPrivateKeySigner 和 PEM 文件仅用于本地开发和测试。

使用 SDK

如果你使用 @fystack/sdk,请在 credentials 中传入 signer 而不是原始密钥,它会为你构建规范字符串并签名每个请求。对于进程内的 PEM 密钥使用 LocalPrivateKeySigner,私钥位于 AWS KMS 中时使用 AwsKmsSigner:

Local PEM key

import { FystackSDK, LocalPrivateKeySigner, Environment } from '@fystack/sdk'

const sdk = new FystackSDK({
  credentials: {
    apiKey: 'YOUR_API_KEY',
    signer: new LocalPrivateKeySigner('-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----')
  },
  workspaceId: 'YOUR_WORKSPACE_ID',
  environment: Environment.Production
})

AwsKmsSigner 需要安装 @aws-sdk/client-kms(采用延迟加载),你也可以通过 client 而不是 clientConfig 传入预先配置好的客户端。它的 clientConfig 会直接传给 new KMSClient(...),因此在基于 LocalStack/ministack 的本地开发与生产环境中有所不同:

Local (LocalStack / ministack)

import { FystackSDK, AwsKmsSigner, Environment } from '@fystack/sdk'

const sdk = new FystackSDK({
  credentials: {
    apiKey: API_KEY,
    signer: new AwsKmsSigner({
      keyId: 'alias/signer',
      clientConfig: {
        region: 'ap-southeast-1',
        endpoint: 'http://localhost:4566',
        credentials: { accessKeyId: 'test', secretAccessKey: 'test' }
      }
    })
  },
  environment: Environment.Production,
  debug: true
})

Production (AWS)

import { FystackSDK, AwsKmsSigner, Environment } from '@fystack/sdk'

const sdk = new FystackSDK({
  credentials: {
    apiKey: API_KEY,
    // Drop endpoint and credentials, the KMS client picks up the
    // task/instance IAM role and the real region automatically.
    signer: new AwsKmsSigner({
      keyId: 'alias/signer',
      clientConfig: { region: 'ap-southeast-1' }
    })
  },
  environment: Environment.Production,
  debug: true
})

切勿在生产环境中硬编码 accessKeyId / secretAccessKey,LocalStack 示例中的这对值是仅限本地使用的固定凭证。请改为由运行时的 IAM 角色提供凭证。

不使用 Node.js?请参阅 Ed25519 签名,了解如何在 Go、Python、PHP 和 Java 中使用本地 PEM 密钥或 AWS KMS 直接签名规范字符串。

使用 OpenSSL 生成密钥对

OpenSSL

openssl genpkey -algorithm ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem

创建 API key 时将 public.pem 的内容粘贴到控制台中,并保留 private.pem 用于签名,以 new LocalPrivateKeySigner(privateKeyPem) 的形式传给 SDK。

使用 AWS KMS 生成密钥对

AWS KMS 支持将 Ed25519 用作非对称签名密钥(ECC_NIST_EDWARDS25519)。先创建密钥,然后导出公钥部分:

Create the key

KEY_ID=$(awslocal kms create-key \
  --key-spec ECC_NIST_EDWARDS25519 --key-usage SIGN_VERIFY \
  --query KeyMetadata.KeyId --output text)
echo "$KEY_ID"

get-public-key 返回的已经是 base64 编码的 DER(SubjectPublicKeyInfo),这正是 PEM 公钥所封装的内容,因此无需再通过 openssl 重新格式化。直接用 PEM 头尾包裹 base64 输出即可:

Export as PEM (shortcut)

{
  echo "-----BEGIN PUBLIC KEY-----"
  awslocal kms get-public-key --key-id alias/signer \
    --query PublicKey --output text
  echo "-----END PUBLIC KEY-----"
} > pub.pem

Ed25519 公钥只有 32 字节,因此 base64 输出足够短,可以保持在一行内。对于更长的密钥,需要按 64 个字符换行(fold -w 64)才能生成有效的 PEM,Ed25519 密钥则不需要这一步。

另一种等效但更长的方式(先解码为 DER,再由 openssl 重新编码为 PEM)会生成完全相同的文件:

Export as PEM (via openssl)

awslocal kms get-public-key --key-id alias/signer \
  --query PublicKey --output text | base64 -d > pub.der
openssl pkey -pubin -inform DER -in pub.der -out pub.pem

无论哪种方式,最终都会得到:

pub.pem

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAKZ0GCR0MBIQGZowZI/1xmWjXlBy09I98JC6Tgn0l0L4=
-----END PUBLIC KEY-----

将其作为该 key 的公钥粘贴到控制台中。私钥保留在 KMS 中,按上文所示使用 new AwsKmsSigner({ keyId: 'alias/signer' }) 签名请求,KMS 永远不会暴露私钥材料。