A simple and fast Go tool for file integrity monitoring. Detects unauthorized file modifications caused by OS command injection and other attacks by recording file hashes during deployment and verifying them periodically.
The name "Kekkai" comes from the Japanese word 結界 (kekkai), meaning "barrier" - a protective boundary that keeps unwanted things out, perfectly representing this tool's purpose of protecting your files from tampering.
Kekkai was designed to solve specific challenges in production server environments:
Traditional tools like tar or file sync utilities (e.g., rsync) include metadata like timestamps in their comparisons, causing false positives when only timestamps change. In environments with heavy NFS usage or dynamic log directories, existing tools become difficult to configure and maintain.
Detects actual content changes, not superficial modifications
Immutable Exclude Rules
Application dependencies (vendor, node_modules) are monitored as they're part of the deployment
Symlink Security
os.Lstat to properly detect symlinks without following themos.Readlink)Prevents attackers from hiding malicious changes through symlink manipulation
Secure Hash Storage with S3
Local file output available for testing
Tamper-Resistant Distribution
# Build from source
git clone https://github.com/catatsuy/kekkai.git
cd kekkai
make
# Or directly with go build
go build -o ./bin/kekkai ./cmd/kekkai
# Run tests
make test
# Generate manifest
kekkai generate --target /var/www/app --output manifest.json
# Verify files
kekkai verify --manifest manifest.json --target /var/www/app
kekkai generate \
--target /var/www/app \
--exclude "*.log" \
--exclude "cache/**" \
--output manifest.json
Kekkai stores manifests in S3 for secure, centralized management. Each deployment updates the same manifest.json file.
# For production deployment (must explicitly specify --base-path)
kekkai generate \
--target /var/www/app \
--s3-bucket my-manifests \
--app-name myapp \
--base-path production # Explicitly required for production
# For staging/development (uses default "development" if not specified)
kekkai generate \
--target /var/www/app \
--s3-bucket my-manifests \
--app-name myapp \
--base-path staging
# During verification (must match the base-path used during generation)
kekkai verify \
--s3-bucket my-manifests \
--app-name myapp \
--base-path production \
--target /var/www/app
Benefits: - Lower S3 costs - Minimal S3 operations - Clean structure - One manifest file per application
# Add to crontab for periodic checks
*/5 * * * * kekkai verify \
--s3-bucket my-manifests \
--app-name myapp \
--base-path production \
--target /var/www/app
# Use cache for faster verification (cache in temp directory)
*/5 * * * * kekkai verify \
--s3-bucket my-manifests \
--app-name myapp \
--base-path production \
--target /var/www/app \
--use-cache \
--verify-probability 0.1
# Use persistent cache in custom directory
*/5 * * * * kekkai verify \
--s3-bucket my-manifests \
--app-name myapp \
--base-path production \
--target /var/www/app \
--use-cache \
--cache-dir /var/cache/kekkai \
--verify-probability 0.1
Configure your monitoring system to alert based on your requirements (e.g., alert after consecutive failures).
These examples show common exclude patterns for various frameworks. Important: Only exclude files generated on the server (logs, cache, uploads). Application dependencies like vendor or node_modules MUST be monitored as they are part of the deployed application.
For production use, replace --output manifest.json with S3 storage options (--s3-bucket, --app-name, --base-path).
kekkai generate \
--target /var/www/app \
--exclude "storage/**" \
--exclude "bootstrap/cache/**" \
--exclude "*.log" \
--output manifest.json
kekkai generate \
--target /var/www/app \
--exclude "*.log" \
--exclude ".npm/**" \
--exclude "tmp/**" \
--output manifest.json
kekkai generate \
--target /var/www/app \
--exclude "log/**" \
--exclude "tmp/**" \
--exclude "public/assets/**" \
--output manifest.json
kekkai generate \
--target /var/www/app \
--exclude "**/__pycache__/**" \
--exclude "media/**" \
--exclude "staticfiles/**" \
--exclude "*.pyc" \
--output manifest.json
For deployment server (write access):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-manifests/*"
}
]
}
For production server (read-only):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::my-manifests/*"
}
]
}
Recommended: Enable S3 versioning to maintain history of manifest changes.
# Optional: Enable versioning for history tracking
aws s3api put-bucket-versioning \
--bucket my-manifests \
--versioning-configuration Status=Enabled
# Enable encryption
aws s3api put-bucket-encryption \
--bucket my-manifests \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'
# Optional: Set lifecycle policy to delete old versions after N days
aws s3api put-bucket-lifecycle-configuration \
--bucket my-manifests \
--lifecycle-configuration '{
"Rules": [{
"Id": "DeleteOldVersions",
"Status": "Enabled",
"NoncurrentVersionExpiration": {
"NoncurrentDays": 30
}
}]
}'
#!/bin/bash
# deploy.sh
set -e
APP_NAME="myapp"
DEPLOY_DIR="/var/www/app"
S3_BUCKET="my-manifests"
# 1. Install dependencies locally
cd ./src
composer install --no-dev
# 2. Deploy application to server
rsync -av ./src/ ${DEPLOY_DIR}/
# 3. Generate manifest and save to S3
# Note: For production, explicitly specify --base-path production
kekkai generate \
--target ${DEPLOY_DIR} \
--exclude "storage/**" \
--exclude "bootstrap/cache/**" \
--s3-bucket ${S3_BUCKET} \
--app-name ${APP_NAME} \
--base-path production # MUST be explicit for production
echo "Deploy completed with integrity manifest"
echo "Manifest saved to: ${S3_BUCKET}/production/${APP_NAME}/manifest.json"
Generate a manifest file.
Options:
-target string Target directory (default ".")
-output string Output file, "-" for stdout (default "-")
-exclude string Exclude pattern (can be specified multiple times)
-s3-bucket string S3 bucket name
-s3-region string AWS region
-base-path string S3 base path (default "development")
-app-name string Application name (creates path: {base-path}/{app-name}/manifest.json)
-format string Output format: text, json (default "text")
-workers int Number of worker threads (0 = auto detect, capped at CPU count)
-rate-limit int Rate limit in bytes per second (0 = no limit)
-timeout int Timeout in seconds (default: 300)
Verify file integrity.
Options:
-manifest string Manifest file path
-s3-bucket string S3 bucket name
-s3-region string AWS region
-base-path string S3 base path (default "development")
-app-name string Application name (reads from: {base-path}/{app-name}/manifest.json)
-target string Target directory to verify (default ".")
-format string Output format: text, json (default "text")
-workers int Number of worker threads (0 = auto detect, capped at CPU count)
-rate-limit int Rate limit in bytes per second (0 = no limit)
-timeout int Timeout in seconds (default: 300)
-use-cache Enable local cache for verification (checks size, mtime, ctime)
-cache-dir string Directory for cache file (default: system temp directory)
-verify-probability float Probability of hash verification with cache hit (0.0-1.0, default: 0.1)
✓ Integrity check passed
Verified 1523 files
{
"success": true,
"timestamp": "2024-01-01T00:00:00Z",
"message": "All files verified successfully",
"details": {
"total_files": 1523,
"verified_files": 1523
}
}
Kekkai uses glob patterns for the --exclude option to skip specific files and directories during manifest generation.
| Pattern | Description | Example |
|---|---|---|
*.ext |
Match files with specific extension | *.log matches app.log, error.log |
dir/* |
Match all files in a directory | logs/* matches logs/app.log |
dir/** |
Match all files recursively | cache/** matches cache/data.db, cache/sessions/abc.txt |
**/*.ext |
Match extension at any depth | **/*.pyc matches app.pyc, lib/utils.pyc |
**/dir/* |
Match directory at any depth | **/logs/* matches logs/app.log, app/logs/error.log |
path/to/file |
Exact path match | config/local.ini matches only that file |
/ as path separator (even on Windows)!pattern support)# Laravel/Symfony
--exclude "storage/**" # User uploads
--exclude "var/cache/**" # Framework cache
--exclude "var/log/**" # Application logs
--exclude "public/uploads/**" # Uploaded files
# Python/Django
--exclude "**/__pycache__/**" # Python cache
--exclude "**/*.pyc" # Compiled Python
--exclude "media/**" # User uploads
--exclude "staticfiles/**" # Collected static files
# Node.js
--exclude "*.log" # Log files
--exclude "tmp/**" # Temporary files
--exclude ".npm/**" # NPM cache
# General
--exclude "*.tmp" # Temporary files
--exclude "*.bak" # Backup files
--exclude ".git/**" # Git repository (if needed)
⚠️ Do NOT exclude application dependencies:
- ❌ --exclude "vendor/**" (PHP dependencies)
- ❌ --exclude "node_modules/**" (Node.js dependencies)
- ❌ --exclude "venv/**" (Python virtual environment)
These are part of your deployed application and must be monitored for tampering.
✅ Only exclude server-generated content: - Log files - Cache directories - User uploads - Temporary files - NFS mounts
Patterns are evaluated in this order:
1. Check for ** recursive matching
2. Special case: **/* or ** matches everything
3. Suffix pattern: dir/** matches everything under dir/
4. Prefix pattern: **/*.ext matches files with extension at any depth
5. Simple glob: Standard shell glob matching with * and ?
Kekkai has comprehensive symlink security to prevent attackers from hiding malicious changes:
Kekkai handles symlinks differently depending on where they appear:
If --target points to a symlink (e.g., /current → /releases/20240101):
- Automatically resolved: Uses filepath.EvalSymlinks to follow the symlink
- Operates on real path: All operations happen in the resolved directory
- Transparent to user: Works exactly as if you specified the real directory
Example:
# These produce identical results:
kekkai generate --target /var/www/current # Symlink to /var/www/releases/20240101
kekkai generate --target /var/www/releases/20240101 # Direct path
Fo
$ claude mcp add kekkai \
-- python -m otcore.mcp_server <graph>