Codelab: Google Workspace의 도메인 확인 자동화

도메인 확인을 자동화해야 하는 이유는?

Cloud Channel API를 사용하면 Google Workspace 사용 권한을 대규모로 프로비저닝할 수 있지만 고객은 여전히 다음 작업을 수행하여 서비스를 설정해야 합니다.

  1. 서비스 약관 동의
  2. 도메인 소유권 확인
  3. MX 레코드 설정

새로 생성된 고객은 관리 콘솔(admin.google.com)에 처음 액세스할 때 안내를 받으며 요구사항 프로세스에 따릅니다.

도메인의 DNS 레코드에 프로그래매틱 방식으로 액세스할 수 있는 경우(예: 도메인을 고객에게 재판매한 경우) 일반적으로 리셀러 고객의 기술 지식이 필요한 2단계와 3단계를 자동화함으로써 활성화 속도를 높일 수 있습니다.

이 Codelab은 Site Verification API를 사용하여 이 자동화를 구현하는 방법을 설명합니다.

시작하기 전에

  • Google Cloud 프로젝트를 설정하고 Cloud Channel API를 호출하는 서비스 계정을 만들려면 API 설정 Codelab을 완료해야 합니다.

  • 채널 서비스 작업 자세히 알아보기

  • 이 Codelab에는 테스트 Partner Sales Console을 사용하는 것이 좋습니다.

이 Codelab에서는 또한 리셀러가 Workspace 엔드 투 엔드 프로비저닝 Codelab을 완료했다고 가정합니다.

개요

Google Workspace 사용 권한을 위한 도메인을 확인하려면 API를 여러 번 호출해야 합니다.

도메인 확인 자동화 단계

Site Verification API는 리셀러 전용이 아닙니다. 도메인 확인은 다양한 Google 제품(Search Console, Google Ads 등) 전반에서 사용되는 신호입니다. 여기에서 설명하는 프로세스에는 리셀러 도메인의 최고 관리자를 도메인의 '소유자'로 설정하고 고객의 첫 번째 관리자를 공동 소유자로 설정하는 방법이 사용됩니다. 이러한 개념에 대한 자세한 내용은 Site Verification API 시작하기 페이지를 참조하세요.

1단계: Site Verification API 준비

2단계: 확인 토큰 받기

이 Codelab은 도메인을 확인하는 가장 일반적인 방법인 TXT DNS 레코드 사용하기에 중점을 둡니다. Site Verification API는 다른 확인 방법을 지원합니다.

TXT 레코드로 배치할 토큰을 검색하려면 type=INET_DOMAINverificationMethod=DNS_TXT에 대한 토큰을 가져와야 합니다.

다음 코드에서 리셀러 정보를 사용하여 이러한 변수를 채웁니다.

  • jsonKeyFile: 서비스 계정을 만들 때 생성된 JSON 키 파일의 경로입니다.
  • resellerAdminUser: 리셀러 도메인 최고 관리자의 이메일 주소입니다.
  • customerDomain: 최종 고객의 도메인입니다. 테스트 Partner Sales Console에서 이 Codelab을 실행하는 경우 도메인 이름 지정 규칙에 따라 도메인 이름을 정해야 합니다.

C#

다음 가져오기를 사용합니다.

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.SiteVerification.v1;
using Google.Apis.SiteVerification.v1.Data;

API 클라이언트를 만들고 토큰을 가져옵니다.

// Set up credentials with user impersonation
ICredential credential = GoogleCredential.FromFile(jsonKeyFile)
                             .CreateScoped("https://www.googleapis.com/auth/siteverification")
                             .CreateWithUser(resellerAdminUser);

// Create the API service
var verificationService = new SiteVerificationService(new BaseClientService.Initializer{
    HttpClientInitializer = credential,
});

// Fetch the token
var request = new SiteVerificationWebResourceGettokenRequest {
  VerificationMethod = "DNS_TXT",
  Site = new SiteVerificationWebResourceGettokenRequest.SiteData {
    Type = "INET_DOMAIN",
    Identifier = customerDomain
  }
};
var response = verificationService.WebResource.GetToken(request).Execute();
string token = response.Token;
Console.WriteLine("Site Verification token: " + token);

Go

다음 가져오기를 사용합니다.

import (
  "context"
  "fmt"
  "os"

  "golang.org/x/oauth2/google"
  "google.golang.org/api/option"
  "google.golang.org/api/siteverification/v1"
)

API 클라이언트를 만들고 토큰을 가져옵니다.

ctx := context.Background()

// Set up credentials with user impersonation
jsonKey, _ := os.ReadFile(jsonKeyFile)
jwt, _ := google.JWTConfigFromJSON(jsonKey, "https://www.googleapis.com/auth/siteverification")
jwt.Subject = resellerAdminUser
tokenSource := jwt.TokenSource(ctx)

// Create the API Service
verificationService, _ := siteverification.NewService(ctx, option.WithTokenSource(tokenSource))

// Fetch the token
req := &siteverification.SiteVerificationWebResourceGettokenRequest{
  Site: &siteverification.SiteVerificationWebResourceGettokenRequestSite{
    Type:       "INET_DOMAIN",
    Identifier: customerDomain,
  },
  VerificationMethod: "DNS_TXT",
}
res, _ := verificationService.WebResource.GetToken(req).Do()
token := res.Token
fmt.Println("Site verification token: " + token)

Java

다음 가져오기를 사용합니다.

import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.siteVerification.SiteVerification;
import com.google.api.services.siteVerification.SiteVerificationScopes;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceGettokenRequest;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceGettokenResponse;
import com.google.api.services.siteVerification.model.SiteVerificationWebResourceResource;
import java.io.FileInputStream;
import java.util.Arrays;

API 클라이언트를 만들고 토큰을 가져옵니다.

// Set up credentials with user impersonation
FileInputStream jsonKeyFileSteam = new FileInputStream(JSON_KEY_FILE);
GoogleCredentials credentials = ServiceAccountCredentials.fromStream(jsonKeyFileSteam)
                                    .createScoped("https://www.googleapis.com/auth/siteverification")
                                    .createDelegated(RESELLER_ADMIN_USER);

// Create the API service
SiteVerification verificationService = new SiteVerification.Builder(
    GoogleNetHttpTransport.newTrustedTransport(),
    JacksonFactory.getDefaultInstance(),
    new HttpCredentialsAdapter(credentials)).build();

// Fetch the token
SiteVerificationWebResourceGettokenRequest request =
    new SiteVerificationWebResourceGettokenRequest()
        .setVerificationMethod("DNS_TXT")
        .setSite(new SiteVerificationWebResourceGettokenRequest.Site()
            .setType("INET_DOMAIN")
            .setIdentifier(CUSTOMER_DOMAIN));
SiteVerificationWebResourceGettokenResponse response =
    verificationService.webResource().getToken(request).execute();
String token = response.getToken();
System.out.println("Site Verification token: " + token);

Node.js

다음 가져오기를 사용합니다.

const {google} = require('googleapis');

API 클라이언트를 만들고 토큰을 가져옵니다.

// Set up credentials with user impersonation
const authJWT = new JWT({
  keyFile: jsonKeyFile,
  scopes: ['https://www.googleapis.com/auth/siteverification'],
  subject: resellerAdminUser,
});

// Create the API service
const verificationService = google.siteVerification({version: 'v1', auth: authJWT});

// Fetch the token
const { data } = await verificationService.webResource.getToken({
  requestBody: {
    site: {
      type: 'INET_DOMAIN',
      identifier: customerDomain,
    },
    verificationMethod: 'DNS_TXT',
  }
});
const token = data.token;
console.log(`Site Verification token: ${token}`);

PHP

API 클라이언트를 만들고 토큰을 가져옵니다.

// Set up credentials with user impersonation
$client = new Google_Client();
$client->setAuthConfig($JSON_KEY_FILE);
$client->setSubject($RESELLER_ADMIN_USER);
$client->setScopes('https://www.googleapis.com/auth/siteverification');

// Create the API service
$verificationService = new Google_Service_SiteVerification($client);

// Fetch the token
$request = new Google_Service_SiteVerification_SiteVerificationWebResourceGettokenRequest([
  'verificationMethod' => 'DNS_TXT',
  'site' => [
    'type' => 'INET_DOMAIN',
    'identifier' => $CUSTOMER_DOMAIN
  ]
]);
$response = $verificationService->webResource->getToken($request);
$token = $response->token;
print 'Site Verification token: ' . $token . PHP_EOL;

Python

다음 가져오기를 사용합니다.

from google.oauth2 import service_account
from apiclient.discovery import build

API 클라이언트를 만들고 토큰을 가져옵니다.

# Set up credentials with user impersonation
credentials = service_account.Credentials.from_service_account_file(
    JSON_KEY_FILE, scopes=["https://www.googleapis.com/auth/siteverification"])
credentials_delegated = credentials.with_subject(RESELLER_ADMIN_USER)

# Create the API service
verification_service = build(serviceName="siteVerification", version="v1",
    credentials=credentials_delegated)

# Fetch the token
response = verification_service.webResource().getToken(
  body={
    "site": {
      "type": "INET_DOMAIN",
      "identifier": CUSTOMER_DOMAIN
    },
    "verificationMethod": "DNS_TXT"
  }).execute()
token = response["token"]
print("Site Verification token: " + token)

3단계: 확인 토큰 입력

코드를 작성하여 고객 도메인의 DNS 레코드에서 토큰을 TXT 레코드로 추가합니다.

새 도메인의 경우 Gmail에 필요한 MX 레코드를 설정해야 합니다.

4단계: 도메인 확인 트리거

토큰이 TXT 레코드로 지정되면 Site Verification API를 호출하여 인증을 트리거할 수 있습니다. 이렇게 하려면 webResource.insert()을(를) 호출합니다.

예상된 토큰을 찾을 수 없으면 400 오류와 함께 호출이 실패합니다. DNS 적용 지연을 상쇄하기 위해 호출이 성공할 때까지 지수 백오프 재시도 전략을 구현할 수 있습니다.

호출이 오류 없이 반환되면 Site Verification API는 도메인이 확인된 것으로 간주하고 webResourceowners 필드에 있는 이메일은 확인된 소유자입니다.

확인 상태가 고객의 Google Workspace 계정에 적용되는 데 약 3시간 정도 걸릴 수 있습니다. 고객의 관리자(provisionCloudIdentity 호출 시 생성)를 owner이(가) webResource인 값으로 설정하여 상태를 즉시 강제로 적용할 수 있습니다.

C#

// Set the customer's admin user as an owner to make sure the domain
// verification status is instantly propagated to the Workspace account
string[] owners = { "admin@" + customerDomain };

var resource = new SiteVerificationWebResourceResource {
  Site = new SiteVerificationWebResourceResource.SiteData {
    Type = "INET_DOMAIN",
    Identifier = customerDomain
  },
  Owners = owners
};

resource = verificationService.WebResource.Insert(resource, "DNS_TXT").Execute();
Console.WriteLine("=== Domain has been verified");

Go

// Set the customer's admin user as an owner to make sure the domain
// verification status is instantly propagated to the Workspace account
resource := &siteverification.SiteVerificationWebResourceResource{
  Site: &siteverification.SiteVerificationWebResourceResourceSite{
    Type:       "INET_DOMAIN",
    Identifier: customerDomain,
  },
  Owners: []string{"admin@" + customerDomain},
}
resource, err := verificationService.WebResource.Insert("DNS_TXT", resource).Do()
if err != nil {
  fmt.Println(err)
} else {
  fmt.Println("=== Domain has been verified")
}

Java

// Set the customer's admin user as an owner to make sure the domain
// verification status is instantly propagated to the Workspace account
SiteVerificationWebResourceResource resource =
    new SiteVerificationWebResourceResource()
        .setSite(new SiteVerificationWebResourceResource.Site()
            .setIdentifier(CUSTOMER_DOMAIN)
            .setType("INET_DOMAIN"))
        .setOwners(Arrays.asList("admin@" + CUSTOMER_DOMAIN));

resource = verificationService.webResource().insert("DNS_TXT", resource).execute();
System.out.println("=== Domain has been verified");

Node.js

// Set the customer's admin user as an owner to make sure the domain
// verification status is instantly propagated to the Workspace account
await verificationService.webResource.insert({
  verificationMethod: 'DNS_TXT',
  requestBody: {
    site: {
      type: 'INET_DOMAIN',
      identifier: customerDomain,
    },
    owners: [`admin@${customerDomain}`],
  }
});
console.log('=== Domain has been verified');

PHP

// Set the customer's admin user as an owner to make sure the domain
// verification status is instantly propagated to the Workspace account
$resource = new Google_Service_SiteVerification_SiteVerificationWebResourceResource([
  'site' => [
    'type' => 'INET_DOMAIN',
    'identifier' => $CUSTOMER_DOMAIN,
  ],
  'owners' => ['admin@' . $CUSTOMER_DOMAIN]
]);

$resource = $verificationService->webResource->insert('DNS_TXT', $resource);
print '=== Domain has been verified' . PHP_EOL;

Python

# Set the customer's admin user as an owner to make sure the domain
# verification status is instantly propagated to the Workspace account
resource = verification_service.webResource().insert(
  verificationMethod="DNS_TXT",
  body={
    "site": {
      "type": "INET_DOMAIN",
      "identifier": CUSTOMER_DOMAIN
    },
    "owners": ["admin@" + CUSTOMER_DOMAIN]
  }).execute()
print("=== Domain has been verified")