AWS Secrets Manager
Overview
The cloudstub-secretsmanager module mocks AWS Secrets Manager. Its operation set is generated from
the AWS Secrets Manager Smithy model; AWS SDK v2 drives it with the JSON / X-Amz-Target protocol.
The core secret operations are state-backed: a secret created with CreateSecret is returned by
a later GetSecretValue or DescribeSecret, updated by PutSecretValue / UpdateSecret, removed
by DeleteSecret, survives a restart when a persistent store directory is configured, and is visible
through the REST API. A SecretId is accepted as either a secret name or a full
ARN. The remaining operations are registered from the model and return well-formed but stateless
placeholder responses. See Supported operations for the full list.
Standalone usage
Start the standalone server with the Secrets Manager module enabled (it is auto-downloaded if not already in the plugin directory):
Applications talk to it through the AWS SDK by pointing the client's endpoint at the mock port
(http://localhost:4566) — see the Test example for a SecretsManagerClient setup
and Standalone Mode for the full configuration.
To inspect and drive secret state from the terminal, use the CLI (clb), or call the
REST API on the API port (4567) directly — for example with curl. Parameters
are passed as query-string values. Store a secret and read it back:
$ clb secretsmanager put --name db-password --value s3cr3t
{
"arn" : "arn:aws:secretsmanager:us-east-1:000000000000:secret:db-password",
"name" : "db-password",
"versionId" : "7568e4c5-4484-4291-a44b-e648b8c47a26"
}
$ clb secretsmanager get --name db-password
{
"arn" : "arn:aws:secretsmanager:us-east-1:000000000000:secret:db-password",
"name" : "db-password",
"secretString" : "s3cr3t",
"versionId" : "7568e4c5-4484-4291-a44b-e648b8c47a26"
}
$ curl -s -X PUT "http://localhost:4567/api/secretsmanager/put?name=db-password&value=s3cr3t"
{"arn":"arn:aws:secretsmanager:us-east-1:000000000000:secret:db-password","name":"db-password","versionId":"7568e4c5-4484-4291-a44b-e648b8c47a26"}
$ curl -s "http://localhost:4567/api/secretsmanager/get?name=db-password"
{"arn":"arn:aws:secretsmanager:us-east-1:000000000000:secret:db-password","name":"db-password","secretString":"s3cr3t","versionId":"7568e4c5-4484-4291-a44b-e648b8c47a26"}
The REST API and the SDK share the same state store, so a secret your application creates through the
SDK is returned by GET /api/secretsmanager/get, and vice versa. See
REST API access for the full route set.
Test example
In embedded mode, add cloudstub-secretsmanager (see Getting Started) and
exercise the service end to end with CloudStubExtension:
import io.cloudstub.junit.CloudStubExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import java.net.URI;
import static org.junit.jupiter.api.Assertions.*;
@ExtendWith(CloudStubExtension.class)
class SecretRoundTripTest {
@Test
void secretStoredIsRetrieved() {
SecretsManagerClient client = SecretsManagerClient.builder()
.endpointOverride(URI.create(System.getProperty("aws.endpoint-url")))
.credentialsProvider(AnonymousCredentialsProvider.create())
.region(Region.US_EAST_1)
.build();
client.createSecret(b -> b.name("db-password").secretString("s3cr3t"));
String value = client.getSecretValue(b -> b.secretId("db-password")).secretString();
assertEquals("s3cr3t", value);
}
}
REST API access
The module exposes a REST API under /api/secretsmanager/…. These routes read and
write the same state as the AWS-protocol stubs — a secret created with the SDK is returned by
GET /api/secretsmanager/get, and vice versa. Parameters are passed as query-string values (e.g.
PUT /api/secretsmanager/put?name=db-password&value=s3cr3t).
| Route | Parameters | Description |
|---|---|---|
GET /api/secretsmanager/list |
— | List secret names |
GET /api/secretsmanager/get |
name |
Get a secret value |
PUT /api/secretsmanager/put |
name, value |
Create or update a secret |
DELETE /api/secretsmanager/delete |
name |
Delete a secret |
Supported operations
State-backed operations return live data from the shared state store:
| Operation | Behavior |
|---|---|
CreateSecret |
Stores the secret; returns its ARN, Name, and VersionId |
GetSecretValue |
Returns the stored SecretString for a name or ARN |
BatchGetSecretValue |
Returns the stored values for a SecretIdList; misses go to Errors |
PutSecretValue |
Replaces the value with a new version; returns the new VersionId |
UpdateSecret |
Updates the value and/or description; returns a new VersionId |
DescribeSecret |
Returns the secret's metadata (ARN, Name, Description, dates, tags) |
DeleteSecret |
Removes the secret and its tags; returns its ARN, Name, DeletionDate |
ListSecrets |
Returns all stored secrets |
TagResource |
Adds/updates tags returned by DescribeSecret |
UntagResource |
Removes the named tag keys |
GetSecretValue, PutSecretValue, UpdateSecret, DescribeSecret, DeleteSecret, TagResource,
and UntagResource return a ResourceNotFoundException (HTTP 400) for a secret that does not exist.
The remaining operations are registered and return well-formed but stateless placeholder responses;
they do not read or mutate state: CancelRotateSecret, DeleteResourcePolicy, GetRandomPassword,
GetResourcePolicy, ListSecretVersionIds, PutResourcePolicy, RemoveRegionsFromReplication,
ReplicateSecretToRegions, RestoreSecret, RotateSecret, StopReplicationToReplica,
UpdateSecretVersionStage, ValidateResourcePolicy.
Limitations
- Only a single current version is tracked per secret — version IDs change but prior versions are
not retained, and
ListSecretVersionIdsis a placeholder. - Version stages are reported as a fixed
AWSCURRENT;UpdateSecretVersionStageis a placeholder. DeleteSecretremoves the secret immediately — recovery windows (RecoveryWindowInDays, scheduled deletion) andRestoreSecretare not simulated.CreateSecreton an existing name overwrites it rather than raisingResourceExistsException.- Rotation, cross-region replication, resource policies, and KMS encryption are placeholders.
SecretBinaryis not stored; onlySecretStringround-trips.BatchGetSecretValuehonors onlySecretIdList; theFiltersparameter is ignored.
See also: Troubleshooting for common integration problems and workarounds.