aboutsummaryrefslogtreecommitdiff
path: root/app/controllers/aws.go
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers/aws.go')
-rw-r--r--app/controllers/aws.go51
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
3import ( 3import (
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.
22type AWSAPI struct { 25type AWSAPI struct {
23 Store models.AccountStore 26 Store models.AccountStore
27 Secrets secrets.Client
28 cache sync.Map // of aws.AWSClient
29}
30
31func (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.
55func (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}