feat: Add Azure instance identitity authentication (#1064)

This enables zero-trust authentication for Azure instances. Now
we support the three major clouds: AWS, Azure, and GCP 😎.
This commit is contained in:
Kyle Carberry
2022-04-19 08:48:13 -05:00
committed by GitHub
parent 118a47e4e1
commit c8246e3e8a
13 changed files with 348 additions and 15 deletions

View File

@ -37,6 +37,11 @@ type AWSInstanceIdentityToken struct {
Document string `json:"document" validate:"required"`
}
type AzureInstanceIdentityToken struct {
Signature string `json:"signature" validate:"required"`
Encoding string `json:"encoding" validate:"required"`
}
// WorkspaceAgentAuthenticateResponse is returned when an instance ID
// has been exchanged for a session token.
type WorkspaceAgentAuthenticateResponse struct {
@ -139,6 +144,38 @@ func (c *Client) AuthWorkspaceAWSInstanceIdentity(ctx context.Context) (Workspac
return resp, json.NewDecoder(res.Body).Decode(&resp)
}
// AuthWorkspaceAzureInstanceIdentity uses the Azure Instance Metadata Service to
// fetch a signed payload, and exchange it for a session token for a workspace agent.
func (c *Client) AuthWorkspaceAzureInstanceIdentity(ctx context.Context) (WorkspaceAgentAuthenticateResponse, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://169.254.169.254/metadata/attested/document?api-version=2020-09-01", nil)
if err != nil {
return WorkspaceAgentAuthenticateResponse{}, nil
}
req.Header.Set("Metadata", "true")
res, err := c.HTTPClient.Do(req)
if err != nil {
return WorkspaceAgentAuthenticateResponse{}, err
}
defer res.Body.Close()
var token AzureInstanceIdentityToken
err = json.NewDecoder(res.Body).Decode(&token)
if err != nil {
return WorkspaceAgentAuthenticateResponse{}, err
}
res, err = c.request(ctx, http.MethodPost, "/api/v2/workspaceagents/azure-instance-identity", token)
if err != nil {
return WorkspaceAgentAuthenticateResponse{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return WorkspaceAgentAuthenticateResponse{}, readBodyAsError(res)
}
var resp WorkspaceAgentAuthenticateResponse
return resp, json.NewDecoder(res.Body).Decode(&resp)
}
// ListenWorkspaceAgent connects as a workspace agent identifying with the session token.
// On each inbound connection request, connection info is fetched.
func (c *Client) ListenWorkspaceAgent(ctx context.Context, logger slog.Logger) (*peerbroker.Listener, error) {