서버 간 프로덕션 애플리케이션 인증 설정

이 가이드에서는 서버 간 프로덕션 애플리케이션을 위한 인증 및 승인을 설정하는 방법을 설명합니다. 인증은 클라이언트의 ID를 확인하는 프로세스를 의미합니다. 승인은 인증된 클라이언트가 특정 리소스에 대해 갖는 권한을 확인하는 프로세스를 의미합니다. 즉, 인증은 누구인지를 확인하고 승인은 무엇을 할 수 있는지를 결정합니다. 지원되는 인증 방법과 이를 선택하는 방법에 대한 자세한 내용은 인증 개요를 참조하세요.

Google은 사용자 인증 정보를 사용하여 할당량과 결제를 위해 애플리케이션을 식별합니다. 사용자 인증 정보는 GCP API, 리소스, 기능 액세스를 승인하는 데도 사용됩니다.

애플리케이션에 사용자 인증 정보 제공

GCP 클라이언트 라이브러리는 애플리케이션 기본 사용자 인증 정보(ADC)라는 전략을 사용하여 애플리케이션의 사용자 인증 정보를 찾습니다. 코드가 클라이언트 라이브러리를 사용하는 경우 이 전략은 다음 순서에 따라 사용자 인증 정보를 확인합니다.

  1. 첫째, ADC는 환경 변수 GOOGLE_APPLICATION_CREDENTIALS가 설정되었는지 확인합니다. 변수가 설정된 경우 ADC는 변수가 가리키는 서비스 계정 파일을 사용합니다. 다음 섹션에서는 환경 변수를 설정하는 방법을 설명합니다.

  2. 환경 변수가 설정되지 않은 경우 ADC는 Compute Engine, Kubernetes Engine, 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 the
	// golang.org/x/oauth2/google package as shown below.
	oauthClient, err := google.DefaultClient(ctx, cloudkms.CloudPlatformScope)
	if err != nil {
		log.Fatal(err)
	}

	kmsService, err := cloudkms.New(oauthClient)
	if err != nil {
		log.Fatal(err)
	}

	_ = kmsService
}

자바

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.
storage
  .getBuckets()
  .then(results => {
    const buckets = results[0];

    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_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

수동으로 서비스 계정 사용자 인증 정보 획득 및 제공

로컬에서 코드를 개발하거나 온프레미스에 애플리케이션을 배포하거나 다른 공용 클라우드에 배포하는 경우 수동으로 서비스 계정 사용자 인증 정보를 만들고 획득할 수 있습니다.

서비스 계정 만들기

다음 단계에서는 서비스 계정을 만드는 방법을 설명합니다. 그러나 소유자 수준 권한을 설정하는 대신 아래 액세스 제한 섹션에 설명된 대로 권한 액세스를 제한해야 합니다.

서비스 계정 사용자 인증 정보 제공

서비스 계정을 만든 후 애플리케이션에 사용자 인증 정보를 제공하기 위한 두 가지 선택안이 있습니다. GOOGLE_APPLICATION_CREDENTIALS 환경 변수를 명시적으로 설정하거나 코드에서 서비스 계정 키 경로를 전달할 수 있습니다.

환경 변수 설정

환경 변수 GOOGLE_APPLICATION_CREDENTIALS를 설정하여 애플리케이션 코드에 사용자 인증 정보를 제공합니다. [PATH]를 서비스 계정 키가 포함된 JSON 파일의 파일 경로로 바꾸고 [FILE_NAME]을 파일 이름으로 바꿉니다. 이 변수는 현재 셸 세션에만 적용되므로 새 세션을 연 경우 변수를 다시 설정합니다.

Linux 또는 macOS

export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"

예:

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/[FILE_NAME].json"

Windows

PowerShell:

$env:GOOGLE_APPLICATION_CREDENTIALS="[PATH]"

예:

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\[FILE_NAME].json"

명령 프롬프트:

set GOOGLE_APPLICATION_CREDENTIALS=[PATH]

위 단계를 완료하고 나면 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)
	}
}

자바

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 storage = new Storage({
  projectId: 'project-id',
  keyFilename: '/path/to/keyfile.json',
});

// Makes an authenticated API request.
storage
  .getBuckets()
  .then(results => {
    const buckets = results[0];

    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 Engine, Kubernetes Engine, App 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)
	}
}

자바

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://www.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)
	}
}

자바

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와 같은 애플리케이션 소스 코드 외부의 사용자 인증 정보를 가리키는 환경 변수를 사용할 수 있습니다.

  • 테스트 환경 및 프로덕션 환경과 같이 각기 다른 컨텍스트에서 서로 다른 사용자 인증 정보를 사용하세요.

  • 제3자가 사용자 인증 정보를 가로채지 못하도록 HTTPS를 통해서만 사용자 인증 정보를 전송하세요. 일반 텍스트로 또는 URL의 일부로 전송하지 마세요.

  • 장시간 사용된 사용자 인증 정보를 클라이언트 측 앱에 내장하지 마세요. 예를 들어 모바일 앱에 서비스 계정 사용자 인증 정보를 내장하지 마세요. 제3자가 클라이언트 측 앱을 검사할 수 있으며 이 경우 손쉽게 사용자 인증 정보를 찾아 사용할 수 있습니다.

  • 더 이상 필요 없는 토큰을 취소하세요.

API 오류 문제해결

Cloud API 오류에서 실패한 API 요청 문제를 해결하는 방법을 알아보세요.

다음 단계

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...