This message was deleted.
# opal
s
This message was deleted.
a
Hi @Vitaly Orbidan, I'm an AI assistant for Permit.io. I'll analyze available sources and get back to you shortly.
The single-topic multi-tenant configuration is designed for dynamic tenant onboarding without service restarts (1) . Based on the documentation, here's how to address your persistence challenge: Recommended Pattern: External API Server The recommended approach is to use an ​*external API server*​ that serves different
DataSourceEntry
configurations dynamically (2) . This solves your persistence problem by centralizing the tenant-to-data-source mapping outside OPAL itself. ​*How it works:*​ 1. Configure
OPAL_DATA_CONFIG_SOURCES
to point to your external API endpoint (set once, no restarts needed) 2. Your external API returns multiple data source entries programmatically based on registered tenants 3. When clients restart, they fetch the current tenant list from your external API This approach handles pagination logic and can serve different configurations based on client identity using JWT claims . Single-Topic Architecture Recap With single-topic configuration, all tenants share one topic (1) :
Copy code
All tenants: OPAL_DATA_TOPICS=tenant_data # no restart needed when adding tenants
Each tenant gets its own data source publishing to the same topic with different destination paths : • ​*Tenant 1*​: External data source A →
tenant_data
topic →
/acl/tenant1
path • ​*Tenant 2*​: External data source B →
tenant_data
topic →
/acl/tenant2
path Adding Tenants Dynamically When you add a tenant via
/data/config
, the update triggers immediately :
Copy code
curl -X POST <http://localhost:7002/data/config> \
  -H "Content-Type: application/json" \
  -d '{
    "entries": [{
      "url": "<http://example_external_data_provider:80/acl/tenant1>",
      "topics": ["tenant_data"],
      "dst_path": "/acl/tenant1"
    }],
    "reason": "Add tenant1 data source"
  }'
No service restart is required when adding new tenants (1) (3) . Addressing Your Questions ​*1. Dynamic tenant onboarding pattern:*​ Yes, build an external config API that returns your tenant-to-data-source mappings (2) . You can break down data loading into multiple entries where each entry fetches a different subset and stores it at different paths . ​*2. Persistence of
/data/config
entries:*​ The documentation confirms that using an external API server for dynamic configuration is the supported pattern for handling persistence . The external server maintains state, not OPAL itself. ​*3. Client-side filtering for service mesh:*​ The single-topic approach means all OPAL clients subscribed to
tenant_data
receive all notifications and must hold all tenants' data (1) . This is a known trade-off: ​*Benefits:*​ • No service restarts required when adding tenants • Better resource utilization - tenants accessible from all OPAL Clients • Real-time data source notifications propagate to all clients without restarts ​*Challenges:*​ • Higher memory footprint per client - every OPAL Client must hold all tenants' data • Increased Data Source load - all OPAL Clients fetch all tenants' data If you need per-tenant resource isolation where each client only stores its tenant's data, the multi-topic architecture would be more appropriate . Would you like guidance on implementing the external config API server pattern?
To learn more, see the sources I considered: [[1] Single-Topic Multi-Tenant Configuration](https://docs.opal.ac/tutorials/single-topic-multi-tenant) [[2] Best approach for handling large initial datasets in OPAL_DATA_CONFIG_SOURCES](https://github.com/permitio/opal/discussions/847) [[3] Single-Topic Multi-Tenant RBAC Example](https://github.com/permitio/opal-example-policy-repo/blob/master/single-topic-multi-tenant/README.md)
v
Sorry - I deleted the message due to formatting issue, but here it is: ----- ## Single-Topic Multi-Tenant: How to Persist Data Config? Hey folks! 👋 Looking for guidance on the single-topic multi-tenant pattern. My setup: • Same policy across all tenants (shared rego) • Different data per tenant (isolated by
dst_path
) • Two deployment modes: service mesh (1 OPA per tenant) and gateway (1 OPA for all tenants) How I'm using it: I push tenant data via
POST /data/config
using two patterns: Pattern A: External URL
Copy code
{
  "entries": [
    {
      "url": "<http://data-api/tenant1/roles>",
      "dst_path": "/acl/tenant1",
      "topics": [
        "tenant_data"
      ]
    }
  ]
}
Pattern B: Inline Data
Copy code
{
  "entries": [
    {
      "url": "<inline://tenant1-roles>",
      "dst_path": "/acl/tenant1",
      "topics": [
        "tenant_data"
      ],
      "data": {
        "admin": [
          "read",
          "write"
        ]
      }
    }
  ]
}
The problem: Neither pattern persists anything. When a client restarts: • External URL — the
dst_path
→
url
mapping is lost • Inline Data — the actual data is lost Clients only know about
OPAL_DATA_CONFIG_SOURCES
(static, requires restart). Questions: 1. What's the recommended pattern for dynamic tenant onboarding with single-topic? Should I build an external config API? 2. Would persistence of
/data/config
entries be useful upstream? Currently persistence is gated behind
OPAL_SCOPES=1
. 3. Bonus: For service mesh, is there a way to filter updates client-side so each OPA only stores its tenant's data? (e.g.,
OPAL_DATA_FILTER_PATH=/acl/tenant1
) Trying to avoid building a separate data config registry or using scopes when I don't need per-tenant policies. Any thoughts? 🙏
a
Thanks for the feedback, glad I was helpful.
v
Thanks! That clarifies the external API pattern for URL-based entries. One follow-up: What about inline data (
"data": {...}
in the entry)? If I push data directly via
POST /data/config
(not fetched from a URL), and the client restarts, that data is lost. Is there a recommended pattern for this, or should inline data always be avoided in favor of external URLs? For the service mesh case, would there be interest in a client-side filter feature? Something like
OPAL_DATA_FILTER_PATH=/acl/tenant1
that discards entries not matching the path. This would allow single-topic simplicity while avoiding memory bloat on sidecars.
^^ @Ask Inkeep
a
Thanks for tagging me @Vitaly Orbidan. I'll look through relevant sources and get back to you shortly.
Based on the available sources, here's what we know about inline data and client-side filtering: ​*Inline Data Pattern*​ The documentation shows data source entries with inline data using the
data
field (1) . However, the sources don't explicitly address persistence of inline data after client restarts. The recommended pattern consistently points to external URLs rather than inline data for dynamic updates (1) (2) . When using external data sources, the endpoint should return a
DataSourceConfig
with entries that point to URLs where data can be fetched (1) . This ensures clients can refetch data after restarts. ​*Client-Side Filtering*​ The sources don't document a built-in
OPAL_DATA_FILTER_PATH
or similar client-side filtering mechanism. The single-topic architecture explicitly states that "all OPAL clients subscribed to
tenant_data
receive all notifications and must hold all tenants' data" (3) . The documented trade-off is clear : • ​*Single-topic*​: All clients hold all tenant data (higher memory per client) • ​*Multi-topic*​: Each client holds only its tenant's data (per-tenant resource isolation) If you need per-tenant resource isolation where each client only stores its tenant's data, the multi-topic architecture would be the appropriate choice . ​*Recommendation*​ For inline data that needs to persist across client restarts, the external API server pattern is the documented approach (1) (2) . Your external API would: 1. Store the tenant data persistently 2. Return
DataSourceEntry
configurations with URLs pointing to endpoints that serve the data 3. Handle the data fetch when clients restart For the client-side filtering feature request, that appears to be functionality not currently documented in OPAL. You might consider opening a feature request on the OPAL GitHub repository.
Thanks for tagging me @Vitaly Orbidan. I'll look through relevant sources and get back to you shortly.
To learn more, see the sources I considered: [[1] How to configure external data sources](https://docs.opal.ac/tutorials/configure_external_data_sources) [[2] Best approach for handling large initial datasets in OPAL_DATA_CONFIG_SOURCES](https://github.com/permitio/opal/discussions/847) [[3] Single-Topic Multi-Tenant Configuration](https://docs.opal.ac/tutorials/single-topic-multi-tenant)
Based on the available sources, here's what I can confirm about inline data and client-side filtering: ​*Inline Data Pattern*​ The documentation shows that data source entries support an
inline_data
field (1) . When configured as an external data source, entries can include inline data, but the sources don't explicitly address how inline data persists after client restarts. The external API pattern returns
DataSourceConfig
with entries pointing to URLs :
Copy code
DataSourceConfig(
    entries=[
        DataSourceEntry(
            url=f"{BACKEND_PUBLIC_URL}/v1/policy/config",
            topics=topics,
            config=HttpFetcherConfig(
                headers={'Authorization': f"Bearer {pdp.client_secret}"}
            )
        )
    ],
)
The recommended approach consistently emphasizes external URLs rather than inline data for dynamic updates (1) (2) . The external API server can break down data loading into multiple entries where each entry fetches a different subset and stores it at different paths (2) . ​*Client-Side Filtering*​ The sources don't document a built-in client-side filtering mechanism like
OPAL_DATA_FILTER_PATH
. The single-topic architecture explicitly states that all OPAL clients subscribed to
tenant_data
receive notifications, with the documented challenge being "Higher memory footprint per client - every OPAL Client must hold all tenants' data" (3) . The architecture trade-offs are : • ​*Single-topic*​: Better resource utilization, no restarts needed, but all clients hold all tenant data • ​*Multi-topic*​: Per-tenant resource isolation, but requires dedicated OPAL Client instances per tenant For feature requests around inline data persistence or client-side filtering, I'd recommend reaching out to the team via the Permit Slack Community to discuss whether these capabilities align with the product roadmap.
To learn more, see the sources I considered: [[1] How to configure external data sources](https://docs.opal.ac/tutorials/configure_external_data_sources) [[2] Best approach for handling large initial datasets in OPAL_DATA_CONFIG_SOURCES](https://github.com/permitio/opal/discussions/847) [[3] Single-Topic Multi-Tenant Configuration](https://docs.opal.ac/tutorials/single-topic-multi-tenant)
n
Hi Vitaly - just checking that you have the info you need.
v
Thanks @Natalia Edelson - I do have enough info at the moment. For the client-side filtering though - do you think it is better to open an issue or start a discussion?
a
Thanks for the feedback, glad I was helpful.
d
Hi Vitaly, I saw the issue you created on github. Thanks for bringing it to our attention.Feel free to try and solve it and create a PR - we're always happy to build our open-source community 🙂
👍 1