Skip to content

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.

# ~/.cloudslash/config.yaml
sau:
  state_backend: local
  local_path: ~/.cloudslash/data/sau-state/

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:

cs daemon --history-url s3://my-org-cloudslash-state/history/

Or set it permanently in config:

daemon:
  history_url: s3://my-org-cloudslash-state/history/

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

cs doctor

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:

s.a.u state           [FAIL]  dynamodb:cloudslash-locks: AccessDeniedException
                              → Check IAM permissions for dynamodb:PutItem