feat: add hierarchical document signing with Vault API

- Introduced a new hierarchical signing system using HashiCorp Vault.
- Added Rust modules for user management, secrets setup, and document API.
- Implemented API endpoints for login, document upload, signing, and verification.
- Updated README with features, usage, and API examples.
This commit is contained in:
Harald Hoyer 2025-03-20 14:39:22 +01:00
parent 0dc662865f
commit f11b83ddf4
7 changed files with 1177 additions and 79 deletions

137
README.md
View file

@ -1,93 +1,90 @@
# Vault Hierarchical Initializer
# Hierarchical Document Signing with HashiCorp Vault
A Rust-based utility for initializing and unsealing HashiCorp Vault in non-dev (production) mode.
This project implements a hierarchical document signing system using HashiCorp Vault. It allows for secure document signing with a requirement of a specific number of signatures from different departmental groups.
## Overview
## Features
This project provides a Docker-based solution for:
- **Hierarchical Signing**: Requires 3 of 5 signatures to validate a document, with at least 1 signature from each department
- **Department Structure**: Two departments (Legal and Finance) with 5 users each
- **Document API**: Upload, sign, and verify documents through a RESTful API
- **Vault Integration**: Leverages HashiCorp Vault's Transit engine for cryptographic operations
1. Running a HashiCorp Vault server in non-dev (production) mode
2. Automatically initializing the Vault instance
3. Unsealing the Vault after initialization
4. Storing unseal keys and root token securely
## System Architecture
## Prerequisites
The system consists of:
- Docker and Docker Compose installed on your system
- Rust (if you want to build the project locally)
1. **Vault Server**: Provides secure storage and cryptographic operations
2. **Rust Application**: Initializes Vault and provides a REST API for document operations
3. **User Hierarchy**: 10 users organized into 2 departments
4. **Signature Requirements**: 3 of 5 signatures needed, with at least 1 from each department
## Configuration
## API Endpoints
In production mode, Vault:
- Starts sealed and requires a threshold of unseal keys to unseal
- Stores data persistently in mounted volumes
- Requires explicit initialization
- Needs manual unsealing after restarts
- **POST /api/login**: Authenticate with username/password and get a token
- **POST /api/documents**: Upload a new document for signing
- **GET /api/documents/:id**: Retrieve document metadata
- **POST /api/documents/:id/sign**: Sign a document with your user credentials
- **GET /api/documents/:id/verify**: Check if a document has sufficient signatures
The implementation uses:
- 5 key shares with a threshold of 3 keys needed for unsealing
- Persistent volume storage for Vault data
## Getting Started
## Usage
### Prerequisites
### Starting Vault with Docker Compose
- Docker and Docker Compose
- Rust development environment (if building from source)
```bash
docker-compose up -d
```
### Running with Docker
This will:
1. Start a Vault server in production mode
2. Run the vault-hier utility to initialize Vault if needed
3. Automatically unseal Vault using the threshold number of keys
4. Save the unseal keys and root token to `vault-credentials.txt` in the mounted volume
1. Start the Vault server and initialization program:
```
docker-compose up -d
```
### Getting Vault Credentials
2. The service will automatically:
- Initialize Vault (if needed)
- Unseal Vault
- Create 10 users in a hierarchical structure
- Start the API server on port 3000
After initialization, you can find the unseal keys and root token in:
3. User credentials:
- Legal department: legal1/legal1pass through legal5/legal5pass
- Finance department: finance1/finance1pass through finance5/finance5pass
```
./vault-credentials.txt
```
### API Usage Examples
Keep these credentials safe! They provide full access to your Vault instance.
1. **Login**:
```bash
curl -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"username":"legal1","password":"legal1pass"}'
```
### Restarting a Sealed Vault
2. **Upload Document**:
```bash
curl -X POST http://localhost:3000/api/documents \
-F "name=Contract" \
-F "file=@/path/to/document.pdf"
```
If your Vault instance restarts, it will start in a sealed state. To unseal it automatically:
3. **Sign Document**:
```bash
curl -X POST http://localhost:3000/api/documents/DOCUMENT_ID/sign \
-H "Content-Type: application/json" \
-d '{"username":"legal1","token":"USER_TOKEN"}'
```
```bash
# Set the unseal keys as environment variables
export VAULT_UNSEAL_KEY_1="your-first-key"
export VAULT_UNSEAL_KEY_2="your-second-key"
export VAULT_UNSEAL_KEY_3="your-third-key"
# Restart the vault-init container to trigger unsealing
docker-compose restart vault-init
```
## Development
### Building the Project Locally
```bash
cargo build --release
```
### Running Tests
```bash
cargo test
```
### Custom Configuration
To modify the key sharing threshold:
1. Edit the `init_req` struct in `src/main.rs`
2. Rebuild the Docker image
4. **Verify Document**:
```bash
curl -X GET http://localhost:3000/api/documents/DOCUMENT_ID/verify
```
## Security Considerations
- In a production environment, never store unseal keys on the same machine as Vault
- Consider using a key management solution like Shamir's Secret Sharing
- Rotate root tokens regularly and use appropriate authentication methods
- All cryptographic operations are performed by Vault's Transit engine
- Each user has their own signing key
- Root token should be secured in production environments
- Consider adding TLS for production deployments
## License
MIT