Skip to content

Commit a0fd9ab

Browse files
author
Chris Gilmer
committed
Complete add-profile subcommand
1 parent 274bc7c commit a0fd9ab

File tree

2 files changed

+105
-28
lines changed

2 files changed

+105
-28
lines changed

cmd/add_profile.go

Lines changed: 105 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ import (
1919
// AddProfileInitFlags sets up the CLI flags for the 'add-profile' subcommand
2020
func AddProfileInitFlags(flag *pflag.FlagSet) {
2121

22-
flag.String(VaultAWSKeychainNameFlag, VaultAWSKeychainNameDefault, "The aws-vault keychain name")
2322
flag.StringSlice(AWSProfileAccountFlag, []string{}, "A comma separated list of AWS profiles and account IDs 'PROFILE1:ACCOUNTID1,PROFILE2:ACCOUNTID2,...'")
24-
flag.String(AWSBaseProfileFlag, "", fmt.Sprintf("The AWS base profile. If none provided will use first profile name from %q flag", AWSProfileAccountFlag))
23+
flag.String(AWSProfileFlag, "", "The AWS profile used to get the source_profile and mfa_serial attributes")
2524
flag.String(AWSRegionFlag, endpoints.UsWest2RegionID, "The AWS region")
26-
flag.String(IAMUserFlag, "", "The IAM user name to setup")
2725
flag.String(IAMRoleFlag, "", "The IAM role name assigned to the user being setup")
2826
flag.String(OutputFlag, "json", "The AWS CLI output format")
2927

@@ -48,10 +46,6 @@ func AddProfileCheckConfig(v *viper.Viper) error {
4846
return fmt.Errorf("AWS Profile and Account ID check failed: %w", err)
4947
}
5048

51-
if err := checkIAMUser(v); err != nil {
52-
return fmt.Errorf("IAM User check failed: %w", err)
53-
}
54-
5549
if err := checkIAMRole(v); err != nil {
5650
return fmt.Errorf("IAM Role check failed: %w", err)
5751
}
@@ -63,19 +57,110 @@ func AddProfileCheckConfig(v *viper.Viper) error {
6357
return nil
6458
}
6559

60+
// AddProfileConfig holds information for the AWS user being configured by this script
61+
type AddProfileConfig struct {
62+
Logger *log.Logger
63+
Config *vault.ConfigFile
64+
65+
IAMRole string
66+
Partition string
67+
Region string
68+
Output string
69+
70+
BaseProfileName string
71+
AWSProfileName string
72+
AWSProfileAccounts []string
73+
AWSProfiles []vault.ProfileSection
74+
MFASerial string
75+
}
76+
77+
// UpdateAWSProfile updates or creates a single AWS profile to the AWS config file
78+
func (apc *AddProfileConfig) UpdateAWSProfile(iniFile *ini.File, profile *vault.ProfileSection, sourceProfile *string) error {
79+
apc.Logger.Printf("Adding the profile %q to the AWS config file", profile.Name)
80+
sectionName := fmt.Sprintf("profile %s", profile.Name)
81+
82+
// Get or create section before updating
83+
var err error
84+
var section *ini.Section
85+
section = iniFile.Section(sectionName)
86+
if section == nil {
87+
section, err = iniFile.NewSection(sectionName)
88+
if err != nil {
89+
return fmt.Errorf("error creating section %q: %w", profile.Name, err)
90+
}
91+
}
92+
93+
// Add the source profile when provided
94+
if sourceProfile != nil {
95+
_, err = section.NewKey("source_profile", *sourceProfile)
96+
if err != nil {
97+
return fmt.Errorf("unable to add source profile: %w", err)
98+
}
99+
}
100+
101+
if err = section.ReflectFrom(&profile); err != nil {
102+
return fmt.Errorf("error mapping profile to ini file: %w", err)
103+
}
104+
_, err = section.NewKey("output", apc.Output)
105+
if err != nil {
106+
return fmt.Errorf("unable to add output key: %w", err)
107+
}
108+
return nil
109+
}
110+
66111
// AddProfile adds a new profile to the AWS config file
67-
func (sc *SetupConfig) AddProfile() error {
112+
func (apc *AddProfileConfig) AddProfile() error {
68113

69-
sc.Logger.Printf("Adding new profiles to the AWS config file: %s", sc.Config.Path)
114+
apc.Logger.Printf("Adding new profiles to the AWS config file: %s", apc.Config.Path)
70115

71116
// load the ini file
72-
iniFile, err := ini.Load(sc.Config.Path)
117+
iniFile, err := ini.Load(apc.Config.Path)
73118
if err != nil {
74119
return fmt.Errorf("unable to load aws config file: %w", err)
75120
}
76121

122+
roleProfileSection := iniFile.Section(fmt.Sprintf("profile %s", apc.AWSProfileName))
123+
// Get the source profile
124+
sourceProfileKey, err := roleProfileSection.GetKey("source_profile")
125+
if err != nil {
126+
return fmt.Errorf("Unable to get source profile from %q: %w", apc.AWSProfileName, err)
127+
}
128+
apc.BaseProfileName = sourceProfileKey.String()
129+
130+
// Get the MFA Serial
131+
mfaSerialKey, err := roleProfileSection.GetKey("mfa_serial")
132+
if err != nil {
133+
return err
134+
}
135+
apc.MFASerial = mfaSerialKey.String()
136+
137+
// Add each of the remaining profiles
138+
for _, profileAccount := range apc.AWSProfileAccounts {
139+
profileAccountParts := strings.Split(profileAccount, ":")
140+
profileName := profileAccountParts[0]
141+
accountID := profileAccountParts[1]
142+
143+
roleProfile := vault.ProfileSection{
144+
Name: profileName,
145+
Region: apc.Region,
146+
MfaSerial: apc.MFASerial,
147+
148+
// Each account assumes a role that is added to the config profile
149+
RoleARN: fmt.Sprintf("arn:%s:iam::%s:role/%s",
150+
apc.Partition,
151+
accountID,
152+
apc.IAMRole),
153+
}
154+
apc.AWSProfiles = append(apc.AWSProfiles, roleProfile)
155+
156+
// Add the role profile with base as the source profile
157+
if err := apc.UpdateAWSProfile(iniFile, &roleProfile, &apc.BaseProfileName); err != nil {
158+
return err
159+
}
160+
}
161+
77162
// save it back to the aws config path
78-
return iniFile.SaveTo(sc.Config.Path)
163+
return iniFile.SaveTo(apc.Config.Path)
79164
}
80165

81166
func addProfileFunction(cmd *cobra.Command, args []string) error {
@@ -122,9 +207,8 @@ func addProfileFunction(cmd *cobra.Command, args []string) error {
122207

123208
// Get command line flag values
124209
awsRegion := v.GetString(AWSRegionFlag)
125-
awsVaultKeychainName := v.GetString(VaultAWSKeychainNameFlag)
126-
// awsProfileAccount := v.GetStringSlice(AWSProfileAccountFlag)
127-
iamUser := v.GetString(IAMUserFlag)
210+
awsProfileAccount := v.GetStringSlice(AWSProfileAccountFlag)
211+
awsProfile := v.GetString(AWSProfileFlag)
128212
iamRole := v.GetString(IAMRoleFlag)
129213
output := v.GetString(OutputFlag)
130214

@@ -142,29 +226,23 @@ func addProfileFunction(cmd *cobra.Command, args []string) error {
142226
logger.Fatal(err)
143227
}
144228

145-
keyring, err := getKeyring(awsVaultKeychainName)
146-
if err != nil {
147-
logger.Fatal(err)
148-
}
149-
150-
setupConfig := SetupConfig{
229+
addProfileConfig := AddProfileConfig{
151230
// Config
152-
Logger: logger,
153-
Config: config,
154-
Keyring: keyring,
231+
Logger: logger,
232+
Config: config,
155233

156234
// Profile Inputs
157-
IAMUser: iamUser,
158235
IAMRole: iamRole,
159236
Region: awsRegion,
160237
Partition: partition,
161238
Output: output,
162239

163-
// RoleProfileName: &awsVaultProfileAccount[0],
164-
// NewProfiles: awsVaultProfileAccount[1:],
240+
// Profiles
241+
AWSProfileAccounts: awsProfileAccount,
242+
AWSProfileName: awsProfile,
165243
}
166244

167-
if err := setupConfig.AddProfile(); err != nil {
245+
if err := addProfileConfig.AddProfile(); err != nil {
168246
logger.Fatal(err)
169247
}
170248

cmd/main_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ func TestCommandSuite(t *testing.T) {
6969
func (suite *commandTestSuite) TestAddProfileFlags() {
7070
suite.Setup(AddProfileInitFlags, []string{
7171
"--aws-profile-account", "test-new:012345678901",
72-
"--iam-user", "me",
7372
"--iam-role", "engineer",
7473
})
7574
suite.NoError(AddProfileCheckConfig(suite.viper))

0 commit comments

Comments
 (0)