Skip to content

Commit

Permalink
Fix caching and add process command
Browse files Browse the repository at this point in the history
 * Local cache was not saving during auto-refresh causing
    future runs to not use the cache and slowing execution after 24hrs.
 * Add support for AWS `credential_process` output in ~/.aws/config
   files

Refs #157
  • Loading branch information
synfinatic committed Nov 23, 2021
1 parent 2153609 commit 6859f25
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
* Will no longer overwrite user defined AWS_DEFAULT_REGION #152
* Remove `--region` flag for `eval` and `exec` commands
* Add `--no-region` flag for `eval and `exec` commands
* Add `process` command for AWS credential_process #157
* Fix bug where cache auto-refresh was not saving the new file, causing future
runs to not utilize the cache

## [v1.3.1] - 2021-11-15

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ been granted access!
* `exec` -- Exec a command with the selected role
* `flush` -- Force delete of cached AWS SSO credentials
* `list` -- List all accounts & roles
* `process` -- Generate JSON for AWS credential_process
* `tags` -- List manually created tags for each role
* `time` -- Print how much time remains for currently selected role
* `version` -- Print the version of aws-sso
Expand Down Expand Up @@ -191,6 +192,19 @@ The following environment variables are automatically set by `exec`:
* `AWS_DEFAULT_REGION` -- Region to use AWS with
* `AWS_SSO_PROFILE` -- User customizable varible using a template

### process

Process allows you to use AWS SSO as an [external credentials provider](
https://docs.aws.amazon.com/cli/latest/topic/config-vars.html#sourcing-credentials-from-external-processes)
with profiles defined in `~/.aws/config`.

Flags:

* `--arn <arn>`, `-a` -- ARN of role to assume (`$AWS_SSO_ROLE_ARN`)
* `--account <account>`, `-A` -- AWS AccountID of role to assume (`$AWS_SSO_ACCOUNTID`)
* `--duration <minutes>`, `-d` -- AWS Session duration in minutes (default 60) (`$AWS_SSO_DURATION`)
* `--role <role>`, `-R` -- Name of AWS Role to assume (requires `--account`) (`$AWS_SSO_ROLE`)

### cache

AWS SSO CLI caches information about your AWS Accounts, Roles and Tags for better
Expand Down
11 changes: 9 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ type CLI struct {
Exec ExecCmd `kong:"cmd,help='Execute command using specified AWS Role/Profile'"`
Flush FlushCmd `kong:"cmd,help='Flush AWS SSO/STS credentials from cache'"`
List ListCmd `kong:"cmd,help='List all accounts / role (default command)'"`
Process ProcessCmd `kong:"cmd,help='Generate JSON for credential_process in ~/.aws/config'"`
Tags TagsCmd `kong:"cmd,help='List tags'"`
Time TimeCmd `kong:"cmd,help='Print out much time before STS Token expires'"`
Version VersionCmd `kong:"cmd,help='Print version and exit'"`
Expand Down Expand Up @@ -227,6 +228,7 @@ func GetRoleCredentials(ctx *RunContext, awssso *sso.AWSSSO, accountid int64, ro

// First look for our creds in the secure store, if we're not forcing a refresh
arn := utils.MakeRoleARN(accountid, role)
log.Debugf("Getting role credentials for %s", arn)
if !ctx.Cli.STSRefresh {
if roleFlat, err := ctx.Settings.Cache.GetRole(arn); err == nil {
if !roleFlat.IsExpired() {
Expand Down Expand Up @@ -281,8 +283,13 @@ func doAuth(ctx *RunContext) *sso.AWSSSO {
if err != nil {
log.WithError(err).Fatalf("Unable to authenticate")
}
if err := ctx.Settings.Cache.Refresh(AwsSSO, s); err != nil {
log.WithError(err).Fatalf("Unable to refresh cache")
if err = ctx.Settings.Cache.Expired(s); err != nil {
if err = ctx.Settings.Cache.Refresh(AwsSSO, s); err != nil {
log.WithError(err).Fatalf("Unable to refresh cache")
}
if err = ctx.Settings.Cache.Save(true); err != nil {
log.WithError(err).Errorf("Unable to save cache")
}
}
return AwsSSO
}
99 changes: 99 additions & 0 deletions cmd/process_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

/*
* AWS SSO CLI
* Copyright (c) 2021 Aaron Turner <synfinatic at gmail dot com>
*
* This program is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or with the authors permission any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import (
"encoding/json"
"fmt"
"time"

//log "github.com/sirupsen/logrus"
"github.com/synfinatic/aws-sso-cli/sso"
"github.com/synfinatic/aws-sso-cli/storage"
"github.com/synfinatic/aws-sso-cli/utils"
)

type ProcessCmd struct {
// AWS Params
Duration int64 `kong:"short='d',help='AWS Session duration in minutes (default 60)',default=60,env='AWS_SSO_DURATION'"`
Arn string `kong:"short='a',help='ARN of role to assume',xor='arn-1',xor='arn-2'"`
AccountId int64 `kong:"name='account',short='A',help='AWS AccountID of role to assume',xor='arn-1'"`
Role string `kong:"short='R',help='Name of AWS Role to assume',xor='arn-2'"`
}

func (cc *ProcessCmd) Run(ctx *RunContext) error {
var err error

// never print the URL since that breaks AWS's eval
if ctx.Settings.UrlAction == "print" {
ctx.Settings.UrlAction = "open"
}

role := ctx.Cli.Process.Role
account := ctx.Cli.Process.AccountId

if len(ctx.Cli.Process.Arn) > 0 {
account, role, err = utils.ParseRoleARN(ctx.Cli.Process.Arn)
if err != nil {
return err
}
}

awssso := doAuth(ctx)
return credentialProcess(ctx, awssso, account, role)
}

type CredentialProcessOutput struct {
Version int
AccessKeyId string
SecretAccessKey string
SessionToken string
Expiration string // ISO8601
}

func NewCredentialsProcessOutput(creds *storage.RoleCredentials) *CredentialProcessOutput {
c := CredentialProcessOutput{
Version: 1,
AccessKeyId: (*creds).AccessKeyId,
SecretAccessKey: (*creds).SecretAccessKey,
SessionToken: (*creds).SessionToken,
Expiration: time.Unix((*creds).ExpireEpoch(), 0).Format(time.RFC3339),
}
return &c
}

func (cpo *CredentialProcessOutput) Output() (string, error) {
b, err := json.Marshal(cpo)
if err != nil {
return "", err
}
return string(b), nil
}

func credentialProcess(ctx *RunContext, awssso *sso.AWSSSO, accountId int64, role string) error {
creds := GetRoleCredentials(ctx, awssso, accountId, role)

cpo := NewCredentialsProcessOutput(creds)
out, err := cpo.Output()
if err != nil {
return err
}
fmt.Printf("%s", out)
return nil
}

0 comments on commit 6859f25

Please sign in to comment.