Class: Cucloud::IamUtils

Inherits:
Object
  • Object
show all
Defined in:
lib/cucloud/iam_utils.rb

Overview

Utilities library for interacting with IAM

Defined Under Namespace

Classes: UnknownComparisonOperatorError

Instance Method Summary collapse

Constructor Details

#initialize(iam_client = Aws::IAM::Client.new) ⇒ IamUtils

Returns a new instance of IamUtils.



8
9
10
# File 'lib/cucloud/iam_utils.rb', line 8

def initialize(iam_client = Aws::IAM::Client.new)
  @iam = iam_client
end

Instance Method Details

#audit_password_policy(audit_criteria = []) ⇒ Array<Hash>

Check password policy against an options hash of audit criteria

Policy format - Array of checks example input: [{ key: "minimum_password_length", operator: "GT", value: 15 }] example output: [{ key: "minimum_password_length", passes: true }]

Parameters:

  • Policy (Array<Hash>)

    against which to audit

Returns:

  • (Array<Hash>)

    Results of each audit check



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
# File 'lib/cucloud/iam_utils.rb', line 62

def audit_password_policy(audit_criteria = [])
  policy_hash = .to_h

  audit_criteria.map do |check|
    case check[:operator]
    when 'EQ'
      {
        key: check[:key],
        passes: policy_hash[check[:key].to_sym].nil? ? false : policy_hash[check[:key].to_sym] == check[:value]
      }
    when 'LTE'
      {
        key: check[:key],
        passes: policy_hash[check[:key].to_sym].nil? ? false : policy_hash[check[:key].to_sym] <= check[:value]
      }
    when 'GTE'
      {
        key: check[:key],
        passes: policy_hash[check[:key].to_sym].nil? ? false : policy_hash[check[:key].to_sym] >= check[:value]
      }
    else
      raise UnknownComparisonOperatorError.new, "Unknown operator #{check[:operator]}"
    end
  end
end

#cornell_provider_configured?Boolean

Is the Cornell SAML Identity Provider configured on this account?

Returns:

  • (Boolean)


105
106
107
# File 'lib/cucloud/iam_utils.rb', line 105

def cornell_provider_configured?
  get_saml_providers.select { |provider| provider[:saml_metadata_document].include? CORNELL_SAML_X509 }.any?
end

#get_account_aliasString

Get the alias set for this account if it exists

Returns:

  • (String)

    Account alias (nil if not set)



14
15
16
17
18
19
20
# File 'lib/cucloud/iam_utils.rb', line 14

def 
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#list_account_aliases-instance_method
  # https://docs.aws.amazon.com/IAM/latest/UserGuide/console_account-alias.html
  # Per user guide: Account can have only one alias

  @iam..[0]
end

#get_account_password_policyAws::IAM::Types::PasswordPolicy

Get password policy for this account

Returns:

  • (Aws::IAM::Types::PasswordPolicy)


50
51
52
53
# File 'lib/cucloud/iam_utils.rb', line 50

def 
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#get_account_password_policy-instance_method
  @iam..password_policy
end

#get_account_summaryHash<String,Integer>

Get report about IAM entity usage and quotas in this account

Returns:

  • (Hash<String,Integer>)

    A hash of key value pairs containing information about IAM entity usage and quotas.



24
25
26
27
28
# File 'lib/cucloud/iam_utils.rb', line 24

def 
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#get_account_summary-instance_method
  # return https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Types/GetAccountSummaryResponse.html#summary_map-instance_method
  @iam..summary_map
end

#get_active_keys_older_than_n_days(n) ⇒ Array<Hash>

Get active access keys on account that are older than specified age (in days)

Parameters:

  • Days (Integer)

    old

Returns:

  • (Array<Hash>)


155
156
157
158
159
# File 'lib/cucloud/iam_utils.rb', line 155

def get_active_keys_older_than_n_days(n)
  get_users.map do |user|
    get_user_access_keys(user[:base_data].user_name).select { |k| k[:days_old] > n && k[:active] }
  end.flatten
end

#get_cert_arn(cert_name) ⇒ Object

Gets the ARN for a given certificate

Parameters:

  • cert_name (String)

    The name of the certificate

  • The (String)

    ARN for the certificate

Raises:

  • (ArgumentError)

    If the provided certificate name is nil



165
166
167
168
169
170
# File 'lib/cucloud/iam_utils.rb', line 165

def get_cert_arn(cert_name)
  raise ArgumentError, '"cert_name" may not be nil' if cert_name.nil?

  cert = @iam.get_server_certificate(server_certificate_name: cert_name)
  cert.server_certificate..arn
end

#get_saml_providersArray<Hash>

Get SAML providers configured for this account

Returns:

  • (Array<Hash>)

    Array of hashes in form { arn: , metadata: }



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/cucloud/iam_utils.rb', line 90

def get_saml_providers
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#list_saml_providers-instance_method
  # returns https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Types/SAMLProviderListEntry.html
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#get_saml_provider-instance_method

  @iam.list_saml_providers.saml_provider_list.map do |provider|
    {
      arn: provider.arn,
      saml_metadata_document: @iam.get_saml_provider(saml_provider_arn: provider.arn).
    }
  end
end

#get_user_access_keys(user_name) ⇒ Array<Hash>

Get access keys for user

Parameters:

  • Username (String)

Returns:

  • (Array<Hash>)

    Array of key hashes - base key data + helper calculations for key age and active/inactive



140
141
142
143
144
145
146
147
148
149
150
# File 'lib/cucloud/iam_utils.rb', line 140

def get_user_access_keys(user_name)
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#list_access_keys-instance_method

  @iam.list_access_keys(user_name: user_name)..map do |key|
    {
      base_data: key,
      active: key.status == 'Active',
      days_old: (Time.now - key.create_date).to_i / (24 * 60 * 60)
    }
  end
end

#get_usersArray<Hash>

Get users that are configured on this account

Returns:

  • (Array<Hash>)

    Array of user hashes - base user type + added lookups for convenience



111
112
113
114
115
116
117
118
119
# File 'lib/cucloud/iam_utils.rb', line 111

def get_users
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#list_users-instance_method
  @iam.list_users.users.map do |user|
    {
      base_data: user, # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Types/User.html
      has_password: user_has_password?(user.user_name)
    }
  end
end

#multiple_providers_configured?Boolean

Does this account have multiple identity providers configured?

Returns:

  • (Boolean)


44
45
46
# File 'lib/cucloud/iam_utils.rb', line 44

def multiple_providers_configured?
  ['Providers'] > 1
end

#root_user_has_api_key?Boolean

Does this account's root user have any API keys?

Returns:

  • (Boolean)


32
33
34
# File 'lib/cucloud/iam_utils.rb', line 32

def root_user_has_api_key?
  ['AccountAccessKeysPresent'] > 0
end

#root_user_mfa_enabled?Boolean

Does this account's root user have MFA enabled?

Returns:

  • (Boolean)


38
39
40
# File 'lib/cucloud/iam_utils.rb', line 38

def root_user_mfa_enabled?
  ['AccountMFAEnabled'] > 0
end

#rotate_iam_credntial(creds_to_rotate, time_to_wait_for_new_cred = 15) ⇒ Hash<string>

Given an IAM credential rotate it. This functions assumes that one of the two access key slots is available. If ther is not an available slot an exception will be raised.

Parameters:

  • creds_to_rotate (Hash<string>)

    IAM access_key_id and and secret_access_key to rotate

  • time_to_wait_for_new_cred (Integer) (defaults to: 15)

    How many seconds to wait for new key to become active

Returns:

  • (Hash<string>)

    new IAM access_key_id and and secret_access_key



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/cucloud/iam_utils.rb', line 177

def rotate_iam_credntial(creds_to_rotate, time_to_wait_for_new_cred = 15)
  # Update AWS config to used the creddentials passed in
  Aws.config.update(credentials: Aws::Credentials.new(creds_to_rotate[:aws_access_key_id],
                                                      creds_to_rotate[:aws_secret_access_key]))
  # now grab the user name form the response
  resp = @iam.get_access_key_last_used(access_key_id: creds_to_rotate[:aws_access_key_id])
  user = resp.user_name

  # create and store new keys
  resp = @iam.create_access_key(user_name: user)
  new_access_key_id = resp.access_key.access_key_id
  new_secret_access_key = resp.access_key.secret_access_key

  # give time for the new credentials to become active
  sleep time_to_wait_for_new_cred

  # use new credentials
  Aws.config.update(credentials: Aws::Credentials.new(new_access_key_id,
                                                      new_secret_access_key))

  # Delete the old keys with the new key
  @iam.delete_access_key(user_name: user,
                         access_key_id: creds_to_rotate[:aws_access_key_id])

  { aws_access_key_id: new_access_key_id, aws_secret_access_key: new_secret_access_key }
end

#user_has_password?(user_name) ⇒ Boolean

Does this user have a password configured?

Parameters:

  • Username (String)

Returns:

  • (Boolean)


124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/cucloud/iam_utils.rb', line 124

def user_has_password?(user_name)
  # https://docs.aws.amazon.com/sdkforruby/api/Aws/IAM/Client.html#get_login_profile-instance_method
  password = true

  begin
    @iam.(user_name: user_name)
  rescue Aws::IAM::Errors::NoSuchEntity
    password = false
  end

  password
end