Creates new API.md with complete API reference including: - Architecture and encryption model documentation - Installation and configuration guides - Authentication methods and API endpoints - Go package API documentation - Error codes and code examples - License tier information Also updates README.md to reference the new API documentation.
459 lines
17 KiB
Markdown
459 lines
17 KiB
Markdown
# GitCaddy Vault
|
|
|
|
**Encrypted Secrets Management for GitCaddy**
|
|
|
|
GitCaddy Vault is a commercial module compiled directly into GitCaddy Server that provides enterprise-grade secrets management within your GitCaddy repositories. Store, version, and securely access credentials, API keys, certificates, and other sensitive data without leaving your Git workflow.
|
|
|
|
## Features
|
|
|
|
### Core Capabilities
|
|
|
|
- **Encrypted Storage** - All secrets encrypted at rest using AES-256-GCM with per-repository encryption keys
|
|
- **Version History** - Full version tracking with rollback capability for all secrets
|
|
- **Audit Logging** - Complete audit trail of all secret access and modifications
|
|
- **CI/CD Tokens** - Scoped tokens for secure automated access during builds and deployments
|
|
|
|
### Secret Types
|
|
|
|
| Type | Description |
|
|
|------|-------------|
|
|
| `key-value` | Simple key-value pairs |
|
|
| `env-file` | Environment file format (KEY=value) |
|
|
| `file` | Arbitrary file content |
|
|
| `certificate` | TLS/SSL certificates |
|
|
| `ssh-key` | SSH private keys |
|
|
|
|
### Lockbox (End-to-End Encryption)
|
|
|
|
Lockbox provides optional client-side encryption where the server **never sees your plaintext secrets**. Perfect for highly sensitive data where you don't want even the server administrator to have access.
|
|
|
|
| Feature | Standard Mode | Lockbox Mode |
|
|
|---------|--------------|--------------|
|
|
| Server sees plaintext | Yes | No |
|
|
| Passphrase required | No | Yes |
|
|
| Recovery if passphrase lost | Yes | No |
|
|
| Web UI viewing | Yes | CLI/SDK only |
|
|
|
|
**How Lockbox Works:**
|
|
1. Client encrypts secret with your passphrase using Argon2id + AES-256-GCM
|
|
2. Encrypted blob is sent to server in `lockbox:v1:...` format
|
|
3. Server wraps the blob with repository DEK (double encryption)
|
|
4. On retrieval, server unwraps DEK layer, returns lockbox blob
|
|
5. Client decrypts with your passphrase
|
|
|
|
**Encryption Scheme:**
|
|
- Key derivation: Argon2id (time=1, memory=64MB, parallelism=4)
|
|
- Cipher: AES-256-GCM with 12-byte nonce
|
|
- Salt: 16 bytes random per secret
|
|
- Format: `lockbox:v1:<base64(salt)>:<base64(nonce||ciphertext||tag)>`
|
|
|
|
### Security Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ GitCaddy Server │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
│ │ Web UI │ │ REST API │ │ CI/CD API │ │
|
|
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
|
|
│ │ │ │ │
|
|
│ └──────────────────┼──────────────────┘ │
|
|
│ │ │
|
|
│ ┌────────▼────────┐ │
|
|
│ │ Vault Service │ │
|
|
│ └────────┬────────┘ │
|
|
│ │ │
|
|
│ ┌──────────────────┼──────────────────┐ │
|
|
│ ┌─────▼─────┐ ┌──────▼──────┐ ┌──────▼──────┐ │
|
|
│ │ Crypto │ │ Models │ │ License │ │
|
|
│ │ Engine │ │ (XORM) │ │ Manager │ │
|
|
│ └───────────┘ └─────────────┘ └─────────────┘ │
|
|
│ │
|
|
│ (Compiled into GitCaddy Server) │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Encryption Hierarchy:**
|
|
1. **Master Key (KEK)** - Server-level key encryption key
|
|
2. **Repository DEK** - Per-repository data encryption key, encrypted by KEK
|
|
3. **Secret Values** - Encrypted using repository DEK with AES-256-GCM
|
|
|
|
## Installation
|
|
|
|
### Requirements
|
|
|
|
- GitCaddy Server v1.0.0 or later (Vault is included automatically)
|
|
- Valid GitCaddy Vault license
|
|
|
|
### Setup
|
|
|
|
GitCaddy Vault is compiled directly into GitCaddy Server - no separate installation required.
|
|
|
|
1. Add your license key via environment variable or file:
|
|
```bash
|
|
# Option 1: Environment variable
|
|
export GITCADDY_LICENSE_KEY="<your-base64-license>"
|
|
|
|
# Option 2: License file
|
|
cp license.key /etc/gitcaddy/license.key
|
|
```
|
|
|
|
2. Restart GitCaddy Server to activate the license
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
| Variable | Description | Default |
|
|
|----------|-------------|---------|
|
|
| `GITCADDY_LICENSE_KEY` | Base64-encoded license key | - |
|
|
| `GITCADDY_LICENSE_FILE` | Path to license file | `/etc/gitcaddy/license.key` |
|
|
| `GITCADDY_VAULT_KEK` | Master key encryption key (32 bytes, hex) | Auto-generated |
|
|
| `GITCADDY_DEV_MODE` | Skip license validation (dev only) | `0` |
|
|
|
|
### License File Locations
|
|
|
|
GitCaddy Server searches for license files in this order:
|
|
1. Path specified by `GITCADDY_LICENSE_FILE`
|
|
2. `/etc/gitcaddy/license.key`
|
|
3. `./custom/license.key`
|
|
4. `./license.key`
|
|
|
|
## Usage
|
|
|
|
### Web Interface
|
|
|
|
Access the Vault tab in any repository where you have admin permissions:
|
|
|
|
```
|
|
https://your-gitcaddy-instance/owner/repo/vault
|
|
```
|
|
|
|
**Managing Secrets:**
|
|
1. Navigate to Repository > Vault > Secrets
|
|
2. Click "New Secret" to create a secret
|
|
3. Use dot notation for organization: `prod.database.password`, `staging.api.key`
|
|
|
|
**Creating CI/CD Tokens:**
|
|
1. Navigate to Repository > Vault > CI/CD Tokens
|
|
2. Click "New Token"
|
|
3. Define the scope (e.g., `read:*`, `read:prod.*`, `write:db.credentials`)
|
|
4. Set expiration time
|
|
5. Copy the token immediately (shown only once)
|
|
|
|
### REST API
|
|
|
|
All API endpoints require a valid vault token in the Authorization header.
|
|
|
|
**Authentication:**
|
|
```bash
|
|
# Bearer token format
|
|
Authorization: Bearer gvt_abc123...
|
|
|
|
# Or token format
|
|
Authorization: token gvt_abc123...
|
|
```
|
|
|
|
**List Secrets:**
|
|
```bash
|
|
curl -H "Authorization: Bearer $VAULT_TOKEN" \
|
|
https://gitcaddy.example.com/api/v1/repos/owner/repo/vault/secrets
|
|
```
|
|
|
|
**Get Secret Value:**
|
|
```bash
|
|
curl -H "Authorization: Bearer $VAULT_TOKEN" \
|
|
https://gitcaddy.example.com/api/v1/repos/owner/repo/vault/secrets/prod.database.password
|
|
```
|
|
|
|
**Create Secret:**
|
|
```bash
|
|
curl -X POST \
|
|
-H "Authorization: Bearer $VAULT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"name": "prod.database.password",
|
|
"description": "Production database credentials",
|
|
"type": "key-value",
|
|
"value": "secret-password-here"
|
|
}' \
|
|
https://gitcaddy.example.com/api/v1/repos/owner/repo/vault/secrets
|
|
```
|
|
|
|
**Update Secret:**
|
|
```bash
|
|
curl -X PUT \
|
|
-H "Authorization: Bearer $VAULT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"type": "key-value",
|
|
"value": "new-secret-value",
|
|
"comment": "Rotated credentials"
|
|
}' \
|
|
https://gitcaddy.example.com/api/v1/repos/owner/repo/vault/secrets/prod.database.password
|
|
```
|
|
|
|
**Delete Secret:**
|
|
```bash
|
|
curl -X DELETE \
|
|
-H "Authorization: Bearer $VAULT_TOKEN" \
|
|
https://gitcaddy.example.com/api/v1/repos/owner/repo/vault/secrets/prod.database.password
|
|
```
|
|
|
|
### CI/CD Integration
|
|
|
|
**GitHub Actions / Gitea Actions:**
|
|
```yaml
|
|
jobs:
|
|
deploy:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Fetch secrets
|
|
run: |
|
|
DB_PASSWORD=$(curl -s -H "Authorization: Bearer ${{ secrets.VAULT_TOKEN }}" \
|
|
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/vault/secrets/prod.database.password" \
|
|
| jq -r '.value')
|
|
echo "::add-mask::$DB_PASSWORD"
|
|
echo "DB_PASSWORD=$DB_PASSWORD" >> $GITHUB_ENV
|
|
```
|
|
|
|
**GitLab CI:**
|
|
```yaml
|
|
deploy:
|
|
script:
|
|
- |
|
|
export DB_PASSWORD=$(curl -s -H "Authorization: Bearer $VAULT_TOKEN" \
|
|
"$CI_SERVER_URL/api/v1/repos/$CI_PROJECT_PATH/vault/secrets/prod.database.password" \
|
|
| jq -r '.value')
|
|
```
|
|
|
|
### Token Scopes
|
|
|
|
Token scopes control access to secrets using a simple grammar:
|
|
|
|
| Scope | Description |
|
|
|-------|-------------|
|
|
| `read:*` | Read access to all secrets |
|
|
| `write:*` | Read and write access to all secrets |
|
|
| `read:prod.*` | Read access to secrets starting with `prod.` |
|
|
| `write:db.credentials` | Write access to specific secret `db.credentials` |
|
|
| `admin` | Full administrative access |
|
|
|
|
**Multiple scopes:** Separate with commas: `read:prod.*,write:staging.*`
|
|
|
|
## License Tiers
|
|
|
|
| Feature | Solo | Pro | Team | Enterprise |
|
|
|---------|------|-----|------|------------|
|
|
| Users | 1 | 5 | 25 | Unlimited |
|
|
| Secrets per repo | 5 | Unlimited | Unlimited | Unlimited |
|
|
| Audit retention | 7 days | 90 days | 1 year | Custom |
|
|
| Version history | No | Yes | Yes | Yes |
|
|
| CI/CD tokens | No | Yes | Yes | Yes |
|
|
| SSO integration | No | No | Yes | Yes |
|
|
| Priority support | No | No | No | Yes |
|
|
|
|
## Database Schema
|
|
|
|
GitCaddy Vault uses the following tables:
|
|
|
|
- `vault_secret` - Secret metadata
|
|
- `vault_secret_version` - Versioned secret values (encrypted)
|
|
- `vault_repo_key` - Per-repository encryption keys
|
|
- `vault_token` - CI/CD access tokens
|
|
- `vault_audit_entry` - Audit log entries
|
|
|
|
## Development
|
|
|
|
### Architecture: Vault ↔ Server Sync
|
|
|
|
**Important for contributors and AI assistants:**
|
|
|
|
GitCaddy Vault is the **source of truth** for vault-related templates and locales. Due to Go plugin compilation limitations, vault code is compiled directly into GitCaddy Server rather than loaded as a dynamic plugin.
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ gitcaddy-vault (this repo) │
|
|
│ SOURCE OF TRUTH for: │
|
|
│ • templates/repo/vault/*.tmpl → UI templates │
|
|
│ • locale/*.json → Translation strings │
|
|
│ • models/, services/, crypto/ → Business logic │
|
|
│ • license/ → License validation │
|
|
└─────────────────────────┬───────────────────────────────────────┘
|
|
│
|
|
BUILD TIME SYNC
|
|
(scripts/sync-vault.sh)
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ gitcaddy-server │
|
|
│ RECEIVES from vault: │
|
|
│ • templates/repo/vault/*.tmpl ← Copied from vault │
|
|
│ • options/locale/*.json ← vault.* keys merged │
|
|
│ │
|
|
│ SERVER-ONLY (not in vault): │
|
|
│ • templates/repo/vault/feature_upgrade.tmpl │
|
|
│ • templates/repo/vault/not_installed.tmpl │
|
|
│ • templates/repo/vault/upgrade.tmpl │
|
|
│ • routers/web/repo/vault/vault.go ← Router glue code │
|
|
│ • services/vault/vault.go ← Service wrappers │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**When making changes:**
|
|
- Edit templates/locales in **gitcaddy-vault** (this repo)
|
|
- The CI build automatically syncs to gitcaddy-server
|
|
- Server-specific templates (upgrade prompts) stay in server repo
|
|
- Go router code stays in server repo (thin integration layer)
|
|
|
|
**Why not Go plugins?**
|
|
Go plugins require exact compiler version and dependency matches between plugin and host. This is fragile in practice, so we compile vault directly into the server binary.
|
|
|
|
### Building
|
|
|
|
The Vault module is compiled directly into GitCaddy Server. To build the server with Vault:
|
|
|
|
```bash
|
|
# Clone GitCaddy Server (includes Vault)
|
|
git clone https://git.marketally.com/gitcaddy/server.git
|
|
cd server
|
|
|
|
# Build the server (Vault is included automatically)
|
|
make build
|
|
|
|
# Run tests
|
|
go test ./...
|
|
```
|
|
|
|
### Keygen Utility
|
|
|
|
The license key generation tool is built separately:
|
|
|
|
```bash
|
|
# Clone the vault repository
|
|
git clone https://git.marketally.com/gitcaddy/vault.git
|
|
cd vault
|
|
|
|
# Build the keygen utility
|
|
go build -o keygen ./cmd/keygen
|
|
```
|
|
|
|
### Generating License Keys
|
|
|
|
```bash
|
|
# Generate a new keypair (do this once, keep private key secure!)
|
|
go run ./cmd/keygen -generate-keys
|
|
|
|
# Sign a license
|
|
go run ./cmd/keygen -sign \
|
|
-email customer@example.com \
|
|
-tier pro \
|
|
-duration 365d \
|
|
-private-key /secure/path/private.key
|
|
```
|
|
|
|
### Local Development
|
|
|
|
Set `GITCADDY_DEV_MODE=1` to skip license validation during development:
|
|
|
|
```bash
|
|
export GITCADDY_DEV_MODE=1
|
|
```
|
|
|
|
## Key Management
|
|
|
|
### Master Key Configuration
|
|
|
|
The vault uses a master Key Encryption Key (KEK) to encrypt repository-level Data Encryption Keys (DEKs). Configure the master key using one of these methods (in priority order):
|
|
|
|
1. **app.ini** (recommended for production):
|
|
```ini
|
|
[vault]
|
|
MASTER_KEY = <64-character-hex-string>
|
|
```
|
|
|
|
2. **Environment variable**:
|
|
```bash
|
|
export GITCADDY_VAULT_KEY="<64-character-hex-string>"
|
|
```
|
|
|
|
3. **Key file**:
|
|
```bash
|
|
export GITCADDY_VAULT_KEY_FILE="/etc/gitcaddy/vault.key"
|
|
```
|
|
|
|
4. **Fallback** (not recommended): If none of the above are set, Gitea's `SECRET_KEY` is used as a fallback.
|
|
|
|
**Generate a secure master key:**
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
### Key Migration
|
|
|
|
If you change your master key or need to migrate from the fallback key to a dedicated master key, use the Key Migration feature.
|
|
|
|
**When to use key migration:**
|
|
- You changed the `MASTER_KEY` in app.ini and existing secrets are now inaccessible
|
|
- Secrets were created using the fallback key before a dedicated master key was configured
|
|
- You see "Encryption Key Mismatch" errors when accessing vault secrets
|
|
|
|
**Web UI:**
|
|
1. Navigate to Repository > Vault > Key Migration (admin only)
|
|
2. Enter the old master key (the previous `MASTER_KEY` or Gitea's `SECRET_KEY`)
|
|
3. Choose the migration scope (this repository or all repositories)
|
|
4. Click "Start Migration"
|
|
|
|
**API:**
|
|
```bash
|
|
curl -X POST \
|
|
-H "Authorization: Bearer $VAULT_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"old_key": "<previous-master-key-or-secret-key>",
|
|
"repo_id": 0
|
|
}' \
|
|
https://gitcaddy.example.com/owner/repo/-/vault/api/migrate-key
|
|
```
|
|
|
|
The `old_key` can be:
|
|
- A 64-character hex string (will be decoded to 32 bytes)
|
|
- Raw text (will be used as-is, padded/truncated to 32 bytes)
|
|
|
|
Set `repo_id` to `0` to migrate the current repository, or specify a repo ID for a specific repository. Instance admins can migrate all repositories at once.
|
|
|
|
### DEK Rotation (Enterprise)
|
|
|
|
For enhanced security, Enterprise license holders can rotate the Data Encryption Key (DEK) for a repository. This generates a new DEK and re-encrypts all secret versions.
|
|
|
|
**Web UI:**
|
|
1. Navigate to Repository > Vault > Key Migration
|
|
2. Click "Rotate DEK" in the DEK Rotation section
|
|
|
|
**API:**
|
|
```bash
|
|
curl -X POST \
|
|
-H "Authorization: Bearer $VAULT_TOKEN" \
|
|
https://gitcaddy.example.com/owner/repo/-/vault/api/rotate-key
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
1. **Key Management** - The master KEK should be stored securely (HSM, KMS, or secure environment variable)
|
|
2. **Token Storage** - Vault tokens are hashed with SHA-256 before storage
|
|
3. **Audit Trail** - All access is logged with IP address and user information
|
|
4. **Soft Delete** - Deleted secrets are retained for recovery before permanent deletion
|
|
5. **TLS Required** - Always use HTTPS in production
|
|
|
|
## Support
|
|
|
|
- **Documentation:** https://docs.gitcaddy.com/vault
|
|
- **Issues:** https://git.marketally.com/gitcaddy/vault/issues
|
|
- **Email:** support@marketally.com
|
|
|
|
## License
|
|
|
|
Business Source License 1.1 - See LICENSE file for details.
|
|
|
|
Copyright 2026 MarketAlly. All rights reserved.
|