api/auth/gcp: GCE auth returns metadata error body as the JWT (no HTTP status check)
- Dominant language
- Go
- Stars
- 36.3k
- Forks
- 4.8k
- PR merge metrics
- PR metrics pending
Description
**Describe the bug**
`getJWTFromMetadataService` in the `api/auth/gcp` module returns the metadata server's response body as the signed JWT without checking the HTTP status code:
```go
resp, err := c.Do(req)
if err != nil {
return "", fmt.Errorf("error making request to metadata service: %w", err)
}
defer resp.Body.Close()
// get jwt from response
body, err := io.ReadAll(resp.Body)
jwt := string(body)
if err != nil {
return "", fmt.Errorf("error reading response from metadata service: %w", err)
}
return jwt, nil
```
`resp.StatusCode` is never inspected. When the instance identity endpoint does not issue a token, its error body is returned as the JWT and `Login` sends it to Vault as the `jwt` login parameter. Vault then rejects it while parsing, so the caller sees something like:
```
unable to parse signed JWT: go-jose/go-jose: compact JWS format must have three parts
```
The real cause, that the metadata endpoint declined to issue an identity token and why, is discarded before the request is made.
Two smaller things in the same function: `err` from `io.ReadAll` is checked after `body` has already been used, and the request is built with `http.NewRequest` rather than `http.NewRequestWithContext`, so the metadata call is not cancellable even though `Login` receives a `context.Context`.
**To Reproduce**
This does not depend on a specific environment; the code path is unconditional. Any response from `http://metadata/computeMetadata/v1/instance/service-accounts/default/identity` that is not a signed JWT is forwarded to Vault verbatim.
1. Configure GCE auth with `NewGCPAuth(role, WithGCEAuth())` and call `Login`.
2. Arrange for the identity endpoint to return a non-200 (for example an environment where the default service account cannot mint an identity token for the requested audience).
3. Observe that the returned error comes from Vault's JWS parsing rather than from the metadata call.
Reported downstream at external-secrets/external-secrets#6239, where users on GKE with Workload Identity hit exactly the parse error above. I have confirmed the missing status check by reading the module; I have not reproduced the GKE-specific conditions myself, so treat the environment detail there as a field report rather than a verified trigger.
**Expected behavior**
A non-2xx response from the metadata service should return an error naming the status code and the response body, so the caller learns that identity-token issuance failed rather than receiving a JWS parse error from Vault. Roughly:
```go
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("metadata service returned %s requesting an identity token: %s",
resp.Status, strings.TrimSpace(string(body)))
}
```
**Environment:**
* Vault Server Version (retrieve with `vault status`): not applicable, the defect is client side and occurs before the login request reaches a server. Reported against Vault OSS 1.x servers.
* Vault CLI Version (retrieve with `vault version`): not applicable, this is the `github.com/hashicorp/vault/api/auth/gcp` Go module rather than the CLI. Present in v0.11.0 and unchanged in v0.12.0, the latest published version. Code is `api/auth/gcp/gcp.go`, `getJWTFromMetadataService`.
* Server Operating System/Architecture: not applicable. Client side runs on linux/amd64 and linux/arm64 in the reported cases.
Vault server configuration file(s):
```hcl
# Not applicable. No server configuration is involved: the malformed jwt is
# constructed client side and only then submitted to auth//login.
```
**Additional context**
The IAM branch of the same `Login` switch is unaffected, since `signJWT` surfaces errors from the IAM API directly. Only the `gceType` branch converts a failed token request into a successful-looking return value.
Contributor guide
Research direction
Start in api/auth/gcp/gcp.go at getJWTFromMetadataService, then trace the gceType branch of Login to see how its return value reaches Vault. Exercise a non-2xx metadata response and verify that completion reports the metadata status and body instead of a JWT parse error; also check the response-read error ordering and context handling described in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- authentication
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100