Skip to content

Commit 9cabb17

Browse files
committed
fix: initial commit
1 parent 0f24b1f commit 9cabb17

File tree

17 files changed

+1798
-0
lines changed

17 files changed

+1798
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ vendor/
2323

2424
# IDEs
2525
.vscode
26+
27+
.ignore*

LICENSE

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENCE
2+
Version 3.1, July 2019
3+
4+
by Sam Hocevar <[email protected]>
5+
theiostream <[email protected]>
6+
7+
8+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENCE
9+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
10+
11+
0. You just DO WHAT THE FUCK YOU WANT TO.

Makefile

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
NAME := aws-cli-auth
2+
VERSION := v0.1.0
3+
REVISION := $(shell git rev-parse --short HEAD)
4+
5+
LDFLAGS := -ldflags="-s -w -X \"github.com/dnitsch/aws-cli-auth/version.Version=$(VERSION)\" -X \"github.com/dnitsch/aws-cli-auth/version.Revision=$(REVISION)\" -extldflags -static"
6+
7+
.PHONY: test test_ci tidy install buildprep build buildmac buildwin
8+
9+
test: test_prereq
10+
go test `go list ./... | grep -v */generated/` -v -mod=readonly -coverprofile=.coverage/out | go-junit-report > .coverage/report-junit.xml && \
11+
gocov convert .coverage/out | gocov-xml > .coverage/report-cobertura.xml
12+
13+
test_ci:
14+
go test ./... -mod=readonly
15+
16+
test_prereq:
17+
mkdir -p .coverage
18+
go install github.com/jstemmer/[email protected] && \
19+
go install github.com/axw/gocov/[email protected] && \
20+
go install github.com/AlekSi/[email protected]
21+
22+
tidy: install
23+
go mod tidy
24+
25+
install:
26+
go mod vendor
27+
28+
.PHONY: clean
29+
clean:
30+
rm -rf bin/*
31+
rm -rf dist/*
32+
rm -rf vendor/*
33+
34+
.PHONY: cross-build
35+
cross-build:
36+
for os in darwin linux windows; do \
37+
[ $$os = "windows" ] && EXT=".exe"; \
38+
for arch in amd64 arm64; do \
39+
GOOS=$$os GOARCH=$$arch CGO_ENABLED=0 go build -a -tags netgo -installsuffix netgo $(LDFLAGS) -o dist/$(NAME)-$$os-$$arch$$EXT .; \
40+
done; \
41+
done
42+
43+
.PHONY: deps
44+
deps:
45+
GO111MODULE=on go mod vendor
46+
47+
.PHONY: dist
48+
dist:
49+
cd dist && \
50+
$(DIST_DIRS) cp ../LICENSE {} \; && \
51+
$(DIST_DIRS) cp ../README.md {} \; && \
52+
$(DIST_DIRS) tar -zcf $(NAME)-$(VERSION)-{}.tar.gz {} \; && \
53+
$(DIST_DIRS) zip -r $(NAME)-$(VERSION)-{}.zip {} \; && \
54+
cd ..
55+
56+

README.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# aws-cli-auth
2+
3+
CLI tool for retrieving AWS temporary credentials using OIDC or SAML providers.
4+
5+
Firstly, this package currently deals with SAML only (OIDC to come), however if you have an OIDC IdP provider set up to AWS you can use this [package](https://github.com/openstandia/aws-cli-oidc) and likewise this [package](https://github.com/Versent/saml2aws) for standard SAML AWS integrations.
6+
7+
If, however, you need to support a non standard user journeys enforced by your IdP i.e. a sub company selection within your organization portal, or a selection screen for different MFA providers - PingID or RSA HardToken etc.... you cannot reliably automate the flow or it would have to be too specific.
8+
9+
As such this approach uses [go-rod](https://github.com/go-rod/rod) library to uniformly allow the user to complete any and all auth steps and selections in a managed browser session up to the point of where the SAMLResponse were to be sent to AWS ACS service `https://signin.aws.amazon.com/saml`. Capturing this via hijack request and posting to AWS STS service to exchange this for the temporary credentials.
10+
11+
The advantage of using SAML is that real users can gain access to the AWS Console UI or programatically and audited as the same person in cloudtrail.
12+
13+
By default the tool creates the session name - which can be audited including the persons username from the localhost.
14+
15+
## Known Issues
16+
17+
- Even though a datadir is created to store the chromium session data it is advised to still open settings and save the username/password manually the first time you are presented with the login screen.
18+
19+
## Install
20+
21+
Download from [Releases page](https://github.com/dnitsch/aws-cli-auth/releases).
22+
23+
MacOS
24+
25+
```bash
26+
curl -L https://github.com/dnitsch/aws-cli-auth/releases/download/v0.1.0/aws-cli-auth-darwin-amd64 -o aws-cli-auth
27+
chmod +x aws-cli-auth
28+
sudo mv aws-cli-auth /usr/local/bin
29+
```
30+
31+
## Usage
32+
33+
```bash
34+
CLI tool for retrieving AWS temporary credentials using OIDC or SAML providers.
35+
Stores them under the $HOME/.aws/credentials file under a specified path
36+
37+
Usage:
38+
aws-cli-auth [command]
39+
40+
Available Commands:
41+
completion Generate the autocompletion script for the specified shell
42+
help Help about any command
43+
saml Get AWS credentials and out to stdout
44+
45+
Flags:
46+
--cfg-section string config section name in the yaml config file
47+
-h, --help help for aws-cli-auth
48+
-r, --role string Set the role you want to assume when SAML or OIDC process completes
49+
-s, --store-profile By default the credentials are returned to stdout to be used by the credential_process
50+
51+
Use "aws-cli-auth [command] --help" for more information about a command.
52+
```
53+
54+
### SAML
55+
56+
57+
58+
```bash
59+
Get AWS credentials and out to stdout through your SAML provider authentication.
60+
61+
Usage:
62+
aws-cli-auth saml <SAML ProviderUrl> [flags]
63+
64+
Flags:
65+
-a, --acsurl string Override the default ACS Url, used for checkin the post of the SAMLResponse (default "https://signin.aws.amazon.com/saml")
66+
-h, --help help for saml
67+
-d, --max-duration int Override default max session duration, in seconds, of the role session [900-43200] (default 900)
68+
--principal string Principal Arn of the SAML IdP in AWS
69+
-p, --provider string Saml Entity StartSSO Url
70+
71+
Global Flags:
72+
--cfg-section string config section name in the yaml config file
73+
-r, --role string Set the role you want to assume when SAML or OIDC process completes
74+
-s, --store-profile By default the credentials are returned to stdout to be used by the credential_process
75+
```
76+
77+
Example:
78+
79+
```bash
80+
aws-cli-auth saml --cfg-section nonprod_saml_admin -p "https://your-idp.com/idp/foo?PARTNER=urn:amazon:webservices" --principal "arn:aws:iam::XXXXXXXXXX:saml-provider/IDP_ENTITY_ID" -r "arn:aws:iam::XXXXXXXXXX:role/Developer" -d 3600 -s
81+
```
82+
83+
The PartnerId in most IdPs is usually `urn:amazon:webservices` - but you can change this for anything you stored it as.
84+
85+
If successful will store the creds under the specified config section in credentials profile as per below example
86+
87+
```ini
88+
[default]
89+
aws_access_key_id = XXXXX
90+
aws_secret_access_key = YYYYYYYYY
91+
92+
[another_profile]
93+
aws_access_key_id = XXXXX
94+
aws_secret_access_key = YYYYYYYYY
95+
96+
[nonprod_saml_admin]
97+
aws_access_key_id = XXXXXX
98+
aws_secret_access_key = YYYYYYYYY
99+
aws_session_token = ZZZZZZZZZZZZZZZZZZZZ
100+
```
101+
102+
To give it a quick test.
103+
104+
```bash
105+
aws sts get-caller-identity --profile=nonprod_saml_admin
106+
```
107+
108+
<!-- ### Integrate aws-cli
109+
110+
[Sourcing credentials with an external process](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sourcing-external.html) describes how to integrate aws-cli with external tool.
111+
You can use `aws-cli-auth` as the external process. Add the following lines to your `.aws/config` file.
112+
113+
```
114+
[profile ]
115+
credential_process=aws-cli-auth get-cred -p myop -r arn:aws:iam::123456789012:role/developer -j -s -d 43200
116+
```
117+
118+
Caution: The AWS temporary credentials will be saved into your OS secret store by using `-s` option to reduce authentication each time you use `aws-cli` tool.
119+
120+
## Licence
121+
122+
Licensed under the [MIT](/LICENSE) license. -->
123+
124+
## Acknowldgements
125+
- [Hiroyuki Wada](https://github.com/wadahiro) [package](https://github.com/openstandia/aws-cli-oidc)
126+
- [Mark Wolfe](https://github.com/wolfeidau) [package](https://github.com/Versent/saml2aws)

aws-cli-auth.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
import "github.com/dnitsch/aws-cli-auth/cmd"
4+
5+
func main() {
6+
cmd.Execute()
7+
}

cmd/root.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/dnitsch/aws-cli-auth/internal/config"
8+
"github.com/spf13/cobra"
9+
"github.com/spf13/viper"
10+
)
11+
12+
var (
13+
cfgSectionName string
14+
cfgFile string
15+
storeInProfile bool
16+
rootCmd = &cobra.Command{
17+
Use: "aws-cli-auth",
18+
Short: "CLI tool for retrieving AWS temporary credentials using SAML providers",
19+
Long: `CLI tool for retrieving AWS temporary credentials using SAML providers.
20+
Stores them under the $HOME/.aws/credentials file under a specified path or returns the crednetial_process payload for use in config`,
21+
}
22+
)
23+
24+
func Execute() {
25+
if err := rootCmd.Execute(); err != nil {
26+
fmt.Errorf(err.Error())
27+
}
28+
}
29+
30+
func init() {
31+
cobra.OnInitialize(initConfig)
32+
rootCmd.PersistentFlags().StringVarP(&role, "role", "r", "", "Set the role you want to assume when SAML or OIDC process completes")
33+
rootCmd.PersistentFlags().StringVarP(&cfgSectionName, "cfg-section", "", "", "config section name in the yaml config file")
34+
rootCmd.PersistentFlags().BoolVarP(&storeInProfile, "store-profile", "s", false, "By default the credentials are returned to stdout to be used by the credential_process. Set this flag to instead store the credentials under a named profile section")
35+
}
36+
37+
func initConfig() {
38+
if cfgFile != "" {
39+
// Use config file from the flag.
40+
viper.SetConfigFile(cfgFile)
41+
} else {
42+
// Find home directory.
43+
home, err := os.UserHomeDir()
44+
cobra.CheckErr(err)
45+
46+
// Search config in home directory with name ".cobra" (without extension).
47+
viper.AddConfigPath(home)
48+
viper.SetConfigType("yaml")
49+
viper.SetConfigName(fmt.Sprintf(".%s", config.SELF_NAME))
50+
}
51+
52+
viper.AutomaticEnv()
53+
viper.WriteConfig()
54+
if err := viper.ReadInConfig(); err == nil {
55+
fmt.Println("Using config file:", viper.ConfigFileUsed())
56+
}
57+
}

cmd/saml.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os/user"
6+
7+
"github.com/dnitsch/aws-cli-auth/internal/config"
8+
"github.com/dnitsch/aws-cli-auth/internal/saml"
9+
"github.com/dnitsch/aws-cli-auth/internal/util"
10+
"github.com/dnitsch/aws-cli-auth/internal/web"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var (
15+
providerUrl string
16+
principalArn string
17+
acsUrl string
18+
role string
19+
duration int
20+
samlCmd = &cobra.Command{
21+
Use: "saml <SAML ProviderUrl>",
22+
Short: "Get AWS credentials and out to stdout",
23+
Long: `Get AWS credentials and out to stdout through your SAML provider authentication.`,
24+
Run: getSaml,
25+
}
26+
)
27+
28+
func init() {
29+
samlCmd.PersistentFlags().StringVarP(&providerUrl, "provider", "p", "", "Saml Entity StartSSO Url")
30+
samlCmd.PersistentFlags().StringVarP(&principalArn, "principal", "", "", "Principal Arn of the SAML IdP in AWS")
31+
samlCmd.PersistentFlags().StringVarP(&acsUrl, "acsurl", "a", "https://signin.aws.amazon.com/saml", "Override the default ACS Url, used for checkin the post of the SAMLResponse")
32+
samlCmd.PersistentFlags().IntVarP(&duration, "max-duration", "d", 900, "Override default max session duration, in seconds, of the role session [900-43200]")
33+
rootCmd.AddCommand(samlCmd)
34+
35+
}
36+
37+
func getSaml(cmd *cobra.Command, args []string) {
38+
if cfgSectionName == "" {
39+
util.Writeln("The SAML provider name is required")
40+
util.Exit(nil)
41+
}
42+
43+
t, err := web.GetSamlLogin(providerUrl, acsUrl)
44+
if err != nil {
45+
fmt.Printf("Err: %v", err)
46+
}
47+
user, err := user.Current()
48+
if err != nil {
49+
fmt.Errorf(err.Error())
50+
}
51+
52+
roleObj := &util.AWSRole{RoleARN: role, PrincipalARN: principalArn, Name: util.SessionName(user.Username, config.SELF_NAME), Duration: duration}
53+
54+
creds, err := saml.LoginStsSaml(t, roleObj)
55+
if err != nil {
56+
fmt.Printf("%v", err)
57+
}
58+
59+
util.SetCredentials(creds, cfgSectionName, storeInProfile)
60+
}

go.mod

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module github.com/dnitsch/aws-cli-auth
2+
3+
go 1.17
4+
5+
require (
6+
github.com/aws/aws-sdk-go v1.43.12
7+
github.com/mitchellh/go-ps v1.0.0
8+
github.com/pkg/errors v0.9.1
9+
github.com/spf13/cobra v1.3.0
10+
github.com/spf13/viper v1.10.1
11+
)
12+
13+
require (
14+
github.com/ysmood/goob v0.3.1 // indirect
15+
github.com/ysmood/gson v0.6.4 // indirect
16+
github.com/ysmood/leakless v0.7.0 // indirect
17+
)
18+
19+
require (
20+
github.com/fsnotify/fsnotify v1.5.1 // indirect
21+
github.com/go-rod/rod v0.103.0
22+
github.com/hashicorp/hcl v1.0.0 // indirect
23+
github.com/inconshreveable/mousetrap v1.0.0 // indirect
24+
github.com/jmespath/go-jmespath v0.4.0 // indirect
25+
github.com/magiconair/properties v1.8.5 // indirect
26+
github.com/mitchellh/mapstructure v1.4.3 // indirect
27+
github.com/pelletier/go-toml v1.9.4 // indirect
28+
github.com/spf13/afero v1.6.0 // indirect
29+
github.com/spf13/cast v1.4.1 // indirect
30+
github.com/spf13/jwalterweatherman v1.1.0 // indirect
31+
github.com/spf13/pflag v1.0.5 // indirect
32+
github.com/subosito/gotenv v1.2.0 // indirect
33+
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
34+
golang.org/x/text v0.3.7 // indirect
35+
gopkg.in/ini.v1 v1.66.2
36+
gopkg.in/yaml.v2 v2.4.0 // indirect
37+
)

0 commit comments

Comments
 (0)