framework icon indicating copy to clipboard operation
framework copied to clipboard

Redis cluster authentication

Open zebamba opened this issue 1 week ago • 1 comments

Laravel Version

12.40.2

PHP Version

8.4

Database Driver & Version

No response

Description

I posted on issue #58000.

I had an issue with phpredis

The error message was:

phpredis - Couldn't map cluster keyspace using any provided seed Solved

Based on the Laravel documentation to set up a Redis cluster connection the config should look like:

'redis' => [

    'client' => env('REDIS_CLIENT', 'phpredis'),

    'options' => [
        'cluster' => env('REDIS_CLUSTER', 'redis'),
        'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
    ],

    'clusters' => [
        'default' => [
            [
                'url' => env('REDIS_URL'),
                'host' => env('REDIS_HOST', '127.0.0.1'),
                'username' => env('REDIS_USERNAME'),
                'password' => env('REDIS_PASSWORD'),
                'port' => env('REDIS_PORT', '6379'),
                'database' => env('REDIS_DB', '0'),
            ],
        ],
    ],

    // ...
],

I had to setup Redis cluster with phpredis with ACL authentication.

The issue I found is when calling method createRedisClusterInstance on PhpRedisConnector class

return tap(new RedisCluster(...$parameters) ...

The fifth argument auth on variable $parameters is set as null.

To solve the issue I had to change my configuration

'redis' => [

        'client' => env('REDIS_CLIENT', 'phpredis'),

        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'redis'),
            'prefix' => env('REDIS_PREFIX', 'my_prefix:'),
            'password' => env('REDIS_USERNAME', null) ? [env('REDIS_USERNAME', null), env('REDIS_PASSWORD', null)] : env('REDIS_PASSWORD', null),
        ],

        'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_HOST_1', '127.0.0.1'),
                    'username' => env('REDIS_USERNAME', null),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', '6379'),
                    'database' => env('REDIS_DB', '0'),
                    'persistent' => true,
                ],
                [
                    'host' => env('REDIS_HOST_2', '127.0.0.1'),
                    'username' => env('REDIS_USERNAME', null),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', '6379'),
                    'database' => env('REDIS_DB', '0'),
                    'persistent' => true,
                ],
                [
                    'host' => env('REDIS_HOST_3', '127.0.0.1'),
                    'username' => env('REDIS_USERNAME', null),
                    'password' => env('REDIS_PASSWORD', null),
                    'port' => env('REDIS_PORT', '6379'),
                    'database' => env('REDIS_DB', '0'),
                    'persistent' => true,
                ],
            ],
        ],

    ],

Also as if you noticed 'persistent' => true, should be inside of each cluster connection.

Issue:

The class that generates the mapping for the variable $parameters is not mapping corrected.

OR

Laravel docs should be updated.

Hey @crynobone.

I did upgrade my Laravel framework 12.40.2 and the PHP version 8.4. and the issue still present. I have worked around

What I noticed on this new version is the 5th parameter is not present at all, as the previous version was set to null.

I do believe the method that maps the config into the $parameter is not reading for each cluster node neither from the options username and password.

The solution for me was to add credentials combined as you see below.

'options' => [
        'cluster' => env('REDIS_CLUSTER', 'redis'),
        'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
        'password' => env('REDIS_USERNAME', null) ? [env('REDIS_USERNAME', null), env('REDIS_PASSWORD', null)] : env('REDIS_PASSWORD', null),
    ],

Steps To Reproduce

Requires a Redis cluster with ACL

I added a test endpoint, as you see I had to keep the cache as database and change to redis on runtime to be able to test this endpoint.

Route::get('/cache-test', [TestController::class, 'cacheTest']);

class TestController extends Controller
{
    public function cacheTest(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'key' => ['required', 'string', 'max:20', 'not_in:key'],
            'value' => ['required', 'string', 'max:100'],
            'ttl' => ['required', 'integer', 'min:20', 'max:180'],
        ], [
            'key.not_in' => 'The key name "key" is reserved and cannot be used.',
        ]);

        config(['cache.default' => 'redis']);

        $client = config('database.redis.client');
        $cacheStore = config('cache.default');

        $ttl = $validated['ttl'];
        $key = $validated['key'];
        $value = $validated['value'];

        try {
            $class = get_class(Redis::connection()->client());

            Cache::put($key, $value, $ttl);
            $cachedValue = Cache::get($key);

            $data = [
                'status' => 'success',
                'message' => 'Redis cache is working!',
                'key_set' => $key,
                'value_retrieved' => $cachedValue,
                'ttl_seconds' => $ttl,
                'store' => $cacheStore,
                'client' => $client,
                'class' => $class,
            ];

            if ($cachedValue && $cachedValue === $value) {
                return response()->json($data);
            }

            $data['status'] = 'failure';
            $data['message'] = 'Cache set but retrieved value does not match.';

            return response()->json($data);
        } catch (Exception $e) {
            return response()->json([
                'status' => 'error',
                'message' => 'Redis connection failed or another cache error occurred.',
                'error_detail' => $e->getMessage(),
            ], 500);
        }
    }
}

zebamba avatar Dec 04 '25 20:12 zebamba