ExCredstash.Dynamo (ExCredstash v0.1.1)
View SourceDynamoDB operations for credential storage.
This module provides functions for interacting with AWS DynamoDB
to store and retrieve encrypted credentials using the official
:aws Erlang SDK.
Table Schema
The credential store table uses:
- Partition key:
name(String) - The secret name - Sort key:
version(String) - Zero-padded version number (19 chars)
Item Structure
Each item contains:
| Attribute | Type | Description |
|-----------|------|-------------|
| name | String | Secret name (partition key) |
| version | String | Zero-padded version, e.g., "0000000000000000001" |
| key | String | Base64-encoded KMS-encrypted data key |
| contents | String | Base64-encoded AES-encrypted secret |
| hmac | Binary | Hex-encoded HMAC of ciphertext |
| digest | String | Hash algorithm (e.g., "SHA256") |
| comment | String | Optional comment |
Usage
# Create a client
client = ExCredstash.Dynamo.client(region: "us-east-1")
# Store a secret
{:ok, :created} = ExCredstash.Dynamo.put_secret(
region: "us-east-1",
name: "my_secret",
version: "0000000000000000001",
key: "base64_encoded_key",
contents: "base64_encoded_contents",
hmac: "hex_encoded_hmac",
digest: "SHA256"
)
# Get the latest version
{:ok, item} = ExCredstash.Dynamo.get_latest_secret(
region: "us-east-1",
name: "my_secret"
)
Summary
Functions
Create an AWS DynamoDB client.
Create the credential-store table if it doesn't exist.
Delete all versions of a secret.
Get the highest version number for a secret.
Get the latest version of a secret.
Get a specific version of a secret.
Get all unique secret names in the table.
List all secrets in the table.
Put a secret item into the table.
Query all versions of a specific secret.
Functions
@spec client(keyword()) :: AWS.Client.t() | {:error, term()}
Create an AWS DynamoDB client.
Uses :aws_credentials to get credentials automatically from the
credential chain (env vars, instance profile, etc.).
Options
:region- AWS region (required):access_key_id- Override access key (optional):secret_access_key- Override secret key (optional):session_token- Override session token (optional)
Examples
# Using default credentials
client = ExCredstash.Dynamo.client(region: "us-east-1")
# With explicit credentials
client = ExCredstash.Dynamo.client(
region: "us-east-1",
access_key_id: "AKIAIOSFODNN7EXAMPLE",
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
)
Create the credential-store table if it doesn't exist.
Uses PAY_PER_REQUEST billing mode by default (on-demand capacity).
Options
:region- AWS region (required):table- Table name (default: "credential-store"):tags- Map of tags to apply to the table (optional)
Returns
{:ok, :created}- Table was created{:ok, :exists}- Table already exists{:error, reason}- Error occurred
Examples
# Create with defaults
{:ok, :created} = ExCredstash.Dynamo.create_table(region: "us-east-1")
# Create with custom name and tags
{:ok, _} = ExCredstash.Dynamo.create_table(
region: "us-east-1",
table: "my-credentials",
tags: %{"Environment" => "production"}
)
@spec delete_secret(keyword()) :: {:ok, non_neg_integer()} | {:error, term()}
Delete all versions of a secret.
Queries for all versions and deletes them one by one.
Options
:region- AWS region (required):table- Table name (default: "credential-store"):name- Secret name (required)
Returns
{:ok, deleted_count}- Number of items deleted{:error, reason}
Examples
{:ok, 3} = ExCredstash.Dynamo.delete_secret(
region: "us-east-1",
name: "old_secret"
)
@spec get_highest_version(keyword()) :: {:ok, non_neg_integer()} | {:error, term()}
Get the highest version number for a secret.
Options
:region- AWS region (required):table- Table name (default: "credential-store"):name- Secret name (required)
Returns
{:ok, version_integer}- The highest version as integer{:ok, 0}- No versions exist{:error, reason}- Error occurred
Examples
{:ok, 3} = ExCredstash.Dynamo.get_highest_version(
region: "us-east-1",
name: "db_password"
)
# Secret doesn't exist
{:ok, 0} = ExCredstash.Dynamo.get_highest_version(
region: "us-east-1",
name: "nonexistent"
)
Get the latest version of a secret.
Uses Query with ScanIndexForward=false and Limit=1 to efficiently retrieve only the highest version.
Options
:region- AWS region (required):table- Table name (default: "credential-store"):name- Secret name (required)
Returns
{:ok, item_map}- The latest secret item{:error, :not_found}- No versions exist{:error, reason}- Other error
Examples
{:ok, item} = ExCredstash.Dynamo.get_latest_secret(
region: "us-east-1",
name: "db_password"
)
Get a specific version of a secret.
Options
:region- AWS region (required):table- Table name (default: "credential-store"):name- Secret name (required):version- Version string (required)
Returns
{:ok, item_map}- The secret item as a map{:error, :not_found}- Item not found{:error, reason}- Other error
Examples
{:ok, item} = ExCredstash.Dynamo.get_secret(
region: "us-east-1",
name: "db_password",
version: "0000000000000000001"
)
Get all unique secret names in the table.
Options
:region- AWS region (required):table- Table name (default: "credential-store")
Returns
{:ok, [String.t()]}- List of unique names, sorted alphabetically{:error, reason}
Examples
{:ok, names} = ExCredstash.Dynamo.list_names(region: "us-east-1")
# ["api_key", "db_password", "secret_token"]
List all secrets in the table.
Returns name, version, and comment for each item. Uses pagination to handle tables with many items.
Options
:region- AWS region (required):table- Table name (default: "credential-store")
Returns
{:ok, [%{name: String.t(), version: String.t(), comment: String.t() | nil}]}{:error, reason}
Examples
{:ok, secrets} = ExCredstash.Dynamo.list_secrets(region: "us-east-1")
# [%{name: "db_password", version: "0000000000000000001", comment: nil}, ...]
Put a secret item into the table.
Uses a conditional expression to prevent overwriting existing versions.
Options
:region- AWS region (required):table- Table name (default: "credential-store"):name- Secret name (required):version- Version string, must be pre-padded (required):key- Base64-encoded encrypted data key (required):contents- Base64-encoded encrypted secret (required):hmac- Hex-encoded HMAC (required):digest- Hash algorithm string (required):comment- Optional comment
Returns
{:ok, :created}- Item created successfully{:error, {:already_exists, version}}- Version already exists{:error, reason}- Other error
Examples
{:ok, :created} = ExCredstash.Dynamo.put_secret(
region: "us-east-1",
name: "db_password",
version: "0000000000000000001",
key: "base64_key_data",
contents: "base64_encrypted_content",
hmac: "hexhmacvalue",
digest: "SHA256",
comment: "Database password for production"
)
Query all versions of a specific secret.
Options
:region- AWS region (required):table- Table name (default: "credential-store"):name- Secret name (required)
Returns
{:ok, [item_map]}- List of all versions{:error, reason}
Examples
{:ok, versions} = ExCredstash.Dynamo.query_secret_versions(
region: "us-east-1",
name: "db_password"
)