Guide · AWS MemoryDB · Access Control

MemoryDB ACL User Management for MCP Servers

MemoryDB requires ACL authentication for every cluster — there is no unauthenticated mode. ACL users combine an authentication string (password) with an access string (permission grammar that scopes commands and keyspaces). This guide walks through creating minimum-privilege users for MCP server probe writers, session readers, and admin operations, the CDK constructs to manage them, and the failure modes that trip up most teams.

How MemoryDB ACLs work

MemoryDB implements the Redis 6 ACL model, but with important differences from self-managed Redis ACLs: ACL users are defined as AWS resources (CfnUser), grouped into an ACL (CfnACL), and the ACL is associated with a cluster (CfnCluster). Changes to users propagate through the ACL to the cluster — you don't configure ACLs on the cluster directly.

Authentication string

The authentication string controls whether the user can log in and what password they use. The format follows Redis 6 ACL SETUSER syntax but is passed to AWS as a JSON field:

"on resetpassword >MyS3cr3tP@ssword"

The on flag is the most commonly missed element. A user created with an authentication string that omits on will be in ACTIVE state in the AWS console but will return WRONGPASS on every login attempt — the cluster rejects the user because the account is disabled.

Access string

The access string controls what the user can do after login. It uses Redis ACL permission grammar:

# Full access (for admin/migration user only)
"on resetpassword >AdminP@ss ~* &* +@all"

# Probe writer: HSET, HGET, EXPIRE, TTL on probe keyspace only
"on resetpassword >ProbeWriterP@ss ~{*}:probe:* ~{*}:session:* +hset +hget +hmget +hmset +hgetall +del +expire +ttl +pttl +exists"

# Probe reader: read-only on probe keyspace
"on resetpassword >ProbeReaderP@ss ~{*}:probe:* +hget +hmget +hgetall +ttl +pttl +exists"

Access string grammar rules:

CDK CfnUser and CfnACL setup

Store authentication strings (passwords) in Secrets Manager, not hardcoded in CDK. The CDK construct takes the authentication string as a plain string, so construct it at deploy time by reading from Secrets Manager via a CDK custom resource or pass it via SSM Parameter Store.

import { aws_memorydb as memorydb, aws_secretsmanager as sm } from 'aws-cdk-lib';

// Store the password in Secrets Manager
const probeWriterSecret = new sm.Secret(this, 'ProbeWriterSecret', {
  secretName: '/mcp-probes/memorydb/probe-writer',
  generateSecretString: {
    excludePunctuation: true,   // Redis passwords can't contain spaces
    passwordLength: 32,
  },
});

// MemoryDB user: probe writer
// Authentication string is the Redis ACL SETUSER format
// AWS requires the full string including 'on resetpassword >'
const probeWriterUser = new memorydb.CfnUser(this, 'ProbeWriterUser', {
  userName: 'mcp-probe-writer',
  accessString: '~{*}:probe:* ~{*}:session:* +hset +hget +hmget +hmset +hgetall +del +expire +ttl +pttl +exists +incr +incrby +decr +zadd +zrangebyscore',
  authenticationMode: {
    type: 'password',
    passwords: [probeWriterSecret.secretValue.unsafeUnwrap()],
  },
});

// MemoryDB user: probe reader (dashboard / analytics service)
const probeReaderSecret = new sm.Secret(this, 'ProbeReaderSecret', {
  secretName: '/mcp-probes/memorydb/probe-reader',
  generateSecretString: {
    excludePunctuation: true,
    passwordLength: 32,
  },
});

const probeReaderUser = new memorydb.CfnUser(this, 'ProbeReaderUser', {
  userName: 'mcp-probe-reader',
  accessString: '~{*}:probe:* ~{*}:session:* +hget +hmget +hgetall +ttl +pttl +exists +zrangebyscore +zcard +zcount',
  authenticationMode: {
    type: 'password',
    passwords: [probeReaderSecret.secretValue.unsafeUnwrap()],
  },
});

// MemoryDB ACL: group users
const acl = new memorydb.CfnACL(this, 'MemoryDbAcl', {
  aclName: 'mcp-probes-acl',
  userNames: [probeWriterUser.userName, probeReaderUser.userName],
  // Note: 'default' user is NOT added here — removing it from the ACL
  // is how you disable unauthenticated access
});

// Reference the ACL in your cluster
// cluster.aclName = acl.aclName (set in CfnCluster definition)

The default user trap

Every MemoryDB cluster starts with a built-in default user. This user has no password and full access. If your ACL includes the default user, anyone who can reach port 6379 can read and write without credentials. You must either:

The default user trap is the most common MemoryDB security misconfiguration in production. The AWS MemoryDB default ACL (open-access) includes the default user and is intentionally insecure — it's provided for development and must be replaced before any production workload.

Password rotation

MemoryDB supports up to two active passwords per user. The rotation strategy uses this dual-password window:

  1. Generate new password, add it to the user alongside the existing password: authenticationMode.passwords = [oldPassword, newPassword]
  2. Deploy the new password to all MCP server instances (update Secrets Manager, trigger a rolling restart or connection pool refresh)
  3. Remove the old password: authenticationMode.passwords = [newPassword]

This ensures no connection interruption during rotation — during the transition window both passwords are valid. The Lambda rotation function in Secrets Manager can implement this pattern via the MemoryDB UpdateUser API.

# AWS CLI: add new password to user (dual-password window)
aws memorydb update-user \
  --user-name mcp-probe-writer \
  --authentication-mode '{"Type":"password","Passwords":["oldPassword","newPassword"]}'

# After deploying new password to all app instances, remove old password
aws memorydb update-user \
  --user-name mcp-probe-writer \
  --authentication-mode '{"Type":"password","Passwords":["newPassword"]}'

After updating a user, MemoryDB propagates the change to the cluster asynchronously. The user status transitions to MODIFYING briefly; existing connections are not dropped during this window. New connections using the new password are accepted as soon as propagation completes (typically under 30 seconds).

TLS enforcement

ACL authentication without TLS is insecure — passwords transmit in plaintext. Always set tlsEnabled: true in your CfnCluster. MemoryDB enforces TLS at the cluster level, not the user level, so a single cluster setting protects all ACL users.

The MemoryDB TLS certificate is signed by Amazon's internal CA. Most Redis clients handle this transparently with tls: {} or ssl: True options. If your client raises certificate validation errors, it may be trying to validate against the public CA bundle — configure it to accept the Amazon CA or disable hostname verification only as a temporary debug step (never in production).

TLS port is still 6379 in MemoryDB (not 6380 as in some self-managed Redis setups). The security group rule does not change between TLS and non-TLS configurations.

tlsEnabled settingEffectUse case
true (required)All connections must use TLS; plaintext connections rejectedAny workload where ACL passwords are sensitive
false (not recommended)Plaintext connections accepted; ACL auth still required but password exposed on networkDevelopment/local VPC testing only

ACL update lifecycle

When you add or remove users from a CfnACL, MemoryDB propagates the change to associated clusters. The ACL transitions through states:

The MODIFYING state is not an error — it's expected during routine user rotation. CloudFormation waits for ACTIVE before marking the resource update complete. If an ACL stays in MODIFYING for more than 15 minutes, check the cluster's status: a cluster in UPDATING state can hold an ACL in MODIFYING.

Monitoring ACL authentication failures

MemoryDB emits a CloudWatch metric AuthenticationErrors per cluster. A non-zero baseline is normal during deployments when old pods reconnect with outdated credentials. A sustained non-zero value after a deployment completes indicates a misconfiguration — a pod was not restarted, a password in Secrets Manager doesn't match the ACL user, or the ACL update hasn't propagated.

// CDK CloudWatch alarm for sustained authentication errors
import { aws_cloudwatch as cloudwatch } from 'aws-cdk-lib';

new cloudwatch.Alarm(this, 'MemoryDbAuthErrorAlarm', {
  metric: new cloudwatch.Metric({
    namespace: 'AWS/MemoryDB',
    metricName: 'AuthenticationErrors',
    dimensionsMap: { ClusterName: 'mcp-probes' },
    statistic: 'Sum',
    period: cdk.Duration.minutes(5),
  }),
  threshold: 10,
  evaluationPeriods: 3,           // 15 minutes of sustained errors
  datapointsToAlarm: 3,
  comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
  alarmDescription: 'MemoryDB authentication errors — check ACL user credentials in Secrets Manager',
  treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
});

How AliveMCP uses MemoryDB ACLs in its own probe infrastructure

AliveMCP runs its probe state store on MemoryDB with three ACL user tiers, mirroring the pattern above:

AliveMCP monitors your MemoryDB ACL health via the AuthenticationErrors metric — if your probe writer starts failing authentication, AliveMCP detects the degraded write path before it affects your uptime data accuracy.