Skip to content

Commit

Permalink
feat: user agent v2.1 second revision
Browse files Browse the repository at this point in the history
- Move the user agent middleware after the signing step in order to gather signature metrics.
- Add request compression metric gathering.
- Add specific testing for signatures.
- Add specific testing for request compression.
- Add specific testing for s3 encryption clients.
- Add credentials metric gathering logic.
- Add tests for credentials metrics.
  • Loading branch information
yenfryherrerafeliz committed Nov 12, 2024
1 parent 8ceb16e commit af9ff37
Show file tree
Hide file tree
Showing 20 changed files with 1,585 additions and 181 deletions.
47 changes: 27 additions & 20 deletions src/AwsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,6 @@ public function __construct(array $args)
if (isset($args['with_resolved'])) {
$args['with_resolved']($config);
}
MetricsBuilder::appendMetricsCaptureMiddleware(
$this->getHandlerList(),
MetricsBuilder::RESOURCE_MODEL
);
$this->addUserAgentMiddleware($config);
}

Expand Down Expand Up @@ -453,7 +449,7 @@ private function addSignatureMiddleware(array $args)
}

$resolver = static function (
CommandInterface $c
CommandInterface $command
) use (
$api,
$provider,
Expand All @@ -465,17 +461,17 @@ private function addSignatureMiddleware(array $args)
$handlerList
) {
if (!$configuredSignatureVersion) {
if (!empty($c['@context']['signing_region'])) {
$region = $c['@context']['signing_region'];
if (!empty($command['@context']['signing_region'])) {
$region = $command['@context']['signing_region'];
}
if (!empty($c['@context']['signing_service'])) {
$name = $c['@context']['signing_service'];
if (!empty($command['@context']['signing_service'])) {
$name = $command['@context']['signing_service'];
}
if (!empty($c['@context']['signature_version'])) {
$signatureVersion = $c['@context']['signature_version'];
if (!empty($command['@context']['signature_version'])) {
$signatureVersion = $command['@context']['signature_version'];
}

$authType = $api->getOperation($c->getName())['authtype'];
$authType = $api->getOperation($command->getName())['authtype'];
switch ($authType){
case 'none':
$signatureVersion = 'anonymous';
Expand All @@ -490,20 +486,21 @@ private function addSignatureMiddleware(array $args)
}

if ($signatureVersion === 'v4a') {
$commandSigningRegionSet = !empty($c['@context']['signing_region_set'])
? implode(', ', $c['@context']['signing_region_set'])
$commandSigningRegionSet = !empty($command['@context']['signing_region_set'])
? implode(', ', $command['@context']['signing_region_set'])
: null;

$region = $signingRegionSet
?? $commandSigningRegionSet
?? $region;

MetricsBuilder::appendMetricsCaptureMiddleware(
$handlerList,
MetricsBuilder::SIGV4A_SIGNING
);
}

// Capture signature metric
$command->getMetricsBuilder()->identifyMetricByValueAndAppend(
'signature',
$signatureVersion
);

return SignatureProvider::resolve($provider, $signatureVersion, $name, $region);
};
$this->handlerList->appendSign(
Expand Down Expand Up @@ -607,9 +604,19 @@ private function addEndpointV2Middleware()
);
}

/**
* Appends the user agent middleware.
* This middleware MUST be appended after the
* signature middleware `addSignatureMiddleware`,
* so that metrics around signatures are properly
* captured.
*
* @param $args
* @return void
*/
private function addUserAgentMiddleware($args)
{
$this->getHandlerList()->prependSign(
$this->getHandlerList()->appendSign(
UserAgentMiddleware::wrap($args),
'user-agent'
);
Expand Down
9 changes: 7 additions & 2 deletions src/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ class Command implements CommandInterface
* @param array $args Arguments to pass to the command
* @param HandlerList $list Handler list
*/
public function __construct($name, array $args = [], ?HandlerList $list = null)
public function __construct(
$name,
array $args = [],
?HandlerList $list = null,
?MetricsBuilder $metricsBuilder = null
)
{
$this->name = $name;
$this->data = $args;
Expand All @@ -41,7 +46,7 @@ public function __construct($name, array $args = [], ?HandlerList $list = null)
if (!isset($this->data['@context'])) {
$this->data['@context'] = [];
}
$this->metricsBuilder = new MetricsBuilder();
$this->metricsBuilder = $metricsBuilder ?: new MetricsBuilder();
}

public function __clone()
Expand Down
5 changes: 4 additions & 1 deletion src/Credentials/AssumeRoleCredentialProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ public function __invoke()
$client = $this->client;
return $client->assumeRoleAsync($this->assumeRoleParams)
->then(function (Result $result) {
return $this->client->createCredentials($result);
return $this->client->createCredentials(
$result,
CredentialSources::STS_ASSUME_ROLE
);
})->otherwise(function (\RuntimeException $exception) {
throw new CredentialsException(
"Error in retrieving assume role credentials.",
Expand Down
24 changes: 14 additions & 10 deletions src/Credentials/AssumeRoleWithWebIdentityCredentialProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ class AssumeRoleWithWebIdentityCredentialProvider

/** @var integer */
private $tokenFileReadAttempts;
/** @var string */
private $source;

/**
* The constructor attempts to load config from environment variables.
* If not set, the following config options are used:
* - WebIdentityTokenFile: full path of token filename
* - RoleArn: arn of role to be assumed
* - SessionName: (optional) set by SDK if not provided
* - source: To identify if the provider was sourced by a profile or
* from environment definition. Default will be `sts_web_id_token`.
*
* @param array $config Configuration options
* @throws \InvalidArgumentException
Expand All @@ -66,15 +70,9 @@ public function __construct(array $config = [])
$this->retries = (int) getenv(self::ENV_RETRIES) ?: (isset($config['retries']) ? $config['retries'] : 3);
$this->authenticationAttempts = 0;
$this->tokenFileReadAttempts = 0;

$this->session = isset($config['SessionName'])
? $config['SessionName']
: 'aws-sdk-php-' . round(microtime(true) * 1000);

$region = isset($config['region'])
? $config['region']
: 'us-east-1';

$this->session = $config['SessionName']
?? 'aws-sdk-php-' . round(microtime(true) * 1000);
$region = $config['region'] ?? 'us-east-1';
if (isset($config['client'])) {
$this->client = $config['client'];
} else {
Expand All @@ -84,6 +82,9 @@ public function __construct(array $config = [])
'version' => 'latest'
]);
}

$this->source = $config['source']
?? CredentialSources::STS_WEB_ID_TOKEN;
}

/**
Expand Down Expand Up @@ -160,7 +161,10 @@ public function __invoke()
$this->authenticationAttempts++;
}

yield $this->client->createCredentials($result);
yield $this->client->createCredentials(
$result,
$this->source
);
});
}
}
26 changes: 18 additions & 8 deletions src/Credentials/CredentialProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,8 @@ public static function env()
$secret,
$token,
null,
$accountId
$accountId,
CredentialSources::ENVIRONMENT
)
);
}
Expand Down Expand Up @@ -417,7 +418,8 @@ public static function assumeRoleWithWebIdentityCredentialProvider(array $config
'WebIdentityTokenFile' => $tokenFromEnv,
'SessionName' => $sessionName,
'client' => $stsClient,
'region' => $region
'region' => $region,
'source' => CredentialSources::ENVIRONMENT_STS_WEB_ID_TOKEN
]);

return $provider();
Expand Down Expand Up @@ -446,7 +448,8 @@ public static function assumeRoleWithWebIdentityCredentialProvider(array $config
'WebIdentityTokenFile' => $profile['web_identity_token_file'],
'SessionName' => $sessionName,
'client' => $stsClient,
'region' => $region
'region' => $region,
'source' => CredentialSources::PROFILE_STS_WEB_ID_TOKEN
]);

return $provider();
Expand Down Expand Up @@ -553,7 +556,8 @@ public static function ini($profile = null, $filename = null, array $config = []
$data[$profile]['aws_secret_access_key'],
$data[$profile]['aws_session_token'],
null,
!empty($data[$profile]['aws_account_id']) ? $data[$profile]['aws_account_id'] : null
$data[$profile]['aws_account_id'] ?? null,
CredentialSources::PROFILE
)
);
};
Expand Down Expand Up @@ -641,7 +645,8 @@ public static function process($profile = null, $filename = null)
$processData['SecretAccessKey'],
$processData['SessionToken'],
$expires,
$accountId
$accountId,
CredentialSources::PROCESS
)
);
};
Expand Down Expand Up @@ -724,7 +729,10 @@ private static function loadRoleProfile(
'RoleArn' => $roleArn,
'RoleSessionName' => $roleSessionName
]);
$credentials = $stsClient->createCredentials($result);
$credentials = $stsClient->createCredentials(
$result,
CredentialSources::STS_ASSUME_ROLE
);

return Promise\Create::promiseFor($credentials);
}
Expand Down Expand Up @@ -918,7 +926,8 @@ private static function getSsoCredentials($profiles, $ssoProfileName, $filename,
$ssoCredentials['secretAccessKey'],
$ssoCredentials['sessionToken'],
$expiration,
$ssoProfile['sso_account_id']
$ssoProfile['sso_account_id'],
CredentialSources::SSO
)
);
}
Expand Down Expand Up @@ -978,7 +987,8 @@ private static function getSsoCredentialsLegacy($profiles, $ssoProfileName, $fil
$ssoCredentials['secretAccessKey'],
$ssoCredentials['sessionToken'],
$expiration,
$ssoProfile['sso_account_id']
$ssoProfile['sso_account_id'],
CredentialSources::SSO_LEGACY
)
);
}
Expand Down
22 changes: 22 additions & 0 deletions src/Credentials/CredentialSources.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Aws\Credentials;

/**
* @internal
*/
class CredentialSources
{
const STATIC = 'static';
const ENVIRONMENT = 'env';
const STS_WEB_ID_TOKEN = 'sts_web_id_token';
const ENVIRONMENT_STS_WEB_ID_TOKEN = 'env_sts_web_id_token';
const PROFILE_STS_WEB_ID_TOKEN = 'profile_sts_web_id_token';
const STS_ASSUME_ROLE = 'sts_assume_role';
const PROFILE = 'profile';
const IMDS = 'instance_profile_provider';
const ECS = 'ecs';
const SSO = 'sso';
const SSO_LEGACY = 'sso_legacy';
const PROCESS = 'process';
}
23 changes: 20 additions & 3 deletions src/Credentials/Credentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Credentials extends AwsCredentialIdentity implements
private $token;
private $expires;
private $accountId;
private $source;

/**
* Constructs a new BasicAWSCredentials object, with the specified AWS
Expand All @@ -26,13 +27,21 @@ class Credentials extends AwsCredentialIdentity implements
* @param string $token Security token to use
* @param int $expires UNIX timestamp for when credentials expire
*/
public function __construct($key, $secret, $token = null, $expires = null, $accountId = null)
public function __construct(
$key,
$secret,
$token = null,
$expires = null,
$accountId = null,
$source = CredentialSources::STATIC
)
{
$this->key = trim((string) $key);
$this->secret = trim((string) $secret);
$this->token = $token;
$this->expires = $expires;
$this->accountId = $accountId;
$this->source = $source;
}

public static function __set_state(array $state)
Expand All @@ -42,7 +51,8 @@ public static function __set_state(array $state)
$state['secret'],
$state['token'],
$state['expires'],
$state['accountId']
$state['accountId'],
$state['source'] ?? null
);
}

Expand Down Expand Up @@ -76,14 +86,20 @@ public function getAccountId()
return $this->accountId;
}

public function getSource()
{
return $this->source;
}

public function toArray()
{
return [
'key' => $this->key,
'secret' => $this->secret,
'token' => $this->token,
'expires' => $this->expires,
'accountId' => $this->accountId
'accountId' => $this->accountId,
'source' => $this->source
];
}

Expand Down Expand Up @@ -111,6 +127,7 @@ public function __unserialize($data)
$this->token = $data['token'];
$this->expires = $data['expires'];
$this->accountId = $data['accountId'] ?? null;
$this->source = $data['source'] ?? null;
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/Credentials/EcsCredentialProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ public function __invoke()
$result['SecretAccessKey'],
$result['Token'],
strtotime($result['Expiration']),
$result['AccountId'] ?? null
$result['AccountId'] ?? null,
CredentialSources::ECS
);
})->otherwise(function ($reason) {
$reason = is_array($reason) ? $reason['exception'] : $reason;
Expand Down
3 changes: 2 additions & 1 deletion src/Credentials/InstanceProfileProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ public function __invoke($previousCredentials = null)
$result['SecretAccessKey'],
$result['Token'],
strtotime($result['Expiration']),
$result['AccountId'] ?? null
$result['AccountId'] ?? null,
CredentialSources::IMDS
);
}

Expand Down
Loading

0 comments on commit af9ff37

Please sign in to comment.