Files
microdao-daarion/ops/secrets/api-keys.sh
Apple ef3473db21 snapshot: NODE1 production state 2026-02-09
Complete snapshot of /opt/microdao-daarion/ from NODE1 (144.76.224.179).
This represents the actual running production code that has diverged
significantly from the previous main branch.

Key changes from old main:
- Gateway (http_api.py): expanded from ~40KB to 164KB with full agent support
- Router: new /v1/agents/{id}/infer endpoint with vision + DeepSeek routing
- Behavior Policy: SOWA v2.2 (3-level: FULL/ACK/SILENT)
- Agent Registry: config/agent_registry.yml as single source of truth
- 13 agents configured (was 3)
- Memory service integration
- CrewAI teams and roles

Excluded from snapshot: venv/, .env, data/, backups, .tgz archives

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 08:46:46 -08:00

280 lines
7.2 KiB
Bash
Executable File

#!/bin/bash
#
# NODE1 API Key Management
# Version: 1.0
# Last Updated: 2026-01-26
#
# Usage:
# ./api-keys.sh create <name> [--admin]
# ./api-keys.sh revoke <key_id>
# ./api-keys.sh list
# ./api-keys.sh rotate-health
# ./api-keys.sh verify <key>
#
set -e
# Paths
KEYS_DIR="/opt/microdao-daarion/secrets"
KEYS_FILE="$KEYS_DIR/api-keys.conf"
HEALTH_TOKEN_FILE="$KEYS_DIR/health-token.conf"
NGINX_KEYS_MAP="$KEYS_DIR/nginx-api-keys.conf"
LOG_FILE="/var/log/microdao/api-keys.log"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Initialize directories
init_dirs() {
mkdir -p "$KEYS_DIR"
mkdir -p "$(dirname $LOG_FILE)"
chmod 700 "$KEYS_DIR"
touch "$KEYS_FILE" "$HEALTH_TOKEN_FILE" "$NGINX_KEYS_MAP"
chmod 600 "$KEYS_FILE" "$HEALTH_TOKEN_FILE" "$NGINX_KEYS_MAP"
}
# Log action (without exposing secrets)
log_action() {
local action="$1"
local key_id="$2"
local details="$3"
echo "$(date '+%Y-%m-%d %H:%M:%S') | $action | key_id=$key_id | $details" >> "$LOG_FILE"
}
# Generate random key
generate_key() {
openssl rand -hex 32
}
# Generate key ID
generate_key_id() {
local name="$1"
local timestamp=$(date +%Y%m%d%H%M%S)
local random=$(openssl rand -hex 4)
echo "kid_${name}_${timestamp}_${random}"
}
# Create new API key
create_key() {
local name="$1"
local is_admin="${2:-false}"
if [ -z "$name" ]; then
echo -e "${RED}Error: Key name required${NC}"
echo "Usage: $0 create <name> [--admin]"
exit 1
fi
local key_id=$(generate_key_id "$name")
local secret=$(generate_key)
local api_key="sk-${secret}"
local created_at=$(date -Iseconds)
local scope="standard"
[ "$is_admin" = "--admin" ] && scope="admin"
# Save to keys file (key_id|name|scope|created_at|hash)
local key_hash=$(echo -n "$api_key" | sha256sum | cut -d' ' -f1)
echo "${key_id}|${name}|${scope}|${created_at}|${key_hash}" >> "$KEYS_FILE"
# Update nginx map
rebuild_nginx_map
log_action "CREATE" "$key_id" "name=$name scope=$scope"
echo -e "${GREEN}API Key Created${NC}"
echo "================================"
echo "Key ID: $key_id"
echo "Name: $name"
echo "Scope: $scope"
echo "API Key: $api_key"
echo "================================"
echo -e "${YELLOW}WARNING: Save this key now. It cannot be retrieved later.${NC}"
}
# Revoke API key
revoke_key() {
local key_id="$1"
if [ -z "$key_id" ]; then
echo -e "${RED}Error: Key ID required${NC}"
echo "Usage: $0 revoke <key_id>"
exit 1
fi
if ! grep -q "^${key_id}|" "$KEYS_FILE" 2>/dev/null; then
echo -e "${RED}Error: Key ID not found${NC}"
exit 1
fi
# Remove from keys file
sed -i "/^${key_id}|/d" "$KEYS_FILE"
# Rebuild nginx map
rebuild_nginx_map
log_action "REVOKE" "$key_id" "revoked"
echo -e "${GREEN}Key revoked: $key_id${NC}"
echo "Run 'nginx -s reload' to apply changes"
}
# List all keys (without secrets)
list_keys() {
echo "API Keys"
echo "========"
echo ""
printf "%-40s %-15s %-10s %s\n" "KEY_ID" "NAME" "SCOPE" "CREATED"
printf "%-40s %-15s %-10s %s\n" "------" "----" "-----" "-------"
if [ -f "$KEYS_FILE" ] && [ -s "$KEYS_FILE" ]; then
while IFS='|' read -r key_id name scope created_at hash; do
printf "%-40s %-15s %-10s %s\n" "$key_id" "$name" "$scope" "${created_at:0:19}"
done < "$KEYS_FILE"
else
echo "(no keys)"
fi
echo ""
echo "Total: $(wc -l < "$KEYS_FILE" 2>/dev/null || echo 0) keys"
}
# Verify a key (returns key_id if valid)
verify_key() {
local api_key="$1"
if [ -z "$api_key" ]; then
echo -e "${RED}Error: API key required${NC}"
exit 1
fi
local key_hash=$(echo -n "$api_key" | sha256sum | cut -d' ' -f1)
while IFS='|' read -r key_id name scope created_at stored_hash; do
if [ "$key_hash" = "$stored_hash" ]; then
echo -e "${GREEN}Valid${NC}"
echo "Key ID: $key_id"
echo "Name: $name"
echo "Scope: $scope"
log_action "VERIFY" "$key_id" "valid"
exit 0
fi
done < "$KEYS_FILE"
echo -e "${RED}Invalid key${NC}"
log_action "VERIFY" "unknown" "invalid"
exit 1
}
# Rotate health token
rotate_health_token() {
local new_token=$(generate_key)
local old_token=""
# Read old token if exists
if [ -f "$HEALTH_TOKEN_FILE" ] && [ -s "$HEALTH_TOKEN_FILE" ]; then
old_token=$(grep "^current=" "$HEALTH_TOKEN_FILE" | cut -d'=' -f2)
fi
# Write new config (current + previous for grace period)
cat > "$HEALTH_TOKEN_FILE" << EOF
# Health Token Configuration
# Generated: $(date -Iseconds)
# Previous token valid for 24h after rotation
current=$new_token
previous=$old_token
rotated_at=$(date -Iseconds)
EOF
chmod 600 "$HEALTH_TOKEN_FILE"
# Update nginx include
cat > "$KEYS_DIR/nginx-health-token.conf" << EOF
# Auto-generated health token map
# Do not edit manually
map \$http_x_health_token \$health_token_valid {
default 0;
"$new_token" 1;
EOF
# Add previous token if exists (grace period)
if [ -n "$old_token" ]; then
echo " \"$old_token\" 1; # previous (grace period)" >> "$KEYS_DIR/nginx-health-token.conf"
fi
echo "}" >> "$KEYS_DIR/nginx-health-token.conf"
chmod 600 "$KEYS_DIR/nginx-health-token.conf"
log_action "ROTATE_HEALTH" "-" "token rotated"
echo -e "${GREEN}Health Token Rotated${NC}"
echo "================================"
echo "New Token: $new_token"
echo "================================"
echo -e "${YELLOW}Update your monitoring systems with the new token.${NC}"
echo "Previous token remains valid for grace period."
echo "Run 'nginx -s reload' to apply changes"
}
# Rebuild nginx API keys map
rebuild_nginx_map() {
cat > "$NGINX_KEYS_MAP" << 'HEADER'
# Auto-generated API keys map
# Do not edit manually - use api-keys.sh
# Format: key hash -> "key_id:scope"
map $api_key_hash $api_key_info {
default "";
HEADER
while IFS='|' read -r key_id name scope created_at hash; do
echo " \"$hash\" \"$key_id:$scope\";" >> "$NGINX_KEYS_MAP"
done < "$KEYS_FILE"
echo "}" >> "$NGINX_KEYS_MAP"
chmod 600 "$NGINX_KEYS_MAP"
}
# Show usage
usage() {
echo "NODE1 API Key Management"
echo ""
echo "Usage:"
echo " $0 create <name> [--admin] Create new API key"
echo " $0 revoke <key_id> Revoke API key"
echo " $0 list List all keys"
echo " $0 verify <api_key> Verify API key"
echo " $0 rotate-health Rotate health check token"
echo ""
echo "Examples:"
echo " $0 create monitoring"
echo " $0 create admin-user --admin"
echo " $0 revoke kid_monitoring_20260126_abc123"
}
# Main
init_dirs
case "${1:-}" in
create)
create_key "$2" "$3"
;;
revoke)
revoke_key "$2"
;;
list)
list_keys
;;
verify)
verify_key "$2"
;;
rotate-health)
rotate_health_token
;;
*)
usage
;;
esac