Skip to content

Port/nautobot rbac group mapping#24

Open
dmathur0 wants to merge 2 commits into
mainfrom
port/nautobot-rbac-group-mapping-mr238
Open

Port/nautobot rbac group mapping#24
dmathur0 wants to merge 2 commits into
mainfrom
port/nautobot-rbac-group-mapping-mr238

Conversation

@dmathur0

@dmathur0 dmathur0 commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Description

Validation

  • Standard CI passes.
  • Kind integration passes, or this PR explains why it was not run.

The kind integration test is manual due to taking ~30 min to complete. When the PR is ready for review,
run Actions -> Kind Integration -> Run workflow against the copy-pr-bot generated
pull-request/<PR_NUMBER> branch. Use the default test_path for the full suite,
or narrow it only while debugging.

Passing Kind Integration run:

Checklist

  • I am familiar with the contributing guidelines in CONTRIBUTING.md.
  • Commits are signed off for DCO compliance.
  • New or existing tests cover these changes, or the PR explains why tests are not needed.
  • Documentation is updated for user-facing behavior changes.
  • Generated artifacts are updated when applicable, such as OpenAPI specs,
    docs screenshots, or Helm/rendered outputs.

Summary by CodeRabbit

  • New Features
    • Add YAML-driven group-mapping to sync IdP groups to Nautobot roles, object permissions, and optional superuser status at JWT login.
    • Option to auto-create referenced Django groups and Helm values to enable/configure group mapping.
  • Behavior Changes
    • Fail-closed mapping load: mapping errors are logged and treated as empty; reconciliation still enforces removals.
  • Tests
    • Comprehensive tests added for mapping load, resolution, sync, and login-time reconciliation.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3877b8ce-96f5-4d85-8bdc-be1e79bfa050

📥 Commits

Reviewing files that changed from the base of the PR and between 91ca8ad and 3b934e2.

📒 Files selected for processing (9)
  • components/nautobot/nv_config_manager_auth/jwt_authentication.py
  • components/nautobot/nv_config_manager_auth/rbac.py
  • components/nautobot/tests/conftest.py
  • components/nautobot/tests/test_jwt_authentication.py
  • components/nautobot/tests/test_rbac.py
  • deploy/helm/templates/_nautobot-configmap-data.tpl
  • deploy/helm/templates/nautobot.yaml
  • deploy/helm/values-local-azure-sso.yaml
  • deploy/helm/values.yaml
🚧 Files skipped from review as they are similar to previous changes (9)
  • components/nautobot/tests/conftest.py
  • components/nautobot/nv_config_manager_auth/jwt_authentication.py
  • deploy/helm/templates/nautobot.yaml
  • deploy/helm/values-local-azure-sso.yaml
  • deploy/helm/templates/_nautobot-configmap-data.tpl
  • deploy/helm/values.yaml
  • components/nautobot/nv_config_manager_auth/rbac.py
  • components/nautobot/tests/test_rbac.py
  • components/nautobot/tests/test_jwt_authentication.py

📝 Walkthrough

Walkthrough

This PR introduces JWT-driven group-mapping RBAC for Nautobot: a new rbac.py module handles YAML-based group-to-permission mappings with fail-closed semantics; JWT auth integration triggers three-pass reconciliation (sync permissions, manage memberships, revoke removed groups) on each login; comprehensive tests validate all paths; Helm configuration wires the feature for Kubernetes deployments.

Changes

JWT-driven Group Mapping RBAC

Layer / File(s) Summary
RBAC module foundation: configuration, error handling, and content-type resolution
components/nautobot/nv_config_manager_auth/rbac.py (lines 1–381)
Introduces configuration gating via mapping_is_configured, exception types (GroupMappingError, GroupMappingReadError, GroupMappingParseError), load_group_mapping with fail-closed YAML parsing/validation, and _resolve_content_types to expand mapping permission specs ("all", app.*, app.model) into Django ContentType rows while excluding sensitive/internal models and logging malformed entries.
RBAC group and permission synchronization orchestration
components/nautobot/nv_config_manager_auth/rbac.py (lines 386–649)
Implements the core sync_groups_and_permissions atomic transaction that runs three ordered reconciliation passes: _sync_group_permissions applies per-action ObjectPermission rows for groups the user holds (with optional auto-create); _sync_group_memberships adds/removes mapping-managed group memberships; _revoke_removed_mapping_groups removes users from retired groups and prunes stale managed permissions. Includes is_superuser_per_mapping helper and special handling for is_superuser groups that skip per-action permission creation.
JWT authentication integration with RBAC sync
components/nautobot/nv_config_manager_auth/jwt_authentication.py (lines 63–386)
Adds NV_CONFIG_MANAGER_GROUP_MAPPING_PATH configuration documentation, updates _sync_superuser_status with extra_superuser_match and extra_superuser_enabled flags to combine env-var and mapping-driven superuser reconciliation, and extends _get_or_create_user_from_claims to defer-import the rbac module, detect configuration, load the YAML with fail-closed logging, compute mapping superuser matching, and trigger group/permission sync while preserving backward-compatible env-var logic.
Test infrastructure: Django stubs and fixtures
components/nautobot/tests/conftest.py (lines 76–110)
Extends the autouse _django_stubs fixture with mocks for django.contrib.auth.models.Group, django.db.transaction.atomic passthrough decorator, and nautobot.users.models.ObjectPermission, enabling tests to exercise RBAC code paths without a real database or Django setup.
JWT authentication and superuser reconciliation tests
components/nautobot/tests/test_jwt_authentication.py (lines 22–798)
Adds rbac fixture for deferred-import and four new test methods to TestSyncSuperuserStatus covering promotion/demotion/preservation when env-var and mapping flags vary; introduces TestGetOrCreateUserFromClaimsMappingStates test suite validating _get_or_create_user_from_claims behavior across unconfigured (no sync), empty-configured (sync with empty mapping, force reconciliation), load-failed (fail-closed with error logs), and loaded-mapping (sync with populated mapping) states.
RBAC module comprehensive test suite
components/nautobot/tests/test_rbac.py (lines 1–1023)
Comprehensive test coverage for load_group_mapping (missing/empty/unconfigured/malformed YAML, error wrapping, boolean strictness), mapping_is_configured gating across env/file combinations, _resolve_content_types expansion rules (all, wildcards, exact models, malformed entries logged/skipped), is_superuser_per_mapping group matching, sync orchestration (empty mapping still revokes, three-pass ordering), _sync_group_permissions (auto-create, skip with logging), _apply_group_permission_config (concurrent upsert safety, stale-perm pruning, manual-perm preservation), and _revoke_removed_mapping_groups (detach/delete semantics, shared-perm retention, managed-marker validation).
Helm templates and values for RBAC configuration
deploy/helm/templates/_nautobot-configmap-data.tpl, deploy/helm/templates/nautobot.yaml, deploy/helm/values.yaml, deploy/helm/values-local-azure-sso.yaml
Helm values define nautobot.rbac.groupMapping (group-to-permission mapping) and autoCreateGroups (auto-create toggle); templates conditionally inject NV_CONFIG_MANAGER_GROUP_MAPPING_PATH and NV_CONFIG_MANAGER_AUTO_CREATE_GROUPS environment variables when mapping is configured; the Nautobot server pod gains a checksum/nautobot-group-mapping annotation for deterministic rollout on mapping changes; volumeMount switches from subPath to directory mount; a new values-local-azure-sso.yaml overlay demonstrates Azure Entra SSO with RBAC group mapping for local development.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • polarweasel
  • jojung1
  • ryanheffernan
  • susanhooks

Poem

🐰 A mapping of groups, from claims to delight,
Three passes per login to set permissions right,
With YAML-driven RBAC, and fail-closed care,
Kubernetes config makes it all fair,
JWT users now dance with Django's embrace! 🎭✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 67.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Port/nautobot rbac group mapping' is vague and generic, using abbreviated terms without clearly conveying what changed or what the main purpose is. Consider a more descriptive title like 'Add YAML-driven group mapping RBAC synchronization for JWT-authenticated users' or 'Implement group-mapping configuration for Nautobot RBAC on login' to clarify the main change.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch port/nautobot-rbac-group-mapping-mr238

Comment @coderabbitai help to get the list of available commands and usage tips.

dmathur0 added 2 commits June 1, 2026 17:58
Adds nv_config_manager_auth.rbac, which reads a YAML group-mapping file on
every JWT login to reconcile Django Group membership and per-action
ObjectPermissions (with optional constraints and is_superuser shortcut)
against the JWT roles claim. Group lifecycle is operator-managed by default;
NV_CONFIG_MANAGER_AUTO_CREATE_GROUPS opts into auto-creation.
_sync_superuser_status now decouples mapping-enabled from per-user-match so
revocation/demotion runs even with an empty or failed-to-parse mapping
(fail-closed). Helm renders the mapping into a directory-mounted ConfigMap
with a pod-template checksum.

Signed-off-by: Davesh Mathur <daveshm@nvidia.com>
Adds values-local-azure-sso.yaml as a generic, scrubbed example: all
tenant/client IDs, secrets, internal hostnames, and cluster contexts are
replaced with <placeholder>s. Shows how to exercise the
nautobot.rbac.groupMapping path against a real Entra ID OIDC provider on a
local kind cluster.

Signed-off-by: Davesh Mathur <daveshm@nvidia.com>
@dmathur0 dmathur0 force-pushed the port/nautobot-rbac-group-mapping-mr238 branch from 91ca8ad to 3b934e2 Compare June 1, 2026 22:59
@dmathur0 dmathur0 changed the title Port/nautobot rbac group mapping mr238 Port/nautobot rbac group mapping Jun 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deploy/helm/templates/_nautobot-configmap-data.tpl`:
- Around line 79-90: The group-mapping ConfigMap and mounts are being rendered
unconditionally so nv_config_manager_auth.rbac (mapping_is_configured() /
DEFAULT_MAPPING_PATH) treats RBAC as configured even when
Values.nautobot.rbac.groupMapping is empty; update
deploy/helm/templates/nautobot.yaml to wrap the ConfigMap, volume, and
volumeMount blocks with a guard that checks for the presence of the key (e.g.,
{{ if hasKey .Values.nautobot.rbac "groupMapping" }} ) so an absent key means
“unconfigured”, and update deploy/helm/values.yaml to remove the default
groupMapping: [] (or set it to null) so the chart will not render the
ConfigMap/mount unless the operator explicitly provides groupMapping.

In `@deploy/helm/values.yaml`:
- Line 2454: The default empty array for groupMapping causes unintended
revoke-all behavior; change the default in values.yaml from "groupMapping: []"
to either remove the key or set "groupMapping: null" (or comment it out) and
update the Helm templates (the ConfigMap/volume creation in nautobot.yaml that
mounts the RBAC file) to be conditional on groupMapping being defined and
non-null so the ConfigMap is only created when the user explicitly configures
groupMapping (this preserves the documented semantics that null/omitted means
"do not touch", while an explicit [] still triggers the revoke-all behavior).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7557663c-2858-4da0-8809-605501b8542b

📥 Commits

Reviewing files that changed from the base of the PR and between 6bec6d7 and 91ca8ad.

📒 Files selected for processing (9)
  • components/nautobot/nv_config_manager_auth/jwt_authentication.py
  • components/nautobot/nv_config_manager_auth/rbac.py
  • components/nautobot/tests/conftest.py
  • components/nautobot/tests/test_jwt_authentication.py
  • components/nautobot/tests/test_rbac.py
  • deploy/helm/templates/_nautobot-configmap-data.tpl
  • deploy/helm/templates/nautobot.yaml
  • deploy/helm/values-local-azure-sso.yaml
  • deploy/helm/values.yaml

Comment thread deploy/helm/templates/_nautobot-configmap-data.tpl
Comment thread deploy/helm/values.yaml
# status__name: "Active"
# - name: "nv-config-manager-admins"
# is_superuser: true
groupMapping: []

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Change default to null or remove the key to avoid unintended revocation.

The default value groupMapping: [] combined with the unconditional ConfigMap creation in nautobot.yaml means the RBAC feature is configured-but-empty by default. From the test context (test_jwt_authentication.py:717-733), an empty configured mapping triggers the "explicit revoke-everyone idiom"—users are removed from all managed groups and permissions on their next JWT login.

This is inconsistent with superuserGroups (line 2383), where [] means "feature disabled, don't touch existing privileges" per the documentation on lines 2374-2383.

Recommended fix: Change the default to:

# groupMapping: []  # commented out, or
groupMapping: null

Combined with conditionalizing the ConfigMap/volume creation (flagged in earlier comment), this ensures:

  • Unconfigured (key not set or null): no ConfigMap, no file, rbac sees unconfigured, no sync runs
  • Configured to []: ConfigMap created with groups: [], rbac sees configured+empty, revoke-all runs
  • Configured to [...]: ConfigMap created with content, rbac syncs as expected

As per the earlier comment, the ConfigMap/volume definitions must also be wrapped in a condition to respect this default.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/helm/values.yaml` at line 2454, The default empty array for
groupMapping causes unintended revoke-all behavior; change the default in
values.yaml from "groupMapping: []" to either remove the key or set
"groupMapping: null" (or comment it out) and update the Helm templates (the
ConfigMap/volume creation in nautobot.yaml that mounts the RBAC file) to be
conditional on groupMapping being defined and non-null so the ConfigMap is only
created when the user explicitly configures groupMapping (this preserves the
documented semantics that null/omitted means "do not touch", while an explicit
[] still triggers the revoke-all behavior).

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.

1 participant