ops-jrz1/specs/002-slack-bridge-integration/contracts/secrets-schema.yaml
Dan ca379311b8 Add Slack bridge integration feature specification
Includes spec, plan, research, data model, contracts, and quickstart guide
for mautrix-slack Socket Mode bridge deployment.
2025-10-26 14:36:44 -07:00

360 lines
13 KiB
YAML

# Secrets Schema Contract: Slack Bridge Credentials
# This contract defines the structure and handling of sensitive credentials
# required for the Slack↔Matrix bridge. All secrets are managed via sops-nix
# with age encryption.
# =============================================================================
# Secret Definitions
# =============================================================================
secrets:
slack-oauth-token:
description: "Slack bot user OAuth token for API operations"
format: "xoxb-[workspace_id]-[token_id]-[secret]"
example: "xoxb-1234567890-1234567890123-AbCdEfGhIjKlMnOpQrStUvWx"
required: true
sensitivity: "high"
scope: "Bot token scopes (29 scopes from app manifest)"
usage: "Provided during `login app` interactive authentication"
rotation: "Manual via Slack app settings → Reinstall app"
storage:
- location: "sops-encrypted secrets.yaml (backup/recovery)"
- location: "Bridge PostgreSQL database (primary storage after login)"
validation:
- "Starts with 'xoxb-'"
- "Length: 50-100 characters"
- "Format: xoxb-[numbers]-[numbers]-[alphanumeric]"
revocation:
- "Slack app settings → OAuth & Permissions → Revoke"
- "Remove app from workspace"
slack-app-token:
description: "Slack app-level token for Socket Mode WebSocket connection"
format: "xapp-[level]-[workspace_id]-[token_id]-[secret]"
example: "xapp-1-A0123456789-1234567890123-abc123def456ghi789jkl012mno345pqr678stu901vwx234yz"
required: true
sensitivity: "high"
scope: "connections:write (Socket Mode)"
usage: "Provided during `login app` interactive authentication"
rotation: "Manual via Slack app settings → App-Level Tokens → Regenerate"
storage:
- location: "sops-encrypted secrets.yaml (backup/recovery)"
- location: "Bridge PostgreSQL database (primary storage after login)"
validation:
- "Starts with 'xapp-'"
- "Length: 80-120 characters"
- "Contains workspace identifier"
revocation:
- "Slack app settings → App-Level Tokens → Revoke"
# =============================================================================
# sops-nix Configuration
# =============================================================================
# File: secrets/secrets.yaml (encrypted)
# ----------------
slack-oauth-token: "ENC[AES256_GCM,data:...,type:str]"
slack-app-token: "ENC[AES256_GCM,data:...,type:str]"
# Age Keys (.sops.yaml)
# ---------------------
keys:
- &vultr_vps age1vuxcwvdvzl2u7w6kudqvnnf45czrnhwv9aevjq9hyjjpa409jvkqhkz32q
# Source: /etc/ssh/ssh_host_ed25519_key on VPS
# Conversion: ssh-to-age < ssh_host_ed25519_key.pub
# Purpose: Production VPS can decrypt secrets at boot
- &admin age18ue40q4fw8uggdlfag7jf5nrawvfvsnv93nurschhuynus200yjsd775v3
# Source: Admin workstation age key
# Purpose: Administrator can edit secrets locally
# Encryption Rules
# ----------------
creation_rules:
- path_regex: secrets/secrets\.yaml$
key_groups:
- age:
- *vultr_vps # VPS auto-decrypts at boot
- *admin # Admin can sops secrets/secrets.yaml
# =============================================================================
# NixOS Declaration (hosts/ops-jrz1.nix)
# =============================================================================
# NOTE: With interactive login approach, these secret declarations are NOT
# required. Tokens are provided via Matrix chat and stored in database.
# The declarations below are for backup/recovery purposes only.
# sops:
# defaultSopsFile: ../secrets/secrets.yaml
# age:
# sshKeyPaths: ["/etc/ssh/ssh_host_ed25519_key"]
#
# secrets:
# slack-oauth-token:
# owner: "mautrix_slack"
# group: "mautrix_slack"
# mode: "0440"
# # Runtime location: /run/secrets/slack-oauth-token
# # Decrypted at boot, available only to mautrix_slack user
#
# slack-app-token:
# owner: "mautrix_slack"
# group: "mautrix_slack"
# mode: "0440"
# # Runtime location: /run/secrets/slack-app-token
# # Decrypted at boot, available only to mautrix_slack user
# =============================================================================
# Runtime Secret Locations
# =============================================================================
# After sops-nix decryption (boot time):
# /run/secrets/slack-oauth-token
# - Permissions: 0440 (-r--r-----)
# - Owner: mautrix_slack:mautrix_slack
# - Storage: tmpfs (RAM-only, cleared on reboot)
# - Usage: NOT used with interactive login approach
# - Purpose: Backup for disaster recovery
# /run/secrets/slack-app-token
# - Permissions: 0440 (-r--r-----)
# - Owner: mautrix_slack:mautrix_slack
# - Storage: tmpfs (RAM-only, cleared on reboot)
# - Usage: NOT used with interactive login approach
# - Purpose: Backup for disaster recovery
# Bridge Database (runtime, primary storage):
# /var/lib/mautrix_slack/mautrix_slack.db (or PostgreSQL)
# - Table: "user"
# - Columns: mxid, slack_user_id, access_token (encrypted)
# - Storage: Persistent, survives reboots
# - Encryption: Filesystem-level (LUKS)
# - Usage: Active tokens after `login app` authentication
# =============================================================================
# Token Generation Process
# =============================================================================
# Step 1: Create Slack App
# -------------------------
# 1. Go to: https://api.slack.com/apps
# 2. Click "Create New App" → "From an app manifest"
# 3. Select workspace: "chochacho"
# 4. Paste manifest from: https://github.com/mautrix/slack/blob/main/app-manifest.yaml
# 5. Review scopes (29 bot scopes, 46 event subscriptions)
# 6. Click "Create"
# Step 2: Enable Socket Mode
# ---------------------------
# 1. In app settings → "Socket Mode"
# 2. Toggle "Enable Socket Mode" → ON
# 3. Click "Generate an app-level token"
# 4. Token name: "socket-mode-token"
# 5. Add scope: "connections:write"
# 6. Click "Generate"
# 7. Copy token (starts with "xapp-") → Save securely
# Step 3: Install App to Workspace
# ---------------------------------
# 1. In app settings → "Install App"
# 2. Click "Install to Workspace"
# 3. Review permissions (29 scopes)
# 4. Click "Allow"
# 5. Copy "Bot User OAuth Token" (starts with "xoxb-") → Save securely
# Step 4: Store Tokens in sops-nix (Optional, for backup)
# --------------------------------------------------------
# 1. Edit encrypted secrets file:
# sops secrets/secrets.yaml
#
# 2. Add tokens:
# slack-oauth-token: "xoxb-..."
# slack-app-token: "xapp-..."
#
# 3. Save (auto-encrypts with age keys)
# 4. Commit to git (encrypted version is safe)
# 5. Deploy configuration (secrets decrypted at boot)
# Step 5: Authenticate Bridge (Primary Method)
# ---------------------------------------------
# 1. Open Matrix client (Element, etc.)
# 2. Start DM with: @slackbot:clarun.xyz
# 3. Send command: "login app"
# 4. Bot prompts: "Please provide bot token"
# 5. Send: "xoxb-..." (paste bot token)
# 6. Bot prompts: "Please provide app token"
# 7. Send: "xapp-..." (paste app token)
# 8. Bot responds: "Successfully logged in" (or error)
# 9. Tokens stored in bridge database (persistent)
# =============================================================================
# Security Best Practices
# =============================================================================
security:
storage:
- rule: "NEVER commit unencrypted tokens to git"
enforcement: ".gitignore excludes secrets.yaml.dec"
- rule: "NEVER hardcode tokens in NixOS configuration"
enforcement: "Use sops-nix or interactive login only"
- rule: "NEVER log tokens in plaintext"
enforcement: "mautrix bridges sanitize logs automatically"
access_control:
- rule: "Tokens only readable by service user"
enforcement: "owner: mautrix_slack, mode: 0440"
- rule: "Tokens cleared on reboot (tmpfs)"
enforcement: "/run/secrets on tmpfs filesystem"
- rule: "Tokens encrypted at rest in database"
enforcement: "LUKS encryption on /var filesystem"
rotation:
- frequency: "Every 90 days (recommended)"
process:
- "Generate new tokens in Slack app settings"
- "Update sops-encrypted secrets.yaml"
- "Re-authenticate bridge via `login app` command"
- "Verify functionality with test message"
- "Revoke old tokens in Slack"
- emergency:
- "If tokens compromised, revoke immediately in Slack"
- "Generate new tokens"
- "Re-authenticate bridge"
- "Review audit logs for unauthorized access"
monitoring:
- "Enable IP allowlisting in Slack app settings (if VPS has static IP)"
- "Monitor Slack app usage dashboard for anomalies"
- "Alert on authentication failures in bridge logs"
- "Track token usage via Slack audit logs (Enterprise Grid)"
# =============================================================================
# Disaster Recovery
# =============================================================================
# Scenario 1: Lost Tokens (Bridge Database Corrupted)
# ----------------------------------------------------
# If bridge database is lost but sops-encrypted secrets.yaml exists:
# 1. Restore from backup or re-deploy service
# 2. Tokens in sops-encrypted secrets.yaml can be retrieved
# 3. Re-authenticate via `login app` command
# 4. Bridge resumes operation
# Scenario 2: Lost Secrets File (Git Repository Intact)
# ------------------------------------------------------
# If secrets.yaml is lost but git repository exists:
# 1. Clone git repository (encrypted secrets.yaml present)
# 2. Decrypt on VPS (age key from SSH host key)
# 3. Extract tokens: sops -d secrets/secrets.yaml | grep slack
# 4. Re-authenticate bridge via `login app` command
# Scenario 3: Complete VPS Failure (Need to Regenerate)
# ------------------------------------------------------
# If VPS is destroyed and no backups exist:
# 1. Go to Slack app settings
# 2. Regenerate app-level token (old token revoked)
# 3. Reinstall app to workspace (new bot token generated)
# 4. Update sops-encrypted secrets.yaml with new tokens
# 5. Deploy to new VPS
# 6. Authenticate bridge via `login app` with new tokens
# Scenario 4: Workspace Migration (Slack → New Workspace)
# --------------------------------------------------------
# If migrating from "delpadtech" to "chochacho":
# 1. Create new Slack app in "chochacho" workspace
# 2. Generate new tokens (different workspace = different tokens)
# 3. Update NixOS config: workspace = "chochacho"
# 4. Update secrets.yaml with new tokens
# 5. Deploy configuration
# 6. Authenticate with new tokens
# 7. Old workspace bridge automatically disconnects
# =============================================================================
# Token Scope Reference
# =============================================================================
# Bot Token Scopes (xoxb-) - 29 Required
# ---------------------------------------
bot_scopes:
channels:
- "channels:read" # List public channels
- "channels:history" # Read messages in public channels
- "channels:write.invites" # Invite users to channels
- "channels:write.topic" # Edit channel topics
groups: # Private channels
- "groups:read"
- "groups:history"
- "groups:write"
- "groups:write.invites"
- "groups:write.topic"
im: # Direct messages
- "im:read"
- "im:history"
- "im:write"
- "im:write.topic"
mpim: # Group direct messages
- "mpim:read"
- "mpim:history"
- "mpim:write"
- "mpim:write.topic"
chat:
- "chat:write" # Send messages
- "chat:write.public" # Send to public channels without joining
- "chat:write.customize" # Customize bot name/avatar (for ghosting)
files:
- "files:read" # Download files
- "files:write" # Upload files
reactions:
- "reactions:read" # View reactions
- "reactions:write" # Add/remove reactions
pins:
- "pins:read" # View pinned messages
- "pins:write" # Pin/unpin messages
users:
- "users:read" # View user info
- "users.profile:read" # View user profiles
- "users:read.email" # View user emails
workspace:
- "team:read" # View workspace info
- "emoji:read" # View custom emoji
# App-Level Token Scopes (xapp-) - 1 Required
# --------------------------------------------
app_scopes:
- "connections:write" # Establish Socket Mode WebSocket connections
# =============================================================================
# Related Documentation
# =============================================================================
# Slack API Scopes: https://api.slack.com/scopes
# sops-nix: https://github.com/Mic92/sops-nix
# Age Encryption: https://age-encryption.org/
# mautrix-slack Auth: https://docs.mau.fi/bridges/go/slack/authentication.html
# =============================================================================
# Version Information
# =============================================================================
# Contract Version: 1.0
# Created: 2025-10-22
# Last Updated: 2025-10-22
# Related Spec: 002-slack-bridge-integration/spec.md
# Security Requirement: FR-007 (sops-nix encrypted secrets)