Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage IAM instance profiles #39

Merged
merged 7 commits into from
Nov 14, 2017
Merged

Manage IAM instance profiles #39

merged 7 commits into from
Nov 14, 2017

Conversation

andrewjhumphrey
Copy link
Contributor

@andrewjhumphrey andrewjhumphrey commented Nov 2, 2017

Instance profiles are a bit of a hybrid between IAM and EC2, but if you've moved IAM management out of your cloudformation templates it feels a little weird to leave the instance profiles behind.

This PR adds the ability to manage instance profiles.

The IAM API call that is used to grab users, groups, roles, policies GetAccountAuthorizationDetails doesn't support instance profiles, so there is a bit of copy'pasta code here to use the ListInstanceProfiles API call. Sorry about that. I suspect that this section might be ripe for a little refactoring. My golang is crappy enough that I haven't attempted that.

Demo

$ ../bin/iamy-darwin-amd64 pull -d .
$ cd envato-platform-development-123456789012/iam/instance_profile/
$ ls -1F
EC2ReadOnly.yaml
aws-elasticbeanstalk-ec2-role.yaml
ecsInstanceRole.yaml
test/
$ cat EC2ReadOnly.yaml 
Roles:
- EC2ReadOnly
$ cp EC2ReadOnly.yaml test/testpath.yaml   # Add role to an instance profile
$ echo '{}' > EC2ReadOnly.yaml # Remove roles from an instance profile
$ cp test/testpath.yaml test/newtestpath.yaml # Create a new instance profile (with path)
$ rm HumpyIAMDBTestRole.yaml  # Remove an instance profile
$ cd ../../..
$ ../bin/iamy-darwin-amd64 push -d . --dry-run
Commands to push changes to AWS:

      aws iam remove-role-from-instance-profile --instance-profile-name EC2ReadOnly --role-name EC2ReadOnly
      aws create-instance-profile --instance-profile-name newtestpath --path /test/
      aws iam add-role-to-instance-profile --instance-profile-name newtestpath --role-name EC2ReadOnly
      aws iam add-role-to-instance-profile --instance-profile-name testpath --role-name EC2ReadOnly
      aws iam delete-instance-profile --instance-profile-name HumpyIAMDBTestRole
Dry-run mode not running aws commands

}
return true
})
if populateInstanceProfileErr != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be here? looks like you've already got a check for this on L136.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's right, the L136 is to escape the iterator function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it needs to be there.
The function that includes line 136 is called by the paging function a.iam.ListInstanceProfilesPages with each back results. So the return false is effectively the break.

iamy/aws.go Outdated
if len(profileResp.Roles) > 0 {
for _, roleResp := range profileResp.Roles {
role := *(roleResp.RoleName)
profile.Roles = append (profile.Roles, role)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we've got an extra bit of whitespace after the append keyword here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like whitespace.
But fixed in 043328d

iamy/aws.go Outdated
Path: *profileResp.Path,
}}
if len(profileResp.Roles) > 0 {
for _, roleResp := range profileResp.Roles {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double spaces after range?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep probably a good idea to run a go fmt over these modified files. I typically add a hook to my editor to run goimports on save @andrewjhumphrey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -113,6 +113,15 @@ type Role struct {
Policies []string `json:"Policies,omitempty"`
}

type InstanceProfile struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we probably want to fix the alignment on this one

type InstanceProfile struct {
	iamService `json:"-"`
	Roles      []string `json:"Roles,omitempty"`
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's aligned if your tabs are set to 8 :-)

iamy/models.go Outdated
@@ -145,6 +154,7 @@ type AccountData struct {
Roles []*Role
Policies []*Policy
BucketPolicies []*BucketPolicy
InstanceProfiles []*InstanceProfile
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should look to align all of these struct fields

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iamy/models.go Outdated
@@ -154,6 +164,7 @@ func NewAccountData(account string) *AccountData {
Groups: []*Group{},
Roles: []*Role{},
Policies: []*Policy{},
InstanceProfiles: []*InstanceProfile{},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should look to align all of these struct fields

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iamy/aws.go Outdated
Name: *profileResp.InstanceProfileName,
Path: *profileResp.Path,
}}
if len(profileResp.Roles) > 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need to wrap the for loop in a length check since golang handles when the range is empty. see https://play.golang.org/p/UUhRUwypIk for an example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, yes. I've cleaned it up in 728fc67 . That was a hail mary debugging attempt when I had:

type InstanceProfile struct {
        iamService              `json:"-"`
        Roles                   []string        `json:"Roles",omitempty`
}

instead of (note the quotes in the omitempty bit)

type InstanceProfile struct {
        iamService              `json:"-"`
        Roles                   []string        `json:"Roles,omitempty"`
}

and It was emitting Roles: null into the YAML instead of ignoring an empty Roles attribute.

@mtibben
Copy link
Member

mtibben commented Nov 2, 2017

This is looking fantastic @andrewjhumphrey, a great addition.

This starts to cut into #35 also. I'm thinking it might be useful to have some kind of mechanism to specify what data you want iamy to manage. Maybe a dotfile where you can specify entities to skip. Any thoughts @pda @lox ?

iamy/awsdiff.go Outdated
}
} else {
// Create instance profile
a.cmds.Add("aws","create-instance-profile","--instance-profile-name",toInstanceProfile.Name,"--path",path(toInstanceProfile.Path))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spacing between these parameters would be 💯

@joho
Copy link

joho commented Nov 2, 2017

Yeah I was worried on initial review that all of a sudden we'd be managing more things with iamy than we expected on an update. Not sure if opt in or opt out is the best model. Maybe opt-out is default for everything available to be maanged at a major release, then on minor releases any new account info is opt-in... then flip it next time we bump major.

Maybe I'm overthinking it, just add this and bump to 3.0.

Also I pulled branch locally to run go fmt, still got one little outstanding whitespace thing.
screen shot 2017-11-02 at 2 08 47 pm

@andrewjhumphrey
Copy link
Contributor Author

I don't see that dryRun indent problem in my tree. Much strange! As that was a change from previous PR I did though (#30) so it's entirely likely I've pooched something.

iamy/models.go Outdated
}

func (ip InstanceProfile) ResourceType() string {
return "instance_profile"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll want to follow the ARN format instance-profile

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iamy/yaml.go Outdated
@@ -13,7 +13,7 @@ import (
)

const pathTemplateBlob = "{{.Account}}/{{.Resource.Service}}/{{.Resource.ResourceType}}{{.Resource.ResourcePath}}{{.Resource.ResourceName}}.yaml"
const pathRegexBlob = `^(?P<account>[^/]+)/(?P<entity>(iam/user|iam/group|iam/policy|iam/role|s3))(?P<resourcepath>.*/)(?P<resourcename>[^/]+)\.yaml$`
const pathRegexBlob = `^(?P<account>[^/]+)/(?P<entity>(iam/instance_profile|iam/user|iam/group|iam/policy|iam/role|s3))(?P<resourcepath>.*/)(?P<resourcename>[^/]+)\.yaml$`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instance-profile as per ARN also here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iamy/yaml.go Outdated
@@ -106,6 +106,10 @@ func (a *YamlLoadDumper) Load() ([]AccountData, error) {
p := Policy{iamService: nameAndPath}
err = a.unmarshalYamlFile(fp, &p)
accounts[accountid].addPolicy(&p)
case "iam/instance_profile":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instance-profile as per ARN also here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c351b24

@pda
Copy link
Contributor

pda commented Nov 2, 2017

I'm thinking it might be useful to have some kind of mechanism to specify what data you want iamy to manage. Maybe a dotfile where you can specify entities to skip.

Yeah some mechanism to opt out of some types (IAM / S3 / EC2 / etc…) could be good. I can't think of a scenario where I'd use it though; I'm happy to track everything it can find. If it's via a config file, I'd strongly prefer a non-dot-file. I hate it when important files are sometimes invisible / excluded from searches / etc.

Somewhat related to opting out of certain types is the auto-ignore of CloudFormation-managed resources based on a dubious pattern match on the resource name. Perhaps that should be opt-in / opt-out or the filter should be configurable?

@mtibben mtibben merged commit f6d5b26 into 99designs:master Nov 14, 2017
@mtibben
Copy link
Member

mtibben commented Nov 14, 2017

Thanks @andrewjhumphrey, also I've made you a contributor with write access as it looks like you're an active user

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants