08 Sep 2026
04:07 PM
- last edited on
09 Sep 2026
07:59 AM
by
MaciejNeumann
Hi everyone,
We're currently reviewing our governance model on Dynatrace Platform (Gen3) and I'd be interested to understand how others are handling application-level data segregation.
Our goal is to allow different teams to access only the observability data related to their own application perimeter, including:
In the past, with Management Zones, we were able to build a fairly complete segregation model by combining MZs, permissions, and settings scoping. Since we're now moving towards Gen3 capabilities only, that approach is no longer available and we're looking for the recommended replacement pattern.
Some of the questions we're trying to answer are:
Ideally, we'd like to achieve a user experience similar to what Management Zones provided in the past: users belonging to a specific application domain should only be able to see data related to that domain, regardless of whether they are looking at logs, traces, metrics, Smartscape, dashboards, investigations, etc.
I'd be interested to hear how other customers have implemented this and what Dynatrace currently recommends for large shared environments.
Thanks in advance for any suggestions or real-world examples!
09 Sep 2026 07:50 AM
I'd recommend building access control on grail fields and primary tags. This, of course, needs a proper tagging strategy first. Tagging is quite easy with new platforms, but it gets much more complicated for legacy systems, especially shared ones (for example host running multiple different applications for multiple teams, for example a docker swarm cluster). New features such as https://docs.dynatrace.com/docs/shortlink/ingest-enrichment-settings have been introduced recently, which will hopefully make it easier. Nevertheless, the tagging strategy (what to have in the primary tags/fields) highly depends on your organisation. I recommend reusing existing metadata as much as possible (like k8s labels, for example).
Segments are only for data filtering, you can't really build any access restrictions with them. Boundaries are the way (or policies including conditions).
Some further improvements are being developed, especially for segregation of settings.
09 Sep 2026 09:30 AM
Thanks for the explanation.
However, I'm still struggling to see how this would work in practice.
From my tests, Grail tags do not seem to behave like classic auto-tags. For example, I created the following rule:
but nothing appears to have been tagged afterwards: neither the namespace itself, nor traces, logs, or events generated from that namespace.
In addition, as far as I can see, Boundary policies cannot currently be filtered using Grail tags, so I'm not sure this would help us implement access segregation.
Could you share a few practical examples of the approach you described?
Our main requirement is to segregate access based on:
In the classic Management Zone model, it was possible to define a perimeter and automatically include the related entities. In the current Gen3 model, we're trying to understand what the recommended equivalent approach is for ensuring consistent access restrictions across logs, traces, metrics, events, Smartscape entities, and frontend monitoring data.
Any example of Boundary policies, primary fields, or tagging strategies used to achieve this would be very helpful.
09 Sep 2026 11:40 PM - edited 09 Sep 2026 11:43 PM
Hello @andreaCaria
The recommendation by @Julius_Loman to use Grail fields + primary tags + boundaries is the right direction. But @andreaCaria your confusion is also valid there's a crucial distinction that explains why your test didn't work.
Why matchesPhrase(k8s.namespace.name, "sport-coll") didn't tag anything. Grail tags are not classic auto-tags. They work completely differently
matchesPhrase(k8s.namespace.name, "sport-coll") is DQL query syntax it's for filtering data you're reading, not for creating tags. There is no "tag rule" equivalent in Gen3 that evaluates and stamps entities. Instead, k8s.namespace.name is already present on every log, span, metric, and event that originates from that namespace automatically, with no rule needed.
I would recommend this Segregation Architecture
1. Use k8s.namespace.name directly (Already works, No config needed) - For Kubernetes-based workloads, k8s.namespace.name is a primary Grail field that is automatically populated on all telemetry. You don't need to create any tagging rule. It's already there.
2. Build Policy Boundaries on k8s.namespace.name - for your sport-coll namespace example, create a boundary:storage:k8s.namespace.name = "sport-coll"
Then attach it to the relevant policies for the team's user group:
ALLOW storage:logs:read WHERE storage:k8s.namespace.name = "sport-coll";
ALLOW storage:spans:read WHERE storage:k8s.namespace.name = "sport-coll";
ALLOW storage:metrics:read WHERE storage:k8s.namespace.name = "sport-coll";
ALLOW storage:events:read WHERE storage:k8s.namespace.name = "sport-coll";
ALLOW storage:entities:read WHERE storage:dt.security_context = "sport-coll";
One thing important here, k8s.namespace.name works for logs/spans/metrics/events. For entities/topology, you need dt.security_context
3. dt.security_context for Entities and shared Infrastructure - You can do this via Dynakube annotation but i am adding steps here through UI
OpenPipeline for logs or spans where you need to derive it from content:
Then the entity boundary condition becomes: storage:dt.security_context = "sport-coll"
4. If you are planning for frontend application example Frontend Application (SPORT-FE-coll)
For RUM/frontend applications, access is controlled at the resource level, not the storage level. The policy statement uses:ALLOW app-engine:apps:execute WHERE app-engine:app-id = "APPLICATION-XXXXXXXX";
Or scope the user group to only see specific application entities via dt.security_context set on the application's underlying process group.
I hope this would help.
Thanks,
Sujit
10 Sep 2026 05:23 AM
Hey @sujit_k_singh
Regarding your point 4, for RUM access it is still controlled at the storage level. You can find out more in these docs https://docs.dynatrace.com/docs/shortlink/rum-on-grail-permissions
The example you provided is for controlling access to the different "apps" or views we have in the Dynatrace platform, such as the infra and ops app, or the notebooks app.
10 Sep 2026 06:45 AM
Hi @Fin_Ubels
Thanks for correction, I didint noticed that one,
So RUM data (user sessions, user events) lives in Grail storage tables and is controlled the same way as logs, spans, and metrics via storage-level policy statements with WHERE conditions.
The app-engine:apps:execute example I gave controls access to Dynatrace UI apps (e.g., who can open the Digital Experience app, Notebooks, etc.) it has nothing to do with restricting which RUM data a user can see.
Correct policy for RUM Frontend Access Restriction
For SPORT-FE-coll frontend application, the correct policy statements are:
ALLOW storage:user.sessions:read WHERE storage:frontend.name = "SPORT-FE-coll";
ALLOW storage:user.events:read WHERE storage:frontend.name = "SPORT-FE-coll";
This restricts the user group to only see sessions and events from that specific frontend consistent with how I'd restrict logs by k8s.namespace.name or spans by dt.security_context.
Thanks,
Sujit
10 Sep 2026 02:07 AM - edited 10 Sep 2026 07:15 AM
For the purposes of this post, when I'm talking about granting access with the new IAM capabilities I'm going to focus only on the new platform capability. So things like classic cloud integrations or extensions that haven't been updated to a Smartscape on Grail compatible version don't apply here.
Management zones are dead, long live management zones?
While it is true that management zones are not the way we manage access in the new Dynatrace platform, the way we think about access does not have to change too much. With a management zone, if you included an entity in one you would give access to all data effectively coming from that entity. With the new IAM boundaries, you can achieve a very similar thing.
Lets say you want to give access to everything within a specific K8s namespace.
The 2 approaches sound very similar, so what is actually different? Management zones as mentioned were entity focused. You would give access to an entity and by extension the data associated with it. New IAM boundaries are record focused. You give access to individual records based on fields attached to them.
With the IAM boundary example above, that boundary would look as simple as:
storage:k8s.namespace.name MATCH ('NamespaceNameHere');
Combine this with a policy that provides access to all tables and this boundary would restrict access to only data where the k8s.namespace.name fields equals NamespaceNameHere.
The last thing to mention here is that you may be thinking "but when I look in the data explorer, none of my metrics have these fields so how will this work?!" and you'd be right! In the classic Dynatrace, things like Service metrics had 1 dimension, the Service entity. However if you hop into a notebook and query the same metric you'll find an explosion of dimensions, and you'll also start to see a pattern of dimensions consistent across many different metrics.
Grail Primary Fields
In the new Dynatrace platform there are what we call "Primary Grail Fields" and these are a set of fields consistent across all data ingested into Dynatrace. The best way I like to view them is through the IAM policy reference doc https://docs.dynatrace.com/docs/shortlink/iam-policystatements#storage which is a very very dry read. It is however my best friend when it comes to navigating the murky IAM waters. The link I provided takes you to the section specific to storage, and what you will find there is that the conditions you can apply to access all of the different storage tables are very similar. Some have different fields you can use but most, if not all, share a base set of fields. They are:
storage:bucket-name, storage:k8s.namespace.name, storage:k8s.cluster.name, storage:host.name, storage:dt.host_group.id, storage:dt.security_context, storage:gcp.project.id, storage:aws.account.id, storage:azure.subscription, storage:azure.resource.group, storage:frontend.name
Where possible Dynatrace will attempt to enrich all data ingested with these fields. This means that you can use these fields to build out your boundaries. These fields are great for building out boundaries as they often already represent boundaries within an environment.
Now, there are some exceptions, for example Extensions don't just magically get these fields filled in, however when setting up an extension configuration you are prompted with the ability to provide values for these fields. And with synthetics, they rely on the security context field.
How I approach IAM
The first thing I do when building out an IAM approach is nail down a host group and security context naming structure. If you can develop a solid security context structure, this can solve 99% of access problems. For example, if I build a security context structure that is something like:
{app}-{stage}-{function}
When filled in that might look like:
Store-Production-Cart
Store-Staging-Database
API-Dev-Gateway
So if this security context is applied on my OneAgents, in my Kubernetes environments, in my cloud, I can build boundaries such as:
storage:dt.security_context MATCH ('API-*'); This gives access to the whole API app
storage:dt.security_context MATCH ('Store-Production-*'); This gives access to the Store Production environment
For small environments, or ones that aren't very complex, you can get away with not using the security context field at all and instead rely solely on primary grail fields. Regardless, once I have that naming convention set the approach I currently use is to build a matrix of the teams and their boundaries. It looks something like:
| Team Name | Azure Sub | AWS account | Host group | K8s cluster | K8s namespace | SecurityContext | Frontend |
| Store Ops | 12345 67890 | N/A | Store-* | Store-Cluster-* | N/A | Store-* | Store-* |
| Store Dev | 67890 | N/A | Store-Dev-* | Store-Cluster-Dev | N/A | Store-Dev-* | Store-Dev |
You may not need to list out all teams, as some may have overlap, or the access restrictions may not need to be so strict. The point of this matrix though is to very simply go through and define what it is each team is allowed to see. We can then very simply turn each of these columns into a boundary.
If we take Store Ops as an example we would create 5 boundaries, one for their subscriptions, one for their host groups, one for their clusters, one for their security contexts and one for their frontend.
The original questions
I think the above is a great way to approach IAM. You may find you need to control access to specific metrics, or all data except spans, or even limit access to specific fields. These are also all possible now, but before diving into the crazy convoluted topics, building that foundation is so important. It prevents things from getting out of hand.
Hopefully the above helps!
10 Sep 2026 09:24 AM
Thanks for the clarification. I did some additional testing and I'm still struggling to understand how boundaries are evaluated when multiple boundaries are assigned to the same policy.
I created a boundary using:
This seems to work correctly in some areas. For example, in Explorer Classic I only see the 4 hosts belonging to the crm-noprod host group.
However, the behavior is not consistent across the platform:
This makes me wonder whether dt.security_context is supported differently depending on the application/view being used.
To allow visibility of specific Frontend applications, I added a second boundary:
and assigned both boundaries to the same policy.
At this point the host filtering breaks completely:
Based on this behavior, I am not sure whether multiple boundaries are evaluated as a union (OR), an intersection (AND), or whether entity type specific rules are applied behind the scenes.
Could you clarify:
10 Sep 2026 09:54 AM
To resolve the first part of the above and allow your boundary to work in the new explorers I would ALWAYS (I can't think of a scenario where I have deviated from this personally) use the MATCH operator instead of = IN or STARTSWITH. This is because these primary fields are in fact often arrays! A record can have multiple security contexts. So = IN and STARTSWITH can have issues as they don't work with an array (maybe IN does but MATCH is just a better IN).
In your example:
storage:dt.security_context = "crm-noprod";
becomes
storage:dt.security_context MATCH ("crm-noprod");
MATCH also supports wild cards, so you could do:
storage:dt.security_context MATCH ("crm-*");
to give access to everything that has a security context starting with crm-
If you want to continue managing access to the classic Smartscape, the solution I have found is creating a sperate policy for storage:entities:read and creating specific boundaries that DON'T use the MATCH operator for it. As is mentioned in the IAM reference, it only supports = IN and STARTSWITH and ONLY supports security context. https://docs.dynatrace.com/docs/shortlink/iam-policystatements#storage-entities-read
Featured Posts