Skip to content

Commit

Permalink
Completed aws login
Browse files Browse the repository at this point in the history
  • Loading branch information
Geet Choubey authored and Geet Choubey committed Jan 7, 2023
1 parent 7515ff4 commit e21145c
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 7 deletions.
5 changes: 2 additions & 3 deletions cmd/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ package cmd
import (
"fmt"

"github.com/geetchoubey/gimme-vault/shared/configuration"
"github.com/spf13/cobra"
)

var keys = [2]string{"username", "accountnumber"}

// configureCmd represents the configure command
var configureCmd = &cobra.Command{
Use: "configure",
Short: "Configure command",
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Setting configuration for profile: [%s]\n", profile)
for _, v := range keys {
for _, v := range configuration.Keys {
reader.ReadValue(v)
}
if err := config.Save(); err != nil {
Expand Down
98 changes: 98 additions & 0 deletions cmd/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
"fmt"
"os/exec"
"time"

"github.com/geetchoubey/gimme-vault/shared/http"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
"golang.org/x/crypto/ssh/terminal"
)

// loginCmd represents the login command
var loginCmd = &cobra.Command{
Use: "login",
Short: "Login to your account",
Run: func(cmd *cobra.Command, args []string) {
if f := config.IsConfigInitialized(); !f {
fmt.Println("no configuration has been set. run 'gimme-vault configure' first")
return
}

isLoginValid := checkLoginValid()
if !isLoginValid {
doLogin()
}
awsCreds := doWriteCredentials()
doExportCredentials(awsCreds)
},
}

func checkLoginValid() bool {
token := config.GetString("token")
if len(token) == 0 {
return false
}
updatedAt := config.GetInt64("updatedAt")
if updatedAt == 0 {
return false
}
updatedAtTime := time.Unix(updatedAt, 0)
return int(time.Since(updatedAtTime).Seconds()) < config.GetInt("leaseDuration")
}

func doLogin() {
fmt.Printf("Logging in using [%s] profile\n", profile)
fmt.Printf("Password: ")
password, err := terminal.ReadPassword(0)
if err != nil {
panic(fmt.Errorf("error reading password %v", err))
}
fmt.Println("Logging in...")
authResponse, err := http.Login(config.GetLoginUrl(), string(password))
if err != nil {
jww.DEBUG.Fatalln(err)
jww.FEEDBACK.Println("Error occurred. Please retry")
return
}
fmt.Println("Successfully logged in")
config.Set("token", authResponse.ClientToken)
config.Set("leaseDuration", authResponse.LeaseDuration)
config.Set("updatedAt", time.Now().Unix())
config.Save()
}

func doWriteCredentials() http.AWSCredentials {
fmt.Println("Writing credentials")
awsResponse, err := http.WriteCredentials(config.GetAWSWriteUrl(), config.GetString("token"))
if err != nil {
panic(fmt.Errorf("error writing credentials %v", err))
}
return awsResponse
}

func run(value string, field string) {

if _, err := exec.Command("aws", "configure", "set", field, value).Output(); err != nil {
panic(fmt.Errorf("error occurred while setting %s %v", field, err))
} else {
fmt.Printf("Set [%s] done\n", field)
}
}

func doExportCredentials(awsCreds http.AWSCredentials) {
run(awsCreds.AccessKey, "aws_access_key_id")
run(awsCreds.SecretKey, "aws_secret_access_key")
run(awsCreds.SecurityToken, "aws_session_token")
run(config.GetString("region"), "default.region")

}

func init() {
rootCmd.AddCommand(loginCmd)
}
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ require (
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect
golang.org/x/text v0.4.0 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/term v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -309,7 +311,11 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -318,6 +324,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
7 changes: 5 additions & 2 deletions shared/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@ type Reader struct {
Config configuration.Config
}

func read() string {
func Read(args ...string) string {
if len(args) == 1 {
fmt.Printf(args[0])
}
reader := bufio.NewReader(os.Stdin)
str, _ := reader.ReadString('\n')
return strings.Trim(str, "\n")
}

func (r *Reader) ReadValue(key string) {
fmt.Printf("%s[%s] ", key, r.Config.GetString(key))
value := read()
value := Read()
if len(value) > 0 {
r.Config.Set(key, value)
}
Expand Down
17 changes: 17 additions & 0 deletions shared/configuration/AWSConfiguration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package configuration

var Keys = []string{"username", "awsAccount", "region", "url", "version", "resource", "action"}

func (c *Config) GetLoginUrl() string {
return c.GetString("url") + "/" +
c.GetString("version") + "/" +
"auth/ldap/login/" +
c.GetString("username")
}

func (c *Config) GetAWSWriteUrl() string {
return c.GetString("url") + "/" +
c.GetString("version") + "/" +
"account/" + c.GetString("awsAccount") +
"/sts/Owner"
}
16 changes: 16 additions & 0 deletions shared/configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,16 @@ type Config struct {
Namespace *string
}

var isConfigInitialized bool

func (c *Config) GetQualifiedKey(key string) string {
return *c.Namespace + "." + key
}

func (c *Config) GetUsername() string {
return c.GetString("username")
}

func (c *Config) GetString(key string) string {
return viper.GetString(c.GetQualifiedKey(key))
}
Expand All @@ -27,6 +33,10 @@ func (c *Config) GetBool(key string) bool {
return viper.GetBool(c.GetQualifiedKey(key))
}

func (c *Config) GetInt64(key string) int64 {
return viper.GetInt64(c.GetQualifiedKey(key))
}

func (c *Config) GetInt(key string) int {
return viper.GetInt(c.GetQualifiedKey(key))
}
Expand All @@ -48,6 +58,10 @@ func (c *Config) Save() error {
return nil
}

func (c *Config) IsConfigInitialized() bool {
return isConfigInitialized
}

func Init(fileName string) {
home, err := os.UserHomeDir()
cobra.CheckErr(err)
Expand All @@ -63,5 +77,7 @@ func Init(fileName string) {
if err := viper.ReadInConfig(); err != nil {
jww.INFO.Println("Configuration not initialized")
// panic(fmt.Errorf("unable to use config file: %v", viper.ConfigFileUsed()))
} else {
isConfigInitialized = true
}
}
48 changes: 48 additions & 0 deletions shared/http/login.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package http

import (
"bytes"
"encoding/json"
"errors"
"io"
"net/http"
)

type AuthResponse struct {
ClientToken string `json:"client_token"`
LeaseDuration int `json:"lease_duration"`
}

type LoginResponse struct {
Auth AuthResponse `json:"auth"`
}

func Login(url string, password string) (AuthResponse, error) {
reqBody, err := json.Marshal(map[string]string{
"password": password,
})
if err != nil {
return AuthResponse{}, err
}
resp, err := http.Post(url, "application/json", bytes.NewBuffer(reqBody))
if err != nil || resp.StatusCode != http.StatusOK {
if err == nil {
return AuthResponse{}, errors.New("got error when logging in")
}
return AuthResponse{}, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
if err != nil {
return AuthResponse{}, err
}
}
var response = LoginResponse{}
if err := json.Unmarshal(body, &response); err != nil {
if err != nil {
return AuthResponse{}, err
}
}
return response.Auth, nil
}
45 changes: 45 additions & 0 deletions shared/http/writeCreds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package http

import (
"bytes"
"encoding/json"
"io"
"net/http"
)

type AWSCredentials struct {
AccessKey string `json:"access_key"`
SecretKey string `json:"secret_key"`
SecurityToken string `json:"security_token"`
}

type Response struct {
Data AWSCredentials `json:"data"`
}

func WriteCredentials(url string, token string) (AWSCredentials, error) {
ttl, _ := json.Marshal(map[string]string{
"ttl": "240m",
})
req, _ := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(ttl))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Vault-Token", token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return AWSCredentials{}, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
if err != nil {
return AWSCredentials{}, err
}
}
var response = Response{}
if err := json.Unmarshal(body, &response); err != nil {
if err != nil {
return AWSCredentials{}, err
}
}
return response.Data, nil
}

0 comments on commit e21145c

Please sign in to comment.