Class: AwsMfa
- Inherits:
-
Object
show all
- Defined in:
- lib/aws_mfa.rb,
lib/aws_mfa/errors.rb,
lib/aws_mfa/shell_command.rb,
lib/aws_mfa/shell_command_result.rb
Defined Under Namespace
Classes: Errors, ShellCommand, ShellCommandResult
Instance Attribute Summary collapse
Instance Method Summary
collapse
Constructor Details
#initialize ⇒ AwsMfa
Returns a new instance of AwsMfa.
9
10
11
12
|
# File 'lib/aws_mfa.rb', line 9
def initialize
validate_aws_installed
@aws_config_dir = find_aws_config
end
|
Instance Attribute Details
#aws_config_dir ⇒ Object
Returns the value of attribute aws_config_dir.
7
8
9
|
# File 'lib/aws_mfa.rb', line 7
def aws_config_dir
@aws_config_dir
end
|
Instance Method Details
#execute ⇒ Object
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
# File 'lib/aws_mfa.rb', line 170
def execute
profile = 'default'
profile_index = ARGV.index('--profile')
if (!profile_index.nil?)
profile = ARGV.delete_at(profile_index + 1)
ARGV.delete_at(profile_index)
end
arn = load_arn(profile)
credentials = load_credentials(arn, profile)
if ARGV.empty?
print_credentials(credentials)
else
export_credentials(credentials)
exec(*ARGV)
end
end
|
#export_credentials(credentials) ⇒ Object
163
164
165
166
167
168
|
# File 'lib/aws_mfa.rb', line 163
def export_credentials(credentials)
ENV['AWS_SECRET_ACCESS_KEY'] = credentials['SecretAccessKey']
ENV['AWS_ACCESS_KEY_ID'] = credentials['AccessKeyId']
ENV['AWS_SESSION_TOKEN'] = credentials['SessionToken']
ENV['AWS_SECURITY_TOKEN'] = credentials['SessionToken']
end
|
#find_aws_config ⇒ Object
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
# File 'lib/aws_mfa.rb', line 18
def find_aws_config
if ENV['AWS_CREDENTIAL_FILE']
aws_config_file = ENV['AWS_CREDENTIAL_FILE']
aws_config_dir = File.dirname(aws_config_file)
else
aws_config_dir = File.join(ENV['HOME'], '.aws')
aws_config_file = File.join(aws_config_dir, 'config')
end
unless File.readable?(aws_config_file)
raise Errors::ConfigurationNotFound, 'Aws configuration not found. You must run `aws configure`'
end
aws_config_dir
end
|
#load_arn(profile = 'default') ⇒ Object
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
# File 'lib/aws_mfa.rb', line 46
def load_arn(profile='default')
arn_file_name = 'mfa_device'
if (! profile.eql? 'default')
arn_file_name = "#{profile}_#{arn_file_name}"
end
arn_file = File.join(aws_config_dir, arn_file_name)
if File.readable?(arn_file)
arn = load_arn_from_file(arn_file)
else
arn = load_arn_from_aws(profile)
write_arn_to_file(arn_file, arn)
end
arn
end
|
#load_arn_from_aws(profile = 'default') ⇒ Object
67
68
69
70
71
72
73
74
|
# File 'lib/aws_mfa.rb', line 67
def load_arn_from_aws(profile='default')
puts 'Fetching MFA devices for your account...'
if mfa_devices(profile).any?
mfa_devices(profile).first.fetch('SerialNumber')
else
raise Errors::DeviceNotFound, 'No MFA devices were found for your account'
end
end
|
#load_arn_from_file(arn_file) ⇒ Object
63
64
65
|
# File 'lib/aws_mfa.rb', line 63
def load_arn_from_file(arn_file)
File.read(arn_file)
end
|
#load_credentials(arn, profile = 'default') ⇒ Object
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
# File 'lib/aws_mfa.rb', line 93
def load_credentials(arn, profile='default')
credentials_file_name = 'mfa_credentials'
if (! profile.eql? 'default')
credentials_file_name = "#{profile}_#{credentials_file_name}"
end
credentials_file = File.join(aws_config_dir, credentials_file_name)
if File.readable?(credentials_file) && token_not_expired?(credentials_file)
credentials = load_credentials_from_file(credentials_file)
else
credentials = load_credentials_from_aws(arn, profile)
write_credentials_to_file(credentials_file, credentials)
end
JSON.parse(credentials).fetch('Credentials')
end
|
#load_credentials_from_aws(arn, profile = 'default') ⇒ Object
114
115
116
117
118
119
120
121
122
123
124
|
# File 'lib/aws_mfa.rb', line 114
def load_credentials_from_aws(arn, profile='default')
code = request_code_from_user
unset_environment
credentials_command = "aws --profile #{profile} --output json sts get-session-token --serial-number #{arn} --token-code #{code}"
result = AwsMfa::ShellCommand.new(credentials_command).call
if result.succeeded?
result.output
else
raise Errors::InvalidCode, 'There was a problem validating the MFA code with AWS'
end
end
|
#load_credentials_from_file(credentials_file) ⇒ Object
110
111
112
|
# File 'lib/aws_mfa.rb', line 110
def load_credentials_from_file(credentials_file)
File.read(credentials_file)
end
|
#mfa_devices(profile = 'default') ⇒ Object
76
77
78
79
80
81
82
83
84
85
86
|
# File 'lib/aws_mfa.rb', line 76
def mfa_devices(profile='default')
@mfa_devices ||= begin
list_mfa_devices_command = "aws --profile #{profile} --output json iam list-mfa-devices"
result = AwsMfa::ShellCommand.new(list_mfa_devices_command).call
if result.succeeded?
JSON.parse(result.output).fetch('MFADevices')
else
raise Errors::Error, 'There was a problem fetching MFA devices from AWS'
end
end
end
|
#print_credentials(credentials) ⇒ Object
156
157
158
159
160
161
|
# File 'lib/aws_mfa.rb', line 156
def print_credentials(credentials)
puts "export AWS_SECRET_ACCESS_KEY='#{credentials['SecretAccessKey']}'"
puts "export AWS_ACCESS_KEY_ID='#{credentials['AccessKeyId']}'"
puts "export AWS_SESSION_TOKEN='#{credentials['SessionToken']}'"
puts "export AWS_SECURITY_TOKEN='#{credentials['SessionToken']}'"
end
|
#request_code_from_user ⇒ Object
130
131
132
133
134
135
|
# File 'lib/aws_mfa.rb', line 130
def request_code_from_user
puts 'Enter the 6-digit code from your MFA device:'
code = $stdin.gets.chomp
raise Errors::InvalidCode, 'That is an invalid MFA code' unless code =~ /^\d{6}$/
code
end
|
#token_not_expired?(credentials_file) ⇒ Boolean
144
145
146
147
148
149
150
151
152
153
154
|
# File 'lib/aws_mfa.rb', line 144
def token_not_expired?(credentials_file)
expiration_period = 12 * 60 * 60
mtime = File.stat(credentials_file).mtime
now = Time.new
if now - mtime < expiration_period
true
else
false
end
end
|
#unset_environment ⇒ Object
137
138
139
140
141
142
|
# File 'lib/aws_mfa.rb', line 137
def unset_environment
ENV.delete('AWS_SECRET_ACCESS_KEY')
ENV.delete('AWS_ACCESS_KEY_ID')
ENV.delete('AWS_SESSION_TOKEN')
ENV.delete('AWS_SECURITY_TOKEN')
end
|
#validate_aws_installed ⇒ Object
14
15
16
|
# File 'lib/aws_mfa.rb', line 14
def validate_aws_installed
raise Errors::CommandNotFound, 'Could not find the aws command' unless which('aws')
end
|
#which(cmd) ⇒ Object
35
36
37
38
39
40
41
42
43
44
|
# File 'lib/aws_mfa.rb', line 35
def which(cmd)
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
exts.each { |ext|
exe = File.join(path, "#{cmd}#{ext}")
return exe if File.executable? exe
}
end
return nil
end
|
#write_arn_to_file(arn_file, arn) ⇒ Object
88
89
90
91
|
# File 'lib/aws_mfa.rb', line 88
def write_arn_to_file(arn_file, arn)
File.open(arn_file, 'w') { |f| f.print arn }
puts "Using MFA device #{arn}. To change this in the future edit #{arn_file}."
end
|
#write_credentials_to_file(credentials_file, credentials) ⇒ Object
126
127
128
|
# File 'lib/aws_mfa.rb', line 126
def write_credentials_to_file(credentials_file, credentials)
File.open(credentials_file, 'w') { |f| f.print credentials }
end
|