Class: BuildCloud::IAMRole

Inherits:
Object
  • Object
show all
Includes:
Component
Defined in:
lib/build-cloud/iamrole.rb

Constant Summary collapse

@@objects =
[]

Instance Method Summary collapse

Methods included from Component

included

Constructor Details

#initialize(fog_interfaces, log, options = {}) ⇒ IAMRole

Returns a new instance of IAMRole.



9
10
11
12
13
14
15
16
17
18
19
# File 'lib/build-cloud/iamrole.rb', line 9

def initialize ( fog_interfaces, log, options = {} )

    @iam     = fog_interfaces[:iam]
    @log     = log
    @options = options

    @log.debug( options.inspect )

    required_options(:rolename, :assume_role_policy_document)

end

Instance Method Details

#createObject



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
# File 'lib/build-cloud/iamrole.rb', line 21

def create

    policies = @options.delete(:policies)

    unless exists?

        @log.info( "Creating new IAM role for #{@options[:rolename]}" )

        # Genuinely don't think I've understood the data model with 
        # this stuff.  In particular how roles, instance profiles etc. relate
        #
        # It does what we need right now though, and can be revisited if necessary

        role = @iam.roles.new( @options )
        role.save

        @log.debug( role.inspect )

        @iam.create_instance_profile( @options[:rolename] )

        @iam.add_role_to_instance_profile( @options[:rolename], @options[:rolename] )

    end

    rationalise_policies( policies )

end

#deleteObject



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/build-cloud/iamrole.rb', line 162

def delete

    return unless exists?

    @log.info( "Deleting IAM role for #{@options[:rolename]}" )

    instance_profiles = @iam.list_instance_profiles_for_role( @options[:rolename] ).body['InstanceProfiles'].map { |k| k['InstanceProfileName'] }
    instance_profiles.each do |ip|
        @iam.delete_instance_profile( ip )
        @iam.remove_role_from_instance_profile( @options[:rolename], ip )
    end

    policies = @iam.list_role_policies( @options[:rolename] ).body['PolicyNames']
    policies.each do |policy|
        @iam.delete_role_policy( @options[:rolename], policy )
    end


    fog_object.destroy

end

#rationalise_policies(policies) ⇒ Object



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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/build-cloud/iamrole.rb', line 54

def rationalise_policies( policies )

    policies = {} if policies.nil?

    managed_policies_to_add  = []
    current_policies = []
    policies_to_add  = []

    # Read all the existing policies from the role object. Turn what we find into
    # a list of hashes, where the hash parameter names match those that we use
    # in the YAML description.  This will aid comparison of current vs. desired policies

    policy_names = @iam.list_role_policies(fog_object.rolename).body["PolicyNames"]
    
    unless policy_names.nil? 

        policy_names.each do |policy_name|

            c = {
                :policy_document => @iam.get_role_policy(fog_object.rolename, policy_name).body["Policy"]["PolicyDocument"],
                :policy_name     => policy_name,
            }

            current_policies << c

        end
    end
    
    # Build add lists
    policies.each do |p|
        @log.debug("Policy action on is #{p}")
        if p[:arn]
            # Ensure any Managed Policies are attached. Fog support is limited, so always adds
            @log.debug("For group #{fog_object.rolename} adding managed policy #{p[:arn]}")
            managed_policies_to_add << { :arn => p[:arn] }
        elsif p[:policy_name]
            @log.debug("For role #{fog_object.rolename} checking policy #{p[:policy_name]}")
            # Assume adding policy
            pa = {
                :policy_document => JSON.parse(p[:policy_document]),
                :policy_name     => p[:policy_name],
            }
            policies_to_add << pa
        end
    end

    
    policies.each do |p|
        @log.debug("For role #{fog_object.rolename}  policy #{p.inspect}")
        
        # If we find a current policy that matches the desired policy, then
        # remove that from the list of current policies - we will remove any
        # remaining policies
        current_policies.delete_if do |c|
            if c[:policy_name] == p[:policy_name]
                @log.debug( "#{p[:policy_name]} already exists" )
                
                # Remove from the policies to add if the policy documents match
                policies_to_add.delete_if do |a|
                    if (c[:policy_name] == a[:policy_name]) and
                       (c[:policy_document] == a[:policy_document])
                        @log.debug("#{p[:policy_name]} is a match" )
                        true
                    else
                        @log.debug("#{p[:policy_name]} is different" )
                        @log.debug("new policy is '#{a[:policy_document]}'")
                        @log.debug("current policy is '#{c[:policy_document]}'")
                        false
                    end
                end
                true # so that delete_if removes the list item
            else
                false
            end
        end
    end

    # At the end of this loop, anything left in the current_policies list
    # represents a policy that's present on the infra, but should be deleted
    # (since there's no matching desired policy), so delete those.

    current_policies.each do |p|

        @log.debug( "Removing policy #{p.inspect}" )
        @log.info( "For role #{fog_object.rolename} removing policy #{p[:policy_name]}" )
        @iam.delete_role_policy(fog_object.rolename, p[:policy_name])

    end

    policies_to_add.each do |p|

        @log.debug( "For role #{fog_object.rolename} adding/updating policy #{p}" )
        @log.info( "For role #{fog_object.rolename} adding/updating policy #{p[:policy_name]}" )
        @iam.put_role_policy( fog_object.rolename, p[:policy_name], p[:policy_document] )

    end
    
    # IAM Role Policy support is not complete in fog-aws, always attach policy
    managed_policies_to_add.each do |p|
        @log.debug( "For role #{fog_object.rolename} attaching policy #{p}" )
        @log.info( "For role #{fog_object.rolename} attaching policy #{p[:arn]}" )
        @iam.attach_role_policy(fog_object.rolename, p[:arn])
    end

end

#readObject Also known as: fog_object



49
50
51
# File 'lib/build-cloud/iamrole.rb', line 49

def read
    @iam.roles.get(@options[:rolename])
end