Skip to content

Conversation

@garciajrx
Copy link

Summary

  • Adds a security-hardened sudoers template (scripts/sudoers.d-agor) for the agorpg daemon user
  • Enables worktree RBAC with minimal privilege escalation by restricting allowed commands
  • Group names constrained to agor_wt_[0-9a-f]{8} pattern to prevent arbitrary group manipulation

Security Features

  • Group management: Only agor_wt_* groups can be created/deleted
  • Filesystem permissions: chgrp/chmod restricted to designated worktree directories with whitelisted modes (2750, 2755, 2775, 2777)
  • Process impersonation: Can only run node/zellij as agor_* users
  • Audit logging: All sudo activity logged to /var/log/agor-sudo.log
  • Environment sanitization: Strips dangerous env vars like LD_PRELOAD

Test plan

  • Verify syntax: sudo visudo -cf scripts/sudoers.d-agor
  • Deploy to test environment and verify sudo -l -U agorpg shows expected commands
  • Test group creation with valid/invalid group names
  • Test chmod/chgrp on worktree directories
  • Test executor impersonation with agor_* user

Add a security-hardened sudoers template for the agorpg daemon user that
enables worktree RBAC with minimal privilege escalation.

- Restrict group operations to agor_wt_[0-9a-f]{8} pattern only
- Whitelist only safe chmod modes (2750, 2755, 2775, 2777)
- Limit chgrp/chmod to designated worktree directories
- Allow process impersonation only for agor_* users
- Include audit logging and environment sanitization
@mistercrunch
Copy link
Member

oh! looks similar to #431

@mistercrunch
Copy link
Member

Asked an agent to compare/review both PRs ... likely to merge as one as I understand the Venn diagram. Will post the ouput

@mistercrunch
Copy link
Member

Now I have a clear picture. Here's the analysis:

PR Comparison: #428 vs #431

Aspect PR #428 (Sudoers Config) PR #431 (Our PR)
Focus System-level security config Application-level service code
Files 1 file: scripts/sudoers.d-agor 13 files across core/daemon/CLI
Purpose Define WHAT commands agorpg user can run via sudo Define HOW/WHEN to call those commands

Relationship: Complementary, not overlapping

PR #428 provides:

  • Sudoers template restricting daemon user (agorpg) to specific commands
  • Security constraints: group names must match agor_wt_[0-9a-f]{8}
  • Allowed commands: groupadd, groupdel, usermod -aG, gpasswd -d, chgrp, chmod
  • Impersonation: can run node/zellij as agor_* users
  • Audit logging to /var/log/agor-sudo.log

PR #431 provides:

  • UnixIntegrationService - orchestration layer that calls those commands
  • CommandExecutor abstraction - routes commands through sudo or direct execution
  • FeathersJS hooks - auto-trigger Unix ops on data changes (owner add/remove, user create)
  • CLI admin commands - ensure-user, delete-user, create-symlink, etc.

Integration Gap

Our SudoCliExecutor currently routes through sudo agor admin <command>, but PR #428's sudoers allows direct system commands. We may need to:

  1. Option A: Align our executor to call the raw commands (groupadd, usermod, etc.) that PR feat(security): add sudoers configuration for RBAC Unix isolation #428 allows
  2. Option B: Add agor admin * commands to the sudoers config

The current group-manager.ts in core already generates raw commands like groupadd agor_wt_<id> - which matches PR #428's pattern.

Bottom line: These PRs are designed to work together. #428 is the security boundary, #431 is the orchestration layer that operates within that boundary.

@mistercrunch
Copy link
Member

Suggested Changes for Integration with #431

Hey! I'm working on #431 which adds the UnixIntegrationService that will call these sudoers-controlled commands. After reviewing both PRs, I have some suggestions to align them:

1. Add agor_users group management

We're using an agor_users group as a namespace for all Agor-managed users. This provides containment - the daemon can only impersonate users that are members of this group.

# --- Group Management ---
+# Global group for all Agor-managed users (impersonation namespace)
+Cmnd_Alias AGOR_USERS_GROUP = \
+    /usr/sbin/groupadd agor_users, \
+    /usr/sbin/groupdel agor_users
+
+Cmnd_Alias AGOR_USERS_GROUP_MEMBERSHIP = \
+    /usr/sbin/usermod -aG agor_users *

# Only allow agor_wt_<8-hex-chars> group names
Cmnd_Alias AGOR_GROUP_CREATE = \

2. Update impersonation to use agor_users group instead of agor_* prefix

This allows natural usernames (max instead of agor_max) while maintaining containment:

-# Impersonation: run commands as any agor_* user
-agorpg ALL=(agor_*) NOPASSWD: AGOR_EXECUTOR, AGOR_TERMINAL
+# Impersonation: run commands as any user in agor_users group
+agorpg ALL=(%agor_users) NOPASSWD: AGOR_EXECUTOR, AGOR_TERMINAL

3. Add permissions section for new aliases

# Group management (as root)
+agorpg ALL=(root) NOPASSWD: AGOR_USERS_GROUP, AGOR_USERS_GROUP_MEMBERSHIP
agorpg ALL=(root) NOPASSWD: AGOR_GROUP_CREATE, AGOR_GROUP_DELETE

Security Model

With these changes:

  • Namespace containment: Daemon can only impersonate users in agor_users group
  • Natural usernames: Users SSH as max@host not agor_max@host
  • Worktree isolation: agor_wt_* groups still control per-worktree access
  • Path containment: chgrp/chmod still restricted to worktree paths

The daemon can add users to agor_users, but cannot add itself (agorpg) or system users - the usermod -aG agor_users * pattern is constrained by the fact that the daemon would need to already be able to impersonate that user to do anything harmful.

Let me know if you have questions or want to discuss the security model!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants