从服务帐户对受 Google IAP 保护的资源的编程访问被拒绝,并出现无效签名错误

Byu*_*Lee 8 jwt google-cloud-platform kubernetes google-kubernetes-engine google-iap

我最近在 GKE 集群中启用了 IAP。

  • 集群版本:1.15.11-gke.11

我按照这里的说明操作:https : //cloud.google.com/iap/docs/enabling-kubernetes-howto

服务配置如下:

---
apiVersion: cloud.google.com/v1beta1
kind: BackendConfig
metadata:
  name: foo-bc-iap
  namespace: foo-test
spec:
  iap:
    enabled: true
    oauthclientCredentials:
      secretName: iap-client-secret
---
apiVersion: v1
kind: Service
metadata:
  name: foo-internal-service
  namespace: foo-test
  annotations:
    cloud.google.com/backend-config: '{"ports":{"80":"foo-bc-iap"}}'
spec:
  type: NodePort # To create Ingress using the service.
  selector:
    app: foo-test
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8081
Run Code Online (Sandbox Code Playgroud)

我使用的凭据是 OAuth 2.0 客户端 ID(类型:Web 应用程序)。

当我在 Kubernetes 服务上激活 IAP 时,确保受 IAP 保护的 API 端点的工作方式不同后,我编写了以下测试程序以确保可以从 JSON 文件“account.json”中提供的服务帐户访问该端点。

在编写此示例应用程序时,我查阅了此文档:https : //cloud.google.com/iap/docs/authentication-howto#iap_make_request-go

  • google.golang.org/api v0.23.0
  • 1.12
func (m *myApp) testAuthz(ctx *cli.Context) error {
    audience := "<The client ID of the credential mentioned above>"
    serviceAccountOption := idtoken.WithCredentialsFile("account.json")

    client, err := idtoken.NewClient(ctx.Context, audience, serviceAccountOption)
    if err != nil {
        return fmt.Errorf("idtoken.NewClient: %v", err)
    }

    requestBody := `{
        <some JSON payload>
    }`

    request, err := http.NewRequest("POST", "https://my.iap.protected/endpoint",
        bytes.NewBuffer([]byte(requestBody)))
    if err != nil {
        return fmt.Errorf("http.NewRequest: %v", err)
    }

    request.Header.Add("Content-Type", "application/json")

    response, err := client.Do(request)
    if err != nil {
        return fmt.Errorf("client.Do: %v", err)
    }
    defer response.Body.Close()

    fmt.Printf("request header = %#v\n", response.Request.Header)
    fmt.Printf("response header = %#v\n", response.Header)

    body, err := ioutil.ReadAll(response.Body)
    if err != nil {
        return fmt.Errorf("ioutil.ReadAll: %v", err)
    }

    fmt.Printf("%d: %s\n", response.StatusCode, string(body))

    return nil
}
Run Code Online (Sandbox Code Playgroud)

但是当我运行它时,我只能看到以下响应。

request header = http.Header{"Authorization":[]string{"Bearer <jwt token>"}, "Content-Type":[]string{"application/json"}, "X-Cloud-Trace-Context":[]string{"c855757f20d155da1140fad1508ae3e5/17413578722158830486;o=0"}}

response header = http.Header{"Alt-Svc":[]string{"clear"}, "Content-Length":[]string{"49"}, "Content-Type":[]string{"text/html; charset=UTF-8"}, "Date":[]string{"Wed, 06 May 2020 22:17:43 GMT"}, "X-Goog-Iap-Generated-Response":[]string{"true"}}

401: Invalid IAP credentials: JWT signature is invalid
Run Code Online (Sandbox Code Playgroud)

正如您在此处看到的,访问被拒绝

所以我认为用于对标头中的 JWT 令牌进行签名的签名可能是错误的。

但我使用 jwt.io 确保了以下内容:

  • 标头中使用的 JWT 令牌由调用方服务帐户的私钥签名
  • header中使用的JWT token可以通过调用者服务账号的公钥进行验证
  • JWT 令牌使用 RS256 算法签名

我还查看了令牌:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "<the service account's private key ID>"
}

{
  "iss": "<email address of the service account>",
  "aud": "",
  "exp": 1588806087,
  "iat": 1588802487,
  "sub": "<email address of the service acocunt>"
}
Run Code Online (Sandbox Code Playgroud)

没有什么奇怪的。

所以我不确定这里发生了什么。如果我禁用 IAP,端点将返回正确的响应

谁能给我一些关于我做错了什么的提示?

Dir*_*aio 3

我尝试了您的代码,发现它不适用于google.golang.org/api v0.23.0,但它确实适用于google.golang.org/api v0.24.0(撰写本文时的最新代码)。

这确实是一个错误,发行说明中提到了以下内容:

When provided, use the TokenSource from options for NewTransport. This fixes a bug in idtoken.NewClient where the wrong TokenSource was being used for authentication.
Run Code Online (Sandbox Code Playgroud)

有趣的是,0.23.0 正在发送一个用服务帐户的私钥签名的令牌,并具有以下声明:

{
  "iss":"xx@xx.iam.gserviceaccount.com",
  "aud":"",
  "exp":1589596554,
  "iat":1589592954,
  "sub":"xx@xx.iam.gserviceaccount.com"
}
Run Code Online (Sandbox Code Playgroud)

0.24.0 发送一个用 google 私钥签名的令牌。(在内部,之前的令牌被交换为谷歌签名的令牌)

{
    "aud":"xxxxxxx-xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com",
    "azp":"xx@xx.iam.gserviceaccount.com",
    "email":"xx@xx.iam.gserviceaccount.com",
    "email_verified":true,
    "exp":1589596508,
    "iat":1589592908,
    "iss":"https://accounts.google.com",
    "sub":"11524xxxxxxxxxxxxxxxx"
}
Run Code Online (Sandbox Code Playgroud)