Google Compute Engine supports instance identity verification: https://cloud.google.com/compute/docs/instances/verifying-instance-identity Using this, we can exchange a signed instance payload for an agent token. @Summary Authenticate agent on Google Cloud instance @ID authenticate-agent-on-google-
(rw http.ResponseWriter, r *http.Request)
| 98 | // @Success 200 {object} agentsdk.AuthenticateResponse |
| 99 | // @Router /api/v2/workspaceagents/google-instance-identity [post] |
| 100 | func (api *API) postWorkspaceAuthGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) { |
| 101 | ctx := r.Context() |
| 102 | var req agentsdk.GoogleInstanceIdentityToken |
| 103 | if !httpapi.Read(ctx, rw, r, &req) { |
| 104 | return |
| 105 | } |
| 106 | |
| 107 | // We leave the audience blank. It's not important we validate who made the token. |
| 108 | payload, err := api.GoogleTokenValidator.Validate(ctx, req.JSONWebToken, "") |
| 109 | if err != nil { |
| 110 | httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{ |
| 111 | Message: "Invalid GCP identity.", |
| 112 | Detail: err.Error(), |
| 113 | }) |
| 114 | return |
| 115 | } |
| 116 | claims := struct { |
| 117 | Google struct { |
| 118 | ComputeEngine struct { |
| 119 | InstanceID string `mapstructure:"instance_id"` |
| 120 | } `mapstructure:"compute_engine"` |
| 121 | } `mapstructure:"google"` |
| 122 | }{} |
| 123 | err = mapstructure.Decode(payload.Claims, &claims) |
| 124 | if err != nil { |
| 125 | httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ |
| 126 | Message: "Error decoding JWT claims.", |
| 127 | Detail: err.Error(), |
| 128 | }) |
| 129 | return |
| 130 | } |
| 131 | api.handleAuthInstanceID(rw, r, claims.Google.ComputeEngine.InstanceID, req.AgentName) |
| 132 | } |
| 133 | |
| 134 | func (api *API) handleAuthInstanceID(rw http.ResponseWriter, r *http.Request, instanceID string, agentName string) { |
| 135 | ctx := r.Context() |