diff options
Diffstat (limited to 'app/controllers/aws.go')
-rw-r--r-- | app/controllers/aws.go | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/app/controllers/aws.go b/app/controllers/aws.go index 5b1765d..4f32942 100644 --- a/app/controllers/aws.go +++ b/app/controllers/aws.go | |||
@@ -2,11 +2,14 @@ package controllers | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "context" | 4 | "context" |
5 | "sync" | ||
5 | 6 | ||
6 | "code.crute.us/mcrute/cloud-identity-broker/app/middleware" | 7 | "code.crute.us/mcrute/cloud-identity-broker/app/middleware" |
7 | "code.crute.us/mcrute/cloud-identity-broker/app/models" | 8 | "code.crute.us/mcrute/cloud-identity-broker/app/models" |
8 | "code.crute.us/mcrute/cloud-identity-broker/cloud/aws" | 9 | "code.crute.us/mcrute/cloud-identity-broker/cloud/aws" |
9 | 10 | ||
11 | "code.crute.us/mcrute/golib/secrets" | ||
12 | |||
10 | "github.com/labstack/echo/v4" | 13 | "github.com/labstack/echo/v4" |
11 | ) | 14 | ) |
12 | 15 | ||
@@ -20,7 +23,49 @@ type requestContext struct { | |||
20 | // This capability does common permission checks and populates a request | 23 | // This capability does common permission checks and populates a request |
21 | // context with user, account, and AWS API information. | 24 | // context with user, account, and AWS API information. |
22 | type AWSAPI struct { | 25 | type AWSAPI struct { |
23 | Store models.AccountStore | 26 | Store models.AccountStore |
27 | Secrets secrets.Client | ||
28 | cache sync.Map // of aws.AWSClient | ||
29 | } | ||
30 | |||
31 | func (h *AWSAPI) getClientFor(ctx context.Context, a *models.Account) (aws.AWSClient, error) { | ||
32 | var client aws.AWSClient | ||
33 | |||
34 | if cv, ok := h.cache.Load(a.ShortName); !ok { | ||
35 | client, err := aws.NewAWSClientFromAccount(ctx, a, h.Secrets) | ||
36 | if err != nil { | ||
37 | return nil, err | ||
38 | } | ||
39 | |||
40 | cv, _ = h.cache.LoadOrStore(a.ShortName, client) | ||
41 | client = cv.(aws.AWSClient) | ||
42 | } else { | ||
43 | client = cv.(aws.AWSClient) | ||
44 | } | ||
45 | |||
46 | return client, nil | ||
47 | } | ||
48 | |||
49 | // Preload enumerates all managed accounts and pre-loads all of the | ||
50 | // clients into the cache. | ||
51 | // | ||
52 | // This exists because there is replication delay of around 5-10 seconds | ||
53 | // for IAM users into other regions so these should be created as early | ||
54 | // in the process lifecycle as possible. | ||
55 | func (h *AWSAPI) Preload(ctx context.Context) []error { | ||
56 | accounts, err := h.Store.List(ctx) | ||
57 | if err != nil { | ||
58 | return []error{err} | ||
59 | } | ||
60 | |||
61 | errors := []error{} | ||
62 | for _, a := range accounts { | ||
63 | _, err = h.getClientFor(ctx, a) | ||
64 | if err != nil { | ||
65 | errors = append(errors, err) | ||
66 | } | ||
67 | } | ||
68 | return errors | ||
24 | } | 69 | } |
25 | 70 | ||
26 | // GetContext checks that the user is authenticated and is authorized to access | 71 | // GetContext checks that the user is authenticated and is authorized to access |
@@ -38,7 +83,7 @@ func (h *AWSAPI) GetContext(c echo.Context) (*requestContext, error) { | |||
38 | return nil, echo.NotFoundHandler(c) | 83 | return nil, echo.NotFoundHandler(c) |
39 | } | 84 | } |
40 | 85 | ||
41 | ac, err := aws.NewAWSClientFromAccount(account) | 86 | client, err := h.getClientFor(c.Request().Context(), account) |
42 | if err != nil { | 87 | if err != nil { |
43 | c.Logger().Errorf("Error building AWS client: %w", err) | 88 | c.Logger().Errorf("Error building AWS client: %w", err) |
44 | return nil, echo.ErrInternalServerError | 89 | return nil, echo.ErrInternalServerError |
@@ -47,6 +92,6 @@ func (h *AWSAPI) GetContext(c echo.Context) (*requestContext, error) { | |||
47 | return &requestContext{ | 92 | return &requestContext{ |
48 | Account: account, | 93 | Account: account, |
49 | Principal: principal, | 94 | Principal: principal, |
50 | AWS: ac, | 95 | AWS: client, |
51 | }, nil | 96 | }, nil |
52 | } | 97 | } |