From 7f8989faa18dfe47c0c5d90fc4510486d200bd82 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 7 Dec 2025 02:38:31 +0000
Subject: [PATCH 1/2] Initial plan
From 24970276026495517cf61bb76e68978826efdd52 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 7 Dec 2025 02:57:18 +0000
Subject: [PATCH 2/2] Add comprehensive user troubleshooting guide
(USER_GUIDE_CN.md)
Co-authored-by: CodeSpaceiiii <129646304+CodeSpaceiiii@users.noreply.github.com>
---
USER_GUIDE_CN.md | 1368 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1368 insertions(+)
create mode 100644 USER_GUIDE_CN.md
diff --git a/USER_GUIDE_CN.md b/USER_GUIDE_CN.md
new file mode 100644
index 0000000..bd59598
--- /dev/null
+++ b/USER_GUIDE_CN.md
@@ -0,0 +1,1368 @@
+# 阿里云 Credentials Java SDK - 用户故障排查指南
+
+## 1. 项目简介
+
+**Alibaba Cloud Credentials for Java** 是阿里云官方提供的 Java 凭证管理工具,用于帮助开发者安全、便捷地管理和获取访问阿里云服务所需的身份凭证。
+
+### 核心能力
+
+- **多种凭证类型支持**:支持 AccessKey、STS Token、ECS RAM 角色、RAM 角色扮演、OIDC、RSA 密钥对、Bearer Token 等多种凭证类型
+- **自动凭证刷新**:对于临时凭证(如 STS Token),SDK 会自动在过期前刷新,无需手动管理
+- **凭证提供链**:支持按优先级从多个来源自动获取凭证,简化配置
+- **安全性**:敏感信息不会输出到日志,支持 IMDSv2 等安全特性
+
+### 典型应用场景
+
+- **本地开发环境**:使用环境变量或配置文件存储 AccessKey,便于本地调试
+- **ECS 实例运行**:通过实例绑定的 RAM 角色自动获取临时凭证,无需硬编码密钥
+- **CI/CD 流水线**:使用 OIDC 或临时 STS Token,避免泄露长期密钥
+- **容器化部署**:通过环境变量或 Credentials URI 动态获取凭证
+- **多云/混合云场景**:使用 RAM 角色扮演实现跨账号或跨平台的凭证管理
+
+---
+
+## 2. 使用前提与环境要求
+
+### 操作系统要求
+
+- **支持平台**:Linux、macOS、Windows
+- **特殊说明**:
+ - ECS RAM 角色凭证仅在阿里云 ECS 实例内可用
+ - OIDC 凭证需要文件系统支持(读取 Token 文件)
+
+### 运行时环境
+
+- **JDK 版本**:**JDK 1.8 或更高版本**(从 1.0.0 版本起不再支持 JDK 7)
+- **构建工具**:Maven 3.x 或 Gradle(推荐 Maven 3.6+)
+
+### Maven 依赖配置
+
+```xml
+
+ com.aliyun
+ credentials-java
+ 1.0.3
+
+```
+
+### 系统依赖
+
+- **网络访问**:
+ - 使用 RAM 角色扮演、OIDC、RSA 密钥对时,需要访问 STS 服务(默认 `sts.aliyuncs.com`)
+ - 使用 ECS RAM 角色时,需要访问 ECS 元数据服务(`100.100.100.200`)
+ - 使用 Credentials URI 时,需要访问指定的 HTTP/HTTPS 服务
+
+- **文件系统权限**:
+ - 配置文件路径默认为 `~/.alibabacloud/credentials`(Linux/macOS)或 `C:\Users\<用户名>\.alibabacloud\credentials`(Windows)
+ - OIDC Token 文件、RSA 私钥文件需要具备读取权限
+
+### 权限要求
+
+- **RAM 权限**:
+ - 使用 RAM 角色扮演时,AccessKey 对应的用户需要拥有 `sts:AssumeRole` 权限
+ - 使用 RSA 密钥对时,需要 `sts:GenerateSessionAccessKey` 权限
+ - 使用 OIDC 时,需要 `sts:AssumeRoleWithOIDC` 权限
+
+- **ECS 实例元数据访问**:
+ - ECS 实例需要绑定 RAM 角色
+ - 安全组规则需允许访问元数据服务(默认已放行)
+
+### 可选环境变量
+
+SDK 支持通过环境变量覆盖配置,常用环境变量包括:
+
+| 环境变量名称 | 用途 | 示例值 |
+|-------------|------|--------|
+| `ALIBABA_CLOUD_ACCESS_KEY_ID` | AccessKey ID | `LTAI5t...` |
+| `ALIBABA_CLOUD_ACCESS_KEY_SECRET` | AccessKey Secret | `xxx...` |
+| `ALIBABA_CLOUD_SECURITY_TOKEN` | STS Token | `CAISxxx...` |
+| `ALIBABA_CLOUD_ROLE_ARN` | RAM 角色 ARN | `acs:ram::123456:role/MyRole` |
+| `ALIBABA_CLOUD_ROLE_SESSION_NAME` | 角色会话名称 | `session-name` |
+| `ALIBABA_CLOUD_OIDC_PROVIDER_ARN` | OIDC 提供商 ARN | `acs:ram::123456:oidc-provider/provider` |
+| `ALIBABA_CLOUD_OIDC_TOKEN_FILE` | OIDC Token 文件路径 | `/var/run/secrets/token` |
+| `ALIBABA_CLOUD_CREDENTIALS_FILE` | 凭证配置文件路径 | `/path/to/credentials` |
+| `ALIBABA_CLOUD_PROFILE` | 使用的配置节名称 | `default` |
+| `ALIBABA_CLOUD_ECS_METADATA` | ECS 角色名称 | `MyEcsRole` |
+| `ALIBABA_CLOUD_IMDSV1_DISABLED` | 禁用 IMDSv1 | `true` |
+| `ALIBABA_CLOUD_ECS_METADATA_DISABLED` | 禁用 ECS 元数据 | `true` |
+| `ALIBABA_CLOUD_CLI_PROFILE_DISABLED` | 禁用 CLI Profile | `true` |
+| `ALIBABA_CLOUD_CREDENTIALS_URI` | 凭证服务 URI | `http://localhost:8080/credentials` |
+
+---
+
+## 3. 快速开始指南
+
+### 安装步骤
+
+#### 1. 添加 Maven 依赖
+
+在项目的 `pom.xml` 文件中添加:
+
+```xml
+
+ com.aliyun
+ credentials-java
+ 1.0.3
+
+```
+
+#### 2. 构建项目
+
+```bash
+mvn clean install
+```
+
+### 配置说明
+
+#### 方式一:使用环境变量(推荐用于容器化部署)
+
+```bash
+export ALIBABA_CLOUD_ACCESS_KEY_ID="your-access-key-id"
+export ALIBABA_CLOUD_ACCESS_KEY_SECRET="your-access-key-secret"
+```
+
+#### 方式二:使用配置文件(推荐用于本地开发)
+
+创建文件 `~/.alibabacloud/credentials`:
+
+```ini
+[default]
+enable = true
+type = access_key
+access_key_id = your-access-key-id
+access_key_secret = your-access-key-secret
+```
+
+#### 方式三:在代码中显式配置
+
+```java
+import com.aliyun.credentials.Client;
+import com.aliyun.credentials.models.Config;
+
+public class Example {
+ public static void main(String[] args) throws Exception {
+ Config config = new Config();
+ config.setType("access_key");
+ config.setAccessKeyId("your-access-key-id");
+ config.setAccessKeySecret("your-access-key-secret");
+
+ Client client = new Client(config);
+ System.out.println("AccessKeyId: " + client.getCredential().getAccessKeyId());
+ }
+}
+```
+
+### 启动与验证
+
+#### 使用默认凭证提供链(零配置)
+
+```java
+import com.aliyun.credentials.Client;
+import com.aliyun.credentials.models.CredentialModel;
+
+public class QuickStart {
+ public static void main(String[] args) {
+ try {
+ // 自动按优先级查找凭证
+ Client client = new Client();
+ CredentialModel credential = client.getCredential();
+
+ System.out.println("凭证类型: " + credential.getType());
+ System.out.println("AccessKeyId: " + credential.getAccessKeyId());
+ System.out.println("提供者: " + credential.getProviderName());
+
+ } catch (Exception e) {
+ System.err.println("获取凭证失败: " + e.getMessage());
+ }
+ }
+}
+```
+
+#### 预期输出示例
+
+```
+凭证类型: access_key
+AccessKeyId: LTAI5t***
+提供者: default/env
+```
+
+---
+
+## 4. 常见问题解答(FAQ)
+
+### 4.1 凭证链相关问题
+
+#### Q1: 报错 "Unable to load credentials from any of the providers in the chain"
+
+**问题现象**:
+```
+com.aliyun.credentials.exception.CredentialException: Unable to load credentials from any of the providers in the chain: [SystemPropertiesCredentialsProvider: ..., EnvironmentVariableCredentialsProvider: ..., ...]
+```
+
+**根本原因**:
+使用默认凭证提供链时(即 `new Client()` 不传参数),SDK 会按以下顺序尝试获取凭证:
+1. 系统属性(System Properties)
+2. 环境变量
+3. OIDC 凭证(如果环境变量配置了相关参数)
+4. Aliyun CLI 配置文件
+5. `~/.alibabacloud/credentials` 配置文件
+6. ECS 实例元数据服务
+7. Credentials URI(如果配置了环境变量)
+
+当所有来源都无法获取到有效凭证时,会抛出此异常。
+
+**解决方案**:
+
+1. **检查环境变量是否正确设置**:
+ ```bash
+ echo $ALIBABA_CLOUD_ACCESS_KEY_ID
+ echo $ALIBABA_CLOUD_ACCESS_KEY_SECRET
+ ```
+
+2. **检查配置文件是否存在且格式正确**:
+ ```bash
+ cat ~/.alibabacloud/credentials
+ ```
+
+ 确保至少有一个启用的配置节:
+ ```ini
+ [default]
+ enable = true
+ type = access_key
+ access_key_id = your-key-id
+ access_key_secret = your-key-secret
+ ```
+
+3. **显式配置凭证,不依赖凭证链**:
+ ```java
+ Config config = new Config();
+ config.setType("access_key");
+ config.setAccessKeyId("your-key-id");
+ config.setAccessKeySecret("your-key-secret");
+ Client client = new Client(config);
+ ```
+
+4. **查看详细错误信息**(错误消息中会列出每个提供者失败的原因):
+ - 仔细阅读每个 Provider 的失败原因
+ - 常见子错误包括:"The specified credentials file is empty"、"Client is not open in the specified credentials file" 等
+
+---
+
+#### Q2: 配置文件存在但仍报 "Client is not open in the specified credentials file"
+
+**问题现象**:
+配置文件 `~/.alibabacloud/credentials` 已创建,但仍提示无法找到配置。
+
+**根本原因**:
+1. 配置节的 `enable` 字段未设置为 `true`(默认为 `false`)
+2. 使用了非 `default` 的配置节名称,但未通过 `ALIBABA_CLOUD_PROFILE` 环境变量指定
+3. 配置文件格式错误(如缺少必要字段)
+
+**解决方案**:
+
+1. **确保启用配置节**:
+ ```ini
+ [default]
+ enable = true # 必须显式设置为 true
+ type = access_key
+ access_key_id = foo
+ access_key_secret = bar
+ ```
+
+2. **使用非 default 配置节时,设置环境变量**:
+ ```bash
+ export ALIBABA_CLOUD_PROFILE=my-profile
+ ```
+
+ 对应配置文件:
+ ```ini
+ [my-profile]
+ enable = true
+ type = access_key
+ ...
+ ```
+
+3. **检查配置文件权限**(Linux/macOS):
+ ```bash
+ ls -l ~/.alibabacloud/credentials
+ # 确保当前用户有读权限
+ chmod 600 ~/.alibabacloud/credentials
+ ```
+
+---
+
+#### Q3: 报错 "The specified credentials file is empty"
+
+**问题现象**:
+```
+CredentialException: The specified credentials file is empty.
+```
+
+**根本原因**:
+通过 `ALIBABA_CLOUD_CREDENTIALS_FILE` 环境变量指定的配置文件路径为空字符串(而非 `null`)。
+
+**解决方案**:
+
+1. **检查环境变量**:
+ ```bash
+ echo "[$ALIBABA_CLOUD_CREDENTIALS_FILE]"
+ # 如果输出为 [],说明是空字符串
+ ```
+
+2. **取消设置或设置正确路径**:
+ ```bash
+ unset ALIBABA_CLOUD_CREDENTIALS_FILE
+ # 或者
+ export ALIBABA_CLOUD_CREDENTIALS_FILE=/path/to/credentials
+ ```
+
+---
+
+### 4.2 AccessKey 凭证问题
+
+#### Q4: 报错 "AccessKeyId must not be null" 或 "AccessKeySecret must not be null"
+
+**问题现象**:
+```java
+java.lang.IllegalArgumentException: AccessKeyId must not be null.
+```
+
+**根本原因**:
+显式配置 `access_key` 或 `sts` 类型凭证时,未提供必需的 `accessKeyId` 或 `accessKeySecret` 字段。
+
+**解决方案**:
+
+1. **检查代码配置**:
+ ```java
+ Config config = new Config();
+ config.setType("access_key");
+ config.setAccessKeyId("LTAI5t..."); // 不能为 null 或空字符串
+ config.setAccessKeySecret("xxx..."); // 不能为 null 或空字符串
+ ```
+
+2. **检查配置文件**:
+ ```ini
+ [default]
+ enable = true
+ type = access_key
+ access_key_id = your-key-id # 必填
+ access_key_secret = your-secret # 必填
+ ```
+
+3. **检查环境变量**:
+ ```bash
+ # 确保两个环境变量都已设置且非空
+ [ -z "$ALIBABA_CLOUD_ACCESS_KEY_ID" ] && echo "AccessKeyId is empty!"
+ [ -z "$ALIBABA_CLOUD_ACCESS_KEY_SECRET" ] && echo "AccessKeySecret is empty!"
+ ```
+
+---
+
+#### Q5: 配置文件中 AccessKey 提示 "The configured access_key_id or access_key_secret is empty"
+
+**问题现象**:
+配置文件中明明设置了 `access_key_id` 和 `access_key_secret`,但仍提示为空。
+
+**根本原因**:
+配置文件中字段名拼写错误,正确的字段名是 `access_key_id` 和 `access_key_secret`(注意下划线),但代码内部解析时可能因为历史原因使用了不同的常量名。
+
+**解决方案**:
+
+1. **严格按照文档使用字段名**:
+ ```ini
+ [default]
+ enable = true
+ type = access_key
+ access_key_id = foo # 注意是 access_key_id,不是 accessKeyId
+ access_key_secret = bar # 注意是 access_key_secret
+ ```
+
+2. **避免字段名中有多余空格或特殊字符**:
+ ```ini
+ # 错误示例
+ access_key_id = foo # 等号前后有多余空格可能导致解析失败
+
+ # 正确示例
+ access_key_id = foo
+ ```
+
+---
+
+### 4.3 STS 临时凭证问题
+
+#### Q6: 报错 "SecurityToken must not be null"
+
+**问题现象**:
+```
+IllegalArgumentException: SecurityToken must not be null.
+```
+
+**根本原因**:
+使用 `sts` 类型凭证时,`securityToken` 是必填字段,但未提供或为空。
+
+**解决方案**:
+
+1. **确保三个字段都提供**:
+ ```java
+ Config config = new Config();
+ config.setType("sts");
+ config.setAccessKeyId("STS.xxx");
+ config.setAccessKeySecret("xxx");
+ config.setSecurityToken("CAISxxx"); // 必填
+ ```
+
+2. **从 STS 服务正确获取 Token**:
+ ```bash
+ # 示例:通过 AssumeRole 获取临时凭证
+ aliyun sts AssumeRole --RoleArn acs:ram::xxx:role/xxx --RoleSessionName test
+ ```
+
+3. **注意 Token 有效期**(默认 1 小时):
+ - STS Token 过期后会导致认证失败
+ - 使用 RAM 角色扮演时,SDK 会自动刷新,无需手动管理
+
+---
+
+### 4.4 ECS RAM 角色问题
+
+#### Q7: 报错 "Failed to connect ECS Metadata Service"
+
+**问题现象**:
+```
+CredentialException: Failed to connect ECS Metadata Service: Connection refused
+```
+
+**根本原因**:
+1. **非 ECS 环境**:在本地开发环境或非阿里云 ECS 实例上运行代码
+2. **网络不通**:元数据服务地址 `100.100.100.200` 无法访问
+3. **超时设置过短**:默认连接超时为 1 秒,读取超时为 1 秒
+
+**解决方案**:
+
+1. **确认运行环境是 ECS 实例**:
+ ```bash
+ curl http://100.100.100.200/latest/meta-data/
+ # 应返回元数据内容,如果失败说明非 ECS 环境
+ ```
+
+2. **本地开发时禁用 ECS 元数据提供者**:
+ ```bash
+ export ALIBABA_CLOUD_ECS_METADATA_DISABLED=true
+ ```
+
+ 或在代码中:
+ ```java
+ AuthUtils.disableECSMetaData(true);
+ ```
+
+3. **增加超时时间**(如果网络延迟较高):
+ ```java
+ Config config = new Config();
+ config.setType("ecs_ram_role");
+ config.setConnectTimeout(5000); // 5 秒
+ config.setTimeout(5000); // 5 秒
+ ```
+
+---
+
+#### Q8: 报错 "The role name was not found in the instance"
+
+**问题现象**:
+```
+CredentialException: The role name was not found in the instance.
+```
+
+**根本原因**:
+1. ECS 实例未绑定 RAM 角色
+2. 指定的角色名称不存在或拼写错误
+
+**解决方案**:
+
+1. **检查实例是否绑定了 RAM 角色**:
+ ```bash
+ # 在 ECS 实例内执行
+ curl http://100.100.100.200/latest/meta-data/ram/security-credentials/
+ # 应返回角色名称,如果返回空或 404,说明未绑定角色
+ ```
+
+2. **在阿里云控制台为实例绑定 RAM 角色**:
+ - 进入 ECS 控制台 -> 实例列表
+ - 选择目标实例 -> 更多 -> 实例设置 -> 授予/收回 RAM 角色
+ - 选择已创建的 RAM 角色并授予
+
+3. **代码中不指定角色名(推荐)**:
+ ```java
+ Config config = new Config();
+ config.setType("ecs_ram_role");
+ // 不设置 roleName,SDK 会自动从元数据服务获取
+ ```
+
+4. **如果必须指定角色名,确保拼写正确**:
+ ```java
+ config.setRoleName("MyEcsRole"); // 与控制台中的角色名一致
+ ```
+
+---
+
+#### Q9: 报错 "IMDS credentials is disabled"
+
+**问题现象**:
+```
+CredentialException: IMDS credentials is disabled.
+```
+
+**根本原因**:
+通过环境变量 `ALIBABA_CLOUD_ECS_METADATA_DISABLED=true` 禁用了 ECS 元数据服务,但代码中仍尝试使用 ECS RAM 角色凭证。
+
+**解决方案**:
+
+1. **取消禁用设置**:
+ ```bash
+ unset ALIBABA_CLOUD_ECS_METADATA_DISABLED
+ ```
+
+2. **或在代码中覆盖**:
+ ```java
+ AuthUtils.disableECSMetaData(false);
+ ```
+
+3. **使用其他凭证类型**(如果确实需要禁用 IMDS):
+ ```java
+ Config config = new Config();
+ config.setType("access_key"); // 改用 AccessKey
+ config.setAccessKeyId("...");
+ config.setAccessKeySecret("...");
+ ```
+
+---
+
+#### Q10: ECS RAM 角色凭证刷新失败
+
+**问题现象**:
+日志中出现 "Failed when checking or refreshing credentials asynchronously",但程序仍能正常运行一段时间。
+
+**根本原因**:
+SDK 默认启用异步凭证刷新机制(每分钟检查一次),网络抖动或元数据服务临时不可用会导致刷新失败,但旧凭证在有效期内仍可使用。
+
+**解决方案**:
+
+1. **这是警告而非错误**,如果偶尔出现可忽略
+2. **检查网络稳定性**:
+ ```bash
+ ping -c 10 100.100.100.200
+ ```
+
+3. **增加超时时间**(如果网络延迟高):
+ ```java
+ config.setConnectTimeout(3000);
+ config.setTimeout(3000);
+ ```
+
+4. **禁用异步刷新**(不推荐):
+ ```java
+ EcsRamRoleCredentialProvider provider = EcsRamRoleCredentialProvider.builder()
+ .roleName("MyRole")
+ .asyncCredentialUpdateEnabled(false) // 禁用异步刷新
+ .build();
+ Client client = new Client(provider);
+ ```
+
+---
+
+### 4.5 RAM 角色扮演(RamRoleArn)问题
+
+#### Q11: 报错 "The configured role_session_name or role_arn is empty"
+
+**问题现象**:
+```
+CredentialException: The configured role_session_name or role_arn is empty.
+```
+
+**根本原因**:
+使用 `ram_role_arn` 类型凭证时,`roleArn` 和 `roleSessionName` 是必填字段。
+
+**解决方案**:
+
+1. **显式配置所有必需字段**:
+ ```java
+ Config config = new Config();
+ config.setType("ram_role_arn");
+ config.setAccessKeyId("...");
+ config.setAccessKeySecret("...");
+ config.setRoleArn("acs:ram::123456789012:role/MyRole"); // 必填
+ config.setRoleSessionName("mySession"); // 必填
+ ```
+
+2. **配置文件格式**:
+ ```ini
+ [default]
+ enable = true
+ type = ram_role_arn
+ access_key_id = foo
+ access_key_secret = bar
+ role_arn = acs:ram::123456789012:role/MyRole
+ role_session_name = mySession
+ ```
+
+3. **使用环境变量**:
+ ```bash
+ export ALIBABA_CLOUD_ROLE_ARN=acs:ram::123456789012:role/MyRole
+ export ALIBABA_CLOUD_ROLE_SESSION_NAME=mySession
+ ```
+
+---
+
+#### Q12: 报错 "InvalidParameter: The parameter RoleSessionName is wrongly formed"
+
+**问题现象**:
+调用 STS AssumeRole 接口时返回参数格式错误。
+
+**根本原因**:
+`roleSessionName` 有格式要求:
+- 长度:2-64 个字符
+- 允许字符:字母、数字、`.`、`@`、`-`、`_`
+- 不能包含特殊字符或空格
+
+**解决方案**:
+
+1. **使用符合规范的会话名称**:
+ ```java
+ config.setRoleSessionName("my-session-2024"); // 正确
+ // config.setRoleSessionName("我的会话"); // 错误:包含中文
+ // config.setRoleSessionName("a"); // 错误:长度不足
+ ```
+
+2. **不设置时会自动生成**(推荐):
+ ```java
+ // SDK 会自动生成形如 "credentials-java-1702345678901" 的会话名
+ Config config = new Config();
+ config.setType("ram_role_arn");
+ config.setRoleArn("...");
+ // 不设置 roleSessionName
+ ```
+
+---
+
+#### Q13: 报错 "You are not authorized to do this action: sts:AssumeRole"
+
+**问题现象**:
+```
+SDK.ServerError: You are not authorized to do this action. You should be authorized by RAM.
+```
+
+**根本原因**:
+1. 用于调用 AssumeRole 的 AccessKey 对应用户无权限
+2. RAM 角色的信任策略未授权当前用户
+3. 角色 ARN 填写错误或角色不存在
+
+**解决方案**:
+
+1. **授予 RAM 用户 AssumeRole 权限**:
+
+ 在 RAM 控制台为用户添加自定义策略:
+ ```json
+ {
+ "Version": "1",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": "sts:AssumeRole",
+ "Resource": "acs:ram::123456789012:role/MyRole"
+ }
+ ]
+ }
+ ```
+
+2. **修改 RAM 角色的信任策略**:
+
+ 在 RAM 控制台 -> 角色管理 -> 信任策略管理,确保包含:
+ ```json
+ {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "RAM": [
+ "acs:ram::123456789012:user/MyUser"
+ ]
+ }
+ }
+ ],
+ "Version": "1"
+ }
+ ```
+
+3. **检查角色 ARN 格式**:
+ ```
+ 正确格式:acs:ram::123456789012:role/MyRole
+ # 其中 123456789012 是账号 ID,MyRole 是角色名
+ ```
+
+---
+
+### 4.6 OIDC 凭证问题
+
+#### Q14: 报错 "OIDCTokenFilePath xxx is not exists" 或 "cannot be read"
+
+**问题现象**:
+```
+CredentialException: OIDCTokenFilePath /var/run/secrets/token is not exists.
+```
+
+**根本原因**:
+1. OIDC Token 文件路径不存在
+2. 文件存在但当前进程无读取权限
+
+**解决方案**:
+
+1. **检查文件是否存在**:
+ ```bash
+ ls -l /var/run/secrets/token
+ ```
+
+2. **确保文件可读**:
+ ```bash
+ chmod 644 /var/run/secrets/token
+ # 或者只给特定用户权限
+ chown myuser:mygroup /var/run/secrets/token
+ chmod 600 /var/run/secrets/token
+ ```
+
+3. **Kubernetes 环境中确保 Volume 挂载正确**:
+ ```yaml
+ volumes:
+ - name: oidc-token
+ projected:
+ sources:
+ - serviceAccountToken:
+ path: token
+ expirationSeconds: 7200
+ audience: "sts.aliyuncs.com"
+ volumeMounts:
+ - name: oidc-token
+ mountPath: /var/run/secrets/tokens
+ readOnly: true
+ ```
+
+4. **检查路径配置**:
+ ```java
+ config.setOidcTokenFilePath("/var/run/secrets/tokens/token"); // 确保路径正确
+ ```
+
+---
+
+#### Q15: 报错 "roleArn does not exist and env ALIBABA_CLOUD_ROLE_ARN is null"
+
+**问题现象**:
+使用 OIDC 凭证时,未提供 `roleArn` 且环境变量也未设置。
+
+**根本原因**:
+OIDC 凭证需要三个必填参数:`roleArn`、`oidcProviderArn`、`oidcTokenFilePath`。如果代码中未提供,SDK 会尝试从环境变量读取,若都不存在则报错。
+
+**解决方案**:
+
+1. **在代码中完整配置**:
+ ```java
+ Config config = new Config();
+ config.setType("oidc_role_arn");
+ config.setRoleArn("acs:ram::123456:role/MyRole");
+ config.setOidcProviderArn("acs:ram::123456:oidc-provider/MyProvider");
+ config.setOidcTokenFilePath("/var/run/secrets/token");
+ config.setRoleSessionName("mySession");
+ ```
+
+2. **使用环境变量(推荐用于 Kubernetes)**:
+ ```bash
+ export ALIBABA_CLOUD_ROLE_ARN=acs:ram::123456:role/MyRole
+ export ALIBABA_CLOUD_OIDC_PROVIDER_ARN=acs:ram::123456:oidc-provider/MyProvider
+ export ALIBABA_CLOUD_OIDC_TOKEN_FILE=/var/run/secrets/token
+ ```
+
+ 然后代码中可以使用默认凭证链:
+ ```java
+ Client client = new Client(); // 自动从环境变量读取 OIDC 配置
+ ```
+
+---
+
+### 4.7 配置文件格式问题
+
+#### Q16: 配置文件解析失败或无法读取
+
+**问题现象**:
+配置文件存在但 SDK 无法正确解析,或抛出 "Unable to open credentials file" 异常。
+
+**根本原因**:
+1. 文件不存在或路径错误
+2. 文件格式错误(INI 格式要求严格)
+3. 文件编码问题(应使用 UTF-8)
+
+**解决方案**:
+
+1. **检查文件路径**:
+ ```bash
+ # Linux/macOS
+ ls -la ~/.alibabacloud/credentials
+
+ # Windows
+ dir C:\Users\<用户名>\.alibabacloud\credentials
+ ```
+
+2. **确保 INI 格式正确**:
+ ```ini
+ # 正确示例
+ [default]
+ enable = true
+ type = access_key
+ access_key_id = foo
+ access_key_secret = bar
+
+ # 常见错误
+ [default # 缺少右括号
+ enable = true
+ type=access_key # 等号两边最好有空格
+ access_key_id = # 值为空
+ ```
+
+3. **检查文件编码**:
+ ```bash
+ file -i ~/.alibabacloud/credentials
+ # 应显示 charset=utf-8
+ ```
+
+4. **使用绝对路径**(避免相对路径问题):
+ ```bash
+ export ALIBABA_CLOUD_CREDENTIALS_FILE=/home/user/.alibabacloud/credentials
+ ```
+
+---
+
+#### Q17: 多个配置节时无法切换
+
+**问题现象**:
+配置文件中定义了多个配置节(如 `[default]`、`[prod]`、`[dev]`),但始终使用 `[default]`。
+
+**根本原因**:
+未通过 `ALIBABA_CLOUD_PROFILE` 环境变量指定要使用的配置节名称。
+
+**解决方案**:
+
+1. **设置环境变量**:
+ ```bash
+ export ALIBABA_CLOUD_PROFILE=prod
+ ```
+
+2. **或在代码中设置**:
+ ```java
+ AuthUtils.setClientType("prod");
+ ```
+
+3. **配置文件示例**:
+ ```ini
+ [default]
+ enable = true
+ type = access_key
+ access_key_id = dev-key
+ access_key_secret = dev-secret
+
+ [prod]
+ enable = true
+ type = ecs_ram_role
+ role_name = ProdRole
+ ```
+
+---
+
+### 4.8 网络与超时问题
+
+#### Q18: 报错 "Read timed out" 或 "Connect timed out"
+
+**问题现象**:
+```
+java.net.SocketTimeoutException: Read timed out
+```
+
+**根本原因**:
+1. 网络延迟过高,超过默认超时时间(连接 10 秒,读取 5 秒)
+2. 目标服务(STS、元数据服务)不可达
+3. 防火墙或安全组阻止访问
+
+**解决方案**:
+
+1. **增加超时时间**:
+ ```java
+ Config config = new Config();
+ config.setType("ram_role_arn");
+ config.setConnectTimeout(30000); // 30 秒
+ config.setTimeout(30000); // 30 秒
+ ```
+
+2. **检查网络连通性**:
+ ```bash
+ # 测试 STS 服务
+ ping sts.aliyuncs.com
+ curl -v https://sts.aliyuncs.com
+
+ # 测试 ECS 元数据服务
+ curl -v http://100.100.100.200/latest/meta-data/
+ ```
+
+3. **检查代理设置**(如果使用代理):
+ ```bash
+ echo $HTTP_PROXY
+ echo $HTTPS_PROXY
+ ```
+
+4. **配置 VPC 内网终端节点**(提高访问速度):
+ ```bash
+ export ALIBABA_CLOUD_VPC_ENDPOINT_ENABLED=true
+ ```
+
+---
+
+#### Q19: 无法访问 STS 服务
+
+**问题现象**:
+使用 RAM 角色扮演、OIDC 或 RSA 密钥对时,报 "Connection refused" 或 "UnknownHostException"。
+
+**根本原因**:
+1. 无外网访问权限(ECS 实例未绑定公网 IP 或 NAT 网关)
+2. 域名解析失败
+3. 自定义 STS Endpoint 配置错误
+
+**解决方案**:
+
+1. **确保可以访问公网**:
+ ```bash
+ ping sts.aliyuncs.com
+ # 如果失败,需要配置公网访问
+ ```
+
+2. **使用 VPC 内网终端节点**(推荐):
+ ```bash
+ export ALIBABA_CLOUD_VPC_ENDPOINT_ENABLED=true
+ ```
+
+ 或在代码中:
+ ```java
+ AuthUtils.enableVpcEndpoint(true);
+ ```
+
+3. **自定义 STS Endpoint**(特殊场景):
+ ```java
+ config.setSTSEndpoint("sts-vpc.cn-hangzhou.aliyuncs.com");
+ ```
+
+4. **检查 DNS 解析**:
+ ```bash
+ nslookup sts.aliyuncs.com
+ ```
+
+---
+
+### 4.9 凭证类型与配置不匹配问题
+
+#### Q20: 报错 "invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair"
+
+**问题现象**:
+```
+CredentialException: invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair
+```
+
+**根本原因**:
+配置的凭证类型(`type` 字段)不在支持的类型列表中,或拼写错误。
+
+**解决方案**:
+
+1. **使用正确的类型名称**:
+ - `access_key`:长期 AccessKey
+ - `sts`:临时 STS Token
+ - `ecs_ram_role`:ECS RAM 角色
+ - `ram_role_arn`:RAM 角色扮演
+ - `oidc_role_arn`:OIDC 凭证
+ - `rsa_key_pair`:RSA 密钥对
+ - `bearer`:Bearer Token
+ - `credentials_uri`:Credentials URI
+
+2. **检查拼写**:
+ ```java
+ // 错误
+ config.setType("accesskey"); // 应为 access_key
+ config.setType("ram_role"); // 应为 ecs_ram_role 或 ram_role_arn
+
+ // 正确
+ config.setType("access_key");
+ ```
+
+---
+
+#### Q21: 使用错误的凭证类型导致字段缺失
+
+**问题现象**:
+例如使用 `ecs_ram_role` 类型时设置了 `accessKeyId` 和 `accessKeySecret`,但凭证无效。
+
+**根本原因**:
+不同凭证类型所需的配置字段不同,混用会导致必需字段缺失。
+
+**解决方案**:
+
+**各类型所需字段对照表**:
+
+| 类型 | 必需字段 | 可选字段 |
+|-----|---------|---------|
+| `access_key` | `accessKeyId`, `accessKeySecret` | - |
+| `sts` | `accessKeyId`, `accessKeySecret`, `securityToken` | - |
+| `ecs_ram_role` | - | `roleName`, `disableIMDSv1` |
+| `ram_role_arn` | `accessKeyId`, `accessKeySecret`, `roleArn`, `roleSessionName` | `policy`, `externalId`, `roleSessionExpiration` |
+| `oidc_role_arn` | `roleArn`, `oidcProviderArn`, `oidcTokenFilePath` | `roleSessionName`, `policy`, `roleSessionExpiration` |
+| `rsa_key_pair` | `publicKeyId`, `privateKeyFile` | `roleSessionExpiration` |
+| `bearer` | `bearerToken` | - |
+| `credentials_uri` | `credentialsUri` | - |
+
+**示例**:
+```java
+// 错误:ECS RAM 角色不需要 AccessKey
+Config config = new Config();
+config.setType("ecs_ram_role");
+config.setAccessKeyId("xxx"); // 多余
+config.setAccessKeySecret("xxx"); // 多余
+
+// 正确
+Config config = new Config();
+config.setType("ecs_ram_role");
+config.setRoleName("MyRole"); // 可选
+```
+
+---
+
+### 4.10 凭证安全与最佳实践问题
+
+#### Q22: 如何避免 AccessKey 泄露?
+
+**问题现象**:
+担心硬编码在代码中的 AccessKey 被泄露到版本控制系统或日志中。
+
+**最佳实践**:
+
+1. **永远不要硬编码凭证**:
+ ```java
+ // ❌ 错误做法
+ config.setAccessKeyId("LTAI5t...");
+ config.setAccessKeySecret("xxxxx");
+
+ // ✅ 正确做法:使用环境变量
+ String keyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
+ config.setAccessKeyId(keyId);
+ ```
+
+2. **生产环境优先使用 RAM 角色**:
+ - ECS 上部署:使用 `ecs_ram_role`
+ - 容器化部署:使用 `oidc_role_arn`
+ - 临时访问:使用 `ram_role_arn` + STS
+
+3. **使用配置文件时注意权限**:
+ ```bash
+ chmod 600 ~/.alibabacloud/credentials
+ # 确保只有当前用户可读写
+ ```
+
+4. **将配置文件添加到 .gitignore**:
+ ```
+ .alibabacloud/
+ *.credentials
+ ```
+
+5. **启用 RAM 最小权限原则**:
+ - 为不同应用创建不同的 RAM 用户
+ - 仅授予必需的权限
+ - 定期轮换 AccessKey
+
+---
+
+#### Q23: 如何在日志中隐藏敏感信息?
+
+**问题现象**:
+担心 AccessKey、Token 等敏感信息出现在日志或错误堆栈中。
+
+**SDK 保护措施**:
+
+SDK 已内置敏感信息脱敏机制:
+- `CredentialModel.toString()` 方法会自动隐藏 `accessKeySecret`、`securityToken`、`bearerToken` 等敏感字段
+- 输出格式:`CredentialModel{accessKeyId='LTAI5t...', type='access_key', ...}` (不显示完整密钥)
+
+**额外建议**:
+
+1. **避免打印完整凭证对象**:
+ ```java
+ // ❌ 避免
+ System.out.println("Full credential: " + credential);
+ logger.info("Credential: {}", credential);
+
+ // ✅ 推荐
+ logger.info("Using credential type: {}", credential.getType());
+ logger.info("Provider: {}", credential.getProviderName());
+ ```
+
+2. **配置日志框架脱敏规则**(以 Logback 为例):
+ ```xml
+
+
+
+ ```
+
+---
+
+#### Q24: 凭证过期后如何自动刷新?
+
+**问题现象**:
+使用 STS 临时凭证时,担心过期后需要重启应用。
+
+**SDK 自动刷新机制**:
+
+SDK 会自动管理临时凭证的刷新,无需手动干预:
+
+1. **RAM 角色扮演(RamRoleArn)**:
+ - SDK 会在凭证过期前 10 分钟自动调用 AssumeRole 刷新
+ - 刷新失败时会使用旧凭证直到完全过期
+ - 支持异步刷新(不阻塞业务请求)
+
+2. **ECS RAM 角色**:
+ - 默认每分钟异步检查一次凭证状态
+ - 在凭证过期前 15 分钟触发刷新
+ - 刷新失败会在日志中记录警告但不影响业务
+
+3. **OIDC 凭证**:
+ - 每次刷新时重新读取 Token 文件
+ - 适用于 Kubernetes ServiceAccount Token 自动轮换场景
+
+**手动控制刷新行为**:
+
+```java
+// 禁用异步刷新(不推荐)
+EcsRamRoleCredentialProvider provider = EcsRamRoleCredentialProvider.builder()
+ .asyncCredentialUpdateEnabled(false)
+ .build();
+
+// 自定义刷新策略
+SessionCredentialsProvider provider = RamRoleArnCredentialProvider.builder()
+ .asyncCredentialUpdateEnabled(true)
+ .prefetchStrategy(PrefetchStrategy.builder()
+ .refreshBeforeExpirationMinutes(10) // 提前 10 分钟刷新
+ .build())
+ .build();
+```
+
+---
+
+### 4.11 调试与故障排查技巧
+
+#### Q25: 如何开启调试日志以定位问题?
+
+**解决方案**:
+
+1. **开启 SDK 日志**:
+
+ SDK 使用 SLF4J 日志框架,配置示例(Logback):
+ ```xml
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+ ```
+
+2. **查看凭证提供者链执行过程**:
+
+ 启用 DEBUG 日志后,会输出类似:
+ ```
+ DEBUG com.aliyun.credentials.provider.DefaultCredentialsProvider - Trying SystemPropertiesCredentialsProvider...
+ DEBUG com.aliyun.credentials.provider.DefaultCredentialsProvider - SystemPropertiesCredentialsProvider failed: ...
+ DEBUG com.aliyun.credentials.provider.DefaultCredentialsProvider - Trying EnvironmentVariableCredentialsProvider...
+ INFO com.aliyun.credentials.provider.DefaultCredentialsProvider - Credentials loaded from env
+ ```
+
+3. **捕获并打印详细异常信息**:
+ ```java
+ try {
+ Client client = new Client();
+ CredentialModel credential = client.getCredential();
+ } catch (CredentialException e) {
+ System.err.println("错误类型: " + e.getClass().getName());
+ System.err.println("错误消息: " + e.getMessage());
+ e.printStackTrace();
+
+ // 查看完整异常链
+ Throwable cause = e.getCause();
+ while (cause != null) {
+ System.err.println("原因: " + cause.getMessage());
+ cause = cause.getCause();
+ }
+ }
+ ```
+
+---
+
+#### Q26: 如何验证当前使用的凭证来源?
+
+**解决方案**:
+
+```java
+Client client = new Client();
+CredentialModel credential = client.getCredential();
+
+System.out.println("凭证类型: " + credential.getType());
+System.out.println("提供者名称: " + credential.getProviderName());
+System.out.println("AccessKeyId: " + credential.getAccessKeyId());
+
+// 提供者名称示例:
+// - "default/env" - 来自环境变量
+// - "default/profile/ram_role_arn" - 来自配置文件的 RAM 角色扮演
+// - "default/ecs_ram_role" - 来自 ECS 元数据服务
+// - "static/ak" - 来自代码显式配置
+```
+
+---
+
+#### Q27: 如何在 CI/CD 环境中安全使用凭证?
+
+**最佳实践**:
+
+1. **使用 OIDC(推荐)**:
+
+ GitHub Actions 示例:
+ ```yaml
+ - name: Configure Aliyun Credentials
+ run: |
+ export ALIBABA_CLOUD_ROLE_ARN="acs:ram::123456:role/GitHubActions"
+ export ALIBABA_CLOUD_OIDC_PROVIDER_ARN="acs:ram::123456:oidc-provider/github"
+ export ALIBABA_CLOUD_OIDC_TOKEN_FILE=$GITHUB_TOKEN_PATH
+ ```
+
+2. **使用加密的环境变量**:
+
+ GitLab CI 示例:
+ ```yaml
+ variables:
+ ALIBABA_CLOUD_ACCESS_KEY_ID: $AK_ID # 在 GitLab 中配置为保护变量
+ ALIBABA_CLOUD_ACCESS_KEY_SECRET: $AK_SECRET
+ ```
+
+3. **使用临时 STS Token**:
+ ```bash
+ # 在 CI 脚本中获取临时凭证
+ TOKEN_RESPONSE=$(aliyun sts AssumeRole --RoleArn xxx --RoleSessionName ci-job)
+ export ALIBABA_CLOUD_ACCESS_KEY_ID=$(echo $TOKEN_RESPONSE | jq -r '.Credentials.AccessKeyId')
+ export ALIBABA_CLOUD_ACCESS_KEY_SECRET=$(echo $TOKEN_RESPONSE | jq -r '.Credentials.AccessKeySecret')
+ export ALIBABA_CLOUD_SECURITY_TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.Credentials.SecurityToken')
+ ```
+
+---
+
+### 4.12 版本升级与兼容性问题
+
+#### Q28: 从 0.x 升级到 1.x 后出现兼容性问题
+
+**问题现象**:
+升级到 1.0.0+ 版本后,原有代码报错或凭证获取失败。
+
+**主要变更**:
+
+1. **JDK 7 不再支持**:
+ - 1.0.0+ 要求 JDK 1.8+
+ - 解决方案:升级 JDK 或使用 0.3.x 版本
+
+2. **部分方法已弃用**:
+ ```java
+ // 旧版本(已弃用)
+ client.getAccessKeyId();
+ client.getAccessKeySecret();
+
+ // 新版本(推荐)
+ CredentialModel credential = client.getCredential();
+ credential.getAccessKeyId();
+ credential.getAccessKeySecret();
+ ```
+
+3. **凭证刷新机制优化**:
+ - 默认启用异步刷新和缓存
+ - 若需旧行为,可显式配置:
+ ```java
+ provider = Provider.builder()
+ .asyncCredentialUpdateEnabled(false)
+ .build();
+ ```
+
+**迁移建议**:
+
+1. **检查 JDK 版本**:
+ ```bash
+ java -version # 确保 >= 1.8
+ ```
+
+2. **更新 Maven 版本号**:
+ ```xml
+
+ com.aliyun
+ credentials-java
+ 1.0.3
+
+ ```
+
+3. **替换弃用方法**:
+ 使用 IDE 的"查找弃用 API"功能批量替换
+
+---
+
+## 5. 总结与建议
+
+### 推荐配置优先级
+
+1. **生产环境(云上部署)**:
+ - ECS:`ecs_ram_role`(无需管理密钥)
+ - Kubernetes:`oidc_role_arn`(与 ServiceAccount 集成)
+ - 函数计算:通过执行角色自动注入
+
+2. **开发/测试环境**:
+ - 配置文件:`~/.alibabacloud/credentials`
+ - 环境变量:`ALIBABA_CLOUD_ACCESS_KEY_ID/SECRET`
+
+3. **CI/CD 环境**:
+ - OIDC(推荐)
+ - 加密的环境变量 + 临时 STS Token
+
+### 常见错误速查表
+
+| 错误关键词 | 可能原因 | 快速解决 |
+|-----------|---------|---------|
+| `Unable to load credentials from any of the providers` | 所有凭证来源都失败 | 检查环境变量或配置文件是否设置 |
+| `must not be null` | 必填字段缺失 | 补充对应字段(如 AccessKeyId、roleArn) |
+| `The specified credentials file is empty` | 环境变量为空字符串 | `unset ALIBABA_CLOUD_CREDENTIALS_FILE` |
+| `Client is not open` | 配置节未启用 | 设置 `enable = true` |
+| `Failed to connect ECS Metadata Service` | 非 ECS 环境或网络不通 | 禁用 ECS 元数据或检查网络 |
+| `The role name was not found` | 实例未绑定 RAM 角色 | 在 ECS 控制台绑定角色 |
+| `not authorized to do this action` | 缺少 RAM 权限 | 授予对应 STS 操作权限 |
+| `OIDCTokenFilePath is not exists` | Token 文件路径错误 | 检查文件路径和权限 |
+| `Read timed out` | 网络超时 | 增加超时时间或检查网络 |
+| `invalid type option` | 凭证类型拼写错误 | 使用正确的类型名(如 `access_key`) |
+
+### 获取帮助
+
+- **官方文档**:https://help.aliyun.com/document_detail/378659.html
+- **GitHub Issues**:https://github.com/aliyun/credentials-java/issues
+- **API 参考**:https://api.aliyun.com/
+- **诊断平台**:https://api.aliyun.com/troubleshoot
+
+---
+
+**最后更新日期**:2025-12-07