Class: AwsRunAs::Main

Inherits:
Object
  • Object
show all
Defined in:
lib/aws_runas/main.rb

Overview

Main program logic for aws-runas - sets up sts asession and assumed role, and hands off environment to called process.

Instance Method Summary collapse

Constructor Details

#initialize(path: nil, profile: default, mfa_code: nil, no_role: nil, duration_seconds: 3600) ⇒ Main

Instantiate the object and set up the path, profile, and populate MFA.

Session timestamp is also registered here to prevent races.



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/aws_runas/main.rb', line 31

def initialize(path: nil, profile: default, mfa_code: nil, no_role: nil, duration_seconds: 3600)
  cfg_path = if path
               path
             else
               AwsRunAs::Config.find_config_file
             end
  @cfg = AwsRunAs::Config.new(path: cfg_path, profile: profile)
  @mfa_code = mfa_code
  @no_role = no_role
  @duration_seconds = duration_seconds
  @session_timestamp = Time.now.to_i
end

Instance Method Details

#assume_roleObject



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/aws_runas/main.rb', line 86

def assume_role
  @role_session_name = session_id
  role_arn = @cfg.load_config_value(key: 'role_arn')
  mfa_serial = @cfg.load_config_value(key: 'mfa_serial') unless ENV.include?('AWS_SESSION_TOKEN')
  if @no_role
    raise 'No mfa_serial in selected profile, session will be useless' if mfa_serial.nil?
    @session = sts_client.get_session_token(
      serial_number: mfa_serial,
      token_code: @mfa_code,
      duration_seconds: @duration_seconds
    )
  else
    @session = Aws::AssumeRoleCredentials.new(
      client: sts_client,
      role_arn: role_arn,
      serial_number: mfa_serial,
      token_code: @mfa_code,
      role_session_name: @role_session_name,
      duration_seconds: @duration_seconds
    )
  end
end

#credentials_envObject



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/aws_runas/main.rb', line 113

def credentials_env
  env = {}
  env['AWS_ACCESS_KEY_ID'] = session_credentials.access_key_id
  env['AWS_SECRET_ACCESS_KEY'] = session_credentials.secret_access_key
  env['AWS_SESSION_TOKEN'] = session_credentials.session_token
  env['AWS_RUNAS_PROFILE'] = @cfg.profile
  unless @cfg.load_config_value(key: 'region').nil?
    env['AWS_REGION'] = @cfg.load_config_value(key: 'region')
    env['AWS_DEFAULT_REGION'] = @cfg.load_config_value(key: 'region')
  end
  if @no_role
    env['AWS_SESSION_EXPIRATION'] = session_credentials.expiration.to_s
    env['AWS_SESSION_EXPIRATION_UNIX'] = DateTime.parse(session_credentials.expiration.to_s).strftime('%s')
  else
    env['AWS_SESSION_EXPIRATION'] = @session.expiration.to_s
    env['AWS_SESSION_EXPIRATION_UNIX'] = DateTime.parse(@session.expiration.to_s).strftime('%s')
    env['AWS_RUNAS_ASSUMED_ROLE_ARN'] = @cfg.load_config_value(key: 'role_arn')
    env['AWS_ROLE_SESSION_NAME'] = @role_session_name
  end
  env
end

#handoff(command: nil, argv: nil, skip_prompt:) ⇒ Object



135
136
137
138
139
140
141
# File 'lib/aws_runas/main.rb', line 135

def handoff(command: nil, argv: nil, skip_prompt:)
  env = credentials_env
  unless command
    AwsRunAs::Utils.handoff_to_shell(env: env, profile: @no_role ? nil : @cfg.profile, skip_prompt: skip_prompt)
  end
  exec(env, command, *argv)
end

#render_access_key_session(caller_identity) ⇒ Object



61
62
63
# File 'lib/aws_runas/main.rb', line 61

def render_access_key_session(caller_identity)
  "aws-runas-session_#{caller_identity.user_id.split(':')[0]}_#{@session_timestamp}"
end

#render_account_user_session(caller_identity) ⇒ Object



57
58
59
# File 'lib/aws_runas/main.rb', line 57

def (caller_identity)
  "aws-runas-session_#{caller_identity.account}_#{caller_identity.arn.split('/')[-1]}_#{@session_timestamp}"
end

#render_classic_sessionObject



53
54
55
# File 'lib/aws_runas/main.rb', line 53

def render_classic_session
  "aws-runas-session_#{@session_timestamp}"
end

#render_modern_session(caller_identity) ⇒ Object

Returns a session name based on the following criteria:

* If the user ARN matches that of an assumed role, return the access key ID
* Otherwise, return the  ID and the user (last part of the ARN).


73
74
75
76
# File 'lib/aws_runas/main.rb', line 73

def render_modern_session(caller_identity)
  return render_access_key_session(caller_identity) if use_access_key_id?(caller_identity)
  (caller_identity)
end

#session_credentialsObject



109
110
111
# File 'lib/aws_runas/main.rb', line 109

def session_credentials
  @session.credentials
end

#session_idObject



78
79
80
81
82
83
84
# File 'lib/aws_runas/main.rb', line 78

def session_id
  caller_identity = sts_client.get_caller_identity
  return render_classic_session if render_modern_session(caller_identity).length > 64
  render_modern_session(caller_identity)
rescue Aws::STS::Errors::AccessDeniedException
  render_classic_session
end

#sts_clientObject



44
45
46
47
48
49
50
51
# File 'lib/aws_runas/main.rb', line 44

def sts_client
  region = @cfg.load_config_value(key: 'region')
  region = 'us-east-1' unless region
  Aws::STS::Client.new(
    profile: @cfg.load_source_profile,
    region: region
  )
end

#use_access_key_id?(caller_identity) ⇒ Boolean

Returns:

  • (Boolean)


65
66
67
68
# File 'lib/aws_runas/main.rb', line 65

def use_access_key_id?(caller_identity)
  caller_identity.arn =~ %r{^arn:aws:sts::\d+:assumed-role\/} ||
    (caller_identity).length > 64
end