使用Java客户端库创建Dataproc集群报compute.regions.get权限缺失错误
问题描述
我参照官方示例使用java-dataproc客户端库创建Dataproc集群,将官方Java示例改写为Scala版本,代码如下:
import com.google.cloud.dataproc.v1._ object CreateCluster extends App { val projectId = "my-project-id" val region = "europe-west1" val clusterName = "test-cluster" val regionEndpoint = s"$region-dataproc.googleapis.com:443" val clusterControllerSettings = ClusterControllerSettings.newBuilder() .setEndpoint(regionEndpoint) .build() val clusterControllerClient = ClusterControllerClient.create(clusterControllerSettings) val masterConfig = InstanceGroupConfig.newBuilder.setMachineTypeUri("n1-standard-2").setNumInstances(1).build val workerConfig = InstanceGroupConfig.newBuilder.setMachineTypeUri("n1-standard-2").setNumInstances(2).build val clusterConfig = ClusterConfig.newBuilder.setMasterConfig(masterConfig).setWorkerConfig(workerConfig).build val cluster = Cluster.newBuilder().setClusterName(clusterName).setConfig(clusterConfig).build() val createClusterAsyncRequest = clusterControllerClient.createClusterAsync(projectId, region, cluster) val createResponse: Cluster = createClusterAsyncRequest.get() println(s"Created cluster: ${createResponse.getClusterName}") clusterControllerClient.close() }
运行代码时抛出报错:io.grpc.StatusRuntimeException: PERMISSION_DENIED: Required 'compute.regions.get' permission for 'projects/my-project/regions/europe-west1'
我已查阅客户端库的授权说明文档,本地运行前已经执行命令配置应用默认登录凭证,确认使用的账号本身拥有所需权限:
- 可以在Compute API参考页面成功执行对应项目、区域的regions.get请求
- 不通过该Java/Scala客户端库时可以正常创建Dataproc集群
补充排查记录
- 后续尝试不带
--scopes参数直接执行gcloud auth application-default login配置凭证,仍然出现相同的权限报错。 - 编写单独测试代码验证
getApplicationDefault获取的凭证权限,测试代码如下:
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport import com.google.api.client.json.gson.GsonFactory import com.google.api.services.compute.Compute import com.google.auth.http.HttpCredentialsAdapter import com.google.auth.oauth2.GoogleCredentials.getApplicationDefault object GetRegions extends App { val project = "my-project-id" val region = "europe-west1" val httpTransport = GoogleNetHttpTransport.newTrustedTransport val jsonFactory = GsonFactory.getDefaultInstance val httpCredentials = new HttpCredentialsAdapter(getApplicationDefault) val computeService = new Compute.Builder(httpTransport, jsonFactory, httpCredentials).build val request = computeService.regions.get(project, region) val response = request.execute System.out.println(response) // 该代码可成功打印区域详情信息 }
该测试代码可以正常调用regions.get接口返回区域详情,但创建Dataproc集群的代码始终提示权限不足。
问题根因
该报错不是账号本身权限不足导致,是Dataproc gRPC客户端的配置问题,核心触发原因有两个:
- 本地应用默认凭证(ADC)没有绑定正确的配额项目,调用时权限校验的项目和代码中传入的项目ID不一致
- 本地网络代理配置没有被gRPC客户端识别,请求被代理拦截后返回了伪造的权限拒绝响应
修复步骤
- 重新配置本地ADC凭证,强制指定配额项目和代码里的
projectId完全一致:
执行完成后清理本地旧的凭证缓存,避免加载到过期凭证文件。gcloud auth application-default login --project=代码中填写的项目ID实际值 - 不要依赖客户端自动加载凭证逻辑,显式在构建配置时指定凭证和权限范围,修改
clusterControllerSettings初始化代码:import com.google.api.gax.core.FixedCredentialsProvider import com.google.auth.oauth2.GoogleCredentials import java.util.Arrays val credentials = GoogleCredentials.getApplicationDefault() .createScoped(Arrays.asList("https://www.googleapis.com/auth/cloud-platform")) val clusterControllerSettings = ClusterControllerSettings.newBuilder() .setEndpoint(regionEndpoint) .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build() - 如果本地使用代理访问公网,gRPC Java客户端默认不会读取系统代理配置,需要在JVM启动参数中显式指定gRPC代理,或者临时关闭代理直连测试:
-Dhttps.proxyHost=代理地址 -Dhttps.proxyPort=代理端口 -Dhttp.proxyHost=代理地址 -Dhttp.proxyPort=代理端口 - 检查引入的java-dataproc客户端依赖版本,升级到1.4.0及以上的稳定版本,旧版本存在gRPC凭证加载丢失权限范围的已知bug。
验证时可以先调用查询集群的接口做连通性测试,不需要直接走创建集群的长耗时流程,确认接口正常返回后再执行创建操作即可。
内容的提问来源于stack exchange,提问作者user2682459
相关产品推荐
相关产品推荐

