Trending:

Two doors, one gateway: Django GRC app gains module-level access to separate teams

Diagram showing module-level access boundaries in a Django GRC app
TechStaged-owned

Summary

  • GitLab restructured a Django internal GRC tool to support two distinct teams—Security Compliance and Internal Audit—by introducing module-level access control.
  • The original tool used login_required on every view, which answered only whether a user was authenticated.
  • The tool needed to enforce authorization, not just authentication, to prevent cross-team data access.

GitLab’s internal GRC tool originally served the Security Compliance team with a login_required gate on every view. When Internal Audit identified a new use case requiring its own data, workflow, and sensitive information, the single-tenant pattern showed a shortcoming: authenticating users alone did not answer whether they should access a given resource.

  • The tool needed to support two distinct customer bases without cross-stream data exposure.
  • A unitary authentication check was insufficient for multi-tenant internal tools.

WHAT CHANGED: A CORE PROJECT WITH TWO MODULE APPS

The team restructured the tool into a core Django project that provides shared authentication, user management, and audit logging. On top of this core, two independent modules were built—one for Security Compliance and one for Internal Audit. Each module owns its own models, views, and API surface, and neither module depends on the other. TechStaged has also covered GitHub adds confidential comments to repository security advisories.

  • Core has zero knowledge of the specific data domains of the two modules to preserve separation.
  • The pattern is designed to be repeatable for future modules that require isolated data handling.

HOW ENFORCEMENT WORKS: MIXINS, PERMISSIONS, AND UI GUARDS

Access control is implemented with a single reusable mechanism in the core app, then subclassed per module. A GroupRequiredMixin checks group membership and raises PermissionDenied if the user isn’t in the required group. Each module uses a dedicated subclass (GasGroupRequiredMixin and IsGasGroupMember) to enforce its boundary. A template filter, user_in_group, supports navigation-level guards so the user interface reflects actual permissions.

  • The mixins enforce authorization at all layers—views, APIs, and navigation.
  • A UX-only navigation guard complements, but does not replace, the security boundary.

WHAT’S NEXT: GUIDANCE FOR TEAMS BUILDING MULTI-TENANT INTERNAL TOOLS

GitLab emphasizes that this approach creates a foundation that future modules can ride on, reducing infrastructure scaffolding when new audiences enter a tool. The article outlines a practical sequence for teams: identify login-versus-authorization gaps, draw module boundaries, implement a single reusable mixin, and enforce access independently across views, APIs, and navigation.

  • Check for login_required versus proper authorization across views.
  • Define shared versus module-specific boundaries before coding.
  • Develop one reusable mixin at the core, then subclass for each module.
  • Enforce access at every layer to ensure UI elements don’t imply security that isn’t there.

Reporting by Owen Blackridge; editing by TechStaged editors

Editorial disclosure: This article was prepared with AI assistance from a source-limited research package and passed TechStaged's automated factual, originality, licensing, and publication checks.

Our Standards: The TechStaged Editorial Principles.

f in

Owen Blackridge

Owen Blackridge

Technology Editor

Owen covers platform shifts, AI launches, and the practical impact of emerging technology on small teams.