line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Amazon::Credentials; |
2
|
|
|
|
|
|
|
# - module for finding and providing AWS credentials |
3
|
11
|
|
|
11
|
|
88075
|
use strict; |
|
11
|
|
|
|
|
24
|
|
|
11
|
|
|
|
|
327
|
|
4
|
11
|
|
|
11
|
|
52
|
use warnings; |
|
11
|
|
|
|
|
20
|
|
|
11
|
|
|
|
|
271
|
|
5
|
|
|
|
|
|
|
|
6
|
11
|
|
|
11
|
|
245
|
use 5.010; |
|
11
|
|
|
|
|
32
|
|
7
|
|
|
|
|
|
|
|
8
|
11
|
|
|
11
|
|
595
|
use parent qw( Exporter Class::Accessor::Fast ); |
|
11
|
|
|
|
|
335
|
|
|
11
|
|
|
|
|
93
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
__PACKAGE__->follow_best_practice; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
__PACKAGE__->mk_accessors( |
13
|
|
|
|
|
|
|
qw( |
14
|
|
|
|
|
|
|
_access_key_id |
15
|
|
|
|
|
|
|
cache |
16
|
|
|
|
|
|
|
cipher |
17
|
|
|
|
|
|
|
container |
18
|
|
|
|
|
|
|
debug |
19
|
|
|
|
|
|
|
decrypt |
20
|
|
|
|
|
|
|
encrypt |
21
|
|
|
|
|
|
|
encryption |
22
|
|
|
|
|
|
|
error |
23
|
|
|
|
|
|
|
expiration |
24
|
|
|
|
|
|
|
imdsv2 |
25
|
|
|
|
|
|
|
imdsv2_token |
26
|
|
|
|
|
|
|
insecure |
27
|
|
|
|
|
|
|
logger |
28
|
|
|
|
|
|
|
order |
29
|
|
|
|
|
|
|
no_passkey_warning |
30
|
|
|
|
|
|
|
print_error |
31
|
|
|
|
|
|
|
profile |
32
|
|
|
|
|
|
|
raise_error |
33
|
|
|
|
|
|
|
region |
34
|
|
|
|
|
|
|
role |
35
|
|
|
|
|
|
|
_secret_access_key |
36
|
|
|
|
|
|
|
_session_token |
37
|
|
|
|
|
|
|
session_token_required |
38
|
|
|
|
|
|
|
source |
39
|
|
|
|
|
|
|
sso_role_name |
40
|
|
|
|
|
|
|
sso_account_id |
41
|
|
|
|
|
|
|
sso_region |
42
|
|
|
|
|
|
|
timeout |
43
|
|
|
|
|
|
|
user_agent |
44
|
|
|
|
|
|
|
) |
45
|
|
|
|
|
|
|
); |
46
|
|
|
|
|
|
|
|
47
|
11
|
|
|
11
|
|
36604
|
use Carp; |
|
11
|
|
|
|
|
23
|
|
|
11
|
|
|
|
|
633
|
|
48
|
11
|
|
|
11
|
|
5597
|
use Config::Tiny; |
|
11
|
|
|
|
|
12713
|
|
|
11
|
|
|
|
|
351
|
|
49
|
11
|
|
|
11
|
|
71
|
use Cwd; |
|
11
|
|
|
|
|
21
|
|
|
11
|
|
|
|
|
762
|
|
50
|
11
|
|
|
11
|
|
773
|
use Data::Dumper; |
|
11
|
|
|
|
|
7164
|
|
|
11
|
|
|
|
|
455
|
|
51
|
11
|
|
|
11
|
|
542
|
use Date::Format; |
|
11
|
|
|
|
|
7773
|
|
|
11
|
|
|
|
|
542
|
|
52
|
11
|
|
|
11
|
|
3103
|
use English qw(-no_match_vars); |
|
11
|
|
|
|
|
11771
|
|
|
11
|
|
|
|
|
65
|
|
53
|
11
|
|
|
11
|
|
3912
|
use Exporter; |
|
11
|
|
|
|
|
30
|
|
|
11
|
|
|
|
|
378
|
|
54
|
11
|
|
|
11
|
|
6165
|
use File::HomeDir; |
|
11
|
|
|
|
|
63367
|
|
|
11
|
|
|
|
|
570
|
|
55
|
11
|
|
|
11
|
|
5410
|
use File::chdir; |
|
11
|
|
|
|
|
35507
|
|
|
11
|
|
|
|
|
954
|
|
56
|
11
|
|
|
11
|
|
3531
|
use HTTP::Request; |
|
11
|
|
|
|
|
149444
|
|
|
11
|
|
|
|
|
411
|
|
57
|
11
|
|
|
11
|
|
5884
|
use JSON::PP qw(decode_json encode_json); |
|
11
|
|
|
|
|
113581
|
|
|
11
|
|
|
|
|
729
|
|
58
|
11
|
|
|
11
|
|
5409
|
use LWP::UserAgent; |
|
11
|
|
|
|
|
205833
|
|
|
11
|
|
|
|
|
431
|
|
59
|
11
|
|
|
11
|
|
82
|
use List::Util qw(pairs any); |
|
11
|
|
|
|
|
22
|
|
|
11
|
|
|
|
|
1409
|
|
60
|
11
|
|
|
11
|
|
5610
|
use MIME::Base64; |
|
11
|
|
|
|
|
7410
|
|
|
11
|
|
|
|
|
696
|
|
61
|
11
|
|
|
11
|
|
5053
|
use POSIX::strptime qw(strptime); |
|
11
|
|
|
|
|
5983
|
|
|
11
|
|
|
|
|
658
|
|
62
|
11
|
|
|
11
|
|
85
|
use Scalar::Util qw(reftype); |
|
11
|
|
|
|
|
21
|
|
|
11
|
|
|
|
|
431
|
|
63
|
11
|
|
|
11
|
|
60
|
use Time::Local; |
|
11
|
|
|
|
|
20
|
|
|
11
|
|
|
|
|
1494
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
use constant { ## no critic (ProhibitConstantPragma, Capitalization) |
66
|
11
|
|
|
|
|
3791
|
AWS_AVAILABILITY_ZONE_URL => |
67
|
|
|
|
|
|
|
q{latest/meta-data/placement/availability-zone}, |
68
|
|
|
|
|
|
|
AWS_CONTAINER_CREDENTIALS_URL => q{http://169.254.170.2/}, |
69
|
|
|
|
|
|
|
AWS_IAM_SECURITY_CREDENTIALS_URL => |
70
|
|
|
|
|
|
|
q{latest/meta-data/iam/security-credentials/}, |
71
|
|
|
|
|
|
|
AWS_METADATA_BASE_URL => q{http://169.254.169.254/}, |
72
|
|
|
|
|
|
|
CACHE_DIR => '.aws/sso/cache', |
73
|
|
|
|
|
|
|
COMMA => q{,}, |
74
|
|
|
|
|
|
|
DEFAULT_CIPHER => q{Cipher::AES}, |
75
|
|
|
|
|
|
|
DEFAULT_REGION => 'us-east-1', |
76
|
|
|
|
|
|
|
DEFAULT_SEARCH_ORDER => q{env,container,role,file}, |
77
|
|
|
|
|
|
|
DEFAULT_TIMEOUT => 2, |
78
|
|
|
|
|
|
|
DEFAULT_WINDOW_INTERVAL => 5, |
79
|
|
|
|
|
|
|
EMPTY => q{}, |
80
|
|
|
|
|
|
|
FALSE => 0, |
81
|
|
|
|
|
|
|
GET_ROLE_CREDENTIALS_HOSTNAME => 'portal.sso.%s.amazonaws.com', |
82
|
|
|
|
|
|
|
GET_ROLE_CREDENTIALS_QUERY => '?account_id=%s&role_name=%s', |
83
|
|
|
|
|
|
|
GET_ROLE_CREDENTIALS_URI => 'federation/credentials', |
84
|
|
|
|
|
|
|
IMDSv2_DEFAULT_TTL => 21_600, |
85
|
|
|
|
|
|
|
IMDSv2_HEADER => q{x-aws-ec2-metadata-token}, |
86
|
|
|
|
|
|
|
IMDSv2_TTL_HEADER => q{x-aws-ec2-metadata-token-ttl-seconds}, |
87
|
|
|
|
|
|
|
IMDSv2_URL => q{latest/api/token}, |
88
|
|
|
|
|
|
|
INSECURE_MODE => 2, |
89
|
|
|
|
|
|
|
ISO8601_FORMAT => q{%Y-%m-%dT%H:%M:%S%z}, |
90
|
|
|
|
|
|
|
LOG_FORMAT => qq{ %s [%s] %s\n }, |
91
|
|
|
|
|
|
|
PASSKEY_FORMAT => q{%08X%08x}, |
92
|
|
|
|
|
|
|
RANDOM_VALUE => 0xffffffff, |
93
|
|
|
|
|
|
|
SECONDS_IN_HOUR => 3600, |
94
|
|
|
|
|
|
|
SECONDS_IN_MINUTE => 60, |
95
|
|
|
|
|
|
|
SLASH => q{/}, |
96
|
|
|
|
|
|
|
TRUE => 1, |
97
|
|
|
|
|
|
|
X_AMZ_SSO_BEARER_TOKEN => ':x-amz-sso_bearer_token', |
98
|
11
|
|
|
11
|
|
93
|
}; |
|
11
|
|
|
|
|
34
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
our $VERSION = '1.1.20'; ## no critic (RequireInterpolation) |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
our @EXPORT_OK |
103
|
|
|
|
|
|
|
= qw( create_passkey set_sso_credentials get_role_credentials ); |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# we only log at debug level, create a default logger |
106
|
|
|
|
|
|
|
{ |
107
|
11
|
|
|
11
|
|
81
|
no strict 'refs'; ## no critic (ProhibitNoStrict) |
|
11
|
|
|
|
|
24
|
|
|
11
|
|
|
|
|
83858
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
*{'Amazon::Credentials::Logger::debug'} = sub { |
110
|
149
|
|
|
149
|
|
1873
|
my ( $self, @message ) = @_; |
111
|
|
|
|
|
|
|
|
112
|
149
|
100
|
|
|
|
435
|
return if !$self->{debug}; |
113
|
|
|
|
|
|
|
|
114
|
26
|
|
|
|
|
612
|
my @tm = localtime time; |
115
|
|
|
|
|
|
|
|
116
|
26
|
|
|
|
|
115
|
my $timestamp = strftime '%c', @tm; |
117
|
|
|
|
|
|
|
|
118
|
26
|
|
|
|
|
2576
|
my $message = sprintf LOG_FORMAT, $timestamp, $PROCESS_ID, @message; |
119
|
|
|
|
|
|
|
|
120
|
26
|
|
|
|
|
71
|
print {*STDERR} $message; |
|
26
|
|
|
|
|
588
|
|
121
|
|
|
|
|
|
|
}; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
caller or __PACKAGE__->main(); |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
######################################################################## |
127
|
|
|
|
|
|
|
sub new { |
128
|
|
|
|
|
|
|
######################################################################## |
129
|
18
|
|
|
18
|
1
|
18200
|
my ( $class, @args ) = @_; |
130
|
|
|
|
|
|
|
|
131
|
18
|
100
|
|
|
|
81
|
my $options = ref $args[0] ? $args[0] : {@args}; |
132
|
|
|
|
|
|
|
|
133
|
18
|
|
|
|
|
42
|
my $passkey = delete $options->{passkey}; |
134
|
|
|
|
|
|
|
|
135
|
18
|
|
|
|
|
181
|
my $self = $class->SUPER::new($options); |
136
|
|
|
|
|
|
|
|
137
|
18
|
|
|
|
|
224
|
$self->_set_defaults; |
138
|
|
|
|
|
|
|
|
139
|
16
|
|
|
|
|
55
|
$self->_init_logger; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# note that multiple instances of the Amazon::Credentials will share |
142
|
|
|
|
|
|
|
# the same passkey...this is probably a bug |
143
|
16
|
50
|
33
|
|
|
57
|
if ( $self->get_passkey && $passkey ) { |
|
|
50
|
|
|
|
|
|
144
|
0
|
0
|
|
|
|
0
|
if ( !$self->get_no_passkey_warning ) { |
145
|
0
|
|
|
|
|
0
|
carp <<'WARNING'; |
146
|
|
|
|
|
|
|
WARNING: the encryption passkey has already been set. Resetting the |
147
|
|
|
|
|
|
|
passkey will require that you restore the original passkey if you are |
148
|
|
|
|
|
|
|
using more than one instance of Amazon::Credentials. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
To turn this warning off set 'no_passkey_warning' to a true value. |
151
|
|
|
|
|
|
|
WARNING |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
0
|
$self->_init_encryption($passkey); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
elsif ( $self->get_passkey ) { |
157
|
0
|
0
|
|
|
|
0
|
if ( !$self->get_no_passkey_warning ) { |
158
|
0
|
|
|
|
|
0
|
carp <<'WARNING'; |
159
|
|
|
|
|
|
|
WARNING: the encryption passkey has already been set. Using the previous passkey. |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
To turn this warning off set 'no_passkey_warning' to a true value. |
162
|
|
|
|
|
|
|
WARNING |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
0
|
|
|
|
|
0
|
$self->_init_encryption( $self->get_passkey ); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
else { |
168
|
16
|
|
|
|
|
59
|
$self->_init_encryption($passkey); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
16
|
100
|
|
|
|
430
|
if ( $self->get_insecure ) { |
172
|
2
|
|
|
|
|
46
|
$self->get_logger->debug( "!! CAUTION !!\n" |
173
|
|
|
|
|
|
|
. "!! You are executing in 'insecure' mode !!\n" |
174
|
|
|
|
|
|
|
. "!! Credentials may be exposed in debug messages !!\n" ); |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# if the caller wants us to use his SSO credentials |
178
|
16
|
50
|
33
|
|
|
439
|
if ( $self->get_sso_role_name && $self->get_sso_account_id ) { |
179
|
0
|
|
0
|
|
|
0
|
my $region = $self->get_sso_region || $self->get_region; |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# this just sets the environmet |
182
|
0
|
|
|
|
|
0
|
set_sso_credentials( $self->get_sso_role_name, $self->get_sso_account_id, |
183
|
|
|
|
|
|
|
$region ); |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# we'll set them from the environment below |
186
|
0
|
|
|
|
|
0
|
$self->set_order( ['env'] ); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
16
|
50
|
33
|
|
|
193
|
if ( !$options->{aws_secret_access_key} |
190
|
|
|
|
|
|
|
|| !$options->{aws_access_key_id} ) { |
191
|
16
|
|
|
|
|
71
|
$self->set_credentials; |
192
|
|
|
|
|
|
|
|
193
|
13
|
100
|
|
|
|
329
|
if ( $self->get__session_token ) { |
194
|
2
|
|
|
|
|
81
|
$self->set_session_token_required(TRUE); |
195
|
|
|
|
|
|
|
} |
196
|
|
|
|
|
|
|
|
197
|
13
|
50
|
|
|
|
380
|
if ( !$self->get_cache ) { |
198
|
0
|
|
|
|
|
0
|
$self->reset_credentials; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
else { |
202
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( 'setting credentials from options ', |
203
|
|
|
|
|
|
|
Dumper( [$options] ) ); |
204
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
0
|
$self->set_credentials($options); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
13
|
100
|
|
|
|
348
|
if ( !$self->get_region ) { |
209
|
5
|
|
33
|
|
|
85
|
$self->set_region( $self->get_region_from_env |
210
|
|
|
|
|
|
|
|| $self->get_default_region ); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
13
|
|
|
|
|
274
|
return $self; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
######################################################################## |
217
|
|
|
|
|
|
|
sub set_default_logger { |
218
|
|
|
|
|
|
|
######################################################################## |
219
|
16
|
|
|
16
|
0
|
40
|
my ( $self, $debug ) = @_; |
220
|
|
|
|
|
|
|
|
221
|
16
|
|
66
|
|
|
330
|
$debug = $debug // $self->get_debug; |
222
|
|
|
|
|
|
|
|
223
|
16
|
|
|
|
|
230
|
my $logger = bless { debug => $debug }, 'Amazon::Credentials::Logger'; |
224
|
|
|
|
|
|
|
|
225
|
16
|
|
|
|
|
330
|
$self->set_logger($logger); |
226
|
|
|
|
|
|
|
|
227
|
16
|
|
|
|
|
190
|
return $self; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
######################################################################## |
231
|
|
|
|
|
|
|
sub reset_credentials { |
232
|
|
|
|
|
|
|
######################################################################## |
233
|
0
|
|
|
0
|
1
|
0
|
my ( $self, $renew ) = @_; |
234
|
|
|
|
|
|
|
|
235
|
0
|
0
|
|
|
|
0
|
if ( !$renew ) { |
236
|
0
|
|
|
|
|
0
|
$self->set__access_key_id(undef); |
237
|
0
|
|
|
|
|
0
|
$self->set__secret_access_key(undef); |
238
|
0
|
|
|
|
|
0
|
$self->set__session_token(undef); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
else { |
241
|
0
|
0
|
|
|
|
0
|
if ( $self->get_cache ) { |
242
|
0
|
|
|
|
|
0
|
$self->set_credentials; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
0
|
|
|
|
|
0
|
return $self; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
######################################################################## |
250
|
|
|
|
|
|
|
sub get_region_from_env { |
251
|
|
|
|
|
|
|
######################################################################## |
252
|
5
|
|
|
5
|
0
|
13
|
my ($self) = @_; |
253
|
|
|
|
|
|
|
|
254
|
5
|
|
33
|
|
|
47
|
my $region = $ENV{AWS_REGION} || $ENV{AWS_DEFAULT_REGION}; |
255
|
|
|
|
|
|
|
|
256
|
5
|
|
|
|
|
63
|
return $region; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
######################################################################## |
260
|
|
|
|
|
|
|
sub get_default_region { |
261
|
|
|
|
|
|
|
######################################################################## |
262
|
5
|
|
|
5
|
1
|
26
|
my ($self) = @_; |
263
|
|
|
|
|
|
|
|
264
|
5
|
|
|
|
|
18
|
my $region = $self->get_region_from_config; |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# only do this if we are sure we are on an EC2 |
267
|
5
|
100
|
100
|
|
|
134
|
if ( $self->get_source && $self->get_source eq 'IAM' ) { |
268
|
|
|
|
|
|
|
# try to get credentials from instance role, but we may not be |
269
|
|
|
|
|
|
|
# executing on an EC2 or container |
270
|
1
|
|
|
|
|
31
|
my $url; |
271
|
|
|
|
|
|
|
|
272
|
1
|
50
|
|
|
|
26
|
if ( $self->get_container ) { |
273
|
1
|
|
|
|
|
17
|
$url = "$ENV{ECS_CONTAINER_METADATA_URI_V4}/task"; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
else { |
276
|
0
|
|
|
|
|
0
|
$url = _create_metadata_url(AWS_AVAILABILITY_ZONE_URL); |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
1
|
50
|
|
|
|
20
|
my $ua = ref $self ? $self->get_user_agent : LWP::UserAgent->new(); |
280
|
|
|
|
|
|
|
|
281
|
1
|
|
|
|
|
10
|
my @headers; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
# add imdsv2 token to metadata request |
284
|
1
|
50
|
33
|
|
|
18
|
if ( !$self->get_container && $self->get_imdsv2_token ) { |
285
|
0
|
|
|
|
|
0
|
@headers = ( IMDSv2_HEADER => $self->get_imdsv2_token ); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
1
|
|
|
|
|
18
|
my $req = HTTP::Request->new( GET => $url, \@headers ); |
289
|
|
|
|
|
|
|
|
290
|
1
|
|
|
|
|
6
|
$region = eval { |
291
|
1
|
|
|
|
|
3
|
my $rsp = $ua->request($req); |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# if not 200, then get out of Dodge |
294
|
1
|
50
|
|
|
|
19
|
croak "could not get availability zone\n" |
295
|
|
|
|
|
|
|
if !$rsp->is_success; |
296
|
|
|
|
|
|
|
|
297
|
1
|
|
|
|
|
7
|
my $content = $rsp->content; |
298
|
1
|
|
|
|
|
10
|
$content =~ s/(\d+)[[:lower:]]+$/$1/xsm; |
299
|
|
|
|
|
|
|
|
300
|
1
|
|
|
|
|
3
|
return $content; |
301
|
|
|
|
|
|
|
}; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
5
|
|
|
|
|
252
|
return $region; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
######################################################################## |
308
|
|
|
|
|
|
|
sub set_credentials { |
309
|
|
|
|
|
|
|
######################################################################## |
310
|
19
|
|
|
19
|
1
|
230
|
my ( $self, $creds ) = @_; |
311
|
|
|
|
|
|
|
|
312
|
19
|
|
|
|
|
456
|
$self->set_error(EMPTY); |
313
|
|
|
|
|
|
|
|
314
|
19
|
|
|
|
|
193
|
$creds = eval { |
315
|
19
|
100
|
|
|
|
66
|
if ( !$creds ) { |
316
|
17
|
|
|
|
|
26
|
$creds = eval { return $self->find_credentials }; |
|
17
|
|
|
|
|
53
|
|
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
19
|
|
66
|
|
|
615
|
$self->set_error( $creds->{error} || $EVAL_ERROR ); |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
croak 'no credentials available' |
322
|
19
|
100
|
66
|
|
|
1349
|
if !$creds->{aws_secret_access_key} || !$creds->{aws_access_key_id}; |
323
|
|
|
|
|
|
|
|
324
|
13
|
|
|
|
|
55
|
$self->set_aws_secret_access_key( $creds->{aws_secret_access_key} ); |
325
|
|
|
|
|
|
|
|
326
|
13
|
|
|
|
|
125
|
$self->set_aws_access_key_id( $creds->{aws_access_key_id} ); |
327
|
|
|
|
|
|
|
|
328
|
13
|
|
66
|
|
|
172
|
$self->set_token( $creds->{token} || $creds->{aws_session_token} ); |
329
|
|
|
|
|
|
|
|
330
|
13
|
|
|
|
|
377
|
$self->set_expiration( $creds->{expiration} ); |
331
|
|
|
|
|
|
|
|
332
|
13
|
|
|
|
|
173
|
return $creds; |
333
|
|
|
|
|
|
|
}; |
334
|
|
|
|
|
|
|
|
335
|
19
|
100
|
100
|
|
|
377
|
if ( $EVAL_ERROR && !$self->get_error ) { |
336
|
5
|
|
|
|
|
129
|
$self->set_error($EVAL_ERROR); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
19
|
|
|
|
|
98
|
undef $EVAL_ERROR; |
340
|
|
|
|
|
|
|
|
341
|
19
|
100
|
100
|
|
|
387
|
croak $self->get_error |
342
|
|
|
|
|
|
|
if $self->get_error && $self->get_raise_error; |
343
|
|
|
|
|
|
|
|
344
|
16
|
100
|
100
|
|
|
501
|
carp $self->get_error |
345
|
|
|
|
|
|
|
if $self->get_error && $self->get_print_error; |
346
|
|
|
|
|
|
|
|
347
|
16
|
|
|
|
|
700
|
return $self; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
######################################################################## |
351
|
|
|
|
|
|
|
sub get_ec2_credentials { |
352
|
|
|
|
|
|
|
######################################################################## |
353
|
0
|
|
|
0
|
1
|
0
|
goto &find_credentials; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
######################################################################## |
357
|
|
|
|
|
|
|
sub find_credentials { |
358
|
|
|
|
|
|
|
######################################################################## |
359
|
17
|
|
|
17
|
1
|
65
|
my ( $self, @args ) = @_; |
360
|
|
|
|
|
|
|
|
361
|
17
|
50
|
|
|
|
69
|
my $options = ref $args[0] ? $args[0] : {@args}; |
362
|
|
|
|
|
|
|
|
363
|
17
|
50
|
|
|
|
71
|
if ( $options->{profile} ) { |
364
|
0
|
|
|
|
|
0
|
$self->set_profile( $options->{profile} ); |
365
|
|
|
|
|
|
|
} |
366
|
|
|
|
|
|
|
|
367
|
17
|
50
|
|
|
|
54
|
if ( $options->{order} ) { |
368
|
0
|
|
|
|
|
0
|
$self->set_order( $options->{order} ); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
17
|
|
|
|
|
32
|
my @search_order; |
372
|
|
|
|
|
|
|
|
373
|
17
|
100
|
33
|
|
|
366
|
if ( $self->get_profile ) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
374
|
14
|
|
|
|
|
114
|
@search_order = ('file'); |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
elsif ( ref $self->get_order && reftype( $self->get_order ) eq 'ARRAY' ) { |
377
|
3
|
|
|
|
|
170
|
@search_order = @{ $self->get_order }; |
|
3
|
|
|
|
|
51
|
|
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
elsif ( !ref $self->get_order ) { |
380
|
0
|
|
|
|
|
0
|
@search_order = split /\s*,\s*/xsm, $self->get_order; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
17
|
|
|
|
|
346
|
$self->get_logger->debug( 'search order ' . join COMMA, @search_order ); |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
my %creds_getters = ( |
386
|
|
|
|
|
|
|
env => sub { |
387
|
2
|
|
|
2
|
|
6
|
return $self->get_creds_from_env,; |
388
|
|
|
|
|
|
|
}, |
389
|
|
|
|
|
|
|
role => sub { |
390
|
0
|
|
|
0
|
|
0
|
return $self->get_creds_from_role; |
391
|
|
|
|
|
|
|
}, |
392
|
|
|
|
|
|
|
container => sub { |
393
|
1
|
|
|
1
|
|
19
|
return $self->get_creds_from_container; |
394
|
|
|
|
|
|
|
}, |
395
|
|
|
|
|
|
|
file => sub { |
396
|
14
|
|
|
14
|
|
62
|
return $self->get_creds_from_ini_file; |
397
|
|
|
|
|
|
|
}, |
398
|
17
|
|
|
|
|
208
|
); |
399
|
|
|
|
|
|
|
|
400
|
17
|
|
|
|
|
30
|
my $creds; |
401
|
|
|
|
|
|
|
|
402
|
17
|
|
|
|
|
52
|
foreach my $location (@search_order) { |
403
|
|
|
|
|
|
|
|
404
|
17
|
|
|
|
|
344
|
$self->get_logger->debug( 'searching for credentials in: ' . $location ); |
405
|
|
|
|
|
|
|
|
406
|
17
|
50
|
|
|
|
94
|
if ( $creds_getters{$location} ) { |
407
|
17
|
|
|
|
|
44
|
$creds = $creds_getters{$location}->(); |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
16
|
100
|
|
|
|
78
|
last if $creds->{source}; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
|
413
|
16
|
|
|
|
|
32
|
foreach my $k ( keys %{$creds} ) { |
|
16
|
|
|
|
|
68
|
|
414
|
|
|
|
|
|
|
|
415
|
68
|
100
|
|
|
|
1052
|
if ( $k !~ /^aws|token/xsm ) { |
|
|
50
|
|
|
|
|
|
416
|
24
|
|
|
|
|
154
|
$self->set( $k, $creds->{$k} ); |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
elsif ( $self->can("set_$k") ) { |
419
|
44
|
|
|
|
|
214
|
$self->can("set_$k")->( $self, $creds->{$k} ); |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
16
|
|
|
|
|
391
|
$self->get_logger->debug( $self->safe_dumper($creds) ); |
424
|
|
|
|
|
|
|
|
425
|
16
|
|
|
|
|
216
|
return $creds; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# +------------------+ |
429
|
|
|
|
|
|
|
# | get_creds_from_* | |
430
|
|
|
|
|
|
|
# +------------------+ |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
######################################################################## |
433
|
|
|
|
|
|
|
sub get_creds_from_env { |
434
|
|
|
|
|
|
|
######################################################################## |
435
|
2
|
|
|
2
|
0
|
4
|
my ($self) = @_; |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
return {} |
438
|
2
|
100
|
66
|
|
|
10
|
if !$ENV{AWS_ACCESS_KEY_ID} || !$ENV{AWS_SECRET_ACCESS_KEY}; |
439
|
|
|
|
|
|
|
|
440
|
1
|
|
|
|
|
21
|
$self->get_logger->debug('fetching credentials from env'); |
441
|
|
|
|
|
|
|
|
442
|
1
|
|
|
|
|
19
|
my @cred_keys = ( |
443
|
|
|
|
|
|
|
aws_access_key_id => 'AWS_ACCESS_KEY_ID', |
444
|
|
|
|
|
|
|
aws_secret_access_key => 'AWS_SECRET_ACCESS_KEY', |
445
|
|
|
|
|
|
|
aws_session_token => 'AWS_SESSION_TOKEN', |
446
|
|
|
|
|
|
|
token => 'AWS_SESSION_TOKEN', |
447
|
|
|
|
|
|
|
); |
448
|
|
|
|
|
|
|
|
449
|
1
|
|
|
|
|
5
|
return populate_creds( 'ENV', \@cred_keys, \%ENV ); |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
######################################################################## |
453
|
|
|
|
|
|
|
sub populate_creds { |
454
|
|
|
|
|
|
|
######################################################################## |
455
|
31
|
|
|
31
|
0
|
1674
|
my ( $source, $cred_keys, $creds_source ) = @_; |
456
|
|
|
|
|
|
|
|
457
|
31
|
|
|
|
|
87
|
my $creds = { source => $source }; |
458
|
|
|
|
|
|
|
|
459
|
31
|
|
|
|
|
90
|
foreach my $p ( pairs @{$cred_keys} ) { |
|
31
|
|
|
|
|
356
|
|
460
|
154
|
|
|
|
|
200
|
my ( $k, $v ) = @{$p}; |
|
154
|
|
|
|
|
299
|
|
461
|
154
|
|
|
|
|
284
|
$creds->{$k} = $creds_source->{$v}; |
462
|
154
|
100
|
|
|
|
325
|
next if $source =~ /env/i; |
463
|
|
|
|
|
|
|
|
464
|
150
|
|
|
|
|
233
|
delete $creds_source->{$v}; |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
31
|
|
|
|
|
213
|
return $creds; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
######################################################################## |
471
|
|
|
|
|
|
|
sub get_creds_from_process { |
472
|
|
|
|
|
|
|
######################################################################## |
473
|
2
|
|
|
2
|
1
|
13
|
my ( $self, $process ) = @_; |
474
|
|
|
|
|
|
|
|
475
|
2
|
|
|
|
|
37
|
$self->get_logger->debug("fetching credentials from $process"); |
476
|
|
|
|
|
|
|
|
477
|
2
|
|
|
|
|
6
|
my $credentials = eval { |
478
|
2
|
100
|
|
|
|
10875
|
open my $fh, q{-|}, $process |
479
|
|
|
|
|
|
|
or croak "could not open pipe to $process\n$OS_ERROR"; |
480
|
|
|
|
|
|
|
|
481
|
1
|
|
|
|
|
32
|
local $RS = undef; |
482
|
|
|
|
|
|
|
|
483
|
1
|
|
|
|
|
9098
|
my $credentials_str = <$fh>; |
484
|
|
|
|
|
|
|
|
485
|
1
|
50
|
|
|
|
62
|
close $fh |
486
|
|
|
|
|
|
|
or croak "could not close filehandle on $process\n"; |
487
|
|
|
|
|
|
|
|
488
|
1
|
|
|
|
|
48
|
return decode_json($credentials_str); |
489
|
|
|
|
|
|
|
}; |
490
|
|
|
|
|
|
|
|
491
|
2
|
100
|
66
|
|
|
12173
|
if ( $EVAL_ERROR || !$credentials ) { |
492
|
1
|
|
|
|
|
346
|
croak "could not get credentials from process\n$EVAL_ERROR\n"; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
|
495
|
1
|
|
|
|
|
59
|
$self->get_logger->debug( $self->safe_dumper($credentials) ); |
496
|
|
|
|
|
|
|
|
497
|
1
|
|
|
|
|
36
|
my @cred_keys = ( |
498
|
|
|
|
|
|
|
aws_access_key_id => 'AccessKeyId', |
499
|
|
|
|
|
|
|
aws_secret_access_key => 'SecretAccessKey', |
500
|
|
|
|
|
|
|
token => 'SessionToken', |
501
|
|
|
|
|
|
|
aws_session_token => 'SessionToken', |
502
|
|
|
|
|
|
|
region => 'Region', |
503
|
|
|
|
|
|
|
expiration => 'Expiration', |
504
|
|
|
|
|
|
|
); |
505
|
|
|
|
|
|
|
|
506
|
1
|
|
|
|
|
14
|
return populate_creds( 'process', \@cred_keys, $credentials ); |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
######################################################################## |
510
|
|
|
|
|
|
|
sub create_config_path { |
511
|
|
|
|
|
|
|
######################################################################## |
512
|
33
|
|
|
33
|
0
|
74
|
my ($config) = @_; |
513
|
|
|
|
|
|
|
|
514
|
33
|
|
|
|
|
131
|
my $fullpath = home . SLASH . $config; |
515
|
|
|
|
|
|
|
|
516
|
33
|
100
|
|
|
|
1878
|
return -e $fullpath ? $fullpath : EMPTY; |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
######################################################################## |
520
|
|
|
|
|
|
|
sub get_region_from_config { |
521
|
|
|
|
|
|
|
######################################################################## |
522
|
5
|
|
|
5
|
0
|
22
|
my ($self) = @_; |
523
|
|
|
|
|
|
|
|
524
|
5
|
|
|
|
|
31
|
my $config = create_config_path('.aws/config'); |
525
|
|
|
|
|
|
|
|
526
|
5
|
100
|
|
|
|
33
|
return if !$config; |
527
|
|
|
|
|
|
|
|
528
|
4
|
|
|
|
|
107
|
$self->get_logger->debug("config: $config"); |
529
|
|
|
|
|
|
|
|
530
|
4
|
|
|
|
|
39
|
my $ini = Config::Tiny->read($config); |
531
|
|
|
|
|
|
|
|
532
|
4
|
|
|
|
|
795
|
my $region; |
533
|
|
|
|
|
|
|
|
534
|
4
|
50
|
|
|
|
23
|
if ( $ini->{default} ) { |
535
|
4
|
|
|
|
|
16
|
$region = $ini->{default}->{region}; |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
4
|
|
50
|
|
|
101
|
$self->get_logger->debug( 'default region: ' . $region // 'undef' ); |
539
|
|
|
|
|
|
|
|
540
|
4
|
|
|
|
|
18
|
return $region; |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
######################################################################## |
544
|
|
|
|
|
|
|
sub get_creds_from_ini_file { |
545
|
|
|
|
|
|
|
######################################################################## |
546
|
14
|
|
|
14
|
0
|
32
|
my ( $self, $profile ) = @_; |
547
|
|
|
|
|
|
|
|
548
|
14
|
|
50
|
|
|
343
|
$profile = $profile || $self->get_profile || 'default'; |
549
|
|
|
|
|
|
|
|
550
|
14
|
|
|
|
|
151
|
my $creds = {}; |
551
|
14
|
|
|
|
|
34
|
my $region; |
552
|
|
|
|
|
|
|
|
553
|
14
|
|
|
|
|
42
|
foreach my $config (qw( .aws/config .aws/credentials )) { |
554
|
28
|
50
|
|
|
|
82
|
last if $creds->{source}; |
555
|
|
|
|
|
|
|
|
556
|
28
|
|
|
|
|
46
|
my $profile_name = $profile; |
557
|
|
|
|
|
|
|
|
558
|
28
|
|
|
|
|
71
|
my $fullpath = create_config_path($config); |
559
|
|
|
|
|
|
|
|
560
|
28
|
50
|
|
|
|
101
|
if ( !$fullpath ) { |
561
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( 'skipping ' . $config . '...not found' ); |
562
|
0
|
|
|
|
|
0
|
next; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
28
|
|
|
|
|
689
|
$self->get_logger->debug( 'reading ' . $config ); |
566
|
|
|
|
|
|
|
|
567
|
28
|
|
|
|
|
149
|
my $ini = Config::Tiny->read($fullpath); |
568
|
|
|
|
|
|
|
|
569
|
28
|
|
|
|
|
7678
|
$self->get_logger->debug( $self->safe_dumper($ini) ); |
570
|
|
|
|
|
|
|
|
571
|
28
|
100
|
|
|
|
100
|
if ( $ini->{default} ) { |
572
|
27
|
|
|
|
|
56
|
$region = $ini->{default}->{region}; |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
|
575
|
28
|
|
|
|
|
34
|
my $section; |
576
|
|
|
|
|
|
|
|
577
|
28
|
100
|
|
|
|
116
|
if ( $ini->{$profile_name} ) { |
|
|
100
|
|
|
|
|
|
578
|
10
|
|
|
|
|
32
|
$section = $ini->{$profile_name}; |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
elsif ( $ini->{"profile $profile_name"} ) { ## config file format |
581
|
2
|
|
|
|
|
8
|
$section = $ini->{"profile $profile_name"}; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
my $process |
585
|
28
|
|
66
|
|
|
121
|
= $ini->{credential_process} || $section->{credential_process}; |
586
|
|
|
|
|
|
|
|
587
|
28
|
100
|
|
|
|
71
|
if ($process) { |
|
|
50
|
|
|
|
|
|
588
|
2
|
|
|
|
|
11
|
$creds = $self->get_creds_from_process($process); |
589
|
1
|
50
|
|
|
|
44
|
$region = $section->{region} ? $section->{region} : $region; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
elsif ($section) { |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# credentials in a config file shouldn't really have a session token, |
594
|
|
|
|
|
|
|
# but if it does we'll capture it as aws_session_token. For |
595
|
|
|
|
|
|
|
# historical reasons pertaining to how other CPAN classes |
596
|
|
|
|
|
|
|
# referred to the token we store it internally as token |
597
|
26
|
|
|
|
|
86
|
my @cred_keys = ( |
598
|
|
|
|
|
|
|
aws_access_key_id => 'aws_access_key_id', |
599
|
|
|
|
|
|
|
aws_secret_access_key => 'aws_secret_access_key', |
600
|
|
|
|
|
|
|
aws_session_token => 'aws_session_token', |
601
|
|
|
|
|
|
|
token => 'aws_session_token', |
602
|
|
|
|
|
|
|
region => 'region', |
603
|
|
|
|
|
|
|
); |
604
|
|
|
|
|
|
|
|
605
|
26
|
|
|
|
|
69
|
$creds = populate_creds( $config, \@cred_keys, $section ); |
606
|
|
|
|
|
|
|
|
607
|
26
|
100
|
66
|
|
|
125
|
if ( !$creds->{aws_access_key_id} || !$creds->{aws_secret_access_key} ) |
608
|
|
|
|
|
|
|
{ |
609
|
18
|
|
|
|
|
94
|
$creds = {}; |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
13
|
|
100
|
|
|
503
|
$self->set_region( $creds->{region} || $region ); |
615
|
|
|
|
|
|
|
|
616
|
13
|
|
|
|
|
182
|
return $creds; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
######################################################################## |
620
|
|
|
|
|
|
|
sub get_creds_from_role { |
621
|
|
|
|
|
|
|
######################################################################## |
622
|
1
|
|
|
1
|
1
|
2
|
my ($self) = @_; |
623
|
|
|
|
|
|
|
|
624
|
1
|
50
|
|
|
|
14
|
if ( $ENV{AWS_EC2_METADATA_DISABLED} eq 'true' ) { |
625
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( |
626
|
|
|
|
|
|
|
'AWS_EC2_METADATA_DISABLED is true, skipping...'); |
627
|
|
|
|
|
|
|
|
628
|
0
|
|
|
|
|
0
|
return {}; |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
# try to get credentials from instance role |
632
|
1
|
|
|
|
|
4
|
my $url = _create_metadata_url(AWS_IAM_SECURITY_CREDENTIALS_URL); |
633
|
|
|
|
|
|
|
|
634
|
1
|
|
|
|
|
24
|
my $ua = $self->get_user_agent; |
635
|
|
|
|
|
|
|
|
636
|
1
|
|
|
|
|
7
|
my $role; |
637
|
|
|
|
|
|
|
|
638
|
1
|
|
|
|
|
4
|
my $creds = { error => undef }; |
639
|
|
|
|
|
|
|
|
640
|
1
|
50
|
|
|
|
20
|
if ( $self->get_imdsv2 ) { |
641
|
0
|
|
|
|
|
0
|
my $token_url = _create_metadata_url(IMDSv2_URL); |
642
|
|
|
|
|
|
|
|
643
|
0
|
|
|
|
|
0
|
my @headers = ( IMDSv2_TTL_HEADER, IMDSv2_DEFAULT_TTL ); |
644
|
|
|
|
|
|
|
|
645
|
0
|
|
|
|
|
0
|
my $token_req = HTTP::Request->new( PUT => $token_url, \@headers ); |
646
|
|
|
|
|
|
|
|
647
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( Dumper $token_req); |
648
|
|
|
|
|
|
|
|
649
|
0
|
|
|
|
|
0
|
my $rsp = $ua->request($token_req); |
650
|
|
|
|
|
|
|
|
651
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( Dumper $rsp); |
652
|
|
|
|
|
|
|
|
653
|
0
|
0
|
|
|
|
0
|
if ( $rsp->is_success ) { |
654
|
0
|
|
|
|
|
0
|
$self->set_imdsv2_token( $rsp->content ); |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
else { |
657
|
0
|
|
|
|
|
0
|
croak "could not retrieve IMDSv2 token\n"; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
1
|
|
|
|
|
14
|
my @cred_keys = ( |
662
|
|
|
|
|
|
|
aws_access_key_id => 'AccessKeyId', |
663
|
|
|
|
|
|
|
aws_secret_access_key => 'SecretAccessKey', |
664
|
|
|
|
|
|
|
token => 'Token', |
665
|
|
|
|
|
|
|
aws_session_token => 'Token', |
666
|
|
|
|
|
|
|
expiration => 'Expiration', |
667
|
|
|
|
|
|
|
); |
668
|
|
|
|
|
|
|
|
669
|
1
|
|
|
|
|
2
|
$creds = eval { |
670
|
|
|
|
|
|
|
# could be infinite, but I don't think so. Either we get an |
671
|
|
|
|
|
|
|
# error ($@), or a non-200 response code |
672
|
1
|
|
|
|
|
3
|
while ( !$creds->{token} ) { |
673
|
|
|
|
|
|
|
|
674
|
2
|
100
|
|
|
|
6
|
if ($role) { |
675
|
1
|
|
|
|
|
2
|
$url .= $role; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
2
|
|
|
|
|
5
|
my @headers; |
679
|
|
|
|
|
|
|
|
680
|
2
|
50
|
33
|
|
|
51
|
if ( $self->get_imdsv2 && $self->get_imdsv2_token ) { |
681
|
0
|
|
|
|
|
0
|
@headers = ( IMDSv2_HEADER, $self->get_imdsv2_token ); |
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
|
684
|
2
|
|
|
|
|
26
|
my $req = HTTP::Request->new( GET => $url, \@headers ); |
685
|
|
|
|
|
|
|
|
686
|
2
|
|
|
|
|
46
|
$self->get_logger->debug( Dumper [ "HTTP REQUEST:\n", $req ] ); |
687
|
|
|
|
|
|
|
|
688
|
2
|
|
|
|
|
11
|
my $rsp = $ua->request($req); |
689
|
|
|
|
|
|
|
|
690
|
2
|
|
|
|
|
56
|
$self->get_logger->debug( $self->dump_response($rsp) ); |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
# if not 200, then get out of Dodge |
693
|
2
|
50
|
|
|
|
8
|
last if !$rsp->is_success; |
694
|
|
|
|
|
|
|
|
695
|
2
|
100
|
|
|
|
12
|
if ($role) { |
696
|
1
|
|
|
|
|
7
|
my $creds_source = decode_json( $rsp->content ); |
697
|
|
|
|
|
|
|
|
698
|
1
|
|
|
|
|
2976
|
$creds = populate_creds( 'IAM', \@cred_keys, $creds_source ); |
699
|
1
|
|
|
|
|
6
|
$creds->{role} = $role; |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
else { |
702
|
1
|
|
|
|
|
3
|
$role = $rsp->content; |
703
|
1
|
|
|
|
|
31
|
$self->get_logger->debug( Dumper [ 'role', $role ] ); |
704
|
|
|
|
|
|
|
|
705
|
1
|
50
|
|
|
|
13
|
last if !$role; |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
|
709
|
1
|
|
|
|
|
3
|
return $creds; |
710
|
|
|
|
|
|
|
}; |
711
|
|
|
|
|
|
|
|
712
|
1
|
50
|
33
|
|
|
7
|
if ( !$creds || $EVAL_ERROR ) { |
713
|
0
|
|
|
|
|
0
|
$creds->{error} = $EVAL_ERROR; |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
1
|
|
|
|
|
4
|
return $creds; |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
######################################################################## |
720
|
|
|
|
|
|
|
sub get_creds_from_container { |
721
|
|
|
|
|
|
|
######################################################################## |
722
|
1
|
|
|
1
|
1
|
4
|
my ( $self, $uri ) = @_; |
723
|
|
|
|
|
|
|
|
724
|
1
|
|
33
|
|
|
7
|
$uri //= $ENV{AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}; |
725
|
|
|
|
|
|
|
|
726
|
1
|
|
|
|
|
2
|
my $creds = {}; |
727
|
|
|
|
|
|
|
|
728
|
1
|
50
|
|
|
|
3
|
if ( !$uri ) { |
729
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( |
730
|
|
|
|
|
|
|
"not running in a container: no URI in environment\n"); |
731
|
0
|
|
|
|
|
0
|
return $creds; |
732
|
|
|
|
|
|
|
} |
733
|
|
|
|
|
|
|
|
734
|
1
|
|
|
|
|
22
|
$self->get_logger->debug( Dumper( [ uri => $uri ] ) ); |
735
|
|
|
|
|
|
|
|
736
|
1
|
|
|
|
|
3
|
$creds = eval { |
737
|
|
|
|
|
|
|
# try to get credentials from instance role |
738
|
1
|
|
|
|
|
3
|
my $url = AWS_CONTAINER_CREDENTIALS_URL . $uri; |
739
|
|
|
|
|
|
|
|
740
|
1
|
|
|
|
|
21
|
my $ua = $self->get_user_agent; |
741
|
|
|
|
|
|
|
|
742
|
1
|
|
|
|
|
9
|
my $req = HTTP::Request->new( GET => $url ); |
743
|
1
|
|
|
|
|
8
|
$req->header(qw( Accept */* )); |
744
|
|
|
|
|
|
|
|
745
|
1
|
|
|
|
|
18
|
$self->get_logger->debug( |
746
|
|
|
|
|
|
|
Dumper [ |
747
|
|
|
|
|
|
|
request => $req, |
748
|
|
|
|
|
|
|
as_string => $req->as_string, |
749
|
|
|
|
|
|
|
] |
750
|
|
|
|
|
|
|
); |
751
|
|
|
|
|
|
|
|
752
|
1
|
|
|
|
|
4
|
my $rsp = $ua->request($req); |
753
|
|
|
|
|
|
|
|
754
|
1
|
|
|
|
|
32
|
$self->get_logger->debug( $self->dump_response($rsp) ); |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
# if not 200, then get out of Dodge |
757
|
1
|
50
|
|
|
|
4
|
if ( $rsp->is_success ) { |
758
|
|
|
|
|
|
|
|
759
|
1
|
|
|
|
|
5
|
my $creds_source = decode_json( $rsp->content ); |
760
|
|
|
|
|
|
|
|
761
|
1
|
|
|
|
|
1717
|
my @cred_keys = ( |
762
|
|
|
|
|
|
|
aws_access_key_id => 'AccessKeyId', |
763
|
|
|
|
|
|
|
aws_secret_access_key => 'SecretAccessKey', |
764
|
|
|
|
|
|
|
token => 'Token', |
765
|
|
|
|
|
|
|
aws_session_token => 'Token', |
766
|
|
|
|
|
|
|
expiration => 'Expiration', |
767
|
|
|
|
|
|
|
); |
768
|
|
|
|
|
|
|
|
769
|
1
|
|
|
|
|
7
|
$creds = populate_creds( 'IAM', \@cred_keys, $creds_source ); |
770
|
1
|
|
|
|
|
4
|
$creds->{container} = 'ECS'; |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
else { |
773
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( 'return code: ' . $rsp->status_line ); |
774
|
|
|
|
|
|
|
} |
775
|
|
|
|
|
|
|
|
776
|
1
|
|
|
|
|
7
|
return $creds; |
777
|
|
|
|
|
|
|
}; |
778
|
|
|
|
|
|
|
|
779
|
1
|
|
|
|
|
14
|
$creds->{error} = $EVAL_ERROR; |
780
|
1
|
|
|
|
|
27
|
$self->get_logger->debug( "EVAL_ERROR: $EVAL_ERROR\n" . Dumper $creds); |
781
|
|
|
|
|
|
|
|
782
|
1
|
|
|
|
|
6
|
return $creds; |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
# +---------+ |
786
|
|
|
|
|
|
|
# | DUMPERS | |
787
|
|
|
|
|
|
|
# +---------+ |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
######################################################################## |
790
|
|
|
|
|
|
|
sub safe_dumper { |
791
|
|
|
|
|
|
|
######################################################################## |
792
|
45
|
|
|
45
|
0
|
371
|
my ( $self, $obj ) = @_; |
793
|
|
|
|
|
|
|
|
794
|
45
|
50
|
|
|
|
135
|
return if !ref $obj; |
795
|
|
|
|
|
|
|
|
796
|
45
|
|
|
|
|
70
|
my $safe_rsp; |
797
|
|
|
|
|
|
|
|
798
|
45
|
100
|
100
|
|
|
861
|
if ( $self->get_insecure && $self->get_insecure =~ /^2$/xsm ) { |
|
|
100
|
|
|
|
|
|
799
|
3
|
|
|
|
|
80
|
$safe_rsp = Dumper [$obj]; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
elsif ( $self->get_insecure ) { |
802
|
3
|
|
|
|
|
168
|
$safe_rsp = Dumper [$obj]; |
803
|
|
|
|
|
|
|
|
804
|
3
|
|
|
|
|
404
|
$safe_rsp |
805
|
|
|
|
|
|
|
=~ s/(.*?)(access_?key[^']+)'([^']+)'([^']+)'/$1$2'$3'...'/ixsmg; |
806
|
|
|
|
|
|
|
|
807
|
3
|
|
|
|
|
42
|
$safe_rsp |
808
|
|
|
|
|
|
|
=~ s/(.*?)(secret_?access[^']+)'([^']+)'([^']+)'/$1$2'$3'...'/ixsmg; |
809
|
|
|
|
|
|
|
|
810
|
3
|
|
|
|
|
14
|
$safe_rsp =~ s/(.*?)(token[^']+)'([^']+)'([^']+)'/$1$2'$3'...'/ixsmg; |
811
|
|
|
|
|
|
|
} |
812
|
|
|
|
|
|
|
else { |
813
|
39
|
|
|
|
|
1040
|
$safe_rsp = '** configuration contents blocked by insecure setting **'; |
814
|
|
|
|
|
|
|
} |
815
|
|
|
|
|
|
|
|
816
|
45
|
|
|
|
|
461
|
return $safe_rsp; |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
######################################################################## |
820
|
|
|
|
|
|
|
sub dump_response { |
821
|
|
|
|
|
|
|
######################################################################## |
822
|
3
|
|
|
3
|
0
|
23
|
my ( $self, $rsp ) = @_; |
823
|
|
|
|
|
|
|
|
824
|
3
|
|
|
|
|
3
|
my $safe_rsp; |
825
|
|
|
|
|
|
|
|
826
|
3
|
50
|
33
|
|
|
53
|
if ( $self->get_insecure && $self->get_insecure =~ /^2$/xsm ) { |
|
|
50
|
|
|
|
|
|
827
|
0
|
|
|
|
|
0
|
$safe_rsp = $rsp; |
828
|
|
|
|
|
|
|
} |
829
|
|
|
|
|
|
|
elsif ( $self->get_insecure ) { |
830
|
0
|
|
|
|
|
0
|
$safe_rsp = {}; |
831
|
|
|
|
|
|
|
|
832
|
0
|
|
|
|
|
0
|
foreach my $k ( keys %{$rsp} ) { |
|
0
|
|
|
|
|
0
|
|
833
|
0
|
0
|
|
|
|
0
|
if ( $k =~ /content/xsm ) { |
834
|
0
|
|
|
|
|
0
|
my $content = $rsp->{$k}; |
835
|
0
|
|
|
|
|
0
|
$content |
836
|
|
|
|
|
|
|
=~ s/\"(AccessKeyId|Token|SecretAccessKey)\"\s+\:\s+\"[^\"]+\"/\"$1\" : \"...\"/gxsm; |
837
|
0
|
|
|
|
|
0
|
$safe_rsp->{$k} = $content; |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
else { |
840
|
0
|
|
|
|
|
0
|
$safe_rsp->{$k} = $rsp->{$k}; |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
else { |
845
|
3
|
|
|
|
|
120
|
$safe_rsp = '** HTTP RESPONSE blocked by insecure setting **'; |
846
|
|
|
|
|
|
|
} |
847
|
|
|
|
|
|
|
|
848
|
3
|
|
|
|
|
13
|
return Dumper [$safe_rsp]; |
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
# +---------------+ |
852
|
|
|
|
|
|
|
# | TOKEN METHODS | |
853
|
|
|
|
|
|
|
# +---------------+ |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
######################################################################## |
856
|
|
|
|
|
|
|
sub is_token_expired { |
857
|
|
|
|
|
|
|
######################################################################## |
858
|
4
|
|
|
4
|
1
|
319
|
my ( $self, $window_interval ) = @_; |
859
|
4
|
|
50
|
|
|
35
|
$window_interval = $window_interval // DEFAULT_WINDOW_INTERVAL; |
860
|
|
|
|
|
|
|
|
861
|
4
|
|
|
|
|
95
|
my $expiration_date = $self->get_expiration(); |
862
|
|
|
|
|
|
|
|
863
|
4
|
|
|
|
|
22
|
my $expired = FALSE; |
864
|
|
|
|
|
|
|
|
865
|
4
|
50
|
|
|
|
10
|
if ( defined $expiration_date ) { |
866
|
|
|
|
|
|
|
# AWS recommends getting credentials 5 minutes prior to expiration |
867
|
4
|
|
|
|
|
9
|
my $g = _iso8601_to_time($expiration_date); |
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
# shave 5 minutes or window interval off of the expiration time |
870
|
4
|
|
|
|
|
7
|
$g -= $window_interval * SECONDS_IN_MINUTE; |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
# (expiration_time - window_interval) - current_time = # of seconds left before expiration |
873
|
4
|
|
|
|
|
7
|
my $seconds_left = $g - time; |
874
|
|
|
|
|
|
|
|
875
|
4
|
50
|
|
|
|
101
|
if ( $self->get_debug ) { |
876
|
0
|
|
|
|
|
0
|
$self->get_logger->debug("seconds left : $seconds_left"); |
877
|
0
|
|
|
|
|
0
|
my $hours = int( $seconds_left / SECONDS_IN_HOUR ); |
878
|
|
|
|
|
|
|
|
879
|
0
|
|
|
|
|
0
|
my $minutes = int( |
880
|
|
|
|
|
|
|
( $seconds_left - $hours * SECONDS_IN_HOUR ) / SECONDS_IN_MINUTE ); |
881
|
|
|
|
|
|
|
|
882
|
0
|
|
|
|
|
0
|
my $seconds = $seconds_left |
883
|
|
|
|
|
|
|
- ( $hours * SECONDS_IN_HOUR + $minutes * SECONDS_IN_MINUTE ); |
884
|
|
|
|
|
|
|
|
885
|
0
|
|
|
|
|
0
|
$self->get_logger->debug( |
886
|
|
|
|
|
|
|
"$hours hours $minutes minutes $seconds seconds until expiry"); |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
|
889
|
4
|
100
|
|
|
|
28
|
$expired = ( $seconds_left < 0 ) ? TRUE : FALSE; |
890
|
|
|
|
|
|
|
|
891
|
4
|
|
|
|
|
111
|
$self->get_logger->debug( |
892
|
|
|
|
|
|
|
Dumper [ |
893
|
|
|
|
|
|
|
expiration_date => $expiration_date, |
894
|
|
|
|
|
|
|
expired => $expired |
895
|
|
|
|
|
|
|
] |
896
|
|
|
|
|
|
|
); |
897
|
|
|
|
|
|
|
} |
898
|
|
|
|
|
|
|
|
899
|
4
|
|
|
|
|
24
|
return $expired; |
900
|
|
|
|
|
|
|
} |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
######################################################################## |
903
|
|
|
|
|
|
|
sub refresh_credentials { |
904
|
|
|
|
|
|
|
######################################################################## |
905
|
0
|
|
|
0
|
1
|
0
|
goto &refresh_token; |
906
|
|
|
|
|
|
|
} |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
######################################################################## |
909
|
|
|
|
|
|
|
sub refresh_token { |
910
|
|
|
|
|
|
|
######################################################################## |
911
|
1
|
|
|
1
|
1
|
645
|
my ($self) = @_; |
912
|
|
|
|
|
|
|
|
913
|
1
|
|
|
|
|
2
|
my $creds; |
914
|
|
|
|
|
|
|
|
915
|
1
|
50
|
33
|
|
|
22
|
if ( $self->get_container && $self->get_container eq 'ECS' ) { |
|
|
50
|
|
|
|
|
|
916
|
0
|
|
|
|
|
0
|
$creds = $self->get_creds_from_container; |
917
|
|
|
|
|
|
|
} |
918
|
|
|
|
|
|
|
elsif ( $self->get_role ) { |
919
|
1
|
|
|
|
|
36
|
$creds = $self->get_creds_from_role; |
920
|
|
|
|
|
|
|
} |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
croak 'unable to refresh token!' |
923
|
1
|
50
|
33
|
|
|
4
|
if !ref $creds || !keys %{$creds}; |
|
1
|
|
|
|
|
5
|
|
924
|
|
|
|
|
|
|
|
925
|
1
|
|
|
|
|
4
|
return $self->set_credentials($creds); |
926
|
|
|
|
|
|
|
} |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
######################################################################## |
929
|
|
|
|
|
|
|
sub credential_keys { |
930
|
|
|
|
|
|
|
######################################################################## |
931
|
3
|
|
|
3
|
1
|
4048
|
my ($self) = @_; |
932
|
|
|
|
|
|
|
|
933
|
3
|
|
|
|
|
6
|
my %credential_keys; |
934
|
|
|
|
|
|
|
|
935
|
3
|
50
|
|
|
|
73
|
if ( !$self->get_cache ) { |
936
|
0
|
|
|
|
|
0
|
my $creds = $self->find_credentials; |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
%credential_keys = ( |
939
|
|
|
|
|
|
|
AWS_ACCESS_KEY_ID => $creds->{aws_access_key_id}, |
940
|
|
|
|
|
|
|
AWS_SECRET_ACCESS_KEY => $creds->{aws_secret_access_key}, |
941
|
|
|
|
|
|
|
AWS_SESSION_TOKEN => $creds->{token}, |
942
|
|
|
|
|
|
|
AWS_SESSION_TOKEN_EXPIRATION => $creds->{expiration}, |
943
|
0
|
|
|
|
|
0
|
); |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
} |
946
|
|
|
|
|
|
|
else { |
947
|
3
|
|
|
|
|
23
|
%credential_keys = ( |
948
|
|
|
|
|
|
|
AWS_ACCESS_KEY_ID => $self->get_aws_access_key_id, |
949
|
|
|
|
|
|
|
AWS_SECRET_ACCESS_KEY => $self->get_aws_secret_access_key, |
950
|
|
|
|
|
|
|
AWS_SESSION_TOKEN => $self->get_token, |
951
|
|
|
|
|
|
|
AWS_SESSION_TOKEN_EXPIRATION => $self->get_expiration, |
952
|
|
|
|
|
|
|
); |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
|
955
|
3
|
50
|
|
|
|
28
|
if ( !defined $credential_keys{AWS_SESSION_TOKEN} ) { |
956
|
3
|
|
|
|
|
6
|
delete $credential_keys{AWS_SESSION_TOKEN}; |
957
|
3
|
|
|
|
|
4
|
delete $credential_keys{AWS_SESSION_TOKEN_EXPIRATION}; |
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
|
960
|
3
|
|
|
|
|
29
|
return \%credential_keys; |
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
######################################################################## |
964
|
|
|
|
|
|
|
sub as_string { |
965
|
|
|
|
|
|
|
######################################################################## |
966
|
1
|
|
|
1
|
1
|
3017
|
my ($self) = @_; |
967
|
|
|
|
|
|
|
|
968
|
1
|
|
|
|
|
13
|
return JSON::PP->new->pretty->encode( $self->credential_keys ); |
969
|
|
|
|
|
|
|
} |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
######################################################################## |
972
|
|
|
|
|
|
|
sub format_credentials { |
973
|
|
|
|
|
|
|
######################################################################## |
974
|
1
|
|
|
1
|
1
|
1576
|
my ( $self, $format ) = @_; |
975
|
|
|
|
|
|
|
|
976
|
1
|
|
50
|
|
|
4
|
$format = $format || "%s %s\n"; |
977
|
|
|
|
|
|
|
|
978
|
1
|
|
|
|
|
4
|
my $credential_keys = $self->credential_keys; |
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
return join EMPTY, |
981
|
2
|
|
50
|
|
|
16
|
map { sprintf $format, $_, $credential_keys->{$_} // EMPTY } |
982
|
1
|
|
|
|
|
2
|
keys %{$credential_keys}; |
|
1
|
|
|
|
|
4
|
|
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
# +----------------------------+ |
986
|
|
|
|
|
|
|
# | CREDENTIALS getters/setter | |
987
|
|
|
|
|
|
|
# +----------------------------+ |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
######################################################################## |
990
|
|
|
|
|
|
|
sub get_aws_access_key_id { |
991
|
|
|
|
|
|
|
######################################################################## |
992
|
9
|
|
|
9
|
0
|
3502
|
my ($self) = @_; |
993
|
|
|
|
|
|
|
|
994
|
9
|
50
|
|
|
|
216
|
if ( !$self->get__access_key_id ) { |
995
|
0
|
|
|
|
|
0
|
$self->set_credentials; |
996
|
|
|
|
|
|
|
} |
997
|
|
|
|
|
|
|
|
998
|
9
|
|
|
|
|
250
|
my $access_key_id |
999
|
|
|
|
|
|
|
= $self->decrypt( $self->get__access_key_id, $self->_fetch_passkey ); |
1000
|
|
|
|
|
|
|
|
1001
|
9
|
50
|
|
|
|
182
|
if ( !$self->get_cache ) { |
1002
|
0
|
|
|
|
|
0
|
$self->set__access_key_id(undef); |
1003
|
|
|
|
|
|
|
} |
1004
|
|
|
|
|
|
|
|
1005
|
9
|
|
|
|
|
122
|
return $access_key_id; |
1006
|
|
|
|
|
|
|
} |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
######################################################################## |
1009
|
|
|
|
|
|
|
sub get_aws_secret_access_key { |
1010
|
|
|
|
|
|
|
######################################################################## |
1011
|
7
|
|
|
7
|
0
|
1247
|
my ($self) = @_; |
1012
|
|
|
|
|
|
|
|
1013
|
7
|
100
|
|
|
|
159
|
if ( !$self->get__secret_access_key ) { |
1014
|
1
|
|
|
|
|
16
|
$self->set_credentials; |
1015
|
|
|
|
|
|
|
} |
1016
|
|
|
|
|
|
|
|
1017
|
7
|
|
|
|
|
164
|
my $secret_access_key |
1018
|
|
|
|
|
|
|
= $self->decrypt( $self->get__secret_access_key, $self->_fetch_passkey ); |
1019
|
|
|
|
|
|
|
|
1020
|
7
|
50
|
|
|
|
124
|
if ( !$self->get_cache ) { |
1021
|
0
|
|
|
|
|
0
|
$self->set__secret_access_key(undef); |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
7
|
|
|
|
|
57
|
return $secret_access_key; |
1025
|
|
|
|
|
|
|
} |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
######################################################################## |
1028
|
|
|
|
|
|
|
sub get_token { |
1029
|
|
|
|
|
|
|
######################################################################## |
1030
|
5
|
|
|
5
|
0
|
15
|
my ($self) = @_; |
1031
|
|
|
|
|
|
|
|
1032
|
5
|
50
|
66
|
|
|
91
|
if ( !$self->get__session_token && $self->get_session_token_required ) { |
1033
|
0
|
|
|
|
|
0
|
$self->set_credentials; |
1034
|
|
|
|
|
|
|
} |
1035
|
|
|
|
|
|
|
|
1036
|
5
|
|
|
|
|
143
|
my $passkey = $self->_fetch_passkey; |
1037
|
5
|
|
|
|
|
88
|
my $token = $self->decrypt( $self->get__session_token, $passkey ); |
1038
|
|
|
|
|
|
|
|
1039
|
5
|
50
|
|
|
|
88
|
if ( !$self->get_cache ) { |
1040
|
0
|
|
|
|
|
0
|
$self->set__session_token(undef); |
1041
|
|
|
|
|
|
|
} |
1042
|
|
|
|
|
|
|
|
1043
|
5
|
|
|
|
|
116
|
return $token; |
1044
|
|
|
|
|
|
|
} |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
######################################################################## |
1047
|
|
|
|
|
|
|
sub set_aws_access_key_id { |
1048
|
|
|
|
|
|
|
######################################################################## |
1049
|
24
|
|
|
24
|
0
|
69
|
my ( $self, $aws_access_key_id, $passkey ) = @_; |
1050
|
|
|
|
|
|
|
|
1051
|
24
|
|
50
|
|
|
56
|
my $key = $aws_access_key_id || undef; |
1052
|
|
|
|
|
|
|
|
1053
|
24
|
50
|
|
|
|
65
|
if ($aws_access_key_id) { |
1054
|
24
|
|
|
|
|
75
|
$key = $self->encrypt( $aws_access_key_id, $passkey ); |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
|
1057
|
24
|
|
|
|
|
507
|
return $self->set__access_key_id($key); |
1058
|
|
|
|
|
|
|
} |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
######################################################################## |
1061
|
|
|
|
|
|
|
sub set_aws_secret_access_key { |
1062
|
|
|
|
|
|
|
######################################################################## |
1063
|
24
|
|
|
24
|
0
|
78
|
my ( $self, $aws_secret_access_key, $passkey ) = @_; |
1064
|
|
|
|
|
|
|
|
1065
|
24
|
|
50
|
|
|
74
|
my $key = $aws_secret_access_key || undef; |
1066
|
|
|
|
|
|
|
|
1067
|
24
|
50
|
|
|
|
66
|
if ($aws_secret_access_key) { |
1068
|
24
|
|
|
|
|
77
|
$key = $self->encrypt( $aws_secret_access_key, $passkey ); |
1069
|
|
|
|
|
|
|
} |
1070
|
|
|
|
|
|
|
|
1071
|
24
|
|
|
|
|
490
|
return $self->set__secret_access_key($key); |
1072
|
|
|
|
|
|
|
} |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
######################################################################## |
1075
|
11
|
|
|
11
|
0
|
86
|
sub set_aws_session_token { goto &set_token; } |
1076
|
0
|
|
|
0
|
0
|
0
|
sub get_aws_session_token { goto &get_token; } |
1077
|
|
|
|
|
|
|
######################################################################## |
1078
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
######################################################################## |
1080
|
|
|
|
|
|
|
sub set_token { |
1081
|
|
|
|
|
|
|
######################################################################## |
1082
|
35
|
|
|
35
|
0
|
76
|
my ( $self, $session_token, $passkey ) = @_; |
1083
|
|
|
|
|
|
|
|
1084
|
35
|
|
100
|
|
|
128
|
my $token = $session_token || undef; |
1085
|
|
|
|
|
|
|
|
1086
|
35
|
100
|
|
|
|
72
|
if ($session_token) { |
1087
|
6
|
|
|
|
|
21
|
$token = $self->encrypt( $session_token, $passkey ); |
1088
|
|
|
|
|
|
|
} |
1089
|
|
|
|
|
|
|
|
1090
|
35
|
|
|
|
|
704
|
return $self->set__session_token($token); |
1091
|
|
|
|
|
|
|
} |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
# +--------------------+ |
1094
|
|
|
|
|
|
|
# | ENCRYPTION METHODS | |
1095
|
|
|
|
|
|
|
# +--------------------+ |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
######################################################################## |
1098
|
|
|
|
|
|
|
sub decrypt { |
1099
|
|
|
|
|
|
|
######################################################################## |
1100
|
21
|
|
|
21
|
1
|
69
|
my ( $self, $str, $passkey ) = @_; |
1101
|
|
|
|
|
|
|
|
1102
|
21
|
50
|
33
|
|
|
376
|
if ( ref $self->get_decrypt && reftype( $self->get_decrypt ) eq 'CODE' ) { |
1103
|
0
|
|
0
|
|
|
0
|
return $self->get_decrypt->( $str, $passkey || $self->_fetch_passkey ); |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
else { |
1106
|
21
|
|
|
|
|
180
|
return $self->_crypt( $str, 'decrypt', $passkey ); |
1107
|
|
|
|
|
|
|
} |
1108
|
|
|
|
|
|
|
} |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
######################################################################## |
1111
|
|
|
|
|
|
|
sub encrypt { |
1112
|
|
|
|
|
|
|
######################################################################## |
1113
|
54
|
|
|
54
|
1
|
105
|
my ( $self, $str, $passkey ) = @_; |
1114
|
|
|
|
|
|
|
|
1115
|
54
|
50
|
33
|
|
|
1111
|
if ( ref $self->get_encrypt && reftype( $self->get_encrypt ) eq 'CODE' ) { |
1116
|
0
|
|
0
|
|
|
0
|
return $self->get_encrypt->( $str, $passkey || $self->_fetch_passkey ); |
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
else { |
1119
|
54
|
|
|
|
|
482
|
return $self->_crypt( $str, 'encrypt', $passkey ); |
1120
|
|
|
|
|
|
|
} |
1121
|
|
|
|
|
|
|
} |
1122
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
######################################################################## |
1124
|
|
|
|
|
|
|
sub create_passkey { |
1125
|
|
|
|
|
|
|
######################################################################## |
1126
|
0
|
|
|
0
|
0
|
0
|
return sprintf PASSKEY_FORMAT, rand RANDOM_VALUE, rand RANDOM_VALUE; |
1127
|
|
|
|
|
|
|
} |
1128
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
######################################################################## |
1130
|
|
|
|
|
|
|
sub rotate_passkey { |
1131
|
|
|
|
|
|
|
######################################################################## |
1132
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $new_passkey ) = @_; |
1133
|
|
|
|
|
|
|
|
1134
|
0
|
0
|
0
|
|
|
0
|
if ( $new_passkey && !ref $new_passkey ) { |
1135
|
0
|
0
|
|
|
|
0
|
if ( $self->get_cache ) { |
1136
|
0
|
|
|
|
|
0
|
$self->set_aws_access_key_id( $self->get_aws_access_key_id, |
1137
|
|
|
|
|
|
|
$new_passkey ); |
1138
|
|
|
|
|
|
|
|
1139
|
0
|
|
|
|
|
0
|
$self->set_aws_secret_access_key( $self->get_aws_secret_access_key, |
1140
|
|
|
|
|
|
|
$new_passkey ); |
1141
|
|
|
|
|
|
|
|
1142
|
0
|
|
|
|
|
0
|
$self->set_token( $self->get_token, $new_passkey ); |
1143
|
|
|
|
|
|
|
} |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
# if caller has his own passkey generator, don't reset |
1146
|
0
|
0
|
|
|
|
0
|
if ( !ref $self->get_passkey ) { |
1147
|
0
|
|
|
|
|
0
|
$self->set_passkey($new_passkey); |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
} |
1150
|
|
|
|
|
|
|
else { |
1151
|
0
|
|
|
|
|
0
|
$new_passkey = $self->create_passkey; |
1152
|
|
|
|
|
|
|
|
1153
|
0
|
|
|
|
|
0
|
$self->rotate_credentials($new_passkey); |
1154
|
|
|
|
|
|
|
} |
1155
|
|
|
|
|
|
|
|
1156
|
0
|
|
|
|
|
0
|
return $new_passkey; |
1157
|
|
|
|
|
|
|
} |
1158
|
|
|
|
|
|
|
|
1159
|
|
|
|
|
|
|
######################################################################## |
1160
|
|
|
|
|
|
|
sub rotate_credentials { |
1161
|
|
|
|
|
|
|
######################################################################## |
1162
|
0
|
|
|
0
|
0
|
0
|
goto &rotate_passkey; |
1163
|
|
|
|
|
|
|
} |
1164
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
######################################################################## |
1166
|
|
|
|
|
|
|
sub set_sso_credentials { |
1167
|
|
|
|
|
|
|
######################################################################## |
1168
|
0
|
|
|
0
|
1
|
0
|
my ( $role_name, $account_id, $region ) = @_; |
1169
|
|
|
|
|
|
|
|
1170
|
0
|
0
|
|
|
|
0
|
croak "usage: __PACKAGE__::set_sso_credentials(role-name, account-id)\n" |
1171
|
|
|
|
|
|
|
if ref $role_name; |
1172
|
|
|
|
|
|
|
|
1173
|
0
|
|
0
|
|
|
0
|
my $credentials = get_role_credentials( |
1174
|
|
|
|
|
|
|
role_name => $role_name, |
1175
|
|
|
|
|
|
|
account_id => $account_id, |
1176
|
|
|
|
|
|
|
region => $region // EMPTY, |
1177
|
|
|
|
|
|
|
); |
1178
|
|
|
|
|
|
|
|
1179
|
0
|
|
|
|
|
0
|
my @cred_keys = ( |
1180
|
|
|
|
|
|
|
accessKeyId => 'AWS_ACCESS_KEY_ID', |
1181
|
|
|
|
|
|
|
secretAccessKey => 'AWS_SECRET_ACCESS_KEY', |
1182
|
|
|
|
|
|
|
sessionToken => 'AWS_SESSION_TOKEN', |
1183
|
|
|
|
|
|
|
); |
1184
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# stuff credentials in environment, upstream caller will set order to 'env' |
1186
|
0
|
0
|
|
|
|
0
|
if ($credentials) { |
1187
|
0
|
|
|
|
|
0
|
foreach my $p ( pairs @cred_keys ) { |
1188
|
0
|
|
|
|
|
0
|
my ( $k, $v ) = @{$p}; |
|
0
|
|
|
|
|
0
|
|
1189
|
0
|
|
|
|
|
0
|
$ENV{$v} = $credentials->{$k}; ## no critic (RequireLocalizedPunctuationVars) |
1190
|
|
|
|
|
|
|
} |
1191
|
|
|
|
|
|
|
} |
1192
|
|
|
|
|
|
|
|
1193
|
0
|
|
|
|
|
0
|
return $credentials; |
1194
|
|
|
|
|
|
|
} |
1195
|
|
|
|
|
|
|
|
1196
|
|
|
|
|
|
|
######################################################################## |
1197
|
|
|
|
|
|
|
sub get_role_credentials { |
1198
|
|
|
|
|
|
|
######################################################################## |
1199
|
0
|
|
|
0
|
1
|
0
|
my (%args) = @_; |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
my ( $account_id, $role_name, $access_token, $region ) |
1202
|
0
|
|
|
|
|
0
|
= @args{qw(account_id role_name access_token region)}; |
1203
|
|
|
|
|
|
|
|
1204
|
0
|
0
|
|
|
|
0
|
if ( !$access_token ) { |
1205
|
0
|
|
|
|
|
0
|
$access_token = _get_access_token(); |
1206
|
|
|
|
|
|
|
} |
1207
|
|
|
|
|
|
|
|
1208
|
0
|
0
|
|
|
|
0
|
croak 'no access token' |
1209
|
|
|
|
|
|
|
if !$access_token; |
1210
|
|
|
|
|
|
|
|
1211
|
0
|
|
0
|
|
|
0
|
$region ||= $ENV{AWS_REGION} || $ENV{AWS_DEFAULT_REGION} || DEFAULT_REGION; |
|
|
|
0
|
|
|
|
|
1212
|
|
|
|
|
|
|
|
1213
|
0
|
|
|
|
|
0
|
my $ua = LWP::UserAgent->new; |
1214
|
0
|
|
|
|
|
0
|
$ua->default_header( X_AMZ_SSO_BEARER_TOKEN, $access_token ); |
1215
|
|
|
|
|
|
|
|
1216
|
0
|
|
|
|
|
0
|
my $host = sprintf GET_ROLE_CREDENTIALS_HOSTNAME, $region; |
1217
|
|
|
|
|
|
|
|
1218
|
0
|
|
|
|
|
0
|
my $query = sprintf GET_ROLE_CREDENTIALS_QUERY, $account_id, $role_name; |
1219
|
|
|
|
|
|
|
|
1220
|
0
|
|
|
|
|
0
|
my $url = sprintf 'https://%s/%s%s', $host, GET_ROLE_CREDENTIALS_URI, |
1221
|
|
|
|
|
|
|
$query; |
1222
|
|
|
|
|
|
|
|
1223
|
0
|
|
|
|
|
0
|
my $rsp = $ua->get($url); |
1224
|
|
|
|
|
|
|
|
1225
|
0
|
0
|
|
|
|
0
|
croak "no response from get($url)\n" |
1226
|
|
|
|
|
|
|
if !$rsp; |
1227
|
|
|
|
|
|
|
|
1228
|
0
|
|
|
|
|
0
|
my $content = eval { |
1229
|
0
|
0
|
0
|
|
|
0
|
return decode_json( $rsp->content ) |
1230
|
|
|
|
|
|
|
if $rsp && $rsp->content_type eq 'application/json'; |
1231
|
|
|
|
|
|
|
}; |
1232
|
|
|
|
|
|
|
|
1233
|
0
|
0
|
|
|
|
0
|
croak sprintf "could not decode response from GetRoleCredentials\n%s", |
1234
|
|
|
|
|
|
|
$EVAL_ERROR |
1235
|
|
|
|
|
|
|
if !$content; |
1236
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
return $content->{roleCredentials} |
1238
|
0
|
0
|
|
|
|
0
|
if $rsp->is_success; |
1239
|
|
|
|
|
|
|
|
1240
|
0
|
0
|
|
|
|
0
|
croak sprintf "Status: %s\n%s", $rsp->status_line, Dumper( $rsp->content ) |
1241
|
|
|
|
|
|
|
if !ref $content; |
1242
|
|
|
|
|
|
|
|
1243
|
0
|
|
|
|
|
0
|
croak sprintf "Status: %s\n%s", $rsp->status_line, $content->{message}; |
1244
|
|
|
|
|
|
|
} |
1245
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
# +-----------------+ |
1247
|
|
|
|
|
|
|
# | PRIVATE METHODS | |
1248
|
|
|
|
|
|
|
# +-----------------+ |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
######################################################################## |
1251
|
|
|
|
|
|
|
sub _init_logger { |
1252
|
|
|
|
|
|
|
######################################################################## |
1253
|
16
|
|
|
16
|
|
43
|
my ($self) = @_; |
1254
|
|
|
|
|
|
|
|
1255
|
16
|
50
|
33
|
|
|
334
|
if ( !$self->get_logger || !ref $self->get_logger ) { |
1256
|
16
|
|
|
|
|
180
|
$self->set_default_logger; |
1257
|
|
|
|
|
|
|
} |
1258
|
|
|
|
|
|
|
|
1259
|
16
|
|
|
|
|
349
|
$self->get_logger->debug( 'using ' . ref( $self->get_logger ) . ' logger' ); |
1260
|
|
|
|
|
|
|
|
1261
|
16
|
|
|
|
|
41
|
return $self; |
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
######################################################################## |
1265
|
|
|
|
|
|
|
sub _set_defaults { |
1266
|
|
|
|
|
|
|
######################################################################## |
1267
|
18
|
|
|
18
|
|
40
|
my ($self) = @_; |
1268
|
|
|
|
|
|
|
|
1269
|
18
|
|
100
|
|
|
521
|
$self->set_debug( $self->get_debug // FALSE ); |
1270
|
|
|
|
|
|
|
|
1271
|
18
|
50
|
|
|
|
1011
|
$self->set_cache( defined $self->get_cache ? $self->get_cache : TRUE ); |
1272
|
|
|
|
|
|
|
|
1273
|
18
|
50
|
|
|
|
837
|
if ( !$self->get_user_agent ) { |
1274
|
|
|
|
|
|
|
# set a very low timeout |
1275
|
18
|
|
50
|
|
|
542
|
$self->set_user_agent( |
1276
|
|
|
|
|
|
|
LWP::UserAgent->new( timeout => $self->get_timeout || DEFAULT_TIMEOUT ) |
1277
|
|
|
|
|
|
|
); |
1278
|
|
|
|
|
|
|
} |
1279
|
|
|
|
|
|
|
|
1280
|
18
|
|
|
|
|
18542
|
my $default_search_order = [ split /\s*,\s*/xsm, DEFAULT_SEARCH_ORDER ]; |
1281
|
|
|
|
|
|
|
|
1282
|
18
|
100
|
|
|
|
398
|
if ( !$self->get_order ) { |
1283
|
7
|
|
|
|
|
156
|
$self->set_order($default_search_order); |
1284
|
|
|
|
|
|
|
} |
1285
|
|
|
|
|
|
|
|
1286
|
18
|
100
|
66
|
|
|
487
|
if ( !ref $self->get_order ) { |
|
|
100
|
|
|
|
|
|
1287
|
3
|
|
|
|
|
162
|
$self->set_order( [ split /\s*,\s*/xsm, $self->get_order ] ); |
1288
|
|
|
|
|
|
|
} |
1289
|
|
|
|
|
|
|
elsif ( ref $self->get_order && reftype( $self->get_order ) ne 'ARRAY' ) { |
1290
|
1
|
|
|
|
|
208
|
croak 'order must be a comma delimited string or array ref'; |
1291
|
|
|
|
|
|
|
} |
1292
|
|
|
|
|
|
|
|
1293
|
17
|
|
|
|
|
954
|
foreach my $loc ( @{ $self->get_order } ) { |
|
17
|
|
|
|
|
286
|
|
1294
|
|
|
|
|
|
|
croak "invalid credential location in search order: [$loc]" |
1295
|
38
|
100
|
|
102
|
|
223
|
if !any {/^$loc$/xsm} @{$default_search_order}; |
|
102
|
|
|
|
|
1062
|
|
|
38
|
|
|
|
|
119
|
|
1296
|
|
|
|
|
|
|
} |
1297
|
|
|
|
|
|
|
|
1298
|
16
|
100
|
100
|
5
|
|
387
|
if ( !$self->get_profile && any {/file/xsm} @{ $self->get_order } ) { |
|
5
|
|
|
|
|
67
|
|
|
5
|
|
|
|
|
199
|
|
1299
|
2
|
|
|
|
|
44
|
$self->set_profile( $ENV{AWS_PROFILE} ); |
1300
|
|
|
|
|
|
|
} |
1301
|
|
|
|
|
|
|
|
1302
|
16
|
|
100
|
|
|
473
|
$self->set_raise_error( $self->get_raise_error // TRUE ); |
1303
|
16
|
|
100
|
|
|
881
|
$self->set_print_error( $self->get_print_error // TRUE ); |
1304
|
|
|
|
|
|
|
|
1305
|
16
|
|
|
|
|
586
|
return $self; |
1306
|
|
|
|
|
|
|
} |
1307
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
######################################################################## |
1309
|
|
|
|
|
|
|
# note that $passkey is a class variable and as such, once initialized |
1310
|
|
|
|
|
|
|
# in the fashion below, will persist for all instances of |
1311
|
|
|
|
|
|
|
# Amazon::Credentials |
1312
|
|
|
|
|
|
|
######################################################################## |
1313
|
|
|
|
|
|
|
{ |
1314
|
|
|
|
|
|
|
my $passkey; |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
######################################################################## |
1317
|
|
|
|
|
|
|
sub get_passkey { |
1318
|
|
|
|
|
|
|
######################################################################## |
1319
|
216
|
|
|
216
|
0
|
489
|
return $passkey; |
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
######################################################################## |
1323
|
|
|
|
|
|
|
sub set_passkey { |
1324
|
|
|
|
|
|
|
######################################################################## |
1325
|
16
|
|
|
16
|
0
|
31
|
my ( $self, $key ) = @_; |
1326
|
|
|
|
|
|
|
|
1327
|
16
|
|
|
|
|
25
|
$passkey = $key; |
1328
|
|
|
|
|
|
|
|
1329
|
16
|
|
|
|
|
21
|
return $passkey; |
1330
|
|
|
|
|
|
|
} |
1331
|
|
|
|
|
|
|
} |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
######################################################################## |
1334
|
|
|
|
|
|
|
sub _fetch_passkey { |
1335
|
|
|
|
|
|
|
######################################################################## |
1336
|
92
|
|
|
92
|
|
221
|
my ($self) = @_; |
1337
|
|
|
|
|
|
|
|
1338
|
92
|
|
|
|
|
116
|
my $passkey = eval { |
1339
|
92
|
50
|
33
|
|
|
178
|
if ( ref $self->get_passkey && reftype( $self->get_passkey ) eq 'CODE' ) { |
1340
|
0
|
|
|
|
|
0
|
return $self->get_passkey->(); |
1341
|
|
|
|
|
|
|
} |
1342
|
|
|
|
|
|
|
else { |
1343
|
92
|
|
|
|
|
161
|
return $self->get_passkey; |
1344
|
|
|
|
|
|
|
} |
1345
|
|
|
|
|
|
|
}; |
1346
|
|
|
|
|
|
|
|
1347
|
92
|
|
|
|
|
231
|
return $passkey; |
1348
|
|
|
|
|
|
|
} |
1349
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
######################################################################## |
1351
|
|
|
|
|
|
|
sub _init_encryption { |
1352
|
|
|
|
|
|
|
######################################################################## |
1353
|
16
|
|
|
16
|
|
40
|
my ( $self, $passkey ) = @_; |
1354
|
|
|
|
|
|
|
|
1355
|
16
|
|
|
|
|
56
|
$self->set_passkey($passkey); |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
# if one is set, both must be set |
1358
|
16
|
50
|
33
|
|
|
348
|
if ( $self->get_encrypt || $self->get_decrypt ) { |
1359
|
0
|
0
|
|
|
|
0
|
croak 'must be a code reference to encrypt()' |
1360
|
|
|
|
|
|
|
if ref $self->get_encrypt ne 'CODE'; |
1361
|
|
|
|
|
|
|
|
1362
|
0
|
0
|
|
|
|
0
|
croak 'must be a code reference to decrypt()' |
1363
|
|
|
|
|
|
|
if ref $self->get_decrypt ne 'CODE'; |
1364
|
|
|
|
|
|
|
|
1365
|
0
|
|
|
|
|
0
|
$self->set_encryption(TRUE); |
1366
|
|
|
|
|
|
|
} |
1367
|
|
|
|
|
|
|
else { |
1368
|
16
|
|
|
|
|
578
|
my $has_crypt_cbc = eval { |
1369
|
16
|
|
|
|
|
2334
|
require Crypt::CBC; |
1370
|
0
|
|
|
|
|
0
|
require Crypt::Cipher::AES; |
1371
|
|
|
|
|
|
|
}; |
1372
|
|
|
|
|
|
|
|
1373
|
16
|
50
|
|
|
|
445
|
if ( !defined $self->get_encryption ) { |
1374
|
|
|
|
|
|
|
# let's make the default to encrypt (if we can) |
1375
|
16
|
50
|
|
|
|
506
|
$self->set_encryption( $has_crypt_cbc ? TRUE : FALSE ); |
1376
|
|
|
|
|
|
|
} |
1377
|
|
|
|
|
|
|
else { |
1378
|
|
|
|
|
|
|
# don't allow encryption if Crypt::CBC not present |
1379
|
0
|
|
0
|
|
|
0
|
$self->set_encryption( $self->get_encryption && $has_crypt_cbc ); |
1380
|
|
|
|
|
|
|
} |
1381
|
|
|
|
|
|
|
|
1382
|
16
|
50
|
33
|
|
|
438
|
if ( $self->get_encryption && !$self->get_cipher ) { |
1383
|
0
|
|
|
|
|
0
|
$self->set_cipher(DEFAULT_CIPHER); |
1384
|
|
|
|
|
|
|
} |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
} |
1387
|
|
|
|
|
|
|
|
1388
|
16
|
50
|
33
|
|
|
369
|
if ( $self->get_encryption && !$self->get_passkey ) { |
1389
|
0
|
|
|
|
|
0
|
$self->set_passkey( $self->create_passkey ); |
1390
|
|
|
|
|
|
|
} |
1391
|
|
|
|
|
|
|
|
1392
|
16
|
|
|
|
|
394
|
return $self->get_encryption; |
1393
|
|
|
|
|
|
|
} |
1394
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
######################################################################## |
1396
|
|
|
|
|
|
|
sub _crypt { |
1397
|
|
|
|
|
|
|
######################################################################## |
1398
|
75
|
|
|
75
|
|
174
|
my ( $self, $str, $op, $passkey ) = @_; |
1399
|
|
|
|
|
|
|
|
1400
|
75
|
100
|
|
|
|
141
|
return if !$str; |
1401
|
|
|
|
|
|
|
|
1402
|
71
|
|
33
|
|
|
252
|
$passkey = $passkey || $self->_fetch_passkey(); |
1403
|
|
|
|
|
|
|
|
1404
|
71
|
|
|
|
|
82
|
my $cipher; |
1405
|
|
|
|
|
|
|
|
1406
|
71
|
50
|
|
|
|
1317
|
if ( $self->get_encryption ) { |
1407
|
0
|
|
|
|
|
0
|
$cipher = Crypt::CBC->new( |
1408
|
|
|
|
|
|
|
'-pass' => $passkey, |
1409
|
|
|
|
|
|
|
'-key' => $passkey, |
1410
|
|
|
|
|
|
|
'-cipher' => $self->get_cipher, |
1411
|
|
|
|
|
|
|
'-nodeprecate' => TRUE, |
1412
|
|
|
|
|
|
|
); |
1413
|
|
|
|
|
|
|
} |
1414
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
# at least obfuscate the credentials |
1416
|
71
|
100
|
|
|
|
452
|
if ( $op eq 'decrypt' ) { |
1417
|
17
|
|
|
|
|
74
|
$str = decode_base64($str); |
1418
|
17
|
50
|
|
|
|
34
|
$str = ref $cipher ? $cipher->decrypt($str) : $str; |
1419
|
|
|
|
|
|
|
} |
1420
|
|
|
|
|
|
|
else { |
1421
|
54
|
50
|
|
|
|
131
|
$str = ref $cipher ? $cipher->encrypt($str) : $str; |
1422
|
54
|
|
|
|
|
203
|
$str = encode_base64($str); |
1423
|
|
|
|
|
|
|
} |
1424
|
|
|
|
|
|
|
|
1425
|
71
|
|
|
|
|
173
|
return $str; |
1426
|
|
|
|
|
|
|
} |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
######################################################################## |
1429
|
|
|
|
|
|
|
sub _iso8601_to_time { |
1430
|
|
|
|
|
|
|
######################################################################## |
1431
|
4
|
|
|
4
|
|
7
|
my $iso8601 = shift; |
1432
|
|
|
|
|
|
|
|
1433
|
4
|
|
|
|
|
28
|
$iso8601 =~ s/^(.*)Z$/$1\+00:00/xsm; |
1434
|
|
|
|
|
|
|
|
1435
|
4
|
|
|
|
|
9
|
my $gmtime = eval { |
1436
|
4
|
|
|
|
|
23
|
local $ENV{TZ} = 'GMT'; |
1437
|
|
|
|
|
|
|
|
1438
|
4
|
|
|
|
|
115
|
timegm( strptime( $iso8601, ISO8601_FORMAT ) ); |
1439
|
|
|
|
|
|
|
}; |
1440
|
|
|
|
|
|
|
|
1441
|
4
|
|
|
|
|
182
|
return $gmtime; |
1442
|
|
|
|
|
|
|
} |
1443
|
|
|
|
|
|
|
|
1444
|
|
|
|
|
|
|
######################################################################## |
1445
|
|
|
|
|
|
|
sub _create_metadata_url { |
1446
|
|
|
|
|
|
|
######################################################################## |
1447
|
1
|
|
|
1
|
|
4
|
my ($url) = @_; |
1448
|
|
|
|
|
|
|
|
1449
|
1
|
|
|
|
|
4
|
return AWS_METADATA_BASE_URL . $url; |
1450
|
|
|
|
|
|
|
} |
1451
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
######################################################################## |
1453
|
|
|
|
|
|
|
sub _get_access_token { |
1454
|
|
|
|
|
|
|
######################################################################## |
1455
|
0
|
|
|
0
|
|
0
|
my ($home) = @_; |
1456
|
|
|
|
|
|
|
|
1457
|
0
|
|
|
|
|
0
|
require File::Find; |
1458
|
|
|
|
|
|
|
|
1459
|
0
|
|
|
|
|
0
|
File::Find->import('find'); |
1460
|
|
|
|
|
|
|
|
1461
|
0
|
|
0
|
|
|
0
|
$home //= $ENV{HOME}; |
1462
|
0
|
|
|
|
|
0
|
my $cache_dir = sprintf '%s/%s', $home, CACHE_DIR; |
1463
|
|
|
|
|
|
|
|
1464
|
0
|
0
|
|
|
|
0
|
croak "no $cache_dir found." |
1465
|
|
|
|
|
|
|
if !-d $cache_dir; |
1466
|
|
|
|
|
|
|
|
1467
|
0
|
|
|
|
|
0
|
my $access_token; |
1468
|
|
|
|
|
|
|
|
1469
|
0
|
|
|
|
|
0
|
my $cwd = getcwd; |
1470
|
|
|
|
|
|
|
|
1471
|
0
|
|
|
|
|
0
|
eval { |
1472
|
|
|
|
|
|
|
|
1473
|
|
|
|
|
|
|
find( |
1474
|
|
|
|
|
|
|
sub { |
1475
|
0
|
0
|
|
0
|
|
0
|
return if !/[.]json$/xsm; |
1476
|
|
|
|
|
|
|
|
1477
|
0
|
|
|
|
|
0
|
local $RS = undef; |
1478
|
|
|
|
|
|
|
|
1479
|
0
|
0
|
|
|
|
0
|
open my $fh, '<', $File::Find::name |
1480
|
|
|
|
|
|
|
or croak 'could not open ' . $File::Find::name; |
1481
|
|
|
|
|
|
|
|
1482
|
0
|
|
|
|
|
0
|
my $json = eval { decode_json(<$fh>) }; |
|
0
|
|
|
|
|
0
|
|
1483
|
|
|
|
|
|
|
|
1484
|
0
|
|
|
|
|
0
|
close $fh; |
1485
|
|
|
|
|
|
|
|
1486
|
0
|
0
|
0
|
|
|
0
|
if ( ref $json && $json->{accessToken} ) { |
1487
|
0
|
|
|
|
|
0
|
$access_token = $json->{accessToken}; |
1488
|
0
|
|
|
|
|
0
|
croak 'found'; |
1489
|
|
|
|
|
|
|
} |
1490
|
|
|
|
|
|
|
|
1491
|
0
|
|
|
|
|
0
|
return; |
1492
|
|
|
|
|
|
|
}, |
1493
|
0
|
|
|
|
|
0
|
$cache_dir |
1494
|
|
|
|
|
|
|
); |
1495
|
|
|
|
|
|
|
}; |
1496
|
|
|
|
|
|
|
|
1497
|
0
|
|
|
|
|
0
|
CORE::chdir $cwd; |
1498
|
|
|
|
|
|
|
|
1499
|
0
|
|
|
|
|
0
|
return $access_token; |
1500
|
|
|
|
|
|
|
} |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
####################################################################### |
1503
|
|
|
|
|
|
|
sub help { |
1504
|
|
|
|
|
|
|
######################################################################## |
1505
|
|
|
|
|
|
|
|
1506
|
0
|
|
|
0
|
0
|
0
|
print {*STDOUT} <<'END_OF_USAGE'; |
|
0
|
|
|
|
|
0
|
|
1507
|
|
|
|
|
|
|
amazon-credentials.sh options |
1508
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
Formats credentials found in env, config, SSO, role |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
Options |
1512
|
|
|
|
|
|
|
------- |
1513
|
|
|
|
|
|
|
--help, -h this |
1514
|
|
|
|
|
|
|
--ec2, -E get credentials from server IAM profile |
1515
|
|
|
|
|
|
|
--env -e get credentials from environment variables |
1516
|
|
|
|
|
|
|
--profile, -p get credentials from profile in credentials configuration |
1517
|
|
|
|
|
|
|
--role, -r get credentials from SSO role |
1518
|
|
|
|
|
|
|
--account, -a use with --role, specify AWS account id |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
$ amazon-credentials.sh --profile=test |
1521
|
|
|
|
|
|
|
export AWS_ACCESS_KEY_ID=AKI***************** |
1522
|
|
|
|
|
|
|
export AWS_SECRET_ACCESS_KEY=**************************************** |
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
$ aws sso login |
1525
|
|
|
|
|
|
|
$ amazon-credentials.sh --role my-sso-role --account 01234567890 |
1526
|
|
|
|
|
|
|
END_OF_USAGE |
1527
|
|
|
|
|
|
|
|
1528
|
0
|
|
|
|
|
0
|
exit 0; |
1529
|
|
|
|
|
|
|
} |
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
######################################################################## |
1532
|
|
|
|
|
|
|
sub export_credentials { |
1533
|
|
|
|
|
|
|
######################################################################## |
1534
|
1
|
|
|
1
|
0
|
4638
|
my ($credentials) = @_; |
1535
|
|
|
|
|
|
|
|
1536
|
1
|
|
50
|
|
|
14
|
$credentials //= \%ENV; |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
my @cred_keys |
1539
|
1
|
|
|
|
|
41
|
= qw(AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN); |
1540
|
|
|
|
|
|
|
|
1541
|
1
|
50
|
|
|
|
4
|
@cred_keys = map { defined $credentials->{$_} ? $_ : () } @cred_keys; |
|
3
|
|
|
|
|
10
|
|
1542
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
return join "\n", |
1544
|
1
|
|
|
|
|
3
|
map { sprintf 'export %s=%s', $_, $credentials->{$_} } @cred_keys; |
|
3
|
|
|
|
|
14
|
|
1545
|
|
|
|
|
|
|
} |
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
######################################################################## |
1548
|
|
|
|
|
|
|
sub main { |
1549
|
|
|
|
|
|
|
######################################################################## |
1550
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
1551
|
|
|
|
|
|
|
|
1552
|
11
|
|
|
11
|
|
9640
|
use Getopt::Long qw(:config no_ignore_case); |
|
11
|
|
|
|
|
119012
|
|
|
11
|
|
|
|
|
62
|
|
1553
|
|
|
|
|
|
|
|
1554
|
0
|
|
|
|
|
|
my %options; |
1555
|
|
|
|
|
|
|
|
1556
|
0
|
0
|
|
|
|
|
if ( |
1557
|
|
|
|
|
|
|
!GetOptions( |
1558
|
|
|
|
|
|
|
\%options, 'help', 'env|e', 'ec2|E', |
1559
|
|
|
|
|
|
|
'profile|p=s', 'role|r=s', 'account|a=s' |
1560
|
|
|
|
|
|
|
) |
1561
|
|
|
|
|
|
|
) { |
1562
|
0
|
|
|
|
|
|
help(); |
1563
|
|
|
|
|
|
|
} |
1564
|
|
|
|
|
|
|
|
1565
|
0
|
0
|
|
|
|
|
if ( $options{help} ) { |
1566
|
0
|
|
|
|
|
|
help(); |
1567
|
|
|
|
|
|
|
} |
1568
|
|
|
|
|
|
|
|
1569
|
0
|
0
|
0
|
|
|
|
if ( $options{role} && $options{account} ) { |
1570
|
|
|
|
|
|
|
my $credentials = Amazon::Credentials::set_sso_credentials( |
1571
|
0
|
|
|
|
|
|
@options{qw(role account region)} ); |
1572
|
|
|
|
|
|
|
|
1573
|
0
|
|
|
|
|
|
print {*STDOUT} export_credentials($credentials); |
|
0
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
|
1575
|
0
|
|
|
|
|
|
exit 0; |
1576
|
|
|
|
|
|
|
} |
1577
|
|
|
|
|
|
|
|
1578
|
0
|
|
|
|
|
|
my @order; |
1579
|
|
|
|
|
|
|
|
1580
|
0
|
0
|
|
|
|
|
if ( $options{env} ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1581
|
0
|
|
|
|
|
|
push @order, 'env'; |
1582
|
|
|
|
|
|
|
} |
1583
|
|
|
|
|
|
|
elsif ( $options{ec2} ) { |
1584
|
0
|
|
|
|
|
|
push @order, 'ec2'; |
1585
|
|
|
|
|
|
|
} |
1586
|
|
|
|
|
|
|
elsif ( $options{profile} ) { |
1587
|
0
|
|
|
|
|
|
push @order, 'file'; |
1588
|
|
|
|
|
|
|
} |
1589
|
|
|
|
|
|
|
|
1590
|
|
|
|
|
|
|
my $creds = $self->new( |
1591
|
0
|
0
|
0
|
|
|
|
profile => $options{profile} // EMPTY, |
1592
|
|
|
|
|
|
|
order => ( @order ? \@order : DEFAULT_SEARCH_ORDER ) |
1593
|
|
|
|
|
|
|
); |
1594
|
|
|
|
|
|
|
|
1595
|
0
|
|
|
|
|
|
print {*STDOUT} $creds->format_credentials("export %s=%s\n"); |
|
0
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
|
1597
|
0
|
|
|
|
|
|
exit 0; |
1598
|
|
|
|
|
|
|
} |
1599
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
1; |
1601
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
__END__ |