Create AWS ElastiCache Users

The aws:elasticache/user:User resource, part of the Pulumi AWS provider, defines ElastiCache users with authentication methods and Redis command permissions. This guide focuses on three capabilities: password and IAM authentication, Redis command access control via access strings, and password rotation with dual credentials.

ElastiCache users authenticate to clusters and must be assigned to user groups to grant actual access. The examples are intentionally small. Combine them with UserGroup resources and cluster configuration for complete access control.

Grant scoped Redis command access with passwords

Most deployments create users with specific command permissions and password authentication, enabling least-privilege access patterns.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.elasticache.User("test", {
    userId: "testUserId",
    userName: "testUserName",
    accessString: "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember",
    engine: "redis",
    passwords: ["password123456789"],
});
import pulumi
import pulumi_aws as aws

test = aws.elasticache.User("test",
    user_id="testUserId",
    user_name="testUserName",
    access_string="on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember",
    engine="redis",
    passwords=["password123456789"])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := elasticache.NewUser(ctx, "test", &elasticache.UserArgs{
			UserId:       pulumi.String("testUserId"),
			UserName:     pulumi.String("testUserName"),
			AccessString: pulumi.String("on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember"),
			Engine:       pulumi.String("redis"),
			Passwords: pulumi.StringArray{
				pulumi.String("password123456789"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.ElastiCache.User("test", new()
    {
        UserId = "testUserId",
        UserName = "testUserName",
        AccessString = "on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember",
        Engine = "redis",
        Passwords = new[]
        {
            "password123456789",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.User;
import com.pulumi.aws.elasticache.UserArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new User("test", UserArgs.builder()
            .userId("testUserId")
            .userName("testUserName")
            .accessString("on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember")
            .engine("redis")
            .passwords("password123456789")
            .build());

    }
}
resources:
  test:
    type: aws:elasticache:User
    properties:
      userId: testUserId
      userName: testUserName
      accessString: on ~app::* -@all +@read +@hash +@bitmap +@geo -setbit -bitfield -hset -hsetnx -hmset -hincrby -hincrbyfloat -hdel -bitop -geoadd -georadius -georadiusbymember
      engine: redis
      passwords:
        - password123456789

The accessString property controls which Redis commands and key patterns the user can execute. The syntax follows the pattern on ~keypattern +@category -command, where on enables the user, ~app::* restricts access to keys matching that pattern, and the command list grants read operations while denying writes. The passwords array holds up to two passwords for authentication.

Authenticate users with IAM credentials

Teams using AWS IAM for centralized identity management can authenticate through IAM instead of managing separate passwords.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.elasticache.User("test", {
    userId: "testUserId",
    userName: "testUserName",
    accessString: "on ~* +@all",
    engine: "redis",
    authenticationMode: {
        type: "iam",
    },
});
import pulumi
import pulumi_aws as aws

test = aws.elasticache.User("test",
    user_id="testUserId",
    user_name="testUserName",
    access_string="on ~* +@all",
    engine="redis",
    authentication_mode={
        "type": "iam",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := elasticache.NewUser(ctx, "test", &elasticache.UserArgs{
			UserId:       pulumi.String("testUserId"),
			UserName:     pulumi.String("testUserName"),
			AccessString: pulumi.String("on ~* +@all"),
			Engine:       pulumi.String("redis"),
			AuthenticationMode: &elasticache.UserAuthenticationModeArgs{
				Type: pulumi.String("iam"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.ElastiCache.User("test", new()
    {
        UserId = "testUserId",
        UserName = "testUserName",
        AccessString = "on ~* +@all",
        Engine = "redis",
        AuthenticationMode = new Aws.ElastiCache.Inputs.UserAuthenticationModeArgs
        {
            Type = "iam",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.User;
import com.pulumi.aws.elasticache.UserArgs;
import com.pulumi.aws.elasticache.inputs.UserAuthenticationModeArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new User("test", UserArgs.builder()
            .userId("testUserId")
            .userName("testUserName")
            .accessString("on ~* +@all")
            .engine("redis")
            .authenticationMode(UserAuthenticationModeArgs.builder()
                .type("iam")
                .build())
            .build());

    }
}
resources:
  test:
    type: aws:elasticache:User
    properties:
      userId: testUserId
      userName: testUserName
      accessString: on ~* +@all
      engine: redis
      authenticationMode:
        type: iam

The authenticationMode property switches from password to IAM authentication. When type is set to iam, users authenticate with AWS credentials rather than ElastiCache-specific passwords. This requires IAM permissions to connect to ElastiCache.

Configure password rotation with dual passwords

Password rotation requires supporting both old and new credentials during the transition period to avoid service interruption.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const test = new aws.elasticache.User("test", {
    userId: "testUserId",
    userName: "testUserName",
    accessString: "on ~* +@all",
    engine: "redis",
    authenticationMode: {
        type: "password",
        passwords: [
            "password1",
            "password2",
        ],
    },
});
import pulumi
import pulumi_aws as aws

test = aws.elasticache.User("test",
    user_id="testUserId",
    user_name="testUserName",
    access_string="on ~* +@all",
    engine="redis",
    authentication_mode={
        "type": "password",
        "passwords": [
            "password1",
            "password2",
        ],
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := elasticache.NewUser(ctx, "test", &elasticache.UserArgs{
			UserId:       pulumi.String("testUserId"),
			UserName:     pulumi.String("testUserName"),
			AccessString: pulumi.String("on ~* +@all"),
			Engine:       pulumi.String("redis"),
			AuthenticationMode: &elasticache.UserAuthenticationModeArgs{
				Type: pulumi.String("password"),
				Passwords: pulumi.StringArray{
					pulumi.String("password1"),
					pulumi.String("password2"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var test = new Aws.ElastiCache.User("test", new()
    {
        UserId = "testUserId",
        UserName = "testUserName",
        AccessString = "on ~* +@all",
        Engine = "redis",
        AuthenticationMode = new Aws.ElastiCache.Inputs.UserAuthenticationModeArgs
        {
            Type = "password",
            Passwords = new[]
            {
                "password1",
                "password2",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.User;
import com.pulumi.aws.elasticache.UserArgs;
import com.pulumi.aws.elasticache.inputs.UserAuthenticationModeArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var test = new User("test", UserArgs.builder()
            .userId("testUserId")
            .userName("testUserName")
            .accessString("on ~* +@all")
            .engine("redis")
            .authenticationMode(UserAuthenticationModeArgs.builder()
                .type("password")
                .passwords(                
                    "password1",
                    "password2")
                .build())
            .build());

    }
}
resources:
  test:
    type: aws:elasticache:User
    properties:
      userId: testUserId
      userName: testUserName
      accessString: on ~* +@all
      engine: redis
      authenticationMode:
        type: password
        passwords:
          - password1
          - password2

ElastiCache allows up to two passwords per user. During rotation, add the new password to the passwords array in authenticationMode, update client applications to use the new credential, then remove the old password. This enables zero-downtime rotation.

Beyond these examples

These snippets focus on specific user-level features: password and IAM authentication, Redis command access control, and password rotation support. They’re intentionally minimal rather than full access control configurations.

The examples may reference pre-existing infrastructure such as IAM permissions for IAM-authenticated users. They focus on configuring the user rather than provisioning clusters or user groups.

To keep things focused, common user patterns are omitted, including:

  • User group membership (requires separate UserGroup resource)
  • No-password authentication (noPasswordRequired)
  • Tagging for organization and cost tracking
  • Multi-region user management

These omissions are intentional: the goal is to illustrate how each user feature is wired, not provide drop-in access control modules. See the ElastiCache User resource reference for all available configuration options.

Let's create AWS ElastiCache Users

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Security & Authentication
Why are my passwords visible in the Pulumi state file?
All arguments including username and passwords are stored in the raw state as plain-text. Consider the security implications of your state file storage when using this resource.
What authentication methods are available for ElastiCache users?
You can use IAM authentication (set authenticationMode.type to iam) or password authentication (set authenticationMode.type to password with a passwords array).
What's the difference between the passwords field and authenticationMode.passwords?
Both can be used for password authentication. You can either use the top-level passwords field or nest passwords within authenticationMode when type is password.
How many passwords can I configure for a user?
You can create up to two passwords for each user.
Configuration & Immutability
What happens if I change the userId or userName?
Both userId and userName are immutable properties. Changing either will force replacement of the entire resource.
What is the accessString and where can I learn its syntax?
The accessString is a required field that defines access permissions for the user. See the AWS documentation on Specifying Permissions Using an Access String for syntax details.
Engine Support
What engines are supported for ElastiCache users?
The supported engines are redis and valkey (case insensitive).

Using a different cloud?

Explore database guides for other cloud providers: