如何在Java中无需JSON文件通过IAM认证连接GCP Pub/Sub服务
无JSON密钥文件连接GCP Pub/Sub的IAM认证实现
本地Java环境测试
本地场景下,可通过GCP应用默认凭据(ADC)的非密钥文件方式完成认证,无需手动放置.json密钥文件,以下是两种可行方案:
方案1:借助gcloud CLI获取临时本地凭据
- 安装并初始化gcloud CLI,完成账号登录:
gcloud auth login - 设置默认GCP项目:
gcloud config set project YOUR_PROJECT_ID - Java代码中直接调用默认凭据方法,ADC会自动读取gcloud登录后的本地缓存凭据,示例代码:
import com.google.cloud.pubsub.v1.Publisher; import com.google.cloud.pubsub.v1.Subscriber; import com.google.pubsub.v1.ProjectTopicName; import com.google.pubsub.v1.ProjectSubscriptionName; import com.google.auth.oauth2.GoogleCredentials; import com.google.api.gax.core.FixedCredentialsProvider; public class PubSubLocalAuthDemo { public static void main(String[] args) throws Exception { // 自动获取本地缓存的凭据(来自gcloud登录,无json文件) GoogleCredentials credentials = GoogleCredentials.getApplicationDefault(); // 绑定Pub/Sub所需权限范围 credentials = credentials.createScoped("https://www.googleapis.com/auth/pubsub"); // 初始化Pub/Sub Publisher ProjectTopicName topicName = ProjectTopicName.of("YOUR_PROJECT_ID", "YOUR_TOPIC_ID"); Publisher publisher = Publisher.newBuilder(topicName) .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build(); // 初始化Pub/Sub Subscriber ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of("YOUR_PROJECT_ID", "YOUR_SUBSCRIPTION_ID"); Subscriber subscriber = Subscriber.newBuilder(subscriptionName, (message, consumer) -> { System.out.println("收到消息:" + message.getData().toStringUtf8()); consumer.ack(); }) .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build(); subscriber.startAsync().awaitRunning(); Thread.sleep(60000); // 保持运行60秒,按需调整 subscriber.stopAsync().awaitTerminated(); publisher.shutdown(); } }
方案2:服务账号模拟(Impersonation)
若需使用特定服务账号权限但不想下载其密钥文件,可通过当前用户账号模拟目标服务账号:
- 确保当前用户账号拥有
roles/iam.serviceAccountTokenCreator权限(允许模拟目标服务账号) - Java代码实现模拟逻辑:
import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.ImpersonatedCredentials; import com.google.cloud.pubsub.v1.Publisher; import com.google.pubsub.v1.ProjectTopicName; import com.google.api.gax.core.FixedCredentialsProvider; public class PubSubImpersonationDemo { public static void main(String[] args) throws Exception { // 获取当前用户的本地凭据(来自gcloud登录) GoogleCredentials sourceCreds = GoogleCredentials.getApplicationDefault() .createScoped("https://www.googleapis.com/auth/cloud-platform"); // 模拟目标服务账号 ImpersonatedCredentials targetCreds = ImpersonatedCredentials.newBuilder() .setSourceCredentials(sourceCreds) .setTargetPrincipal("TARGET_SERVICE_ACCOUNT@YOUR_PROJECT_ID.iam.gserviceaccount.com") .setTargetScopes(new String[]{"https://www.googleapis.com/auth/pubsub"}) .setLifetime(3600) // 凭据有效期(秒) .build(); // 初始化Publisher(后续逻辑同方案1) ProjectTopicName topicName = ProjectTopicName.of("YOUR_PROJECT_ID", "YOUR_TOPIC_ID"); Publisher publisher = Publisher.newBuilder(topicName) .setCredentialsProvider(FixedCredentialsProvider.create(targetCreds)) .build(); // 发布消息逻辑 // ... publisher.shutdown(); } }
GCP容器环境部署(GKE/Cloud Run)
容器环境下直接使用工作负载身份(Workload Identity),完全无需密钥文件,通过IAM绑定实现权限映射:
步骤1:配置工作负载身份(以GKE为例)
- 创建或选择一个GCP服务账号,为其分配Pub/Sub相关权限(如
roles/pubsub.publisher、roles/pubsub.subscriber) - 创建Kubernetes服务账号(KSA),并绑定到目标GCP服务账号(GSA):
gcloud iam service-accounts add-iam-policy-binding GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \ --member="serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]" \ --role="roles/iam.workloadIdentityUser" - 在K8s部署文件中指定Pod使用该KSA:
apiVersion: apps/v1 kind: Deployment metadata: name: pubsub-app spec: template: spec: serviceAccountName: KSA_NAME containers: - name: pubsub-container image: YOUR_IMAGE_URL
步骤2:容器内Java代码
容器内无需特殊配置,直接调用默认凭据方法即可,ADC会自动通过工作负载身份获取凭据:
import com.google.cloud.pubsub.v1.Subscriber; import com.google.pubsub.v1.ProjectSubscriptionName; import com.google.auth.oauth2.GoogleCredentials; import com.google.api.gax.core.FixedCredentialsProvider; public class PubSubContainerDemo { public static void main(String[] args) throws Exception { // 自动获取工作负载身份凭据 GoogleCredentials credentials = GoogleCredentials.getApplicationDefault() .createScoped("https://www.googleapis.com/auth/pubsub"); ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of("YOUR_PROJECT_ID", "YOUR_SUBSCRIPTION_ID"); Subscriber subscriber = Subscriber.newBuilder(subscriptionName, (message, consumer) -> { System.out.println("容器内收到消息:" + message.getData().toStringUtf8()); consumer.ack(); }) .setCredentialsProvider(FixedCredentialsProvider.create(credentials)) .build(); subscriber.startAsync().awaitRunning(); Thread.sleep(60000); subscriber.stopAsync().awaitTerminated(); } }
若部署到Cloud Run,只需在部署时指定服务账号:
gcloud run deploy YOUR_SERVICE_NAME \ --image YOUR_IMAGE_URL \ --service-account GSA_NAME@PROJECT_ID.iam.gserviceaccount.com \ --region YOUR_REGION
代码逻辑与上述容器示例一致。
内容的提问来源于stack exchange,提问作者Susheel Rao
相关产品推荐
相关产品推荐

