Using NullProvider for credentials with Localstack causes unexpected behavior
I am using localstack for development and noticed a discrepancy between the official AWS SDK and Async AWS.
My configuration is:
[
'region' => 'us-west-2',
'endpoint' => 'http://localhost:4566',
]
If I use (eg) AsyncAws\Sqs\SqsClient to create a new queue called "test":
$client->createQueue(['QueueName' => 'test']);
When I check it via CLI:
aws --endpoint-url http://localhost:4566 --region us-west-2 sqs list-queues --no-cli-pager
There is no output, as if the queue wasn't created. But when I do:
aws --endpoint-url http://localhost:4566 --region us-east-1 sqs list-queues --no-cli-pager
{
"QueueUrls": [
"http://localhost:4566/000000000000/test"
]
}
It exists, but not in the region that I specified.
Further making this weird is that not only do I have region set in the config, but also for my default profile in ~/.aws/config.
Somewhere along the line, Async AWS is losing track of the region.
Digging deeper, it appears that using NullProvider as the credential provider causes this issue to appear. When I set credentials as:
- $credentials = new NullProvider();
+ $credentials = new ConfigurationProvider();
Then everything seems to work as expected.
Could you please provide a reproducer? how do you create the client?
In this case, it is SqsClient but the same applies to any AsyncAws client.
My configuration before, which was not working:
$config = [
'region' => 'us-west-2',
'endpoint' => 'http://localhost:4566',
];
$credentials = new NullProvider();
$client = new SqsClient($config, $credentials);
After figuring out the root cause and updating:
$config = [
'region' => 'us-west-2',
'endpoint' => 'http://localhost:4566',
'accessKeyId' => 'test',
'accessKeySecret' => 'test',
];
$credentials = ChainProvider::createDefaultChain();
$client = new SqsClient($config, $credentials);
Actually, AWS uses region for 2 things:
- defining the endpoint URL (ie https://sqs.us-west-2.amazonaws.com.cn)
- signing the request (the name of the region is part of the signature)
I don't know how localstack works internally, but I believe it extracts the region from the signature. That's why the request must be signed and you have to provide credentials.
I'm not sure what is the best solution for AsyncAws
- always signing the request with empty is/secret. I'm :-1: for this one. Could break for 3rd party providers that does not expect a signature)
- sign the request when user provides both region and endpoint (Could break providers too)
- explain the issue in our documentation
WDYT @Nyholm ?
I believe it extracts the region from the signature
I think the solution here is simply documenting that NullProvider cannot be used with Localstack and that ConfigurationProvider with test:test credentials should be used instead. Or creating a specific TestProvider that does exactly that: use test:test as the access id and secret.
Interesting.
Yeah. I agree with both of you. Let's add a section in the docs about "Localstack" or local development.