I am in the midst of setting up a load generator into elasticache memcached cluster https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/WhatIs.html to test degenerate cases for distributed sts assumed role cache.
The way my load generator works is that
- I assume a single AWS STS role once in an ec2 instance in the same vpc where my elasticache cluster resides.
- I create a key value pair, where my key is a uuid and my value is the credentials serialized.
- I then generate n k,v pairs where n is a configuration I can provide as a command line argument.
- I put each k,v pair into a memcache cluster.
I use memjs https://www.npmjs.com/package/memjs to put the creds in there.
So far so good, but I am curious how I would get it to work with https://aws.amazon.com/about-aws/whats-new/2022/05/amazon-elasticache-memcached-supports-encryption-data-transit/
It looks like I do not need a custom cert chain : https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/in-transit-encryption-mc.html and I got the basic connection to work.
However I cannot figure out how to do this in node js. Can someone help me out with this?
The full code for my load generator is
// Script to fill up an elasticache cluster with credentials
const commandLineUsage = require('command-line-usage')
const commandLineArgs = require('command-line-args')
const optionDefinitions = [
{ name: 'clusterEndpoint', type: String, description: "Elasticache (Memcached) Cluster to set credentials into. In host:port format" },
{ name: 'clusterRegion', type: String, description: "Region where cluster lives" },
{ name: 'roleArnToAssume', type: String, description: "STS Role ARN to assume. Assumed role creds will be uploaded to Elastiache" },
{ name: 'cacheTtlInSeconds', type: Number, description: "Time to live in STS Cache" },
{ name: 'numCredsToUpload', type: Number, description: "Number of times to assume role and upload credentials" },
]
const options = commandLineArgs(optionDefinitions)
console.log("Seen args")
console.log(options)
if (options.clusterEndpoint === undefined ||
options.roleArnToAssume === undefined ||
options.cacheTtlInSeconds === undefined ||
options.numCredsToUpload === undefined ||
options.clusterRegion === undefined) {
console.log("Invalid parameters. Please provide all options below")
const usage = commandLineUsage([
{
header: 'Options',
optionList: optionDefinitions
}
])
console.log(usage)
} else {
const clusterEndpoint = options.clusterEndpoint
const roleArnToAssume = options.roleArnToAssume
const cacheTtlInSeconds = options.cacheTtlInSeconds
const numCredsToUpload = options.numCredsToUpload
const clusterRegion = options.clusterRegion
// Setup memcached client
const memjs = require('memjs')
const memcachedClient = memjs.Client.create(clusterEndpoint)
// Setup STS client
const sts = require('@aws-sdk/client-sts')
const stsClient = new sts.STSClient({ region: clusterRegion })
const serialize = require('serialize-javascript')
const { v4: uuidv4 } = require('uuid')
const stsAssumeRoleCommand = new sts.AssumeRoleCommand({
RoleArn: roleArnToAssume,
RoleSessionName: "SessionName"
})
const stsAssumedRole = stsClient.send(stsAssumeRoleCommand)
for (var i = 0; i < numCredsToUpload; i++) {
const key = uuidv4()
stsAssumedRole.then(
(data) => {
const dataToPutIn = serialize(data.Credentials)
return memcachedClient.set(key, dataToPutIn, { expires:cacheTtlInSeconds }, (err, _) => {
if (err !== null) {
console.log("Caught error while setting creds " + err.toString())
throw err
}
console.log("Successfully put memcached key : " + key + " and value " + dataToPutIn)
})
}).catch((error) => {
throw error
}).finally(() => {
// finally.
}
)
}
}
and my dependency closure is
{
"dependencies": {
"@aws-sdk/client-sts": "^3.245.0",
"command-line-args": "^5.2.1",
"command-line-usage": "^6.1.3",
"memcached": "^2.2.2",
"memjs": "^1.3.0",
"serialize-javascript": "^6.0.1",
"uuid": "^8.3.2"
}
}
I was half expecting some property in the memjs client init, but I cannot seem to find it. Is there an alternative way/mechanism to maybe listen in on this traffic and then encrypt it (if say this or any other library does not support tls).
2
Answers
There don’t appear to be any nodeJS Memcached clients that support TLS at the moment, based on a review of the existing OSS clients (memjs, node-memcached, memcached, mc, nodejs-memcache).
You can use nodeJS ‘tls’ module to connect to a Memcached server over TLS, but you will need to create and parse Memcached API requests/responses manually. Here’s an example for nodeJS TLS client.
If Java or PHP are applicable, you can use ElastiCache’s Memcached clients with TLS.
To download the ElastiCache Memcached cluster client:
Sign in to the Amazon Web Services Management Console and open the ElastiCache console at https://console.amazonaws.cn/elasticache/.
From the ElastiCache console, choose ElastiCache Cluster Client.
From the Download ElastiCache Memcached Cluster Client list, choose the ElastiCache Cluster Client that matches your preferred language, version and AMI architecture, then choose the Download button.
More related links:
How to use the Java client with TLS
How to use the PHP client with TLS
Additionally, please note that memjs client only supports binary protocol, which is on deprecation path since memcached 1.6. You might want to consider using a memcached client with ASCII protocol support. Pymemcache client is a good choice.