forked from jdevelop/go-aws-mfa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmfa.go
114 lines (92 loc) · 3.05 KB
/
mfa.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package main
import (
"bufio"
"fmt"
"log"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/go-ini/ini"
)
var (
credsFile = os.Getenv("HOME") + "/.aws/credentials"
cfgFile = os.Getenv("HOME") + "/.aws/config"
)
func fatalErr(err error, msg string) {
if err != nil {
log.Fatal(msg+":", err)
}
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go-aws-mfa [profile]")
os.Exit(1)
}
profile := os.Args[1]
fmt.Printf("Authenticating for %s\n", profile)
credsini, err := ini.Load(credsFile)
fatalErr(err, "Failed to load credentials file")
srcProfile := credsini.Section(profile).Key("long_term").MustString("")
assumeRole := credsini.Section(profile).Key("assume_role").MustString("")
if srcProfile == "" {
srcProfile = profile
}
ltProfile := srcProfile + "-long-term"
cred := credsini.Section(ltProfile)
mfasn := cred.Key("aws_mfa_device").MustString("")
id := cred.Key("aws_access_key_id").MustString("")
key := cred.Key("aws_secret_access_key").MustString("")
fmt.Println("Sourcing creds from", ltProfile)
if id == "" || key == "" {
fmt.Println("ERROR: couldn't find key id or access key")
os.Exit(1)
}
if assumeRole != "" {
fmt.Println("Assuming role", assumeRole)
}
fmt.Println("Using the MFA device", mfasn)
sess, err := session.NewSession(&aws.Config{Credentials: credentials.NewSharedCredentials("", ltProfile)})
fatalErr(err, "ERROR: failed to create session")
fmt.Printf("Enter MFA code: ")
r := bufio.NewReader(os.Stdin)
code, _, err := r.ReadLine()
fatalErr(err, "ERROR: failed to read MFA code")
mfaCode := string(code)
if len(code) != 6 {
fmt.Println("ERROR: code must be 6 digits")
os.Exit(1)
}
stSec, err := credsini.NewSection(profile)
fatalErr(err, "ERROR: failed to create a new section for "+profile)
validUntil := time.Now()
_sts := sts.New(sess)
if assumeRole == "" {
res, err := _sts.GetSessionToken(&sts.GetSessionTokenInput{
TokenCode: &mfaCode,
SerialNumber: &mfasn,
})
fatalErr(err, "ERROR: failed to get session token")
stSec.NewKey("aws_access_key_id", *res.Credentials.AccessKeyId)
stSec.NewKey("aws_secret_access_key", *res.Credentials.SecretAccessKey)
stSec.NewKey("aws_session_token", *res.Credentials.SessionToken)
validUntil = *res.Credentials.Expiration
} else {
res, err := _sts.AssumeRole(&sts.AssumeRoleInput{
TokenCode: &mfaCode,
SerialNumber: &mfasn,
RoleArn: &assumeRole,
RoleSessionName: &profile,
})
fatalErr(err, "ERROR: failed to assume role")
stSec.NewKey("aws_access_key_id", *res.Credentials.AccessKeyId)
stSec.NewKey("aws_secret_access_key", *res.Credentials.SecretAccessKey)
stSec.NewKey("aws_session_token", *res.Credentials.SessionToken)
validUntil = *res.Credentials.Expiration
}
err = credsini.SaveTo(credsFile)
fatalErr(err, "ERROR: failed to update profile with new credentials")
fmt.Printf("Credentials updated for %s, valid until %s\n", profile, validUntil.In(time.Local))
}