Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .github/workflows/vault.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: LocalStack Vault Extension Tests

on:
push:
paths:
- vault/**
branches:
- main
pull_request:
paths:
- .github/workflows/vault.yml
- vault/**
workflow_dispatch:

env:
LOCALSTACK_DISABLE_EVENTS: "1"
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}

jobs:
integration-tests:
name: Run Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Vault
uses: eLco/setup-vault@v1

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Setup LocalStack and extension
run: |
cd vault

# Pull Docker images in parallel
docker pull localstack/localstack-pro &
docker pull hashicorp/vault:latest &
docker pull public.ecr.aws/lambda/python:3.11 &
pip install localstack awscli-local[ver1]

# Install and build extension
make install
make lint
make dist
localstack extensions -v install file://$(ls ./dist/localstack_vault-*.tar.gz)

# Wait for Docker pulls to complete
wait

# Start LocalStack with extension
DEBUG=1 EXTENSION_DEV_MODE=1 localstack start -d
localstack wait

- name: Run pytest tests
run: |
cd vault
make test

- name: Run sample app (Lambda + Vault Extension)
run: |
cd vault
make sample-app

- name: Print logs
if: always()
run: |
localstack logs
localstack stop
24 changes: 24 additions & 0 deletions vault/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Python
.venv/
build/
dist/
.eggs/
*egg-info/
__pycache__/
.pytest_cache/

# Terraform
.terraform/
.terraform.lock.hcl
terraform.tfstate*
*.tfplan

# OS
.DS_Store

# Temp files
*.zip
/tmp/

# Ignored Directories
sample-app-terraform/
55 changes: 55 additions & 0 deletions vault/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
VENV_BIN = python3 -m venv
VENV_DIR ?= .venv
VENV_ACTIVATE = $(VENV_DIR)/bin/activate
VENV_RUN = . $(VENV_ACTIVATE)

usage: ## Shows usage for this Makefile
@cat Makefile | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'

venv: $(VENV_ACTIVATE)

$(VENV_ACTIVATE): pyproject.toml
test -d .venv || $(VENV_BIN) .venv
$(VENV_RUN); pip install --upgrade pip setuptools plux
$(VENV_RUN); pip install -e .[dev]
touch $(VENV_DIR)/bin/activate

clean:
rm -rf .venv/
rm -rf build/
rm -rf .eggs/
rm -rf *.egg-info/

install: venv ## Install dependencies
$(VENV_RUN); python -m plux entrypoints

dist: venv ## Create distribution
$(VENV_RUN); python -m build

publish: clean-dist venv dist ## Publish extension to pypi
$(VENV_RUN); pip install --upgrade twine; twine upload dist/*

entrypoints: venv # Generate plugin entrypoints for Python package
$(VENV_RUN); python -m plux entrypoints

format: ## Run ruff to format the whole codebase
$(VENV_RUN); python -m ruff format .; python -m ruff check --output-format=full --fix .

lint: ## Run ruff to lint the codebase
$(VENV_RUN); python -m ruff check --output-format=full .

test: ## Run pytest tests (requires LocalStack running)
$(VENV_RUN); python -m pytest tests/ -v

sample-app: ## Deploy sample app with Lambda + Vault
@echo "Setting up Vault secrets..."
sample-app-extension/bin/setup-vault.sh
@echo "Deploying Lambda function with Vault Lambda Extension..."
sample-app-extension/bin/deploy-lambda.sh
@echo "Testing Lambda invocation..."
sample-app-extension/bin/test-lambda.sh

clean-dist: clean
rm -rf dist/

.PHONY: clean clean-dist dist install publish usage venv format lint test sample-app
104 changes: 104 additions & 0 deletions vault/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# HashiCorp Vault on LocalStack

This [LocalStack Extension](https://github.com/localstack/localstack-extensions) runs [HashiCorp Vault](https://www.vaultproject.io/) alongside LocalStack for secrets management testing.

## Prerequisites

- Docker
- LocalStack Pro (free trial available)
- `localstack` CLI

## Install from GitHub repository

```bash
localstack extensions install "git+https://github.com/localstack/localstack-extensions.git#egg=localstack-extension-vault&subdirectory=vault"
```

## Install local development version

```bash
make install
localstack extensions dev enable .
```

Start LocalStack with `EXTENSION_DEV_MODE=1`:

```bash
EXTENSION_DEV_MODE=1 localstack start
```

## Usage

Vault is available at `http://vault.localhost.localstack.cloud:4566`.

### Add Secrets

```bash
export VAULT_ADDR=http://vault.localhost.localstack.cloud:4566
export VAULT_TOKEN=root

# Add a secret
vault kv put secret/my-app/config api_key=secret123 db_password=hunter2

# Verify
vault kv get secret/my-app/config
```

### Use with Lambda

Deploy a Lambda with the [Vault Lambda Extension](https://github.com/hashicorp/vault-lambda-extension) layer and these environment variables:

| Variable | Value |
|----------|-------|
| `VAULT_ADDR` | `http://vault.localhost.localstack.cloud:4566` |
| `VAULT_AUTH_PROVIDER` | `aws` |
| `VAULT_AUTH_ROLE` | `default-lambda-role` |
| `VAULT_SECRET_PATH_*` | Path to your secret (e.g., `secret/data/my-app/config`) |
| `VAULT_SECRET_FILE_*` | Where extension writes secrets (e.g., `/tmp/secrets/myapp`) |

See `sample-app-extension/` for a complete working example.

## Configuration

| Environment Variable | Default | Description |
|---------------------|---------|-------------|
| `VAULT_ROOT_TOKEN` | `root` | Dev mode root token |
| `VAULT_PORT` | `8200` | Vault API port (internal) |

## Pre-configured Resources

### Secrets Engines

| Path | Type | Description |
|------|------|-------------|
| `secret/` | KV v2 | Key-value secrets storage |
| `transit/` | Transit | Encryption as a service |

### Auth Methods

| Path | Type | Description |
|------|------|-------------|
| `aws/` | AWS IAM | Pre-configured for Lambda IAM auth |

### Policies

| Name | Permissions |
|------|-------------|
| `default-lambda-policy` | Full access to `secret/*` and `transit/*` |

## Sample App

See `sample-app-extension/` for a complete working example using the official Vault Lambda Extension layer.

```bash
make sample-app
```

## Limitations

- **Ephemeral**: All secrets are lost when LocalStack restarts
- **Dev mode only**: No production Vault features (seal/unseal, HA, etc.)

## Disclaimer

This extension is not affiliated with HashiCorp. Vault is a trademark of HashiCorp, Inc.
1 change: 1 addition & 0 deletions vault/localstack_vault/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# HashiCorp Vault Extension for LocalStack
Loading