view release on metacpan or search on metacpan
Tue Dec 11 12:53:58 2018 Rob Lauer <rlauer6@comcast.net>
[1.0.10-1]:
* configure.ac: bump release
* cpan/Makefile.am: rename tarball for minor release only
* src/main/perl/t/02-credentials.t: GMT, not UTC
* README.md: mention 'make cpan'
* cpan/extra-files: new
Mon Dec 10 13:44:31 2018 Rob Lauer <rlauer6@comcast.net>
[1.0.10]:
* ChangeLog: new
* bootstrap: new
* configure.ac
- bump minor release
ChangeLog
lib/Amazon/Credentials.pm
Makefile.PL
MANIFEST This list of files
t/00-credentials.t
t/01-credentials.t
t/02-credentials.t
META.yml Module YAML meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)
{
"abstract" : "AWS credentials discoverer",
"author" : [
"Rob Lauer <rlauer6@comcast.net>"
],
"dynamic_config" : 1,
"generated_by" : "ExtUtils::MakeMaker version 6.68, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
---
abstract: 'AWS credentials discoverer'
author:
- 'Rob Lauer <rlauer6@comcast.net>'
build_requires:
Data::Dumper: '2.145'
Date::Format: '2.24'
ExtUtils::MakeMaker: '0'
File::Path: '2.09'
File::Temp: '0.2301'
JSON: '2.59'
Module::Loaded: '0.08'
Makefile.PL view on Meta::CPAN
use strict;
use warnings;
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'Amazon::Credentials',
AUTHOR => 'Rob Lauer <rlauer6@comcast.net>',
VERSION_FROM => 'lib/Amazon/Credentials.pm',
ABSTRACT => 'AWS credentials discoverer',
LICENSE => 'perl',
PL_FILES => {},
PREREQ_PM => {
'Class::Accessor' => '0.31',
'Data::Dumper' => '2.145',
'Date::Format' => '2.24',
'Exporter' => '5.68',
'File::HomeDir' => '1.00',
'File::chdir' => '0.1008',
'HTTP::Request' => '6.00',
lib/Amazon/Credentials.pm view on Meta::CPAN
use Data::Dumper;
use Date::Format;
use Exporter;
use HTTP::Request;
use JSON;
use LWP::UserAgent;
use POSIX::strptime qw/strptime/;
use Time::Local;
use Scalar::Util qw/reftype/;
use constant AWS_IAM_SECURITY_CREDENTIALS_URL => 'http://169.254.169.254/latest/meta-data/iam/security-credentials/';
use constant AWS_AVAILABILITY_ZONE_URL => 'http://169.254.169.254/latest/meta-data/placement/availability-zone';
use constant AWS_CONTAINER_CREDENTIALS_URL => 'http://169.254.170.2';
use vars qw/$VERSION @EXPORT/;
$VERSION = '1.0.10-1'; $VERSION=~s/\-.*$//;
@EXPORT = qw/$VERSION/;
# we only log at debug level, create a default logger
lib/Amazon/Credentials.pm view on Meta::CPAN
=head1 NAME
C<AWS::Credentials>
=head1 SYNOPSIS
my $aws_creds = new Amazon::Credentials({order => [qw/env file container role/]});
=head1 DESCRIPTION
Class to find AWS credentials from either the environment,
configuration files, instance meta-data or container role.
You can specify the order using the C<order> option in the constructor
to determine the order in which the class will look for credentials.
The default order is I<environent>, I<file>, I<container>, I<instance
meta-data>. See L</new>.
=head1 METHODS
=head2 new
new( options );
my $aws_creds = new Amazon::Credential( { profile => 'sandbox', debug => 1 });
lib/Amazon/Credentials.pm view on Meta::CPAN
=item aws_access_key_id
AWS access key.
=item aws_secret_access_key
AWS secret access key.
I<Note: If you pass the access keys in the constructor then the
constructor will not look in other places for credentials.>
=item debug
Set to true for verbose troubleshooting information.
=item logger
Pass in your own logger that has a C<debug()> method. Otherwise the
default logger will output debug messages to STDERR.
=item user_agent
Pass in your own user agent, otherwise LWP will be used. I<Probably
only useful to override this for testing purposes.>
=item profile
The profile name in the configuration file (F<~/.aws/config> or
F<~/.aws/credentials>).
my $aws_creds = new Amazon::Credentials({ profile => 'sandbox' });
The class will also look for the environment variable C<AWS_PROFILE>,
so you can invoke your script like this:
$ AWS_PROFILE=sandbox my-script.pl
=item order
An array reference containing tokens that specifies the order in which the class will
search for credentials.
default: role, env, file
Example:
my $creds = new Amazon::Credentials( { order => [ qw/file env role/] });
=over 5
=item env - Environment
If there exists an environment variable $AWS_PROFILE, then an attempt
will be made to retrieve credentials from the credentials file using
that profile, otherwise we'll look for these environment variables to
provide credentials.
C<AWS_ACCESS_KEY_ID>
C<AWS_SECRET_ACCESS_KEY>
C<AWS_SESSION_TOKEN>
I<Note that when you set the environment variable AWS_PROFILE, the
order essentially is overridden and we'll look in your credential
files (F<~/.aws/config>, F<~/.aws/credentials>) for your credentials.
=item file - Configuration Files
=over 10
=item ~/.aws/config
=item ~/.aws/credentials
=back
The class will attempt to find the credentials in either of these two
files. You can also specify a profile to use for looking up the
credentials by passing it into the constructor or setting in an the
environment variable C<AWS_PROFILE>. If no profile is provided, the
default credentials or the first profile found is used.
my $aws_creds = new Amazon::Credentials({ order => [qw/environment role file/] });
=item container - Task Role
If the process is running in a container, the container may have a
task role. We'll look credentials using the container metadata
service.
http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
=item role - Instance Role
The class will use the
I<http://169.254.169.254/latest/meta-data/iam/security-credential> URL
to look for an instance role and credentials.
Keep in mind that these credentials include a token that needs to be
passed to Amazon APIs when using the credentials returned when using
instance meta-data. That token has an expiration and should be
refreshed as required.
if ( $aws_creds->is_token_expired() ) {
$aws_creds->refresh_token()
}
=back
=item region
lib/Amazon/Credentials.pm view on Meta::CPAN
$self->set_user_agent(new LWP::UserAgent);
}
$self->set_profile($ENV{AWS_PROFILE})
unless $self->get_profile;
$self->set_region($ENV{AWS_REGION} || $self->get_default_region)
unless $self->get_region;
unless ( $self->get_aws_secret_access_key && $self->get_aws_access_key_id ) {
$self->set_credentials;
}
$self;
}
=pod
=head2 get_default_region
Returns the region of the currently running instance. The constructor
lib/Amazon/Credentials.pm view on Meta::CPAN
You can also invoke this as a class method:
$ AWS_REGION=$(perl -MAmazon::Credentials -e 'print Amazon::Credentials::get_default_region;')
=cut
sub get_default_region {
my $self = shift;
# try to get credentials from instance role, but we may not be
# executing on an EC2 or container.
my $url = AWS_AVAILABILITY_ZONE_URL;
my $ua = ref($self) ? $self->get_user_agent : new LWP::UserAgent;
my $req = HTTP::Request->new( GET => $url );
my $region = eval {
my $rsp = $ua->request($req);
lib/Amazon/Credentials.pm view on Meta::CPAN
my $region = $rsp->content;
$region =~s/([0-9]+)[a-z]+$/$1/;
$region;
};
return $region;
}
sub set_credentials {
my $self = shift;
my $creds = shift || $self->get_ec2_credentials();
if ( $creds->{aws_secret_access_key} && $creds->{aws_access_key_id} ) {
$self->set_aws_secret_access_key($creds->{aws_secret_access_key});
$self->set_aws_access_key_id($creds->{aws_access_key_id});
$self->set_token($creds->{token});
$self->set_expiration($creds->{expiration});
}
else {
die "no credentials available\n";
}
}
=pod
=head2 get_ec2_credentials (deprecated)
=head2 find_credentidals
find_credentials( option => value, ...);
You normally don't want to use this method. It's automatically invoked
by the constructor if you don't pass in any credentials. Accepts a
hash or hash reference consisting of keys (C<order> or C<profile>) in
the same manner as the constructor.
=cut
sub get_ec2_credentials {
goto &find_credentials;
}
sub find_credentials {
my $self = shift;
my %options = ref($_[0]) ? %{$_[0]} : @_;
$options{order} = $self->get_order || [ qw/env role container file/ ];
$options{profile} = $options{profile} || $self->get_profile;
if (defined $options{profile} ) {
$options{order} = ['file'];
}
lib/Amazon/Credentials.pm view on Meta::CPAN
$creds = $self->get_creds_from_container();
last if ! $@ && $creds->{container};
};
/role/ && do {
$creds = $self->get_creds_from_role();
last if ! $@ && $creds->{role};
};
/file/ && do {
# look for ~/.aws/config and/or .aws/credentials
use File::chdir;
use File::HomeDir;
foreach my $config ( ".aws/config", ".aws/credentials" ) {
# reset this since we have hav
my $profile_name = $options{profile};
local $CWD = home;
next unless -e $config;
open my $fh, "<$config" or die "could not open credentials file!";
my $last_profile = '';
my $profile_to_find = $profile_name;
# look for credentials...by interating through credentials file
while (<$fh>) {
chomp;
my $current_line = $_;
# once we find a profile section that matches, undef it
# ./aws/credentials uses [profile-name]
# ./aws/config uses [profile profile-name]
if (/^\s*region\s*=\s*(.*?)\s*$/ ) {
my $region = $1;
# go ahead and use this region setting IF:
# 1. this is the default profile (we may reset region later though)
# 2. the profile we want to use is this profile
# 3. we are not in a profile at all (this is yet another default)
if ( $last_profile =~/default/ ||
($profile_to_find && $last_profile =~/$profile_to_find/) ||
lib/Amazon/Credentials.pm view on Meta::CPAN
=pod
=head2 is_token_expired
is_token_expired( window-interval )
Returns true if the token is about to expire (or is
expired). C<window-interval> is the time in minutes before the actual
expiration time that the method should consider the token expired.
The default is 5 minutes. Amazon states that new credentials will be
available I<at least> 5 minutes before a token expires.
=cut
sub is_token_expired {
my $self = shift;
my $window_interval = shift || 5;
my $expiration_date = $self->get_expiration();
my $expired = 0;
if ( defined $expiration_date ) {
# AWS recommends getting credentials 5 minutes prior to expiration
my $g = _iso8601_to_time($expiration_date);
# shave 5 minutes or window interval off of the expiration time
$g -= $window_interval * 60;
# (expiration_time - window_interval) - current_time = # of seconds left before expiration
my $seconds_left = $g - time;
if ( $self->get_debug ) {
my $hours = int($seconds_left/3600);
lib/Amazon/Credentials.pm view on Meta::CPAN
=item expiration
Token expiration date.
=item role
IAM role if available.
=item source
Will be 'IAM' if role and credentials found.
=back
=cut
sub get_creds_from_role {
my $self = shift;
my $creds = {};
# try to get credentials from instance role
my $url = AWS_IAM_SECURITY_CREDENTIALS_URL;
my $ua = $self->get_user_agent;
my $role;
eval {
# could be infinite, but I don't think so. Either we get an
# error ($@), or a non-200 response code
while ( ! $creds->{token} ) {
lib/Amazon/Credentials.pm view on Meta::CPAN
$creds->{error} = $@ if $@;
$creds;
}
=pod
=head2 refresh_token
refresh_token() (deprecated)
refresh_credentials()
Retrieves a fresh set of IAM credentials.
if ( $creds->is_token_expired ) {
$creds->refresh_token()
}
=cut
sub refresh_credentials {
goto &refresh_token;
}
sub refresh_token {
my $self = shift;
my $creds;
if ( $self->get_role && $self->get_role eq 'ECS' ) {
$creds = $self->get_creds_from_container;
}
elsif ( $self->get_role ) {
$creds = $self->get_creds_from_role;
}
$self->get_logger->debug(Dumper [$creds])
if $self->get_debug;
die "unable to refresh token!"
unless ref($creds);
$self->set_credentials($creds);
}
sub get_creds_from_container {
my $self = shift;
my $creds = {};
if ( exists $ENV{AWS_CONTAINER_CREDENTIALS_RELATIVE_URI} ) {
# try to get credentials from instance role
my $url = sprintf("%s%s", AWS_CONTAINER_CREDENTIALS_URL, $ENV{AWS_CONTAINER_CREDENTIALS_RELATIVE_URI});
my $ua = $self->get_user_agent;
my $req = HTTP::Request->new( GET => $url );
$req->header("Accept", "*/*");
$self->get_logger->debug(Dumper [ "HTTP REQUEST:\n", $req ])
if $self->get_debug;
$self->get_logger->debug(Dumper [ $req->as_string ])
t/01-credentials.t view on Meta::CPAN
use Test::More tests => 6;
use File::Temp qw/:mktemp/;
use File::Path;
use Data::Dumper;
BEGIN {
use_ok('Amazon::Credentials');
}
my $home = mkdtemp("amz-credentials-XXXXX");
my $credentials_file = eval {
mkdir "$home/.aws";
open (my $fh, ">$home/.aws/credentials") or BAIL_OUT("could not create temporary credentials file");
print $fh <<eot;
[default]
region = us-west-1
[foo]
aws_access_key_id=foo-aws-access-key-id
aws_secret_access_key=foo-aws-secret-access-key
[bar]
aws_access_key_id=bar-aws-access-key-id
aws_secret_access_key=bar-aws-secret-access-key
region = us-east-1
eot
close $fh;
"$home/.aws/credentials";
};
$ENV{HOME} = "$home";
$ENV{AWS_PROFILE} = undef;
my $creds = new Amazon::Credentials({ order => [qw/file/]});
ok(ref($creds), 'find credentials');
is($creds->get_aws_access_key_id, 'foo-aws-access-key-id', 'default profile');
is($creds->get_region, 'us-west-1', 'default region');
print "wtf\n";
$creds = new Amazon::Credentials({ profile => 'bar', order => [qw/file/], region => 'foo'});
is($creds->{aws_access_key_id}, 'bar-aws-access-key-id', 'retrieve profile');
is($creds->get_region, 'us-east-1', 'region');
t/02-credentials.t view on Meta::CPAN
use Module::Loaded;
mark_as_loaded(HTTP::Request);
mark_as_loaded(HTTP::Response);
mark_as_loaded(LWP::UserAgent);
use_ok('Amazon::Credentials');
}
my $home = mkdtemp("amz-credentials-XXXXX");
my $credentials_file = eval {
mkdir "$home/.aws";
open (my $fh, ">$home/.aws/credentials") or BAIL_OUT("could not create temporary credentials file");
print $fh <<eot;
[foo]
aws_access_key_id=foo-aws-access-key-id
aws_secret_access_key=foo-aws-secret-access-key
[bar]
aws_access_key_id=bar-aws-access-key-id
aws_secret_access_key=bar-aws-secret-access-key
eot
close $fh;
"$home/.aws/credentials";
};
$ENV{HOME} = "$home";
$ENV{AWS_PROFILE} = undef;
my $creds = new Amazon::Credentials({ order => [qw/file/], debug => $ENV{DEBUG} ? 1 : 0 });
ok(ref($creds), 'find credentials');
my %new_creds = (
aws_access_key_id => 'biz-aws-access-key-id',
aws_secret_access_key => 'biz-aws-secret-access-key',
token => 'biz',
expiration => time2str("%Y-%m-%dT%H:%M:%SZ", time + -5 + (5 * 60), "GMT")
);
$creds->set_credentials(\%new_creds);
ok($creds->is_token_expired, 'is_token_expired() - yes?') or
diag(Dumper [ $creds->get_expiration(), time2str("%Y-%m-%dT%H:%M:%SZ", time, "GMT")]);
# is_expired() should be true 5 or less minutes before expiration time
$creds->set_expiration(time2str("%Y-%m-%dT%H:%M:%SZ", time + 5 + (5 * 60),"GMT"));
ok(! $creds->is_token_expired, 'is_token_expired() - no?') or
diag(Dumper [ $creds->get_expiration(), time2str("%Y-%m-%dT%H:%M:%SZ", time, "GMT")]);
# expire token
$creds->set_expiration(time2str("%Y-%m-%dT%H:%M:%SZ", time + -5 + (5 * 60),"GMT"));