サーバー間での本番環境アプリケーションの認証の設定

このガイドでは、サーバー間の本番環境アプリケーションの認証と承認の設定方法について説明します。認証とは、クライアントの身元を判別するためのプロセスです。承認とは、認証されたクライアントが特定のリソースに対してどのような権限を持つかを決定するためのプロセスです。つまり、認証とはユーザーを識別するもので、承認とはユーザーが行えることを決定するものです。サポートされている認証方法とその選択方法について詳しくは、認証の概要をご覧ください。

Google は、認証情報を使用して、割り当ておよび課金対象のアプリケーションを識別します。また、ユーザーの認証情報は、GCP API、リソース、および機能へのアクセスを承認するためにも使用されます。

アプリケーションの認証情報を指定する

認証情報の自動検出

GCP クライアント ライブラリでは、アプリケーションのデフォルト認証情報(ADC)と呼ばれる方式を使用してアプリケーションの認証情報を検出します。コードでクライアント ライブラリが使用される際は、この方式により、以下の順番で認証情報がチェックされます。

  1. まず、ADC は環境変数 GOOGLE_APPLICATION_CREDENTIALS が設定されているか確認します。変数が設定されている場合、ADC はその変数が指しているサービス アカウント ファイルを使用します。環境変数の設定方法については、次のセクションで説明します。

  2. 環境変数が設定されていない場合、ADC では、サービスで実行されているアプリケーションに応じて、Compute Engine、Kubernetes Engine、Cloud Run、App Engine、または Cloud Functions によって提供されているデフォルトのサービス アカウントを使用します。

  3. ADC が上記のどの認証情報も使用できない場合、エラーが発生します。

以下のサンプルコードは、この方式の動作を説明するものです。このサンプルでは、アプリケーション認証情報は明示的には指定されていません。しかし、GOOGLE_APPLICATION_CREDENTIALS 環境変数が設定されているか、アプリケーションが Compute Engine、Kubernetes Engine、App Engine、または Cloud Functions で実行されている限り、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)
    	}

    	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();

    try {
      // Makes an authenticated API request.
      const results = await storage.getBuckets();

      const [buckets] = results;

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

PHP

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

    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

この方式はテストや試験運用をするときに役立ちますが、アプリケーションで使用されている認証情報を特定するのが難しくなります。次のセクションで説明するように、アプリケーションがどの認証情報を使用するかを明示的に指定することをおすすめします。

サービス アカウントの認証情報の手動による取得と提供

コードをローカルで開発する、アプリケーションをオンプレミスでデプロイする、別のパブリック クラウドにデプロイするなどの場合、サービス アカウントの認証情報を手動で作成して取得できます。

サービス アカウントを作成する

次に示す手順では、サービス アカウントを作成する方法について説明します。ただし、オーナーレベルの権限を設定する代わりに、アクセスを制限するで後述するように、アクセスを該当する権限にのみ制限する必要があります。

all

サービス アカウントの認証情報を指定する

サービス アカウントを作成した後、アプリケーションの認証情報を指定するには 2 つの選択肢があります。GOOGLE_APPLICATION_CREDENTIALS 環境変数を設定することも、サービス アカウント キーへのパスをコードで明示的に渡すこともできます。

環境変数を設定する
display_as_tabs

上記の手順を完了すると、アプリケーションの認証情報を指定するで前述したように、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)
    {
        var credential = GoogleCredential.FromFile(jsonPath)
            .CreateScoped(LanguageServiceClient.DefaultScopes);
        var channel = new Grpc.Core.Channel(
            LanguageServiceClient.DefaultEndpoint.ToString(),
            credential.ToChannelCredentials());
        var client = LanguageServiceClient.Create(channel);
        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)
    	}
    	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.
    try {
      const [buckets] = await storage.getBuckets();

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

PHP

namespace Google\Cloud\Samples\Auth;

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

    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

Compute Engine、Kubernetes Engine、App Engine フレキシブル環境、および Cloud Functions での証情報の取得

アプリケーションが Compute EngineKubernetes EngineApp Engine フレキシブル環境、または Cloud Functions で実行されている場合、独自のサービス アカウントを作成する必要はありません。Compute Engine には自動で作成されるデフォルトのサービス アカウントが含まれているためです。ただし、必要に応じて、インスタンスごとに異なるサービス アカウントを割り当てることもできます。新しいインスタンスを作成すると、そのインスタンスは自動的にデフォルト サービス アカウントとして実行可能になり、デフォルト設定された承認権限を使用できます。詳しくは、Compute Engine のデフォルトのサービス アカウントをご覧ください。

サービス アカウントをセットアップすると、上記のセクションで説明されているように、コードを変更しなくても、ADC で認証情報を暗黙的に検出できるようになります。明示的な Compute Engine 認証情報を使用する必要がある場合は、以下のサンプルコードに示されているように、明示的に指定できます。

以下のサンプルを実行するには、Cloud Storage クライアント ライブラリをインストールする必要があります。

C#

// Some APIs, like Storage, accept a credential in their Create()
    // method.
    public object AuthExplicitComputeEngine(string projectId)
    {
        // Explicitly request service account credentials from the compute
        // engine instance.
        GoogleCredential credential =
            GoogleCredential.FromComputeCredential();
        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 AuthExplicitComputeEngine(string projectId)
    {
        var credential = GoogleCredential.FromComputeCredential();
        var channel = new Grpc.Core.Channel(
            LanguageServiceClient.DefaultEndpoint.ToString(),
            credential.ToChannelCredentials());
        var client = LanguageServiceClient.Create(channel);
        AnalyzeSentiment(client);
        return 0;
    }

Go


    // explicitDefault finds the default credentials.
    //
    // It is very uncommon to need to explicitly get the default credentials in Go.
    // Most of the time, client libraries can use Application Default Credentials
    // without having to pass the credentials in directly. See implicit above.
    func explicitDefault(projectID string) {
    	ctx := context.Background()

    	creds, err := google.FindDefaultCredentials(ctx, storage.ScopeReadOnly)
    	if err != nil {
    		log.Fatal(err)
    	}
    	client, err := storage.NewClient(ctx, option.WithCredentials(creds))
    	if err != nil {
    		log.Fatal(err)
    	}
    	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 authCompute() {
      // Explicitly request service account credentials from the compute engine instance.
      GoogleCredentials credentials = ComputeEngineCredentials.create();
      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

'use strict';

    const {auth, Compute} = require('google-auth-library');

    /**
     * This example directly instantiates a Compute client to acquire credentials.
     * Generally, you wouldn't directly create this class, rather call the
     * `auth.getClient()` method to automatically obtain credentials.
     */
    async function main() {
      const client = new Compute({
        // Specifying the serviceAccountEmail is optional. It will use the default
        // service account if one is not defined.
        serviceAccountEmail: 'some-service-account@example.com',
      });
      const projectId = await auth.getProjectId();
      const url = `https://dns.googleapis.com/dns/v1/projects/${projectId}`;
      const res = await client.request({url});
      console.log(res.data);
    }

    main().catch(console.error);
    

PHP

namespace Google\Cloud\Samples\Auth;

    // Imports GCECredentials and the Cloud Storage client library.
    use Google\Auth\Credentials\GCECredentials;
    use Google\Cloud\Storage\StorageClient;

    function auth_cloud_explicit_compute_engine($projectId)
    {
        $gceCredentials = new GCECredentials();
        $config = [
            'projectId' => $projectId,
            'credentialsFetcher' => $gceCredentials,
        ];
        $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_compute_engine(project):
        from google.auth import compute_engine
        from google.cloud import storage

        # Explicitly use Compute Engine credentials. These credentials are
        # available on Compute Engine, App Engine Flexible, and Container Engine.
        credentials = compute_engine.Credentials()

        # Create the client using the credentials and specifying a project ID.
        storage_client = storage.Client(credentials=credentials, project=project)

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

Ruby

require "googleauth"
    require "google/cloud/env"
    require "google/cloud/storage"

    # Explicitly use Compute Engine credentials and a project ID to create a new
    # Cloud Storage client. These credentials are available on Compute Engine,
    # App Engine Flexible, and Container Engine.
    storage = Google::Cloud::Storage.new project: Google::Cloud.env.project_id,
                                         keyfile: Google::Auth::GCECredentials.new

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

App Engine スタンダード環境での認証情報の取得

アプリケーションが App Engine スタンダード環境で実行されている場合、App Engine App Identity API を使用して認証情報を取得できます。

サービス アカウントをセットアップすると、上記のセクションで説明されているように、コードを変更しなくても、ADC で認証情報を暗黙的に検出できるようになります。明示的な App Engine 認証情報を使用する必要がある場合は、以下のサンプルコードに示されているように、明示的に指定できます。

以下のサンプルを実行するには、Cloud Storage クライアント ライブラリをインストールする必要があります。

PHP

namespace Google\Cloud\Samples\Auth;

    // Imports AppIdentityCredentials and the Cloud Storage client library.
    use Google\Auth\Credentials\AppIdentityCredentials;
    use Google\Cloud\Storage\StorageClient;

    function auth_cloud_explicit_app_engine($projectId)
    {
        # Learn more about scopes at https://cloud.google.com/storage/docs/authentication#oauth-scopes
        $scope = 'https://www.googleapis.com/auth/devstorage.read_only';
        $gaeCredentials = new AppIdentityCredentials($scope);
        $config = [
            'projectId' => $projectId,
            'credentialsFetcher' => $gaeCredentials,
        ];
        $storage = new StorageClient($config);

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

Go


    // explicitDefault finds the default credentials.
    //
    // It is very uncommon to need to explicitly get the default credentials in Go.
    // Most of the time, client libraries can use Application Default Credentials
    // without having to pass the credentials in directly. See implicit above.
    func explicitDefault(projectID string) {
    	ctx := context.Background()

    	creds, err := google.FindDefaultCredentials(ctx, storage.ScopeReadOnly)
    	if err != nil {
    		log.Fatal(err)
    	}
    	client, err := storage.NewClient(ctx, option.WithCredentials(creds))
    	if err != nil {
    		log.Fatal(err)
    	}
    	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 authAppEngineStandard() throws IOException {
      // Explicitly request service account credentials from the app engine standard instance.
      GoogleCredentials credentials = AppEngineCredentials.getApplicationDefault();
      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());
      }
    }

Python

def explicit_app_engine(project):
        from google.auth import app_engine
        import googleapiclient.discovery

        # Explicitly use App Engine credentials. These credentials are
        # only available when running on App Engine Standard.
        credentials = app_engine.Credentials()

        # Explicitly pass the credentials to the client library.
        storage_client = googleapiclient.discovery.build(
            'storage', 'v1', credentials=credentials)

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

アクセスを制限する

アプリケーションには、該当する GCP API、機能、またはリソースの操作に必要な承認権限のみを付与するようにしてください。GCP では、Cloud Identity and Access Management(Cloud IAM)を使用してアクセスを制御します。サービス アカウントを作成するときに、Cloud IAM 役割を選択することで、アクセスを制限できます。サービス アカウントを作成するときに Owner 役割を選択する手順については、認証のスタートガイドで説明しています。この値は、いつでも変更できます。詳しくはサービス アカウントへの役割の付与をご覧ください。

認証情報を管理する際のベスト プラクティス

機密データにアクセスするには、認証情報が必要です。以下の事項は、そのようなリソースへのアクセスを保護するのに役立ちます。

  • API キー、OAuth トークン、およびサービス アカウント認証情報など、認証に関する重要な情報をソースコード内に組み込まないでください。代わりに、アプリケーションのソースコードの外部にある認証情報を指す環境変数を使用できます(Cloud Key Management Service など)。

  • テスト環境と本番環境のように、異なるコンテキストには異なる認証情報を使用してください。

  • 認証情報が第三者に盗まれないように、認証情報の転送は必ず HTTPS を使用して行ってください。クリアテキストや URL の一部として転送しないようご注意ください。

  • 有効期間が長い認証情報をクライアント側アプリケーションに組み込まないでください。たとえば、モバイルアプリには、サービス アカウント認証情報を組み込まないでください。クライアント側アプリケーションを調べることは可能なため、認証情報が第三者によって簡単に見つけられて、使用されてしまう可能性があります。

  • 不要になったトークンは無効にしてください

API エラーのトラブルシューティング

API リクエストが失敗した場合のトラブルシューティング方法について詳しくは、Cloud API のエラーをご覧ください。

次のステップ