-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Confirm by changing [ ] to [x] below to ensure that it's a bug:
- I've gone though Developer Guide and API reference
- I've checked AWS Forums and StackOverflow for answers
- I've searched for previous similar issues and didn't find any solution
Describe the bug
When using the PHP SDK within a Kubernetes pod, using IAM roles for service accounts (https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html), with the default provider chain, the credentials are fetched by \Aws\Credentials\AssumeRoleWithWebIdentityCredentialProvider from the file identified by the environment variable with name \Aws\Credentials\CredentialProvider::ENV_TOKEN_FILE (in our case, the file is /var/run/secrets/eks.amazonaws.com/serviceaccount/token - this is coming from using IAM roles for service accounts). At some point after a token refresh the next time the SDK attempts to fetch the token
| $token = file_get_contents($this->tokenFile); |
Aws\Exception\CredentialsException with message
Error retrieving credentials from the instance profile metadata server. (cURL error 7: Failed to connect to 169.254.169.254 port 80: Connection refused (see https://curl.haxx.se/libcurl/c/libcurl-errors.html))
Version of AWS SDK for PHP?
3.133.6
Version of PHP (php -v)?
7.3.13
To Reproduce (observed behavior)
Create a Kubernetes pod using the default provider chain (retrieving credentials from a token file) and set a short refresh period for the token (to see the issue sooner). The code below recreates the client on each loop - in production code we only create it once now, but the issue still occurs because we're using PHP FPM and the realpath cache stays with the child worker, so is not cleared on each request
<?php
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;
use Aws\Credentials\CredentialProvider;
const WAIT_TIME_IN_SECONDS = 10;
while (true) {
//Create a S3Client
$s3Client = new S3Client([
//'profile' => 'default',
'region' => 'us-west-2',
'version' => '2006-03-01'
]);
$date = date('Y-m-d H:i:s');
echo sprintf('%s Sleeping %s seconds%s', $date, WAIT_TIME_IN_SECONDS, PHP_EOL);
sleep(WAIT_TIME_IN_SECONDS);
//Listing all S3 Bucket
$buckets = $s3Client->listBuckets();
foreach ($buckets['Buckets'] as $bucket) {
// echo sprintf(' %s%s', $bucket['Name'], PHP_EOL);
}
}
Expected behavior
The token file should always be successfully retrieved if it is present.
Screenshots
If applicable, add screenshots to help explain your problem.
Additional context
The issue appears to be related to the realpath cache (the issue relates to reading Kubernetes secrets, which this post highlights as hitting issues with the realpath cache https://pracucci.com/php-realpath-cache-and-kubernetes-secrets-configmap-updates.html) .
The token file is a symlink. When the token is refreshed this symlink changes, meaning the PHP realpath cache entry for this becomes invalid. So the next time the line
| $token = file_get_contents($this->tokenFile); |
We alleviated the issue by manually clearing the realpath cache for this file before creating the SDK client, but it is still hit upon occasion.
We believe that changing the highlighted line in \Aws\Credentials\AssumeRoleWithWebIdentityCredentialProvider to
$token = file_get_contents($this->tokenFile);
if (false === $token) {
clearstatcache(true, $this->tokenFile);
$token = file_get_contents($this->tokenFile);
}
would resolve this.