-
-
Notifications
You must be signed in to change notification settings - Fork 233
feat: SFTP access control, enforcement mode, file transfer logging, and user role expiry #1681
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Hello @Eugeny, I am not sure why the test aer failing in the Github Action as I have ran them locally and they passed without an issue. Looks like the issue is 2 different test timeout in CI each time due to Docker resource exhaustion after ~160 tests (maybe). |
|
Thank you for the PR! After a cursory glance, it doesn't seem to actually prevent the user from writing/reading data from the FS as there's still nothing stopping them from doing so from within their shell session? |
|
@Eugeny Thanks fro the feedback, this PR design was mainly around the SCP/SFTP subsystem of SSH, It is possible to intercept the SSH session commands as it is the same-ish mechanism used for recording the SSH session. This PR also does not cover these use-cases too:
If you think it is mandatory feature to be able to have this in this PR, I will work on it but I will need sometime before being able to deliver this 🙏 Thanks again fro the review |
|
I see - unfortunately there's no security gained by this PR as-is unless shell and exec sessions are also forbidden, because there's still (a very easy) way to read/write arbitrary files. So while it might tick the boxes for a specific security audit, it doesn't actually prevent unauthorized access. It's fundamentally impossible to selectively restrict command execution in shell sessions too, since the SSH server only sees user keystrokes and display output and has no concept of "commands" per se (except exec requests, but again the user can bypass that by simply running commands in the shell). It's not possible to "recognize" and parse shell input either because that's trivially bypassable by encrypting the commands/inputs, saving it remotely and decrypting it there, so it's never visible on the SSH protocol. As it is, I'm currently tending towards not accepting this as a feature, however I'm still interested in some parts of this PR, if you could separate them out:
|
|
@Eugeny I will separate the TTL role assignment feature, and look into the usage of rssh-sftp for the SFTP audit logging, for audit log purposes only ! While I am at it I added some screenshot to this PR, even if it will not move forward I really appreciate the review 🙏 |
|
@Eugeny
Follow-up question, would it be acceptable to update this feature to:
|
|
Could you please reformulate the second half of your reply? I couldn't parse it 😓 |
|
Sorry @Eugeny for the not clear comment, It was done little bit too lat in the night 😓 To address this, I suggest adding a Restricted Shell mode to make targets truly "File Transfer Only." Regarding this proposal:
|
|
@Eugeny Hello, did you have the time tou check my last comment please ? |
|
Thanks for getting back to me and sorry for the delay!
Yes - blocking
See above - enabling SFTP permissions should not be possible when interactive sessions are allowed.
We can leave these out - no reason to use legacy SCP in 2026. |
|
@Eugeny Thanks a lot for the clarification I will add those requirements then ! |
3209fca to
0dec921
Compare
Implement granular file transfer permissions allowing administrators to control upload/download access on a per-role-per-target basis. - Add database migrations for permission columns on target_roles table - Add SFTP protocol parser with fine-grained operation blocking - Add SCP command parser for upload/download detection - Integrate permission checks into SSH session handling - Add Admin API endpoints for managing file transfer permissions - Add Admin UI toggles in Target configuration page - Add E2E tests for permission enforcement
- Add SFTP packet parsing for Open, Read, Write, Close operations - Add SCP command parsing for upload/download detection - Implement permission enforcement at packet level in SSH session - Track file transfers with size and SHA256 hash calculation - Log file_transfer events with status, direction, protocol, and metadata - Add pending_reads tracking for accurate SFTP download byte counting - Update LogViewer UI to display file transfer events with direction arrows
- Add ssh-server container with test user for SCP/SFTP testing - Update docker-compose with warpgate and ssh-server services - Ignore docker/data/ directory for persistent test data
- 10 permission tests covering SFTP/SCP upload/download allow/deny scenarios - 2 logging tests verifying file_transfer events in JSON logs - Tests use wait_port for reliable warpgate restart handling
- Changed SFTP subsystem to always allow connection for SSH targets - Permission enforcement now happens at operation level (Open, Read, Write) - Added detailed error messages including action and target name - Example: 'Permission denied: file upload is not allowed on target prod-server' This improves UX when users have restricted file transfer permissions, replacing cryptic 'subsystem request failed' errors with actionable messages.
Implements time-limited user role assignments with automatic tracking of all role changes in a history table. Roles can have an optional expiry timestamp and all modifications (granted, revoked, expiry changes) are recorded with actor information and timestamps. Features: - User role assignments can expire at a specified timestamp - Expired roles are filtered out during authorization - Full history tracking with UserRoleHistory entity - API endpoints for managing and viewing role expiry - Re-enable expired roles by updating/removing expiry
Adds default file upload/download permissions at the role level that can be inherited or overridden by target-role assignments. Roles now define baseline file transfer policies that apply to all SSH targets unless explicitly overridden. Features: - Role-level allowFileUpload and allowFileDownload flags - API endpoints to get and update role file transfer defaults - Defaults are inherited by target-role assignments when not overridden
Allows targets to override role file transfer defaults with three-way options (inherit/allow/deny) for upload and download permissions separately. This enables fine-grained control where specific targets can restrict or permit file transfers regardless of role defaults. Features: - Nullable allow_file_upload and allow_file_download columns - null = inherit from role, true = force allow, false = force deny - API endpoints to get and update target-role file transfer permissions - Updated authorization logic to respect override hierarchy - E2E tests for file transfer permission scenarios
Implements comprehensive UI for managing user role assignments with time-based expiry and viewing historical changes. Features: - Quick expiry presets (4h, 8h, 12h, 1d, 3d, 7d) for common durations - Custom datetime picker for precise expiry control - Real-time expiry status display (e.g., "Expires in 3h 59min") - Expired roles treated as unassigned and can be re-enabled - Re-enabling expired role removes expiry (makes permanent) - Inline role history section with load more pagination - History shows all role changes with actor and timestamp information - Modal with improved layout and horizontal button arrangement
Adds UI for managing role-level file transfer defaults and target-level permission overrides with clean, compact controls. Features: - Role page: Simple checkboxes for default upload/download permissions - Target page: Collapsible file transfer section per role - Three-way select dropdowns (Inherit/Allow/Deny) for upload and download - Collapsed state shows current permission summary - Compact horizontal layout with input groups - Shows inherited role defaults in select options for clarity
Add 100ms delay after SSH server startup to allow full initialization in resource-constrained CI environments. This may help prevent timeout issues when many Docker containers are running concurrently. Tests continue to pass locally (12/12 in 14s).
Ignore development environment files: - AGENTS.md (OpenCode agent instructions) - mise.toml (personal mise configuration) - .github/workflows/opencode.yml (local workflow) - *.log files (session logs) - thoughts/ directory (documentation drafts) - docker/*.sample.yaml (personal config samples)
This reverts commit 1c14bf6.
Migrate from custom SFTP parser (~590 lines) to russh-sftp 2.1 codec wrapper (~150 lines), achieving 49% code reduction in the SFTP module. Changes: - Add russh-sftp 2.1 dependency - Create new codec.rs with packet_to_operation(), packet_to_response(), and build_denial_response() wrappers - Remove parser.rs (465 lines) and response.rs (126 lines) - Update session.rs to use codec functions instead of custom parser - Simplify types.rs by removing redundant type definitions The russh-sftp library provides proper SFTP protocol parsing while Warpgate's codec.rs handles access control and metadata extraction. Refs: thoughts/plans/russh-sftp_migration.md
Remove the entire SCP module (parser, types, mod) and all SCP references from session.rs. SCP is obsolete — legacy scp commands now pass through as regular exec commands with no special handling. Update doc comments from 'SCP/SFTP' to 'SFTP' in entity definitions, API docs, and config providers.
… blocking Add instance-wide sftp_permission_mode setting (strict/permissive) stored in DB parameters table. In strict mode, shell, exec, and port forwarding channels are blocked for targets with SFTP restrictions, making them truly SFTP-only. In permissive mode, SFTP rules are enforced but shell access remains available. - Add DB migration for sftp_permission_mode column - Add shell_blocked field to FileTransferPermission with 6 unit tests - Block shell, exec, direct-tcpip, direct-streamlocal, tcpip-forward, and streamlocal-forward channels when restrictions are active - Handle SFTP EXTENDED packets with safe/write/unknown allowlist - Add max_file_size enforcement on Write operations - Add advanced restriction UI (allowed_paths, blocked_extensions, max_file_size) to Role.svelte and Target.svelte - Add enforcement mode dropdown to Parameters.svelte - Add permissive mode warning banners to Role/Target UI
- CredentialEditor: fix curly braces, use SvelteSet instead of Set - RoleHistoryModal: handle PaginatedResponse type, fix Date formatting - CreateApiTokenModal: remove semicolons from toLocalISO function - User.svelte: fix lint warnings - Rust API files: minor fixes for consistency
Add 28 E2E tests covering: - File transfer permissions (default, download, upload, API, multi-role) - Transfer logging and denied transfer logging - Strict mode (shell blocked, shell allowed, SFTP works, port forwarding) - Permissive mode (shell allowed, SFTP enforced) - Advanced restrictions (allowed_paths, blocked_extensions, case sensitivity) - Role-level defaults and target-role overrides - Exec and remote forwarding blocking in strict mode Fix test_ssh_client_auth_config.py: add missing AddUserRoleRequest argument required by updated SDK from user role expiry feature.
Update bytes 1.11.0->1.11.1, time 0.3.44->0.3.47, thiserror 2.0.17->2.0.18 to resolve cargo-deny vulnerability warnings in CI.
…ssignment - Show expired roles with strikethrough, reduced opacity, and red Expired badge - Add Re-enable button for expired roles that opens expiry modal - Inline expiry modal on new role assignment (permanent default, presets) - Add labeled Expiry button (clock icon + text) replacing icon-only - Past-date validation on datetime-local input with min constraint - Live countdown timer (60s interval) showing time remaining - Confirmation dialog before revoking a role - Auto-load role history on first expand - Add 30-day preset to expiry options
- 14 role expiry tests: grant with TTL, expired denied, re-enable, revoke, reactivate, history audit trail, API state listing - 18 SFTP operation tests: remove, rename, mkdir, rmdir, setstat, symlink, max_file_size enforcement, extended packets (statvfs), metadata ops, and strict mode streamlocal blocking
8330df8 to
040f7d2
Compare
feat: SFTP access control, enforcement mode, file transfer logging, and user role expiry
Closes #1679
Summary
Implements comprehensive SFTP file transfer access control with an instance-wide enforcement mode, audit logging, and user role expiry management. Key changes since the initial PR:
strict/permissive) — in strict mode, shell/exec/port forwarding are blocked for SFTP-restricted targetsmax_file_sizeenforcement — now checks cumulative bytes during Write operationsFeatures Implemented
SFTP File Transfer Access Control
Role-Level Defaults
Roles define baseline file transfer permissions that apply to all SSH targets:
allow_file_upload/allow_file_download— toggle switches (default: true)allowed_paths— glob patterns restricting accessible directoriesblocked_extensions— file extensions to block (case-insensitive)max_file_size— maximum upload size in bytesAPI:
GET/PUT /role/{id}/file-transferTarget-Role Overrides
Target-role assignments can inherit role defaults OR explicitly override:
API:
GET/PUT /targets/{id}/roles/{role_id}/file-transferHierarchy:
SFTP Permission Enforcement Mode (NEW)
Instance-wide
sftp_permission_modesetting stored in DB parameters table:In strict mode, when SFTP restrictions are active:
session) channel rejected with: "Shell access is disabled for this target (SFTP-only mode)"direct-tcpipanddirect-streamlocalchannels blocked (prevents SSH tunneling bypass)tcpip-forwardandstreamlocal-forwardrequests blockedSFTP EXTENDED packet handling:
statvfs@openssh.com,fstatvfs@openssh.com,fsync@openssh.com,limits@openssh.composix-rename@openssh.com,hardlink@openssh.com,lsetstat@openssh.comAPI:
GET/PUT /parameters(field:sftp_permission_mode)SCP Protocol Removal
Removed the entire legacy SCP module per maintainer feedback:
warpgate-protocol-ssh/src/scp/(parser, types, mod — 332 lines)session.rs(~150 lines)scpcommands now pass through as regular exec commands (blocked in strict mode, unhandled in permissive mode)File Transfer Audit Logging
All SFTP operations logged with comprehensive details:
file_transferDatabase:
FileTransferLogentity with migrationm00027User Role Expiry
User role assignments can expire automatically:
expires_attimestamp on role assignmentsUserRoleHistorytableAPI:
POST /users/{id}/roles/{role_id}— Add with optional expiryGET/PUT/DELETE /users/{id}/roles/{role_id}/expiry— Manage expiryGET /users/{id}/roles/{role_id}/history— View audit trailAdmin UI
Global Settings (Parameters):
Role Management:
Target Management:
User Management:
Terraform Provider Support
The companion terraform-provider-warpgate has been updated with full support:
Role defaults:
Target overrides:
User role expiry:
Technical Details
Database Migrations
m00026_scp_sftp_access_control— Initial permission columnsm00027_file_transfer_logging— Logging table and indexesm00028_user_role_expiry_history— Expiry and history trackingm00029_role_file_transfer_defaults— Role-level defaultsm00030_target_role_nullable_overrides— Inheritance modelm00031_user_role_expiry_history— History table refinementsm00032_sftp_permission_mode— Enforcement mode column in parameters tableProtocol Implementation
SSH_FXP_OPEN,SSH_FXP_WRITE,SSH_FXP_READ,SSH_FXP_EXTENDEDpacketsis_shell_blocked()checks enforcement mode + active restrictionsTesting
Performance
Breaking Changes
None — All changes are backward compatible:
strict(secure by default, but only activates when restrictions exist)Security Considerations
Documentation
Testing Instructions
SFTP Permissions (Strict Mode):
Permissive Mode:
User Role Expiry:
Checklist
Related
Screenshots
Role UI - Upload/Download Toggles
Show Screenshot
Target UI - Role Attribution for Upload/Download Override
Show Screenshot
User UI - Role Assignment History
Show Screenshot
User UI - Role Expiry Setting
Show Screenshot
User UI - Role Expiry Countdown
Show Screenshot
User UI - Make Role Permanent
Show Screenshot
User UI - Role History
Show Screenshot