Module: Awskeyring::Awsapi

Defined in:
lib/awskeyring/awsapi.rb

Overview

AWS API methods for Awskeyring

Constant Summary collapse

ADMIN_POLICY =

Admin policy as json

{
  Version: '2012-10-17',
  Statement: [{
    Action: '*',
    Resource: '*',
    Effect: 'Allow'
  }]
}.to_json.freeze
AWS_SIGNIN_URL =

AWS Signin url

'https://signin.aws.amazon.com/federation'
AWS_ENV_VARS =

AWS Env vars

%w[
  AWS_ACCOUNT_NAME
  AWS_ACCESS_KEY_ID
  AWS_ACCESS_KEY
  AWS_CREDENTIAL_EXPIRATION
  AWS_SECRET_ACCESS_KEY
  AWS_SECRET_KEY
  AWS_SECURITY_TOKEN
  AWS_SESSION_TOKEN
].freeze
TWELVE_HOUR =

Twelve hours in seconds

(60 * 60 * 12)
ONE_HOUR =

One hour in seconds

(60 * 60 * 1)
ONE_DAY =

Days in seconds

(24 * 60 * 60)

Class Method Summary collapse

Class Method Details

.get_cred_json(key:, secret:, token:, expiry:) ⇒ String

Genarates AWS CLI compatible JSON see credential_process in AWS Docs

Parameters:

  • key (String)

    The aws_access_key_id

  • secret (String)

    The aws_secret_access_key

  • token (String)

    The aws_session_token

  • expiry (String)

    expiry time

Returns:

  • (String)

    credential_process json



108
109
110
111
112
113
114
115
116
# File 'lib/awskeyring/awsapi.rb', line 108

def self.get_cred_json(key:, secret:, token:, expiry:)
  JSON.pretty_generate(
    Version: 1,
    AccessKeyId: key,
    SecretAccessKey: secret,
    SessionToken: token,
    Expiration: expiry
  )
end

.get_credentials_from_file(account:) ⇒ Hash

Retrieve credentials from the AWS Credentials file

Parameters:

  • account (String)

    the profile name wanted

Returns:

  • (Hash)

    with the new credentials key The aws_access_key_id secret The aws_secret_access_key token The aws_session_token expiry expiry time



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/awskeyring/awsapi.rb', line 168

def self.get_credentials_from_file(account:)
  creds = Aws::SharedCredentials.new(profile_name: )
  {
    account: ,
    key: creds.credentials.access_key_id,
    secret: creds.credentials.secret_access_key,
    token: creds.credentials.session_token,
    expiry: Time.new + TWELVE_HOUR,
    role: nil
  }
end

.get_env_array(params = {}) ⇒ Hash

Generates Environment Variables for the AWS CLI

Parameters:

  • params (Hash) (defaults to: {})

    including

    String

    account The aws account name

    String

    key The aws_access_key_id

    String

    secret The aws_secret_access_key

    String

    token The aws_session_token

Returns:

  • (Hash)

    env_var hash



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/awskeyring/awsapi.rb', line 126

def self.get_env_array(params = {})
  env_var = {}
  env_var['AWS_DEFAULT_REGION'] = 'us-east-1' unless region

  params[:expiration] = Time.at(params[:expiry]).iso8601 unless params[:expiry].nil?

  params.each_key do |param_name|
    AWS_ENV_VARS.each do |var_name|
      if var_name.include?(param_name.to_s.upcase) && !params[param_name].nil?
        env_var[var_name] = params[param_name]
      end
    end
  end

  env_var
end

.get_login_url(key:, secret:, token:, path:, user:) ⇒ String

Retrieves an AWS Console login url

Parameters:

  • key (String)

    The aws_access_key_id

  • secret (String)

    The aws_secret_access_key

  • token (String)

    The aws_session_token

  • user (String)

    The local username

  • path (String)

    within the Console to access

Returns:

  • (String)

    login_url to access



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/awskeyring/awsapi.rb', line 188

def self.(key:, secret:, token:, path:, user:)
  console_url = "https://console.aws.amazon.com/#{path}/home"

  unless token
    cred = get_token({ key: key, secret: secret, user: user, duration: TWELVE_HOUR })
    key = cred[:key]
    secret = cred[:secret]
    token = cred[:token]
  end

  session_json = {
    sessionId: key,
    sessionKey: secret,
    sessionToken: token
  }.to_json

  destination_param = "&Destination=#{CGI.escape(console_url)}"

  "#{AWS_SIGNIN_URL}?Action=login#{token_param(session_json: session_json)}#{destination_param}"
end

.get_token(params = {}) ⇒ Hash

Retrieves a temporary session token from AWS

Parameters:

  • params (Hash) (defaults to: {})

    including key The aws_access_key_id secret The aws_secret_access_key user The local username mfa The users MFA arn code The MFA code duration time in seconds until expiry role_arn ARN of the role to assume

Returns:

  • (Hash)

    with the new credentials key The aws_access_key_id secret The aws_secret_access_key token The aws_session_token expiry expiry time



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
# File 'lib/awskeyring/awsapi.rb', line 59

def self.get_token(params = {}) # rubocop:disable  Metrics/AbcSize, Metrics/MethodLength
  ENV['AWS_DEFAULT_REGION'] = 'us-east-1' unless region
  sts = Aws::STS::Client.new(access_key_id: params[:key], secret_access_key: params[:secret])

  params[:mfa] = nil unless params[:code]
  begin
    response =
      if params[:role_arn]
        sts.assume_role(
          duration_seconds: params[:duration].to_i,
          role_arn: params[:role_arn],
          role_session_name: params[:user],
          serial_number: params[:mfa],
          token_code: params[:code]
        )
      elsif params[:code]
        sts.get_session_token(
          duration_seconds: params[:duration].to_i,
          serial_number: params[:mfa],
          token_code: params[:code]
        )
      else
        sts.get_federation_token(
          name: params[:user],
          policy: ADMIN_POLICY,
          duration_seconds: params[:duration]
        )
      end
  rescue Aws::STS::Errors::AccessDenied => e
    warn e.to_s
    exit 1
  end

  {
    key: response.credentials[:access_key_id],
    secret: response.credentials[:secret_access_key],
    token: response.credentials[:session_token],
    expiry: response.credentials[:expiration]
  }
end

.regionString

Get the current region

Returns:

  • (String)

    current configured region



226
227
228
229
230
# File 'lib/awskeyring/awsapi.rb', line 226

def self.region
  keys = %w[AWS_REGION AMAZON_REGION AWS_DEFAULT_REGION]
  region = ENV.values_at(*keys).compact.first
  region || Aws.shared_config.region(profile: 'default')
end

.retry_backoff(&block) ⇒ Object

Retry the call with backoff

Parameters:

  • block (Block)

    the block to retry.



269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/awskeyring/awsapi.rb', line 269

def self.retry_backoff(&block)
  retries ||= 1
  begin
    yield block
  rescue Aws::IAM::Errors::InvalidClientTokenId => e
    if retries < 4
      sleep 2**retries
      retries += 1
      retry
    end
    warn e.message
    exit 1
  end
end

.rotate(account:, key:, secret:, key_message:) ⇒ String

Rotates the AWS access keys

Parameters:

  • key (String)

    The aws_access_key_id

  • secret (String)

    The aws_secret_access_key

  • account (String)

    the associated account name.

Returns:

  • (String)

    key The aws_access_key_id

  • (String)

    secret The aws_secret_access_key

  • (String)

    account the associated account name.



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/awskeyring/awsapi.rb', line 240

def self.rotate(account:, key:, secret:, key_message:) # rubocop:disable  Metrics/MethodLength
  ENV['AWS_DEFAULT_REGION'] = 'us-east-1' unless region
  iam = Aws::IAM::Client.new(access_key_id: key, secret_access_key: secret)

  if iam.list_access_keys[:access_key_metadata].length > 1
    warn key_message
    exit 1
  end

  new_key = iam.create_access_key[:access_key]
  iam = Aws::IAM::Client.new(
    access_key_id: new_key[:access_key_id],
    secret_access_key: new_key[:secret_access_key]
  )
  retry_backoff do
    iam.delete_access_key(
      access_key_id: key
    )
  end
  {
    account: ,
    key: new_key[:access_key_id],
    secret: new_key[:secret_access_key]
  }
end

.verify_cred(key:, secret:, token: nil) ⇒ Object

Verify Credentials are active and valid

Parameters:

  • key (String)

    The aws_access_key_id

  • secret (String)

    The aws_secret_access_key

  • token (String) (defaults to: nil)

    The aws_session_token



148
149
150
151
152
153
154
155
156
157
158
# File 'lib/awskeyring/awsapi.rb', line 148

def self.verify_cred(key:, secret:, token: nil)
  begin
    ENV['AWS_DEFAULT_REGION'] = 'us-east-1' unless region
    sts = Aws::STS::Client.new(access_key_id: key, secret_access_key: secret, session_token: token)
    sts.get_caller_identity
  rescue Aws::Errors::ServiceError => e
    warn e.to_s
    exit 1
  end
  true
end