LocalStack (AWS Emulation)¶
LocalStack emulates AWS services locally for testing the secrets module without cloud accounts.
Features¶
Offline development: No AWS account required
Fast iteration: No network latency
CI/CD testing: Reproducible isolated tests
Cost savings: No cloud charges
Quick Start¶
cd infra
# Start LocalStack only
docker compose up -d localstack
# Check it's ready (wait for "LocalStack Ready" message)
docker compose logs -f localstack
Pre-configured Resources¶
The bootstrap script (localstack/init-aws.sh) creates these resources on startup:
Service |
Resource |
Description |
|---|---|---|
KMS |
|
Symmetric encryption key |
S3 |
|
Bucket for encrypted files |
Secrets Manager |
|
Test secret with API credentials |
Usage¶
AWS CLI¶
Prerequisites:
AWS CLI v2 must be installed (see Local Infrastructure)
Install the wrapper:
pip install kstlib[infra-tools]
The awslocal command is a thin wrapper around aws that automatically targets LocalStack:
# List KMS keys
awslocal kms list-keys
# Encrypt data
awslocal kms encrypt \
--key-id alias/kstlib-test \
--plaintext "my secret" \
--output text --query CiphertextBlob
# List S3 buckets
awslocal s3 ls
# Get secret value
awslocal secretsmanager get-secret-value --secret-id kstlib/test/api-key
awslocal has a known bug on Windows (cannot determine HOME directory). Add this function to your PowerShell profile ($PROFILE):
function awslocal {
$env:HOME = $env:USERPROFILE
$env:AWS_ACCESS_KEY_ID = "test"
$env:AWS_SECRET_ACCESS_KEY = "test"
aws --endpoint-url=http://localhost:4566 --region us-east-1 @args
}
Then use it the same way as on Linux/macOS:
awslocal kms list-keys
awslocal s3 ls
awslocal secretsmanager get-secret-value --secret-id kstlib/test/api-key
Python / boto3¶
import boto3
# Configure client for LocalStack
kms = boto3.client(
'kms',
endpoint_url='http://localhost:4566',
region_name='us-east-1',
aws_access_key_id='test',
aws_secret_access_key='test'
)
# Encrypt
response = kms.encrypt(
KeyId='alias/kstlib-test',
Plaintext=b'my secret data'
)
ciphertext = response['CiphertextBlob']
# Decrypt
response = kms.decrypt(CiphertextBlob=ciphertext)
plaintext = response['Plaintext']
Configuration¶
Copy the environment template and adjust as needed:
cp .env.example .env
Available settings:
Variable |
Default |
Description |
|---|---|---|
|
4566 |
Gateway port |
|
us-east-1 |
AWS region |
|
1 |
Persist data between restarts |
|
0 |
Enable debug logging |
CI/CD Integration¶
GitHub Actions¶
services:
localstack:
image: localstack/localstack:latest
ports:
- 4566:4566
env:
SERVICES: kms,s3,secretsmanager
steps:
- name: Wait for LocalStack
run: |
timeout 30 bash -c 'until curl -s http://localhost:4566/_localstack/health | grep -q running; do sleep 1; done'
pytest Fixture¶
import pytest
import boto3
@pytest.fixture
def kms_client():
"""KMS client configured for LocalStack."""
return boto3.client(
'kms',
endpoint_url='http://localhost:4566',
region_name='us-east-1',
aws_access_key_id='test',
aws_secret_access_key='test'
)
def test_encrypt_decrypt(kms_client):
# Encrypt
encrypted = kms_client.encrypt(
KeyId='alias/kstlib-test',
Plaintext=b'test data'
)
# Decrypt
decrypted = kms_client.decrypt(
CiphertextBlob=encrypted['CiphertextBlob']
)
assert decrypted['Plaintext'] == b'test data'
Troubleshooting¶
Container won’t start¶
# Check logs
docker compose logs localstack
Verify port is available:
lsof -i :4566
netstat -an | findstr 4566
Init script not running¶
The bootstrap script (init-aws.sh) runs automatically on container start. If resources aren’t created:
# Check script executed
docker compose logs localstack | grep "LocalStack Ready"
# Run manually if needed
docker compose exec localstack bash /etc/localstack/init/ready.d/init-aws.sh
Full reset¶
docker compose down -v
docker compose up -d localstack
See Also¶
Secrets Workflow - SOPS-based secrets management
Secrets Management - SecretResolver documentation