Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

From AWS Secrets Manager

Move from AWS Secrets Manager (ASM) to ScaiVault. Like the HashiCorp Vault migration, the recommended path is incremental: federate first, migrate per-namespace, retire the ASM secrets when nothing reads them.

The structural difference vs Vault: ASM's flat naming (no real hierarchy beyond /-separated prefixes) maps cleanly onto ScaiVault's path scheme. The main thing to think about is what to do about ASM's automatic rotation — ScaiVault has its own rotation, so you can either turn ASM's off and use ScaiVault's, or leave ASM rotating and have ScaiVault federate-sync the result.

What you need#

  • ScaiVault token with secrets:write, federation:write, admin.
  • AWS IAM credentials with secretsmanager:Get* and secretsmanager:ListSecrets for the relevant secrets. Optionally secretsmanager:DeleteSecret for cleanup.
  • An ASM region (or several — repeat the setup per region if multi-region).

1. Inventory#

bash
1
2
3
aws secretsmanager list-secrets --region us-east-1 \
  --query 'SecretList[*].[Name,Description,Tags[?Key==`environment`].Value | [0]]' \
  --output table

Group by purpose:

  • Per-service credentials (typical: prod/billing/stripe, prod/billing/database).
  • ASM-rotated database passwords (managed by ASM, rotated via Lambda).
  • Encryption material referenced by KMS aliases.

2. Set up IAM for ScaiVault#

A minimum policy:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret",
        "secretsmanager:ListSecrets",
        "secretsmanager:ListSecretVersionIds"
      ],
      "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/*"
    }
  ]
}

Attach to an IAM user or role that ScaiVault will use. Note the ARN pattern restricts to the prod/ prefix; tighten further as you migrate per-team.

3. Store the AWS credentials in ScaiVault#

bash
1
2
3
4
5
6
7
curl -X PUT https://scaivault.scailabs.ai/v1/secrets/infra/aws/sm-reader \
  -H "Authorization: Bearer $SCAIVAULT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {"access_key_id": "AKIA...", "secret_access_key": "..."},
    "secret_type": "json"
  }'

Or, if ScaiVault is running in AWS with an IAM role, configure the federation backend to use that role directly — no static creds needed.

4. Configure federation#

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
curl -X POST https://scaivault.scailabs.ai/v1/federation/backends \
  -H "Authorization: Bearer $SCAIVAULT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "aws-prod-sm",
    "type": "aws-secrets-manager",
    "config": {
      "region": "us-east-1",
      "credentials_path": "infra/aws/sm-reader"
    },
    "path_mapping": {
      "external/aws/**": "prod/**"
    },
    "mode": "sync",
    "sync_interval": "15m"
  }'

Why sync and not proxy? ASM charges per API call (~$0.05 per 10,000 reads). For a hot path, sync into local storage is much cheaper. Set sync_interval to whatever staleness your application tolerates — most services can live with 15 minutes.

For low-volume sensitive secrets where freshness matters more than cost, use proxy instead.

Verify a read:

bash
1
2
3
# ASM secret "prod/billing/stripe" -> ScaiVault path "external/aws/billing/stripe"
curl -H "Authorization: Bearer $SCAIVAULT_TOKEN" \
     https://scaivault.scailabs.ai/v1/secrets/external/aws/billing/stripe

Should return whatever ASM has at prod/billing/stripe.

5. Migrate one secret to the new path scheme#

Federation gives you read access through ScaiVault, but the path is awkward (external/aws/...). Move to a cleaner scheme that doesn't telegraph the origin.

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Read from ASM via federation
value=$(curl -s -H "Authorization: Bearer $SCAIVAULT_TOKEN" \
  https://scaivault.scailabs.ai/v1/secrets/external/aws/billing/stripe | jq -c .data)

# Write to the new canonical path
curl -X PUT https://scaivault.scailabs.ai/v1/secrets/environments/production/billing/stripe \
  -H "Authorization: Bearer $SCAIVAULT_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"data\": $value,
    \"secret_type\": \"json\",
    \"metadata\": {
      \"tags\": [\"billing\", \"stripe\", \"migrated-from-asm\"],
      \"owner\": \"team:billing\"
    },
    \"options\": {\"max_versions\": 10}
  }"

Script the whole batch:

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import httpx, os

SV  = "https://scaivault.scailabs.ai"
SVT = os.environ["SCAIVAULT_TOKEN"]
H   = {"Authorization": f"Bearer {SVT}"}

MAPPING = {
    "external/aws/billing/stripe":     "environments/production/billing/stripe",
    "external/aws/billing/database":   "environments/production/billing/database",
    "external/aws/reporting/salesforce": "shared/integrations/salesforce/oauth",
}

for src, dst in MAPPING.items():
    value = httpx.get(f"{SV}/v1/secrets/{src}", headers=H).json()
    httpx.put(
        f"{SV}/v1/secrets/{dst}",
        headers=H,
        json={
            "data": value["data"],
            "secret_type": value.get("secret_type", "json"),
            "metadata": {"tags": ["migrated-from-asm"]},
        },
    ).raise_for_status()
    print(f"  {src} -> {dst}")

6. Repoint consumers#

Same pattern as the .env migration tutorial: config flag, staging rollout, production rollout with fallback, remove fallback.

For most apps using the AWS SDK directly, the change is replacing:

python
1
2
3
import boto3
client = boto3.client("secretsmanager")
secret = json.loads(client.get_secret_value(SecretId="prod/billing/stripe")["SecretString"])

with:

python
1
2
3
from scaivault_sdk import SyncScaiVaultClient
client = SyncScaiVaultClient(base_url=..., token=...)
secret = client.secrets.read("environments/production/billing/stripe").data

The path is now product-facing, not AWS-account-specific.

7. Handle ASM-rotated secrets#

ASM secrets with rotation enabled have a Lambda function that owns the rotation. Two paths:

Option A — turn off ASM rotation, use ScaiVault's.

  1. Migrate the secret to ScaiVault.
  2. In AWS Console (or via API): disable rotation on the ASM secret.
  3. Create a ScaiVault rotation policy and assign the migrated secret.
  4. If the secret needs the rotation to happen at the source system (e.g. RDS password), wire a webhook on rotation.due that re-runs the equivalent logic against the source.

Option B — keep ASM rotation, ScaiVault syncs the result.

  1. Migrate to ScaiVault. Keep ASM as the authority.
  2. Configure federation in sync mode — every 15min ScaiVault picks up the latest version from ASM.
  3. Consumers read from ScaiVault. When ASM rotates, the new value propagates to ScaiVault on the next sync cycle.
  4. Bounded staleness: up to sync_interval. For most apps with retries, this is fine.

Option A is the long-term path. Option B is the right transitional choice if you don't want to rebuild the rotation Lambda logic right now.

8. Clean up#

After consumers read from the new paths and audit shows zero reads from federated external/aws/... paths:

bash
1
2
3
4
5
# In AWS
aws secretsmanager delete-secret --secret-id prod/billing/stripe \
  --recovery-window-in-days 30 --region us-east-1

# When you're sure, run again with --force-delete-without-recovery

If you keep federation in place (Option B), don't delete the ASM secret — ScaiVault still depends on it.

ASM-specific considerations#

Versioning. ASM has version IDs (UUIDs); ScaiVault has integer versions. The federation sync maps AWSCURRENT to the current ScaiVault version. ASM versions you care about preserving need to be exported separately — ScaiVault won't recreate the full ASM history.

Tags. ASM tags don't map cleanly to ScaiVault metadata.tags (ASM tags are key/value; ScaiVault tags are bare strings). The federation backend flattens ASM tags into ScaiVault tag strings of the form key=value by default. Customize via path_mapping's transform option if you need a different scheme.

Lambda rotation. Disable in ASM before turning off the consumers. Otherwise the Lambda rotates the underlying DB password while consumers are still reading from ASM with cached creds. Order of operations: disable rotation → migrate → switch consumers → turn off ASM secret.

Cross-region replication. If your ASM secrets are replicated across regions, configure a ScaiVault federation backend per region; same source mapping, different config.region.

Common questions#

"ASM is much cheaper than ScaiVault for our use case." ScaiVault doesn't charge per-API-call, so high-read-volume workloads usually come out ahead. But run the numbers on your specific traffic shape before committing.

"We use ASM with KMS customer-managed keys." Those keys stay in KMS; ScaiVault doesn't move them. If you want to migrate the KMS configuration itself, that's a separate workstream — your AWS KMS keys are still your AWS KMS keys.

"Can ASM read from ScaiVault instead of the reverse?" Not directly. ASM doesn't have a federation feature. You'd need a Lambda that polls ScaiVault and writes back to ASM — possible but rarely worth the effort. Better to move consumers off ASM.

What's next#

Updated 2026-05-17 13:26:50 View source (.md) rev 1