exchange uses the Google Compute Engine Metadata API to fetch a signed JWT, and exchange it for a session token for a workspace agent. The requesting instance must be registered as a resource in the latest history for a workspace.
(ctx context.Context)
| 48 | // |
| 49 | // The requesting instance must be registered as a resource in the latest history for a workspace. |
| 50 | func (g *GoogleSessionTokenExchanger) exchange(ctx context.Context) (AuthenticateResponse, error) { |
| 51 | if g.serviceAccount == "" { |
| 52 | // This is the default name specified by Google. |
| 53 | g.serviceAccount = "default" |
| 54 | } |
| 55 | gcpClient := metadata.NewClient(g.client.HTTPClient) |
| 56 | if g.gcpClient != nil { |
| 57 | gcpClient = g.gcpClient |
| 58 | } |
| 59 | |
| 60 | // "format=full" is required, otherwise the responding payload will be missing "instance_id". |
| 61 | jwt, err := gcpClient.Get(fmt.Sprintf("instance/service-accounts/%s/identity?audience=coder&format=full", g.serviceAccount)) |
| 62 | if err != nil { |
| 63 | return AuthenticateResponse{}, xerrors.Errorf("get metadata identity: %w", err) |
| 64 | } |
| 65 | // request without the token to avoid re-entering this function |
| 66 | res, err := g.client.RequestWithoutSessionToken(ctx, http.MethodPost, "/api/v2/workspaceagents/google-instance-identity", GoogleInstanceIdentityToken{ |
| 67 | JSONWebToken: jwt, |
| 68 | AgentName: g.agentName, |
| 69 | }) |
| 70 | if err != nil { |
| 71 | return AuthenticateResponse{}, err |
| 72 | } |
| 73 | defer res.Body.Close() |
| 74 | if res.StatusCode != http.StatusOK { |
| 75 | return AuthenticateResponse{}, codersdk.ReadBodyAsError(res) |
| 76 | } |
| 77 | var resp AuthenticateResponse |
| 78 | return resp, json.NewDecoder(res.Body).Decode(&resp) |
| 79 | } |
nothing calls this directly
no test coverage detected