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

Support exclude-path #45

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Usage: miam [options]
--export-concurrency N
--target REGEXP
--exclude REGEXP
--exclude-path PATH
--ignore-login-profile
--no-color
--no-progress
Expand Down
1 change: 1 addition & 0 deletions bin/miam
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ ARGV.options do |opt|
opt.on('' , '--export-concurrency N', Integer) {|v| options[:export_concurrency] = v }
opt.on('' , '--target REGEXP') {|v| (options[:target] ||= []) << Regexp.new(v) }
opt.on('' , '--exclude REGEXP') {|v| (options[:exclude] ||= []) << Regexp.new(v) }
opt.on('' , '--exclude-path PATH') {|v| (options[:exclude_path] ||= []) << v }
opt.on('' , '--ignore-login-profile') { options[:ignore_login_profile] = true }
opt.on('' , '--no-access-key') { options[:no_access_key] = true }
opt.on('' , '--no-color') { options[:color] = false }
Expand Down
32 changes: 20 additions & 12 deletions lib/miam/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ class Miam::Client
def initialize(options = {})
@options = {
format: :ruby,
exclude: []
exclude: [],
exclude_path: [],
}.merge(options)
aws_config = options.delete(:aws_config) || {}
@iam = Aws::IAM::Client.new(aws_config)
Expand Down Expand Up @@ -82,7 +83,7 @@ def walk_users(expected, actual, group_users)
updated = scan_rename(:user, expected, actual, group_users)

expected.each do |user_name, expected_attrs|
next unless target_matched?(user_name)
next unless target_matched?(user_name, expected_attrs)

actual_attrs = actual.delete(user_name)

Expand All @@ -103,7 +104,7 @@ def walk_users(expected, actual, group_users)
end

actual.each do |user_name, attrs|
next unless target_matched?(user_name)
next unless target_matched?(user_name, attrs)

@driver.delete_user(user_name, attrs)

Expand Down Expand Up @@ -179,7 +180,7 @@ def walk_groups(expected, actual, actual_users, group_users)
updated = scan_rename(:group, expected, actual, group_users)

expected.each do |group_name, expected_attrs|
next unless target_matched?(group_name)
next unless target_matched?(group_name, expected_attrs)

actual_attrs = actual.delete(group_name)

Expand All @@ -194,7 +195,7 @@ def walk_groups(expected, actual, actual_users, group_users)
end

actual.each do |group_name, attrs|
next unless target_matched?(group_name)
next unless target_matched?(group_name, attrs)

users_in_group = group_users.delete(group_name) || []
@driver.delete_group(group_name, attrs, users_in_group)
Expand All @@ -218,7 +219,7 @@ def walk_roles(expected, actual, instance_profile_roles)
updated = false

expected.each do |role_name, expected_attrs|
next unless target_matched?(role_name)
next unless target_matched?(role_name, expected_attrs)

actual_attrs = actual.delete(role_name)

Expand All @@ -232,7 +233,7 @@ def walk_roles(expected, actual, instance_profile_roles)
end

actual.each do |role_name, attrs|
next unless target_matched?(role_name)
next unless target_matched?(role_name, attrs)

instance_profile_names = []

Expand Down Expand Up @@ -279,6 +280,7 @@ def walk_role_settings(role_name, expected_settings, actual_settings)

def walk_assume_role_policy(role_name, expected_assume_role_policy, actual_assume_role_policy)
updated = false

expected_assume_role_policy.sort_array!
actual_assume_role_policy.sort_array!

Expand Down Expand Up @@ -333,7 +335,7 @@ def walk_instance_profiles(expected, actual, actual_roles, instance_profile_role
updated = false

expected.each do |instance_profile_name, expected_attrs|
next unless target_matched?(instance_profile_name)
next unless target_matched?(instance_profile_name, expected_attrs)

actual_attrs = actual.delete(instance_profile_name)

Expand All @@ -347,7 +349,7 @@ def walk_instance_profiles(expected, actual, actual_roles, instance_profile_role
end

actual.each do |instance_profile_name, attrs|
next unless target_matched?(instance_profile_name)
next unless target_matched?(instance_profile_name, attrs)

roles_in_instance_profile = instance_profile_roles.delete(instance_profile_name) || []
@driver.delete_instance_profile(instance_profile_name, attrs, roles_in_instance_profile)
Expand Down Expand Up @@ -478,7 +480,8 @@ def pre_walk_managed_policies(expected, actual)
updated = false

expected.each do |policy_name, expected_attrs|
next unless target_matched?(policy_name)
next unless target_matched?(policy_name, expected_attrs)

actual_attrs = actual.delete(policy_name)

if actual_attrs
Expand Down Expand Up @@ -513,7 +516,8 @@ def post_walk_managed_policies(actual)
updated = false

actual.each do |policy_name, actual_attrs|
next unless target_matched?(policy_name)
next unless target_matched?(policy_name, actual_attrs)

@driver.delete_managed_policy(policy_name, actual_attrs[:path])
updated = true
end
Expand All @@ -539,13 +543,17 @@ def load_file(file)
end
end

def target_matched?(name)
def target_matched?(name, attrs)
result = true

if @options[:exclude]
result &&= @options[:exclude].all? {|r| name !~ r }
end

if @options[:exclude_path]
result &&= @options[:exclude_path].select{|v| attrs[:path] == v }.empty? if attrs.key? :path
end

if @options[:target]
result &&= @options[:target].any? {|r| name =~ r}
end
Expand Down
237 changes: 237 additions & 0 deletions spec/miam/exclude_path_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
describe 'exclude path option' do
let(:dsl) do
<<-RUBY
user "bob", :path=>"/developer/" do
login_profile :password_reset_required=>true

groups(
"Admin",
"SES"
)

policy "S3" do
{"Statement"=>
[{"Action"=>
["s3:Get*",
"s3:List*"],
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

user "mary", :path=>"/staff/" do
policy "S3" do
{"Statement"=>
[{"Action"=>
["s3:Get*",
"s3:List*"],
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

group "Admin", :path=>"/admin/" do
policy "Admin" do
{"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

group "SES", :path=>"/ses/" do
policy "ses-policy" do
{"Statement"=>
[{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

role "my-role", :path=>"/any/" do
instance_profiles(
"my-instance-profile"
)

assume_role_policy_document do
{"Version"=>"2012-10-17",
"Statement"=>
[{"Sid"=>"",
"Effect"=>"Allow",
"Principal"=>{"Service"=>"ec2.amazonaws.com"},
"Action"=>"sts:AssumeRole"}]}
end

policy "role-policy" do
{"Statement"=>
[{"Action"=>
["s3:Get*",
"s3:List*"],
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

instance_profile "my-instance-profile", :path=>"/profile/"
RUBY
end

before(:each) do
apply { dsl }
end

context 'when exclude a user' do
let(:exclude_path_admin) do
<<-RUBY
user "mary", :path=>"/staff/" do
policy "S3" do
{"Statement"=>
[{"Action"=>
["s3:Get*",
"s3:List*"],
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

group "Admin", :path=>"/admin/" do
policy "Admin" do
{"Statement"=>[{"Effect"=>"Allow", "Action"=>"*", "Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

group "SES", :path=>"/ses/" do
policy "ses-policy" do
{"Statement"=>
[{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

role "my-role", :path=>"/any/" do
instance_profiles(
"my-instance-profile"
)

assume_role_policy_document do
{"Version"=>"2012-10-17",
"Statement"=>
[{"Sid"=>"",
"Effect"=>"Allow",
"Principal"=>{"Service"=>"ec2.amazonaws.com"},
"Action"=>"sts:AssumeRole"}]}
end

policy "role-policy" do
{"Statement"=>
[{"Action"=>
["s3:Get*",
"s3:List*"],
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

instance_profile "my-instance-profile", :path=>"/profile/"
RUBY
end

subject { client(exclude_path_admin: ['/admin/'] ) }

it do
updated = apply(subject) { exclude_path_admin }
expect(updated).to be_falsey
end
end

context 'when exclude a group, a role and an instance profile' do
let(:exclude_path_developer_and_staff) do
<<-RUBY
user "bob", :path=>"/developer/" do
login_profile :password_reset_required=>true

groups(
"Admin",
"SES"
)

policy "S3" do
{"Statement"=>
[{"Action"=>
["s3:Get*",
"s3:List*"],
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

user "mary", :path=>"/staff/" do
policy "S3" do
{"Statement"=>
[{"Action"=>
["s3:Get*",
"s3:List*"],
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end

group "SES", :path=>"/ses/" do
policy "ses-policy" do
{"Statement"=>
[{"Effect"=>"Allow", "Action"=>"ses:SendRawEmail", "Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess"
)
end
RUBY
end

subject { client(exclude_path_developer_and_staff: ['/developer/', '/staff/']) }

it do
updated = apply(subject) { exclude_path_developer_and_staff }
expect(updated).to be_falsey
end
end
end