-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathazure.go
More file actions
67 lines (59 loc) · 2.19 KB
/
azure.go
File metadata and controls
67 lines (59 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package agentsdk
import (
"context"
"encoding/json"
"net/http"
"github.com/coder/coder/v2/codersdk"
)
type AzureInstanceIdentityToken struct {
Signature string `json:"signature" validate:"required"`
Encoding string `json:"encoding" validate:"required"`
// AgentName optionally selects a specific agent when multiple
// agents share the same instance identity. An empty string is
// treated as unspecified.
AgentName string `json:"agent_name,omitempty"`
}
// AzureSessionTokenExchanger exchanges Azure attested metadata for a Coder session token.
// @typescript-ignore AzureSessionTokenExchanger
type AzureSessionTokenExchanger struct {
client *codersdk.Client
agentName string
}
func WithAzureInstanceIdentity(opts ...InstanceIdentityOption) SessionTokenSetup {
cfg := applyInstanceIdentityOptions(opts)
return func(client *codersdk.Client) RefreshableSessionTokenProvider {
return &InstanceIdentitySessionTokenProvider{
TokenExchanger: &AzureSessionTokenExchanger{client: client, agentName: cfg.AgentName},
}
}
}
// AuthWorkspaceAzureInstanceIdentity uses the Azure Instance Metadata Service to
// fetch a signed payload, and exchange it for a session token for a workspace agent.
func (a *AzureSessionTokenExchanger) exchange(ctx context.Context) (AuthenticateResponse, 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 AuthenticateResponse{}, nil
}
req.Header.Set("Metadata", "true")
res, err := a.client.HTTPClient.Do(req)
if err != nil {
return AuthenticateResponse{}, err
}
defer res.Body.Close()
var token AzureInstanceIdentityToken
err = json.NewDecoder(res.Body).Decode(&token)
if err != nil {
return AuthenticateResponse{}, err
}
token.AgentName = a.agentName
res, err = a.client.RequestWithoutSessionToken(ctx, http.MethodPost, "/api/v2/workspaceagents/azure-instance-identity", token)
if err != nil {
return AuthenticateResponse{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return AuthenticateResponse{}, codersdk.ReadBodyAsError(res)
}
var resp AuthenticateResponse
return resp, json.NewDecoder(res.Body).Decode(&resp)
}