Amazon-Credentials

 view release on metacpan or  search on metacpan

lib/Amazon/Credentials.pm  view on Meta::CPAN

package Amazon::Credentials;

use strict;
use warnings;

use parent qw/Class::Accessor Exporter/;

__PACKAGE__->follow_best_practice;
__PACKAGE__->mk_accessors(qw/aws_secret_access_key aws_access_key_id token region
			     user_agent profile debug expiration role container order 
			     serialized logger
			    /);

use Data::Dumper;
use Date::Format;
use Exporter;
use HTTP::Request;
use JSON;
use LWP::UserAgent;
use POSIX::strptime qw/strptime/;

lib/Amazon/Credentials.pm  view on Meta::CPAN

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
{
  no strict 'refs';
  
  *{'Amazon::Credentials::Logger::debug'} = sub {
    shift;
    my @tm = localtime(time);
    print STDERR sprintf("%s [%s] %s", strftime("%c", @tm), $$, @_);
  };
}

=pod

=head1 NAME

lib/Amazon/Credentials.pm  view on Meta::CPAN

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 });

C<options> is a hash of keys that represent options.  Any of the
options can also be retrieved using their corresponding 'get_{option}
method.

Options are listed below.

=over 5

=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>).

lib/Amazon/Credentials.pm  view on Meta::CPAN

	    $creds->{aws_access_key_id} = $1;
	  }
	  elsif (/^\s*aws_session_token\s*=\s*(.*)$/) {
	    last if defined $creds->{token};
	    $creds->{token} = $1;
	  }
	}
	  
	close $fh;
	  
	$self->get_logger->debug(Dumper [ $creds ])
	  if $self->get_debug;
	
	$creds->{source} = $config if $creds->{aws_secret_access_key} && $creds->{aws_access_key_id};
      }
	
      last if $creds->{source};
    };
  }
  
  foreach ( keys %$creds) {
    $self->set($_, $creds->{$_});

lib/Amazon/Credentials.pm  view on Meta::CPAN

  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);
      my $minutes = int(($seconds_left - $hours * 3600)/60);
      my $seconds = $seconds_left - ($hours * 3600 + $minutes * 60);
      $self->get_logger->debug(sprintf("%d hours %d minutes %d seconds until expiry\n", $hours, $minutes, $seconds));
    }
    
    $expired = ($seconds_left < 0) ? 1 : 0;
    
    $self->get_logger->debug(Dumper [ "EXPIRATION TIME: " . $expiration_date, "EXPIRED: " . $expired])
      if $self->get_debug;
  }

  return $expired;
}

sub _iso8601_to_time {
  my $iso8601 = shift;
  
  $iso8601 =~s/^(.*)Z$/$1\+00:00/;

lib/Amazon/Credentials.pm  view on Meta::CPAN


  eval {
    # could be infinite, but I don't think so.  Either we get an
    # error ($@), or a non-200 response code
    while ( ! $creds->{token} ) {
      
      $url .= $role if $role;
      
      my $req = HTTP::Request->new( GET => $url );
      
      $self->get_logger->debug(Dumper [ "HTTP REQUEST:\n", $req ])
	if $self->get_debug;
      
      my $rsp = $ua->request($req);
      
      $self->get_logger->debug(Dumper [ "HTTP RESPONSE:\n", $rsp ])
	if $self->get_debug;
      
      # if not 200, then get out of Dodge
      last unless $rsp->is_success;
      
      if ( $role ) {
	$creds->{serialized} = $rsp->content;
	my $this = from_json($creds->{serialized});
	@{$creds}{qw/source role aws_access_key_id aws_secret_access_key token expiration/} =
	  ('IAM',$role, @{$this}{qw/AccessKeyId SecretAccessKey Token Expiration/});
      }
      else {
	$role = $rsp->content;
	$self->get_logger->debug(Dumper ['role', $role])
	  if $self->get_debug;

	last unless $role;
      }
    }
  };
  
  $creds->{error} = $@ if $@;
  
  $creds;
}

lib/Amazon/Credentials.pm  view on Meta::CPAN

  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;

lib/Amazon/Credentials.pm  view on Meta::CPAN

  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 ])
      if $self->get_debug;
    
    my $rsp = $ua->request($req);
    
    $self->get_logger->debug(Dumper [ "HTTP RESPONSE:\n", $rsp ])
      if $self->get_debug;
    
    # if not 200, then get out of Dodge
    if ( $rsp->is_success ) {
      $creds->{serialized} = $rsp->content;
      my $this = from_json($rsp->content);
      @{$creds}{qw/source container aws_access_key_id aws_secret_access_key token expiration/} =
	('IAM','ECS', @{$this}{qw/AccessKeyId SecretAccessKey Token Expiration/});
    }
    else {
      $self->get_logger->debug( "return code: " . $rsp->status_line . "\n");
    }
    
    $creds->{error} = $@ if $@;
  }
  
  $creds;
}

=pod

t/02-credentials.t  view on Meta::CPAN

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);



( run in 0.249 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )