在Lambda上用Bref运行Laravel时的AWS Token配置错误问题
问题描述
我在AWS Lambda上通过Bref运行Laravel应用,serverless.yml配置如下:
service: lambdajob provider: name: aws region: us-east-2 environment: APP_ENV: ${sls:stage} QUEUE_CONNECTION: sqs SQS_QUEUE: lambda-jobs-${sls:stage} SQS_PREFIX: https://sqs.us-east-2.amazonaws.com/xxxxxxxxxxx CACHE_DRIVER: dynamodb DYNAMODB_CACHE_TABLE: testtools-staging-cache LOG_CHANNEL: stderr TELESCOPE_ENABLED: false DB_HOST: ${ssm:/${sls:stage}/DB_HOST} DB_DATABASE: ${ssm:/${sls:stage}/DB_DATABASE} DB_PASSWORD: ${ssm:/${sls:stage}/DB_PASSWORD} DB_USERNAME: ${ssm:/${sls:stage}/DB_USERNAME} AWS_BUCKET: staging iam: role: arn:aws:iam::xxxxxxxx:role/lambda-role package: exclude: - .env - node_modules/** - public/storage - resources/js/** - rr - docker/** - storage/logs/** - storage/app/** - storage/framework/** - tests/** functions: worker: handler: Bref\\LaravelBridge\\Queue\\QueueHandler timeout: 900 runtime: php-81 events: - sqs: arn: Fn::GetAtt: [ YourQueueName, Arn ] batchSize: 1 plugins: - ./vendor/bref/bref - serverless-lift resources: Resources: YourQueueName: Type: AWS::SQS::Queue Properties: QueueName: lambda-jobs-${sls:stage} VisibilityTimeout: 900 RedrivePolicy: maxReceiveCount: 3 deadLetterTargetArn: Fn::GetAtt: [ YourQueueFailedName, Arn ] YourQueueFailedName: Type: AWS::SQS::Queue Properties: QueueName: lambda-jobs-failed-${sls:stage} MessageRetentionPeriod: 1209600
配置可正常触发Lambda执行任务,但出现以下错误:
Invalid configuration value provided for "token". Expected Aws\Token\TokenInterface|Aws\CacheInterface|array|bool|callable, but got string
我尝试在BrefServiceProvider的fixAwsCredentialsConfig方法中将token转换为Aws\\Token\\Token对象:
private function fixAwsCredentialsConfig(): void { $accessKeyId = $_SERVER['AWS_ACCESS_KEY_ID'] ?? null; $sessionToken = $_SERVER['AWS_SESSION_TOKEN'] ?? null; $sessionToken = new AwsToken($sessionToken); // 手动添加的代码 //.... }
但又出现新错误:
taging.ERROR: Object of class Aws\Token\Token could not be converted to string {"exception":"[object] (Error(code: 0): Object of class Aws\\Token\\Token could not be converted to string at /var/task/vendor/aws/aws-sdk-php/src/Signature/SignatureV4.php:328)
尝试创建带__toString方法的自定义Token类后,又遇到GuzzleHttp不接受Token对象的错误。
使用的包版本:
- laravel: 8.83.27
- bref/bref: 2.3.2
- bref/laravel-bridge: 2.4.0
- aws/aws-sdk-php: 3.317.1
解决方案
1. 恢复BrefServiceProvider的原始代码
不要手动修改fixAwsCredentialsConfig方法,Bref的Laravel桥接已经内置了Lambda环境下的AWS凭证处理逻辑,原始代码会正确将环境变量中的字符串类型token注入到Laravel配置中,同时AWS SDK会自动完成字符串到TokenInterface的转换。
原始方法代码:
private function fixAwsCredentialsConfig(): void { $accessKeyId = $_SERVER['AWS_ACCESS_KEY_ID'] ?? null; $sessionToken = $_SERVER['AWS_SESSION_TOKEN'] ?? null; if ($accessKeyId === null) { return; } $config = config('services.aws', []); $config['key'] = $accessKeyId; $config['secret'] = $_SERVER['AWS_SECRET_ACCESS_KEY'] ?? null; if ($sessionToken !== null) { $config['token'] = $sessionToken; } $config['region'] = $_SERVER['AWS_REGION'] ?? $config['region'] ?? null; config(['services.aws' => $config]); }
2. 检查Laravel的AWS服务配置
确保config/services.php中的AWS配置未对token做额外处理,保持默认的环境变量引用即可:
return [ // 其他服务配置... 'aws' => [ 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'token' => env('AWS_SESSION_TOKEN'), 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 'version' => 'latest', ], // 其他服务配置... ];
3. 确保Lambda IAM角色权限正确
验证Lambda使用的IAM角色(arn:aws:iam::xxxxxxxx:role/lambda-role)具备以下权限:
- SQS队列的读写权限
- DynamoDB缓存表的读写权限
- RDS数据库的访问权限(如果使用RDS)
- 其他应用依赖的AWS资源权限
4. 清除Laravel配置缓存
Lambda部署时,确保清除配置缓存,避免旧缓存导致的配置冲突。可以在部署流程中添加php artisan config:clear命令,或者在serverless.yml中配置部署钩子:
functions: worker: # 现有配置... hooks: post-package: - php artisan config:clear
5. 验证版本兼容性
当前使用的包版本组合是兼容的,如果问题仍存在,可以尝试更新Bref及Laravel桥接到最新稳定版,同时确保aws/aws-sdk-php版本与Bref的要求匹配。
内容的提问来源于stack exchange,提问作者Hadi Aghandeh

