以服务帐号身份进行身份验证

本主题介绍了如何以服务帐号身份对应用进行身份验证。 如需了解有关向 Google Cloud API 进行身份验证的一般信息(包括常见的身份验证场景和策略),请参阅身份验证概览。如需详细了解服务帐号,请参阅 Identity and Access Management 文档中的服务帐号

自动查找凭据

如果您的应用在 Google Cloud 环境中运行,并且您已经向该环境附加服务帐号,则您的应用可以检索该服务帐号的凭据。然后,应用可以使用这些凭据来调用 Google Cloud API。

您可以将服务帐号附加到许多不同 Google Cloud 服务的资源,包括 Compute Engine、Google Kubernetes Engine、App Engine、Cloud Run 和 Cloud Functions。我们建议使用此策略,因为这种做法比手动传递凭据更便捷、更安全。

此外,我们建议您在应用中使用 Google Cloud 客户端库。Google Cloud 客户端库使用名为“应用默认凭据”(ADC) 的库来自动查找您的服务帐号凭据。ADC 会按以下顺序查找服务帐号凭据:

  1. 如果设置了环境变量 GOOGLE_APPLICATION_CREDENTIALS,则 ADC 使用该变量指向的服务帐号密钥或配置文件。

  2. 如果未设置环境变量 GOOGLE_APPLICATION_CREDENTIALS,则 ADC 使用关联到运行代码的资源的服务帐号。

    此服务帐号可能是 Compute Engine、Google Kubernetes Engine、App Engine、Cloud Run 或 Cloud Functions 提供的默认服务帐号,也可能是您创建的用户管理的服务帐号

  3. 如果 ADC 无法使用上述任何凭据,则会引发错误。

以下代码示例展示了如何在应用代码中使用 ADC 库。要运行此示例,您必须安装 Cloud Storage 客户端库

C#

public object AuthImplicit(string projectId)
{
    // If you don't specify credentials when constructing the client, the
    // client library will look for credentials in the environment.
    var credential = GoogleCredential.GetApplicationDefault();
    var storage = StorageClient.Create(credential);
    // Make an authenticated API request.
    var buckets = storage.ListBuckets(projectId);
    foreach (var bucket in buckets)
    {
        Console.WriteLine(bucket.Name);
    }
    return null;
}

Go


// implicit uses Application Default Credentials to authenticate.
func implicit() {
	ctx := context.Background()

	// For API packages whose import path is starting with "cloud.google.com/go",
	// such as cloud.google.com/go/storage in this case, if there are no credentials
	// provided, the client library will look for credentials in the environment.
	storageClient, err := storage.NewClient(ctx)
	if err != nil {
		log.Fatal(err)
	}
	defer storageClient.Close()

	it := storageClient.Buckets(ctx, "project-id")
	for {
		bucketAttrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(bucketAttrs.Name)
	}

	// For packages whose import path is starting with "google.golang.org/api",
	// such as google.golang.org/api/cloudkms/v1, use NewService to create the client.
	kmsService, err := cloudkms.NewService(ctx)
	if err != nil {
		log.Fatal(err)
	}

	_ = kmsService
}

Java

static void authImplicit() {
  // If you don't specify credentials when constructing the client, the client library will
  // look for credentials via the environment variable GOOGLE_APPLICATION_CREDENTIALS.
  Storage storage = StorageOptions.getDefaultInstance().getService();

  System.out.println("Buckets:");
  Page<Bucket> buckets = storage.list();
  for (Bucket bucket : buckets.iterateAll()) {
    System.out.println(bucket.toString());
  }
}

Node.js

// Imports the Google Cloud client library.
const {Storage} = require('@google-cloud/storage');

// Instantiates a client. If you don't specify credentials when constructing
// the client, the client library will look for credentials in the
// environment.
const storage = new Storage();
// Makes an authenticated API request.
async function listBuckets() {
  try {
    const results = await storage.getBuckets();

    const [buckets] = results;

    console.log('Buckets:');
    buckets.forEach(bucket => {
      console.log(bucket.name);
    });
  } catch (err) {
    console.error('ERROR:', err);
  }
}
listBuckets();

PHP

// Imports the Cloud Storage client library.
use Google\Cloud\Storage\StorageClient;

/**
 * Authenticate to a cloud client library using a service account implicitly.
 *
 * @param string $projectId The Google project ID.
 */
function auth_cloud_implicit($projectId)
{
    $config = [
        'projectId' => $projectId,
    ];

    # If you don't specify credentials when constructing the client, the
    # client library will look for credentials in the environment.
    $storage = new StorageClient($config);

    # Make an authenticated API request (listing storage buckets)
    foreach ($storage->buckets() as $bucket) {
        printf('Bucket: %s' . PHP_EOL, $bucket->name());
    }
}

Python

def implicit():
    from google.cloud import storage

    # If you don't specify credentials when constructing the client, the
    # client library will look for credentials in the environment.
    storage_client = storage.Client()

    # Make an authenticated API request
    buckets = list(storage_client.list_buckets())
    print(buckets)

Ruby

# project_id = "Your Google Cloud project ID"

require "google/cloud/storage"

# If you don't specify credentials when constructing the client, the client
# library will look for credentials in the environment.
storage = Google::Cloud::Storage.new project: project_id

# Make an authenticated API request
storage.buckets.each do |bucket|
  puts bucket.name
end

手动传递凭据

如果您的应用在未关联服务帐号的环境(例如本地或其他云服务商)中运行,您应该使用工作负载身份联合

如果您无法使用工作负载身份联合,则必须创建一个服务帐号以及一个或多个服务帐号密钥,这些密钥是与该服务帐号关联的凭据。您可以手动将服务帐号密钥传递到您的应用。

请务必查看管理服务帐号密钥的最佳实践

创建服务帐号

以下步骤介绍了如何创建服务帐号(如果您没有该帐号):

控制台

创建服务帐号:

  1. 在控制台中,打开创建服务帐号页面。

    打开“创建服务帐号”
  2. 选择您的项目。
  3. 服务帐号名称字段中,输入一个名称。控制台会根据此名称填充服务帐号 ID 字段。

    服务帐号说明字段中,输入说明。例如,Service account for quickstart

  4. 点击创建并继续
  5. 如需提供对项目的访问权限,请向服务帐号授予以下角色:Project > Owner

    选择角色列表中,选择一个角色。

    如需添加其他角色,请点击 添加其他角色,然后添加其他各个角色。

  6. 点击继续
  7. 点击完成以完成服务帐号的创建过程。

    不要关闭浏览器窗口。您将在下一步骤中用到它。

创建服务帐号密钥:

  1. 在控制台中,点击您创建的服务帐号的电子邮件地址。
  2. 点击密钥
  3. 点击添加密钥,然后点击创建新密钥
  4. 点击创建。JSON 密钥文件将下载到您的计算机上。
  5. 点击关闭

gcloud

设置身份验证:

  1. 创建服务帐号:

    gcloud iam service-accounts create NAME

    NAME 替换为服务帐号的名称。

  2. 向服务帐号授予角色。对以下每个 IAM 角色运行以下命令一次:roles/owner

    gcloud projects add-iam-policy-binding PROJECT_ID --member="serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com" --role=ROLE

    替换以下内容:

    • SERVICE_ACCOUNT_NAME:服务帐号的名称
    • PROJECT_ID:您在其中创建服务帐号的项目的 ID
    • ROLE:要授予的角色
  3. 生成密钥文件:

    gcloud iam service-accounts keys create FILE_NAME.json --iam-account=SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com

    替换以下内容:

    • FILE_NAME:密钥文件的名称
    • SERVICE_ACCOUNT_NAME:服务帐号的名称
    • PROJECT_ID:您在其中创建服务帐号的项目的 ID

通过环境变量传递凭据

通过设置环境变量 GOOGLE_APPLICATION_CREDENTIALS 向应用代码提供身份验证凭据。此变量仅适用于当前的 Shell 会话。如果您希望变量应用于未来的 Shell 会话,请在 shell 启动文件中设置变量,例如在 ~/.bashrc~/.profile 文件中。

Linux 或 macOS

export GOOGLE_APPLICATION_CREDENTIALS="KEY_PATH"

KEY_PATH 替换为包含您的服务帐号密钥的 JSON 文件的路径。

例如:

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

Windows

对于 PowerShell:

$env:GOOGLE_APPLICATION_CREDENTIALS="KEY_PATH"

KEY_PATH 替换为包含您的服务帐号密钥的 JSON 文件的路径。

例如:

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

对于命令提示符:

set GOOGLE_APPLICATION_CREDENTIALS=KEY_PATH

KEY_PATH 替换为包含您的服务帐号密钥的 JSON 文件的路径。

完成上述步骤后,ADC 可以自动查找您的凭据,如以上部分所述。我们建议您使用 ADC,因为需要使用的代码更少且代码可在不同的环境中移植。

使用代码传递凭据

如以下示例中所示,您可以选择在代码中明确指向服务帐号文件。必须安装 Cloud Storage 客户端库才能运行以下示例。

C#

        // Some APIs, like Storage, accept a credential in their Create()
        // method.
        public object AuthExplicit(string projectId, string jsonPath)
        {
            // Explicitly use service account credentials by specifying
            // the private key file.
            var credential = GoogleCredential.FromFile(jsonPath);
            var storage = StorageClient.Create(credential);
            // Make an authenticated API request.
            var buckets = storage.ListBuckets(projectId);
            foreach (var bucket in buckets)
            {
                Console.WriteLine(bucket.Name);
            }
            return null;
        }
        // Other APIs, like Language, accept a channel in their Create()
        // method.
        public object AuthExplicit(string projectId, string jsonPath)
        {
            LanguageServiceClientBuilder builder = new LanguageServiceClientBuilder
            {
                CredentialsPath = jsonPath
            };

            LanguageServiceClient client = builder.Build();
            AnalyzeSentiment(client);
            return 0;
        }

Go


// explicit reads credentials from the specified path.
func explicit(jsonPath, projectID string) {
	ctx := context.Background()
	client, err := storage.NewClient(ctx, option.WithCredentialsFile(jsonPath))
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()
	fmt.Println("Buckets:")
	it := client.Buckets(ctx, projectID)
	for {
		battrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(battrs.Name)
	}
}

Java

static void authExplicit(String jsonPath) throws IOException {
  // You can specify a credential file by providing a path to GoogleCredentials.
  // Otherwise credentials are read from the GOOGLE_APPLICATION_CREDENTIALS environment variable.
  GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(jsonPath))
        .createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
  Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();

  System.out.println("Buckets:");
  Page<Bucket> buckets = storage.list();
  for (Bucket bucket : buckets.iterateAll()) {
    System.out.println(bucket.toString());
  }
}

Node.js

// Imports the Google Cloud client library.
const {Storage} = require('@google-cloud/storage');

// Instantiates a client. Explicitly use service account credentials by
// specifying the private key file. All clients in google-cloud-node have this
// helper, see https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/docs/authentication.md
// const projectId = 'project-id'
// const keyFilename = '/path/to/keyfile.json'
const storage = new Storage({projectId, keyFilename});

// Makes an authenticated API request.
async function listBuckets() {
  try {
    const [buckets] = await storage.getBuckets();

    console.log('Buckets:');
    buckets.forEach(bucket => {
      console.log(bucket.name);
    });
  } catch (err) {
    console.error('ERROR:', err);
  }
}
listBuckets();

PHP

namespace Google\Cloud\Samples\Auth;

// Imports the Cloud Storage client library.
use Google\Cloud\Storage\StorageClient;

/**
 * Authenticate to a cloud client library using a service account explicitly.
 *
 * @param string $projectId           The Google project ID.
 * @param string $serviceAccountPath  Path to service account credentials JSON.
 */
function auth_cloud_explicit($projectId, $serviceAccountPath)
{
    # Explicitly use service account credentials by specifying the private key
    # file.
    $config = [
        'keyFilePath' => $serviceAccountPath,
        'projectId' => $projectId,
    ];
    $storage = new StorageClient($config);

    # Make an authenticated API request (listing storage buckets)
    foreach ($storage->buckets() as $bucket) {
        printf('Bucket: %s' . PHP_EOL, $bucket->name());
    }
}

Python

def explicit():
    from google.cloud import storage

    # Explicitly use service account credentials by specifying the private key
    # file.
    storage_client = storage.Client.from_service_account_json(
        'service_account.json')

    # Make an authenticated API request
    buckets = list(storage_client.list_buckets())
    print(buckets)

Ruby

# project_id = "Your Google Cloud project ID"
# key_file   = "path/to/service-account.json"
require "google/cloud/storage"

# Explicitly use service account credentials by specifying the private key
# file.
storage = Google::Cloud::Storage.new project: project_id, keyfile: key_file

# Make an authenticated API request
storage.buckets.each do |bucket|
  puts bucket.name
end

排查 API 错误

如需详细了解如何对失败的 API 请求进行问题排查,请参阅 Cloud API 错误

后续步骤

自行试用

如果您是 Google Cloud 新手,请创建一个帐号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。

免费开始使用