/
keychain.go
99 lines (84 loc) · 3.14 KB
/
keychain.go
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright 2022 Namespace Labs Inc; All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package teleport
import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/aws/aws-sdk-go-v2/service/ecr/types"
dockertypes "github.com/docker/cli/cli/config/types"
"github.com/google/go-containerregistry/pkg/authn"
"namespacelabs.dev/foundation/internal/console"
"namespacelabs.dev/foundation/internal/fnerrors"
"namespacelabs.dev/foundation/internal/providers/aws/ecr"
"namespacelabs.dev/foundation/std/tasks"
"namespacelabs.dev/foundation/universe/teleport/configuration"
)
type ecrTeleportKeychain struct {
conf *configuration.Configuration
}
func (tk ecrTeleportKeychain) Resolve(ctx context.Context, res authn.Resource) (authn.Authenticator, error) {
if tk.conf.GetTeleport().GetEcrCredentialsProxyApp() == "" {
return authn.DefaultKeychain.Resolve(res)
}
config, err := tk.ecrAuth(ctx)
if err != nil {
return nil, err
}
return authn.FromConfig(authn.AuthConfig{
Username: config.Username,
Password: config.Password,
}), nil
}
func (tk ecrTeleportKeychain) ecrAuth(ctx context.Context) (*dockertypes.AuthConfig, error) {
appCreds, err := resolveTeleportAppCreds(tk.conf.GetTeleport(), tk.conf.GetTeleport().GetEcrCredentialsProxyApp())
if err != nil {
return nil, err
}
return tasks.Return(ctx, tasks.Action("teleport.ecr-auth"), func(ctx context.Context) (*dockertypes.AuthConfig, error) {
return ecr.RefreshAuth(ctx,
func(ctx context.Context) ([]types.AuthorizationData, error) {
cert, err := tls.LoadX509KeyPair(appCreds.certFile, appCreds.keyFile)
if err != nil {
return nil, fnerrors.New("teleport: failed to load client TLS certificate")
}
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
},
},
}
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://%s", appCreds.endpoint), nil)
if err != nil {
fmt.Fprintf(console.Debug(ctx), "teleport: failed to create ECR credentials request: %v\n", err)
return nil, fnerrors.New("teleport: failed to create ECR credentials request")
}
resp, err := httpClient.Do(req)
if err != nil {
fmt.Fprintf(console.Debug(ctx), "HTTP request to Teleport app failed: %v\n", err)
return nil, fnerrors.New("teleport: failed to request ECR credentials")
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Fprintf(console.Debug(ctx), "failed to read HTTP request body: %v\n", err)
return nil, fnerrors.New("teleport: failed to read ECR credentials")
}
var authzData []types.AuthorizationData
if err := json.Unmarshal(data, &authzData); err != nil {
fmt.Fprintf(console.Debug(ctx), "failed to parse HTTP request body: %v\n", err)
return nil, fnerrors.New("teleport: failed to parse ECR credentials")
}
return authzData, nil
},
func(ctx context.Context) (string, error) {
return tk.conf.GetRegistry(), nil
},
)
})
}