exchange uses the Amazon Metadata API to fetch a signed payload, 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)
| 41 | // |
| 42 | // The requesting instance must be registered as a resource in the latest history for a workspace. |
| 43 | func (a *AWSSessionTokenExchanger) exchange(ctx context.Context) (AuthenticateResponse, error) { |
| 44 | req, err := http.NewRequestWithContext(ctx, http.MethodPut, "http://169.254.169.254/latest/api/token", nil) |
| 45 | if err != nil { |
| 46 | return AuthenticateResponse{}, nil |
| 47 | } |
| 48 | req.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "21600") |
| 49 | res, err := a.client.HTTPClient.Do(req) |
| 50 | if err != nil { |
| 51 | return AuthenticateResponse{}, err |
| 52 | } |
| 53 | defer res.Body.Close() |
| 54 | token, err := io.ReadAll(res.Body) |
| 55 | if err != nil { |
| 56 | return AuthenticateResponse{}, xerrors.Errorf("read token: %w", err) |
| 57 | } |
| 58 | |
| 59 | req, err = http.NewRequestWithContext(ctx, http.MethodGet, "http://169.254.169.254/latest/dynamic/instance-identity/signature", nil) |
| 60 | if err != nil { |
| 61 | return AuthenticateResponse{}, nil |
| 62 | } |
| 63 | req.Header.Set("X-aws-ec2-metadata-token", string(token)) |
| 64 | res, err = a.client.HTTPClient.Do(req) |
| 65 | if err != nil { |
| 66 | return AuthenticateResponse{}, err |
| 67 | } |
| 68 | defer res.Body.Close() |
| 69 | signature, err := io.ReadAll(res.Body) |
| 70 | if err != nil { |
| 71 | return AuthenticateResponse{}, xerrors.Errorf("read token: %w", err) |
| 72 | } |
| 73 | |
| 74 | req, err = http.NewRequestWithContext(ctx, http.MethodGet, "http://169.254.169.254/latest/dynamic/instance-identity/document", nil) |
| 75 | if err != nil { |
| 76 | return AuthenticateResponse{}, nil |
| 77 | } |
| 78 | req.Header.Set("X-aws-ec2-metadata-token", string(token)) |
| 79 | res, err = a.client.HTTPClient.Do(req) |
| 80 | if err != nil { |
| 81 | return AuthenticateResponse{}, err |
| 82 | } |
| 83 | defer res.Body.Close() |
| 84 | document, err := io.ReadAll(res.Body) |
| 85 | if err != nil { |
| 86 | return AuthenticateResponse{}, xerrors.Errorf("read token: %w", err) |
| 87 | } |
| 88 | |
| 89 | // request without the token to avoid re-entering this function |
| 90 | res, err = a.client.RequestWithoutSessionToken(ctx, http.MethodPost, "/api/v2/workspaceagents/aws-instance-identity", AWSInstanceIdentityToken{ |
| 91 | Signature: string(signature), |
| 92 | Document: string(document), |
| 93 | AgentName: a.agentName, |
| 94 | }) |
| 95 | if err != nil { |
| 96 | return AuthenticateResponse{}, err |
| 97 | } |
| 98 | defer res.Body.Close() |
| 99 | if res.StatusCode != http.StatusOK { |
| 100 | return AuthenticateResponse{}, codersdk.ReadBodyAsError(res) |
nothing calls this directly
no test coverage detected