使用Google Cloud Platform服务帐户查询GSuite Directory API

时间:2019-04-26 11:56:43

标签: go google-cloud-platform jwt gsuite

我想查询GSuite Admin SDK Directory API以返回Go中一个组中的所有用户,并通过GCP服务帐户身份验证(脚本将在Google Compute Engine VM或作为Google Cloud Function)。

我使用的服务帐户(我们称其为my-service-account@my-project.iam.gserviceaccount.com)已在GSuite中获得了必要的范围:

我还有一个GSuite Admin 帐户(我们将其称为my-admin@my-domain.com)。该帐户将用于授权(请参见the docs on delegation)。

我可以使用以下代码返回一个组中的所有用户(基于上面提供的链接中的代码,并且我删除了大多数错误处理,以使代码更短):

package main

import (
    "io/ioutil"
    "log"
    "os"

    "golang.org/x/net/context"
    "golang.org/x/oauth2/google"
    admin "google.golang.org/api/admin/directory/v1"
)

func main() {
    srv := createAdminDirectoryService(
        os.Getenv("SERVICE_ACCOUNT_FILE_PATH"),
        os.Getenv("GSUITE_ADMIN_USER_EMAIL"),
    )
    members := listUsersInGroup(srv, os.Args[1])
    log.Println(members)
}

func createAdminDirectoryService(serviceAccountFilePath,
                                 gsuiteAdminUserEmail string) *admin.Service {
    jsonCredentials, _ := ioutil.ReadFile(serviceAccountFilePath)

    config, _ := google.JWTConfigFromJSON(
        jsonCredentials,
        admin.AdminDirectoryGroupMemberReadonlyScope,
    )
    config.Subject = gsuiteAdminUserEmail

    ctx := context.Background()
    client := config.Client(ctx)

    srv, _ := admin.New(client)
    return srv
}

func listUsersInGroup(srv *admin.Service, groupEmail string) []string {
    members, err := srv.Members.List(groupEmail).Do()
    if err != nil {
        log.Fatal(err)
    }

    membersEmails := make([]string, len(members.Members))
    for i, member := range members.Members {
        membersEmails[i] = member.Email
    }

    return membersEmails
}

如您所见,该代码必须具有my-service-account@my-project.iam.gserviceaccount.com的JSON密钥文件。这是我发现创建jwt.Config对象的唯一方法。

此外,请注意,委托是通过config.Subject = gsuiteAdminUserEmail行完成的;没有那个,我得到了错误:

googleapi: Error 403: Insufficient Permission: Request had insufficient authentication scopes., insufficientPermissions

无论如何,正在运行:

SERVICE_ACCOUNT_FILE_PATH=/path/to/json/key/of/my/service/account \
GSUITE_ADMIN_USER_EMAIL=my-admin@my-domain.com \
go run main.go my-group@my-domain.com

成功打印my-group@my-domain.com中的所有用户。

但是,由于此代码将从使用my-service-account@my-project.iam.gserviceaccount.com作为服务帐户的Google Compute Engine VM(或Google Cloud Function)运行,因此需要JSON密钥似乎很可笑该服务帐户的身份进行身份验证(因为我已经在VM或GCF内部以my-service-account@my-project.iam.gserviceaccount.com身份进行身份验证)。

我尝试用以下代码替换createAdminDirectoryService()的内容,以身份验证为启动脚本的用户(使用默认凭据):

func createAdminDirectoryService() *admin.Service {
    ctx := context.Background()

    client, _ := google.DefaultClient(ctx, scopes...)

    srv, _ := admin.New(client)
    return srv
}

但是列出用户会返回错误:

googleapi: Error 403: Insufficient Permission: Request had insufficient authentication scopes., insufficientPermissions

由于这是我删除代表团时遇到的相同错误,因此我认为这是相关的。实际上,在admin.Service创建期间,我没有在任何地方提供我的GSuite管理员帐户。

任何人都可以帮助您解决以下问题之一:

  • 我如何直接向在Google Compute Engine VM或Google Cloud Function上运行go脚本的用户进行身份验证?
  • 我真的需要一个JSON密钥文件来生成jwt.Config对象吗?
  • 我研究了golang.org/x/oauth2/google的源代码,可以得到oauth2.Config而不是jwt.Config,但是似乎不可能用oauth2令牌“委托”。我还能如何执行委派?

2 个答案:

答案 0 :(得分:0)

这篇文章有点旧,但希望能帮到你:

我遇到了同样的问题,并通过更改计算实例中的 OAuth 范围使其工作(默认情况下,范围仅包括 https://www.googleapis.com/auth/cloud-platform)。就我而言,我必须添加 https://www.googleapis.com/auth/admin.directory.group.readonly 范围。可以使用 gcloud compute instances set-service-account 命令来完成。这样,从元数据服务器收到的服务帐户不记名令牌就具有访问 Admin Directory API 的正确范围。

遗憾的是,它无法为 Cloud Functions 完成,因为 Cloud Functions OAuth 范围似乎不可自定义。

有关详细信息,请参阅 this post

顺便说一句,现在还可以授予服务帐户访问 Admin Directory API without domain-wide delegation 的权限。

答案 1 :(得分:-1)

    r, err := srv.Users.List().
        ViewType("domain_public").
        Customer("my_customer").
        OrderBy("email").
        Do()

尝试使用它。