State Backends¶
s.a.u needs a place to store saga state, distributed locks, and audit logs. LocalBackend by default. DynamoDB for distributed teams.
Default¶
Local BadgerDB
Out of the box, CloudSlash uses a BadgerDB-backed local state store. No configuration required.
The local backend is suitable for: - Single-user workstations - Single-process CI/CD runners - Local development and testing
Not safe for concurrent daemons
The local backend uses flock() on the state directory. Running two daemon instances on the same machine pointing at the same state directory will cause one to fail with a lock error. Use DynamoDB for multi-process setups.
Distributed¶
DynamoDB + S3
For multi-user, multi-process, or team deployments, delegate state management to AWS:
# ~/.cloudslash/config.yaml
sau:
state_backend: dynamodb
dynamodb:
table_name: cloudslash-locks
region: us-east-1
s3:
bucket: my-org-cloudslash-state
prefix: sau/
region: us-east-1
DynamoDB Table Setup¶
Create the table with a LockID partition key:
aws dynamodb create-table \: table-name cloudslash-locks \: attribute-definitions AttributeName=LockID,AttributeType=S \: key-schema AttributeName=LockID,KeyType=HASH \: billing-mode PAY_PER_REQUEST \: region us-east-1
S3 Bucket Setup¶
aws s3 mb s3://my-org-cloudslash-state: region us-east-1
# Block all public access
aws s3api put-public-access-block \: bucket my-org-cloudslash-state \: public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
Distributed Lock¶
How It Works
Before executing any remediation step, s.a.u performs a conditional PutItem on DynamoDB:
input := &dynamodb.PutItemInput{
TableName: &tableName,
Item: item,
ConditionExpression: aws.String("attribute_not_exists(LockID)"),
}
If the condition fails (another process holds the lock), the s.a.u execution thread enters exponential backoff (base: 100ms, max: 30s) and retries until the configured lock_timeout is reached. On timeout, the saga is cancelled and logged as LOCK_TIMEOUT in the audit ledger.
IAM Policy¶
The daemon process needs these permissions on the DynamoDB table and S3 bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:*:table/cloudslash-locks"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-org-cloudslash-state",
"arn:aws:s3:::my-org-cloudslash-state/sau/*"
]
}
]
}
Remote Shared History¶
S3
Separate from the s.a.u lock, CloudSlash can store scan history in S3 for sharing across team members:
Or set it permanently in config:
This lets team members run cs diff and cs trend against shared history without each running their own full scan.
Lock Timeout Configuration¶
sau:
state_backend: dynamodb
lock_timeout: 60s # How long to wait for a lock before giving up
lock_ttl: 300s # TTL written to DynamoDB item (prevents stale locks on crash)
If the daemon crashes while holding a lock, the DynamoDB item's TTL ensures the lock is automatically released after lock_ttl seconds: no manual cleanup required.
Verifying the Backend¶
The doctor command checks state backend connectivity as part of its adaptive diagnostics. You should see:
s.a.u state [OK] dynamodb:cloudslash-locks (us-east-1)
S3 history [OK] s3://my-org-cloudslash-state/sau/ (accessible)
If there's a connectivity issue: