Create AWS ElastiCache Users

The aws:elasticache/user:User resource, part of the Pulumi AWS provider, defines ElastiCache users with authentication methods and access permissions for Redis or Valkey clusters. This guide focuses on three capabilities: password and IAM authentication, access string permissions, and dual-password rotation.

ElastiCache users don’t operate independently; they must be attached to user groups, which are then associated with clusters. The examples are intentionally small. Combine them with ElastiCache user groups and cluster configuration.

Create a user with password authentication and scoped access

Most deployments create users with password-based authentication and access strings that limit which commands and keys they can use.

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 defines what the user can do. The syntax follows the pattern: on (user is active), ~app::* (key pattern), -@all (deny all commands), then +@read +@hash (allow specific command categories). The passwords array holds one or two passwords for authentication. All credentials are stored in plain-text in Pulumi state.

Authenticate users with IAM instead of passwords

Teams using AWS IAM for centralized identity can authenticate through IAM policies rather than managing 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, ElastiCache validates requests using AWS IAM credentials instead of passwords. The accessString still controls command and key permissions.

Configure password rotation with dual passwords

ElastiCache supports up to two passwords per user, enabling zero-downtime rotation.

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

The authenticationMode property with type password accepts a passwords array with up to two entries. During rotation, add the new password while keeping the old one, update clients, then remove the old password. Both passwords work simultaneously during the transition.

Beyond these examples

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

The examples assume pre-existing infrastructure such as ElastiCache Redis or Valkey clusters. Users must be attached to user groups separately. They focus on user configuration rather than provisioning clusters or groups.

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

  • User group attachment (users must be added to groups separately)
  • Tag-based organization (tags property)
  • Passwordless access (noPasswordRequired)
  • Access string syntax and command categories

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 & State Management
Are my passwords stored securely in Pulumi state?
No, all arguments including usernames and passwords are stored in plain-text in the Pulumi state file. Consider using IAM authentication instead of passwords for better security, and ensure your state files are properly secured.
Authentication & Passwords
What authentication methods are available for ElastiCache users?
You can use IAM authentication or password-based authentication. Configure this via the authenticationMode property with type set to either iam or password.
How do I use IAM authentication instead of passwords?
Set authenticationMode.type to iam and don’t specify the passwords field. This avoids storing credentials in state.
How many passwords can I set for a user?
You can create up to two passwords for each user using the passwords array.
Can I create a user without requiring a password?
Yes, set noPasswordRequired to true to indicate no password is needed for the user.
Access Control & Permissions
How do I restrict what commands a user can execute?
Use the accessString property with Redis ACL syntax to control permissions. For example, you can allow specific commands like +@read +@hash while denying others like -setbit -bitfield. See the AWS documentation on Access Strings for detailed syntax.
Configuration & Immutability
What properties can't be changed after creating a user?
Both userId and userName are immutable. Changing either requires replacing the resource, so plan these values carefully during initial creation.
What engines are supported for ElastiCache users?
ElastiCache users support redis and valkey engines (case insensitive).

Using a different cloud?

Explore database guides for other cloud providers: