Skip to content

Commit

Permalink
Refactor credential handling and add tests (#25)
Browse files Browse the repository at this point in the history
* Refactor credential handling and add tests

* add more cache tests, run tests in pre-commit

* start adding refreshable cred provider tests

* add more refreshable cred provider tests

* explicitly set golang version in pre-commit

* round all the times!

* how about unix timestamps

* add custom time type to fix json unmarshaling
  • Loading branch information
patricksanders authored Dec 9, 2020
1 parent 76bebb0 commit 87839a8
Show file tree
Hide file tree
Showing 20 changed files with 1,120 additions and 153 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/precommit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/setup-go@v2
with:
go-version: '^1.15.6'
- uses: pre-commit/action@v2.0.0
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ repos:
- id: go-fmt
- id: go-vet
- id: go-imports
- id: no-go-testing
- id: go-unit-tests
- id: go-mod-tidy
113 changes: 113 additions & 0 deletions cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright 2020 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cache

import (
"fmt"
"strings"
"sync"

"github.com/netflix/weep/creds"
"github.com/netflix/weep/errors"
log "github.com/sirupsen/logrus"
)

var GlobalCache CredentialCache

type CredentialCache struct {
RoleCredentials map[string]*creds.RefreshableProvider
DefaultRole string
mu sync.RWMutex
}

func init() {
GlobalCache = CredentialCache{
RoleCredentials: make(map[string]*creds.RefreshableProvider),
}
}

// getCacheSlug returns a string unique to a particular combination of a role and chain of roles to assume.
func getCacheSlug(role string, assume []string) string {
elements := append([]string{role}, assume...)
return strings.Join(elements, "/")
}

func (cc *CredentialCache) Get(role string, assumeChain []string) (*creds.RefreshableProvider, error) {
log.WithFields(log.Fields{
"role": role,
"assumeChain": assumeChain,
}).Info("retrieving credentials")
c, ok := cc.get(getCacheSlug(role, assumeChain))
if ok {
log.Debugf("found credentials for %s in cache", role)
return c, nil
}
return nil, errors.NoCredentialsFoundInCache
}

func (cc *CredentialCache) GetOrSet(client *creds.Client, role, region string, assumeChain []string) (*creds.RefreshableProvider, error) {
c, err := cc.Get(role, assumeChain)
if err == nil {
return c, nil
}
log.Debugf("no credentials for %s in cache, creating", role)

c, err = cc.set(client, role, region, assumeChain)
if err != nil {
return nil, err
}

return c, nil
}

func (cc *CredentialCache) SetDefault(client *creds.Client, role, region string, assumeChain []string) error {
_, err := cc.set(client, role, region, assumeChain)
if err != nil {
return err
}
cc.DefaultRole = getCacheSlug(role, assumeChain)
return nil
}

func (cc *CredentialCache) GetDefault() (*creds.RefreshableProvider, error) {
if cc.DefaultRole == "" {
return nil, errors.NoDefaultRoleSet
}
c, ok := cc.get(cc.DefaultRole)
if ok {
return c, nil
}
return nil, errors.NoCredentialsFoundInCache
}

func (cc *CredentialCache) get(slug string) (*creds.RefreshableProvider, bool) {
cc.mu.RLock()
defer cc.mu.RUnlock()
c, ok := cc.RoleCredentials[slug]
return c, ok
}

func (cc *CredentialCache) set(client *creds.Client, role, region string, assumeChain []string) (*creds.RefreshableProvider, error) {
c, err := creds.NewRefreshableProvider(client, role, region, assumeChain, false)
if err != nil {
return nil, fmt.Errorf("could not generate creds: %w", err)
}
cc.mu.Lock()
defer cc.mu.Unlock()
cc.RoleCredentials[getCacheSlug(role, assumeChain)] = c
return c, nil
}
Loading

0 comments on commit 87839a8

Please sign in to comment.