異なる ID システムを同期する

Google Cloud Search のアクセス制御は、ユーザーの Google アカウントに基づいて行われます。コンテンツをインデックスに登録する際、アイテムのすべての ACL は、有効な Google ユーザー ID またはグループ ID(メールアドレス)に解決される必要があります。

多くの場合、リポジトリは Google アカウントを直接把握しません。代わりに、ユーザーはローカル アカウントで表されるか、ユーザーのメールアドレス以外の ID プロバイダと ID による連携ログインを使用して、各アカウントを識別できます。この ID は外部 ID と呼ばれます。

管理コンソールを使用して作成された ID ソースは、以下の方法で ID システム間のこのギャップを埋めるのに役立ちます。

以下のいずれかの場合に ID ソースを使用します。

  • リポジトリは、Google Workspace または Google Cloud Directory 内のユーザーのプライマリ メールアドレスを認識しません。
  • リポジトリは、Google Workspace のメールベースのグループに対応しないアクセス制御用のグループを定義しています。

ID ソースを使用すると、ID マッピングからインデックス登録が分離されるため、インデックス登録の効率が向上します。この分離により、ACL の作成時およびアイテムのインデックス登録時にユーザーの検索を延期できます。

デプロイの例

図 1 は、オンプレミスとクラウドの両方のリポジトリが企業で使用されているデプロイの例を示しています。各リポジトリでは、異なるタイプの外部 ID を使用してユーザーを参照します。

デプロイの例
図 1. さまざまな ID タイプを使用した企業のデプロイ例

リポジトリ 1 は、SAML を使用してアサートされたメールアドレスを使用してユーザーを識別します。リポジトリ 1 には Google Workspace または Cloud Directory 内のユーザーのプライマリ メールアドレスに関する知識があるため、ID ソースは必要ありません。

リポジトリ 2 はオンプレミス ディレクトリと直接統合され、ユーザーを sAMAccountName 属性で識別します。リポジトリ 2 は sAMAccountName 属性を外部 ID として使用するため、ID ソースが必要です。

ID ソースを作成する

ID ソースが必要な場合は、Cloud Search でユーザー ID をマッピングするをご覧ください。

ACL とインデック スデータを作成するには ID ソースの ID が必要になるため、コンテンツ コネクタを作成する前に ID ソースを作成する必要があります。前述のように、ID ソースを作成すると、Cloud Directory にカスタム ユーザー プロパティも作成されます。このプロパティを使用して、リポジトリ内の各ユーザーの外部 ID を記録します。このプロパティには、規則 IDENTITY_SOURCE_ID_identity を使用して名前が付けられます。

以下の表は、2 つの ID ソースを示しています。1 つは外部 ID として SAM アカウント名(sAMAccountName)を保持する ID ソース、もう 1 つは外部 ID としてユーザー ID(uid)を保持する ID ソースです。

ID ソース ユーザー プロパティ 外部 ID
id1 id1_identity sAMAccountName
id2 id2_identity uid

企業内のユーザーを参照するために使用される可能性のある外部 ID ごとに、ID ソースを作成します。

以下の表は、Google アカウントと 2 つの外部 ID(id1_identity と id2_identity)を持つユーザーとその値が Cloud Directory にどのように表示されるかを示しています。

ユーザー メール id1_identity id2_identity
Ann ann@example.com example\ann 1001

インデックス登録用に ACL を作成するときに、3 つの異なる ID(Google メール、sAMAccountName、uid)を使用して同じユーザーを参照できます。

ユーザー ACL を作成する

指定された外部 ID を使用してプリンシパルを作成するには、getUserPrincpal() メソッドまたは getGroupPrincipal() メソッドを使用します。

以下の例は、ファイル権限を取得する方法を示しています。これらの権限には、ファイルにアクセスできる各ユーザーの名前が含まれます。

FilePermissionSample.java
/**
 * Sample for mapping permissions from a source repository to Cloud Search
 * ACLs. In this example, POSIX file permissions are used a the source
 * permissions.
 *
 * @return Acl
 * @throws IOException if unable to read file permissions
 */
static Acl mapPosixFilePermissionToCloudSearchAcl(Path pathToFile) throws IOException {
  // Id of the identity source for external user/group IDs. Shown here,
  // but may be omitted in the SDK as it is automatically applied
  // based on the `api.identitySourceId` configuration parameter.
  String identitySourceId = "abcdef12345";

  // Retrieve the file system permissions for the item being indexed.
  PosixFileAttributeView attributeView = Files.getFileAttributeView(
      pathToFile,
      PosixFileAttributeView.class,
      LinkOption.NOFOLLOW_LINKS);

  if (attributeView == null) {
    // Can't read, return empty ACl
    return new Acl.Builder().build();
  }

  PosixFileAttributes attrs = attributeView.readAttributes();
  // ...
}

次のコード スニペットは、属性に保存されている外部 ID(externalUserName)を使用してオーナーであるプリンシパルを作成する方法を示しています。

FilePermissionSample.java
// Owner, for search quality.
// Note that for principals the name is not the primary
// email address in Cloud Directory, but the local ID defined
// by the OS. Users and groups must be referred to by their
// external ID and mapped via an identity source.
List<Principal> owners = Collections.singletonList(
    Acl.getUserPrincipal(attrs.owner().getName(), identitySourceId)
);

最後に、以下のコード スニペットは、ファイルの閲覧者であるプリンシパルを作成する方法を示しています。

FilePermissionSample.java
// List of users to grant access to
List<Principal> readers = new ArrayList<>();

// Add owner, group, others to readers list if permissions
// exist. For this example, other is mapped to everyone
// in the organization.
Set<PosixFilePermission> permissions = attrs.permissions();
if (permissions.contains(PosixFilePermission.OWNER_READ)) {
  readers.add(Acl.getUserPrincipal(attrs.owner().getName(), identitySourceId));
}
if (permissions.contains(PosixFilePermission.GROUP_READ)) {
  String externalGroupName = attrs.group().getName();
  Principal group = Acl.getGroupPrincipal(externalGroupName, identitySourceId);
  readers.add(group);
}
if (permissions.contains(PosixFilePermission.OTHERS_READ)) {
  Principal everyone = Acl.getCustomerPrincipal();
  readers.add(everyone);
}

閲覧者とオーナーのリストを取得したら、ACL を作成できます。

FilePermissionSample.java
// Build the Cloud Search ACL. Note that inheritance of permissions
// from parents is omitted. See `setInheritFrom()` and `setInheritanceType()`
// methods on the builder if required by your implementation.
Acl acl = new Acl.Builder()
    .setReaders(readers)
    .setOwners(owners)
    .build();

基盤となる REST API は、プリンシパルの作成時に ID にパターン identitysources/IDENTITY_SOURCE_ID/users/EXTERNAL_ID を使用します。前の表に戻ると、Ann の id1_identity(SAMAccountName)で ACL を作成すると、ID は次のように解決されます。

identitysources/id1_identity/users/example/ann

この ID 全体は、外部 ID と Cloud Directory に保存されている Google ID の橋渡しをするので、ユーザーの中間 ID と呼ばれます。

リポジトリに使用される ACL のモデル化の詳細については、ACL をご覧ください。

グループのマッピング

ID ソースは、ACL で使用されるグループの名前空間としても機能します。この名前空間機能を使用して、セキュリティ目的でのみ使用されるグループまたはリポジトリに対してローカルなグループを作成およびマッピングできます。

Cloud Identity Groups API を使用してグループを作成し、メンバーシップを管理します。グループを ID ソースに関連付けるには、ID ソースのリソース名をグループ名前空間として使用します。

次のコード スニペットは、Cloud Identity Groups API を使用してグループを作成する方法を示しています。

CreateGroupCommand.java
String namespace = "identitysources/" + idSource;
Group group = new Group()
    .setGroupKey(new EntityKey().setNamespace(namespace).setId(groupId))
    .setDescription("Demo group")
    .setDisplayName(groupName)
    .setLabels(Collections.singletonMap("system/groups/external", ""))
    .setParent(namespace);
try {
  CloudIdentity service = Utils.buildCloudIdentityService();
  Operation createOperation = service.groups().create(group).execute();

  if (createOperation.getDone()) {
    // Note: The response contains the data for a Group object, but as
    // individual fields. To convert to a Group instance, either populate
    // the fields individually or serialize & deserialize to/from JSON.
    //
    // Example:
    // String json = service.getJsonFactory().toString(response);
    // Group createdGroup =  service.getObjectParser()
    //     .parseAndClose(new StringReader(json), Group.class);
    System.out.printf("Group: %s\n",
        createOperation.getResponse().toString());
  } else {
    // Handle case where operation not yet complete, poll for
    // completion. API is currently synchronous and all operations return
    // as completed.
    // ...
  }
} catch (Exception e) {
  System.err.printf("Unable to create group: %s", e.getMessage());
  e.printStackTrace(System.err);
}

グループ ACL を作成する

グループ ACL を作成するには、getGroupPrincipal() メソッドを使用して、指定された外部 ID からグループ プリンシパルを作成します。次に、次のように Acl.Builder クラスを使用して ACL を構築します。

FilePermissionSample.java
if (permissions.contains(PosixFilePermission.GROUP_READ)) {
  String externalGroupName = attrs.group().getName();
  Principal group = Acl.getGroupPrincipal(externalGroupName, identitySourceId);
  readers.add(group);
}

ID コネクタ

Google 以外の外部 ID で ACL を作成してアイテムをインデックス登録することはできますが、ユーザーの外部 ID が Cloud Directory の Google ID に解決されるまで、ユーザーは検索でアイテムを表示できません。Cloud Directory がユーザーの Google ID と外部 ID の両方を認識できるようにするには、以下の 3 つの方法があります。

  • 管理コンソールから個々のユーザー プロファイルを手動で更新します。この方法は、いくつかのユーザー プロファイルを使用したテストとプロトタイピングでのみ使用することをおすすめします。
  • Directory API を使用して外部 ID を Google ID にマッピングします。このプロセスは、Identity Connector SDK を使用できない場合におすすめの方法です。
  • Identity Connector SDK を使用して ID コネクタを作成します。この SDK により、Directory API を使用して簡単に ID をマッピングできます。

ID コネクタは、外部 ID を企業の ID(ユーザーとグループ)から Google Cloud Search で使用される内部 Google ID にマッピングするためのプログラムです。ID ソースを作成する必要がある場合は、ID コネクタを作成する必要があります。

Google Cloud Directory Sync(GCDS)は ID コネクタの一例です。この ID コネクタは、他のシステムで ID を表すユーザー属性とともに、Microsoft の Active Directory のユーザーとグループの情報を Cloud Directory にマッピングします。

REST API を使用して ID を同期する

REST API を使用して ID を同期するには、update メソッドを使用します。

ID の再マッピング

アイテムの ID を別の ID に再マッピングした後、新しい ID を保持するには、アイテムを再インデックスする必要があります。たとえば

  • マッピングをユーザーから削除したり、別のユーザーに再マッピングしたりしても、元のマッピングはインデックスを再作成するまで保持されます。
  • アイテム ACL に存在するマッピングされたグループを削除してから、同じ groupKey を持つ新しいグループを作成した場合、アイテムが再作成されるまで、新しいグループはアイテムへのアクセス権を提供しません。