# 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)