-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
124 lines (105 loc) · 3.44 KB
/
main.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
115
116
117
118
119
120
121
122
123
124
package main
import (
"encoding/json"
"errors"
"fmt"
"github.com/mitchellh/mapstructure"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/xgfone/gconf/v4"
"io/ioutil"
"strings"
)
var (
credentialsFile string
profile string
)
type AWSProfile struct {
AccessKeyID string `mapstructure:"aws_access_key_id" json:"AWS_ACCESS_KEY_ID,omitempty"`
SecretAccessKey string `mapstructure:"aws_secret_access_key" json:"AWS_SECRET_ACCESS_KEY,omitempty"`
SessionToken string `mapstructure:"aws_session_token" json:"AWS_SESSION_TOKEN,omitempty"`
Region string `mapstructure:"region" json:"AWS_REGION,omitempty"`
RoleArn string `mapstructure:"role_arn" json:"AWS_ROLE_ARN,omitempty"`
RoleSessionName string `mapstructure:"role_session_name" json:"AWS_ROLE_SESSION_NAME,omitempty"`
SourceProfile string `mapstructure:"source_profile" json:"AWS_SOURCE_PROFILE,omitempty"`
}
func (p AWSProfile) Validate() error {
noAccessKeyID := p.AccessKeyID == ""
noSecretAccessKey := p.SecretAccessKey == ""
noSourceProfile := p.SourceProfile == ""
noRoleArn := p.RoleArn == ""
if noSourceProfile && noRoleArn {
// expect an access key ID and secret access key
if noAccessKeyID {
return errors.New("no `aws_access_key_id` found in profile")
}
if noSecretAccessKey {
return errors.New("no `aws_secret_access_key` found in profile")
}
}
if noAccessKeyID && noSecretAccessKey {
// expect a source profile and role arn
if noSourceProfile {
return errors.New("no `source_profile` found in profile")
}
if noRoleArn {
return errors.New("no `role_arn` found in profile")
}
}
return nil
}
func ParseAWSProfile(credentialsData []byte, profile string) (AWSProfile, error) {
awsProfile := AWSProfile{}
// check profile exists
if !strings.Contains(string(credentialsData), fmt.Sprintf("[%s]", profile)) {
return awsProfile, fmt.Errorf("no profile found with name: `%s`", profile)
}
// INI -> generic map
rawData := make(map[string]interface{})
err := gconf.NewIniDecoder(profile).Decode(credentialsData, rawData)
if err != nil {
return awsProfile, fmt.Errorf("failed to parse AWS profile from source: %s", err)
}
// generic map -> awsProfile
err = mapstructure.Decode(rawData, &awsProfile)
if err != nil {
return awsProfile, fmt.Errorf("failed to parse AWS profile from loaded source: %s", err)
}
if err := awsProfile.Validate(); err != nil {
return awsProfile, fmt.Errorf("invalid AWS profile [%s]: %s", profile, err)
}
return awsProfile, nil
}
var awsProfileCmd = &cobra.Command{
Use: "aw-profile-parser",
Short: "AWS profile parser",
Long: `AWS profile parser reads and validates a profile.`,
Version: "1.0.0",
RunE: func(cmd *cobra.Command, args []string) error {
// read credentials file
data, err := ioutil.ReadFile(credentialsFile)
if err != nil {
return fmt.Errorf("error reading file: %s", err)
}
awsProfile, err := ParseAWSProfile(data, profile)
if err != nil {
return err
}
result, err := json.MarshalIndent(awsProfile, "", " ")
if err != nil {
return err
}
fmt.Println(string(result))
return nil
},
}
func main() {
err := awsProfileCmd.Execute()
if err != nil {
log.Fatalf("Error executing command: %s", err)
}
}
func init() {
awsProfileCmd.PersistentFlags().StringVarP(&credentialsFile, "credentials", "c", "", "AWS credentials file")
awsProfileCmd.PersistentFlags().StringVarP(&profile, "profile", "p", "default", "AWS profile name")
}