Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix caching and add process command #158

Merged
merged 1 commit into from
Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}