Skip to content

Add optional namespaces field to policy entries for namespace-scoped authorization #2325

@thjaeckle

Description

@thjaeckle

Summary

Add an optional namespaces field to policy entries that restricts the entry's applicability to things within matching namespaces. This enables namespace-scoped authorization without changes to the search index structure.

Motivation

Policy entries currently apply universally regardless of the thing's namespace. This limitation affects:

  1. Multi-Tenant Scenarios: Organizations need tenant isolation without maintaining separate policies per tenant
  2. Namespace-Based Organization: Different user groups need different permissions per namespace (e.g., vehicle managers vs. facility managers)

Proposed Solution

Add an optional namespaces array to policy entries:

{
  "policyId": "com.acme:shared-policy",
  "entries": {
    "vehicle-admins": {
      "subjects": { "nginx:fleet-manager": { "type": "generated" } },
      "resources": { "thing:/": { "grant": ["READ", "WRITE"], "revoke": [] } },
      "namespaces": ["com.acme.vehicles", "com.acme.vehicles.*"]
    },
    "analysts": {
      "subjects": { "nginx:data-analyst": { "type": "generated" } },
      "resources": { "thing:/": { "grant": ["READ"], "revoke": [] } }
    }
  }
}

Semantics

namespaces field Behavior
Absent Entry applies to all namespaces (backward compatible)
Empty array [] Same as absent
Array with patterns Entry only applies when thing's namespace matches at least one pattern

Namespace Pattern Matching

  • com.acme - exact match only
  • com.acme.* - matches everything below com.acme but not com.acme itself

To match both: ["com.acme", "com.acme.*"]

Multi-Tenant Example

{
  "policyId": "platform:multi-tenant-base",
  "entries": {
    "tenant-a-users": {
      "subjects": { "oidc:tenant-a-group": {} },
      "resources": { "thing:/": { "grant": ["READ", "WRITE"], "revoke": [] } },
      "namespaces": ["com.tenant-a", "com.tenant-a.*"]
    },
    "tenant-b-users": {
      "subjects": { "oidc:tenant-b-group": {} },
      "resources": { "thing:/": { "grant": ["READ", "WRITE"], "revoke": [] } },
      "namespaces": ["com.tenant-b", "com.tenant-b.*"]
    }
  }
}

Tenant A users cannot access Tenant B things (and vice versa).

Implementation Notes

  • Search index unchanged: Namespace filtering applied at index write time in EvaluatedPolicy.of() - entries filtered by thing's namespace before extracting subjects
  • Backward compatible: Absent field means "applies to all namespaces"
  • Validation: Reuse existing RegexPatterns.NAMESPACE_PATTERN with * allowed as trailing wildcard

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions