-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Write our credentials in the format of ~/.aws/credentials for tooling that requires this. Fixes: #867
- Loading branch information
1 parent
4828e6e
commit 3f2b9e6
Showing
9 changed files
with
243 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/synfinatic/aws-sso-cli/internal/awsconfig" | ||
) | ||
|
||
type CredentialsCmd struct { | ||
File string `kong:"short='f',help='File to write credentials to (default: stdout)',predictor='allFiles'"` | ||
Append bool `kong:"short='a',help='Append to the file instead of overwriting'"` | ||
Profiles []string `kong:"required,short='p',name='profiles',help='Profiles to write credentials for',predictor='profile'"` | ||
} | ||
|
||
func (cc *CredentialsCmd) Run(ctx *RunContext) error { | ||
cache := ctx.Settings.Cache.GetSSO() | ||
awssso := doAuth(ctx) | ||
|
||
creds := []awsconfig.ProfileCredentials{} | ||
|
||
for _, profile := range ctx.Cli.Credentials.Profiles { | ||
roleFlat, err := cache.Roles.GetRoleByProfile(profile, ctx.Settings) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
pCreds := GetRoleCredentials(ctx, awssso, roleFlat.AccountId, roleFlat.RoleName) | ||
|
||
creds = append(creds, awsconfig.ProfileCredentials{ | ||
Profile: profile, | ||
AccessKeyId: pCreds.AccessKeyId, | ||
SecretAccessKey: pCreds.SecretAccessKey, | ||
SessionToken: pCreds.SessionToken, | ||
Expires: pCreds.ExpireString(), | ||
}) | ||
} | ||
|
||
var err error | ||
switch cc.File { | ||
case "": | ||
err = awsconfig.PrintProfileCredentials(creds) | ||
|
||
default: | ||
flags := os.O_CREATE | os.O_WRONLY | os.O_TRUNC | ||
if cc.Append { | ||
flags = os.O_CREATE | os.O_WRONLY | os.O_APPEND | ||
} | ||
err = awsconfig.WriteProfileCredentials(ctx.Cli.Credentials.File, flags, creds) | ||
|
||
} | ||
|
||
return err | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package awsconfig | ||
|
||
/* | ||
* AWS SSO CLI | ||
* Copyright (c) 2021-2024 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 ( | ||
"fmt" | ||
"io" | ||
"os" | ||
"text/template" | ||
) | ||
|
||
const ( | ||
CREDENTIALS_TEMPLATE = `{{range $profile := . }} | ||
[{{ $profile.Profile }}] | ||
# Expires: {{ $profile.Expires }} | ||
aws_access_key_id = {{ $profile.AccessKeyId }} | ||
aws_secret_access_key = {{ $profile.SecretAccessKey }} | ||
aws_session_token = {{ $profile.SessionToken }} | ||
{{end}} | ||
` | ||
) | ||
|
||
type ProfileCredentials struct { | ||
Profile string | ||
AccessKeyId string | ||
SecretAccessKey string | ||
SessionToken string | ||
Expires string | ||
} | ||
|
||
func genProfileCredentials(output io.Writer, creds []ProfileCredentials) error { | ||
if len(creds) == 0 { | ||
return fmt.Errorf("no credentials to write") | ||
} | ||
t := template.Must(template.New("template").Parse(CREDENTIALS_TEMPLATE)) | ||
return t.Execute(output, creds) | ||
} | ||
|
||
// AwsCredentialsFile generates a new AWS credentials file or writes to STDOUT | ||
// cfile is the path to the file to write to, or "" to write to stdout | ||
// flags is the flags to pass to os.OpenFile | ||
// creds is the list of credentials to write | ||
func WriteProfileCredentials(cfile string, flags int, creds []ProfileCredentials) error { | ||
var ofile *os.File | ||
var err error | ||
|
||
ofile, err = os.OpenFile(cfile, flags, 0600) | ||
if err != nil { | ||
return err | ||
} | ||
defer ofile.Close() | ||
|
||
return genProfileCredentials(ofile, creds) | ||
} | ||
|
||
func PrintProfileCredentials(creds []ProfileCredentials) error { | ||
return genProfileCredentials(os.Stdout, creds) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package awsconfig | ||
|
||
/* | ||
* AWS SSO CLI | ||
* Copyright (c) 2021-2024 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 ( | ||
"bytes" | ||
"io" | ||
"os" | ||
"testing" | ||
|
||
"github.com/MakeNowJust/heredoc" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGenProfileCredentials(t *testing.T) { | ||
// Create a buffer to capture STDOUT | ||
buf := &bytes.Buffer{} | ||
|
||
// Create example ProfileCredentials | ||
creds := []ProfileCredentials{ | ||
{ | ||
Profile: "first", | ||
AccessKeyId: "AKIAIOSFODNN7EXAMPLE", | ||
SecretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", | ||
SessionToken: "AQoDYXdzEJr...<remainder of security token>", | ||
Expires: "2024-06-03 17:56:11 -0700 PDT", | ||
}, | ||
{ | ||
Profile: "second", | ||
AccessKeyId: "AKIAYOMAMMAEXAMPLE", | ||
SecretAccessKey: "wJalrXUtnFEMI/YESMAN/bPxRfiCYEXAMPLEKEY", | ||
SessionToken: "AQoEdBaglyJunior...<remainder of security token>", | ||
Expires: "2024-06-03 18:58:01 -0700 PDT", | ||
}, | ||
} | ||
|
||
err := genProfileCredentials(buf, creds) | ||
assert.NoError(t, err) | ||
|
||
credsResult := heredoc.Doc(` | ||
[first] | ||
# Expires: 2024-06-03 17:56:11 -0700 PDT | ||
aws_access_key_id = AKIAIOSFODNN7EXAMPLE | ||
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY | ||
aws_session_token = AQoDYXdzEJr...<remainder of security token> | ||
[second] | ||
# Expires: 2024-06-03 18:58:01 -0700 PDT | ||
aws_access_key_id = AKIAYOMAMMAEXAMPLE | ||
aws_secret_access_key = wJalrXUtnFEMI/YESMAN/bPxRfiCYEXAMPLEKEY | ||
aws_session_token = AQoEdBaglyJunior...<remainder of security token> | ||
`) | ||
|
||
assert.Equal(t, credsResult, buf.String()) | ||
|
||
// replace os.Stdout with our buffer | ||
old := os.Stdout | ||
r, w, _ := os.Pipe() | ||
os.Stdout = w | ||
|
||
err = PrintProfileCredentials(creds) | ||
assert.NoError(t, err) | ||
w.Close() | ||
output, _ := io.ReadAll(r) | ||
assert.Equal(t, credsResult, string(output)) | ||
|
||
// restore stdout | ||
os.Stdout = old | ||
} | ||
|
||
func TestGenProfileCredentialsErrors(t *testing.T) { | ||
// Test with an empty slice | ||
buf := &bytes.Buffer{} | ||
err := genProfileCredentials(buf, []ProfileCredentials{}) | ||
assert.Error(t, err) | ||
} |