[role="xpack"]
[[apm-spaces]]
=== Control access to APM data

Starting in version 8.2.0, the APM app is <<xpack-spaces,{kib} Space>> aware.
This allows you to separate your data--and access to that data--by team, use case, service environment,
or any other filter that you choose.

To take advantage of this feature, your APM data needs to be written to different data steams.
One way to accomplish this is with different namespaces.
For example, you can send production data to an APM integration with a namespace of `production`,
while sending staging data to a different APM integration with a namespace of `staging`.

Multiple APM integration instances is not required though. The simplest way to take advantage of this feature
is by creating filtered aliases. See the guide below for more information.

[float]
[[apm-spaces-example]]
=== Guide: Separate staging and production data

This guide will explain how to separate your staging and production data.
This can be helpful to either remove noise when troubleshooting a production issue,
or to create more granular access control for certain data.

This guide assumes that you:

* Are sending both staging and production APM data to an {es} cluster.
* Have configured the `environment` variable in your APM agent configurations.
This variable sets the `service.environment` field in APM documents.
You should have documents where `service.environment: production` and `service.environment: staging`.
If this field is empty, see <<environment-selector,service environment filter>> to learn how to set this value.

[float]
==== Step 1: Create filtered aliases

The APM app uses index patterns to query your APM data. An index pattern can match data streams, indices, and/or aliases.
The default values are:

[options="header"]
|====
| Index setting     | Default index pattern
| Error             | `logs-apm*`
| Span/Transaction  | `traces-apm*`
| Metrics           | `metrics-apm*`
|====

NOTE: The default index settings also query the `apm-*` data view.
This data view matches APM data shipped in earlier versions of APM (prior to v8.0).

Instead of querying the default APM data views, we can create filtered aliases for the APM app to query.
A filtered alias is a secondary name for a group of data streams that has a user-defined
filter to limit the documents that the alias can access.

To separate `staging` and `production` APM data, we'd need to create six filtered aliases--three
aliases for each service environment:

[options="header"]
|====
| Index setting    | `production` env         | `staging` env
| Error            | `production-logs-apm`    | `staging-logs-apm`
| Span/Transaction | `production-traces-apm`  | `staging-traces-apm`
| Metrics          | `production-metrics-apm` | `staging-metrics-apm`
|====

The `production-<event>-apm` aliases will contain a filter that only provides access to documents
where the `service.environment` is `production`.
Similarly, the `staging-<event>-apm` aliases will contain a filter that only provides access to documents
where the `service.environment` is `staging`.

To create these six filtered aliases, use the {es} {ref}/indices-aliases.html[Aliases API].
In {kib}, open **Dev Tools** and run the following POST requests.

[%collapsible%open]
.`traces-apm*` production alias example
====
[source, console]
----
POST /_aliases?pretty
{
  "actions": [
    {
      "add": {
        "index": "traces-apm*", <1>
        "alias": "production-traces-apm", <2>
        "filter": {
          "term": {
            "service.environment": {
              "value": "production" <3>
            }
          }
        }
      }
    }
  ]
}
----
<1> This example matches the APM traces data stream
<2> The alias must not match the default APM index (`traces-apm*,apm-*`)
<3> Only match documents where `service.environment: production`
====

[%collapsible]
.`logs-apm*` production alias example
====
[source, console]
----
POST /_aliases?pretty
{
  "actions": [
    {
      "add": {
        "index": "logs-apm*", <1>
        "alias": "production-logs-apm", <2>
        "filter": {
          "term": {
            "service.environment": {
              "value": "production" <3>
            }
          }
        }
      }
    }
  ]
}
----
<1> This example matches the APM logs data stream
<2> The alias must not match the default APM index (`logs-apm*,apm-*`)
<3> Only match documents where `service.environment: production`
====

[%collapsible]
.`metrics-apm*` production alias example
====
[source, console]
----
POST /_aliases?pretty
{
  "actions": [
    {
      "add": {
        "index": "metrics-apm*", <1>
        "alias": "production-metrics-apm", <2>
        "filter": {
          "term": {
            "service.environment": {
              "value": "production" <3>
            }
          }
        }
      }
    }
  ]
}
----
<1> This example matches the APM metrics data stream
<2> The alias must not match the default APM index (`metrics-apm*,apm-*`)
<3> Only match documents where `service.environment: production`
====

[%collapsible]
.`traces-apm*` staging alias example
====
[source, console]
----
POST /_aliases?pretty
{
  "actions": [
    {
      "add": {
        "index": "traces-apm*", <1>
        "alias": "staging-traces-apm", <2>
        "filter": {
          "term": {
            "service.environment": {
              "value": "staging" <3>
            }
          }
        }
      }
    }
  ]
}
----
<1> This example matches the APM traces data stream
<2> The alias must not match the default APM index (`traces-apm*,apm-*`)
<3> Only match documents where `service.environment: staging`
====

[%collapsible]
.`logs-apm*` staging alias example
====
[source, console]
----
POST /_aliases?pretty
{
  "actions": [
    {
      "add": {
        "index": "logs-apm*", <1>
        "alias": "staging-logs-apm", <2>
        "filter": {
          "term": {
            "service.environment": {
              "value": "staging" <3>
            }
          }
        }
      }
    }
  ]
}
----
<1> This example matches the APM logs data stream
<2> The alias must not match the default APM index (`logs-apm*,apm-*`)
<3> Only match documents where `service.environment: staging`
====

[%collapsible]
.`metrics-apm*` staging alias example
====
[source, console]
----
POST /_aliases?pretty
{
  "actions": [
    {
      "add": {
        "index": "metrics-apm*", <1>
        "alias": "staging-metrics-apm", <2>
        "filter": {
          "term": {
            "service.environment": {
              "value": "staging" <3>
            }
          }
        }
      }
    }
  ]
}
----
<1> This example matches the APM metrics data stream
<2> The alias must not match the default APM index (`metrics-apm*,apm-*`)
<3> Only match documents where `service.environment: staging`
====

[float]
==== Step 2: Create {kib} spaces

Next, you'll need to create a {Kib} space for each service environment.
To create these spaces, navigate to **Stack Management** > **Spaces** > **Create a space**.
For this guide, we've created two Kibana spaces, one named `production` and one named `staging`.

See <<spaces-managing>> for more information on creating a space.

[float]
==== Step 3: Update APM index settings in each space

Now we can change the default data views that the APM app queries in each space.

Open the APM app and navigate to **Settings** > **Indices**.
Use the table below to update your settings for each space.
The values in each column match the names of the filtered aliases we created in step one.

[options="header"]
|====
| Index setting        | `production` space       | `staging` space
| Error indices        | `production-logs-apm`    | `staging-logs-apm`
| Span indices         | `production-traces-apm`  | `staging-traces-apm`
| Transaction indices  | `production-traces-apm`  | `staging-traces-apm`
| Metrics indices      | `production-metrics-apm` | `staging-metrics-apm`
|====

[role="screenshot"]
image::settings/images/apm-settings.png[APM app settings in Kibana]

[float]
==== Step 4: Create {kib} access roles

In {kib}, navigate to **Stack Management** > **Roles** and click **Create role**.

You'll need to create two roles: one for `staging` users (we'll call this role `staging_apm_viewer`)
and one for `production` users (we'll call this role `production_apm_viewer`).

Using the table below, assign each role the following privileges:

[options="header"]
|====
| Privileges        | `production_apm_viewer`       | `staging_apm_viewer`
| Index privileges  | index: `production-*-apm`, privilege: `read`   | index: `staging-*-apm`, privilege: `read`
| Kibana privileges | space: `production`, feature privileges: `APM and User Experience: read`  | space: `staging`, feature privileges: `APM and User Experience: read`
|====

[role="screenshot"]
image::./images/apm-roles-config.png[APM role config example]

Alternatively, you can use the
{es} {ref}/security-api-put-role.html[Create or update roles API]:

[%collapsible%open]
.Create a `production_apm_viewer` role
====
This request creates a `production_apm_viewer` role:

[source, console]
----
POST /_security/role/production_apm_viewer
{
  "cluster": [ ],
  "indices": [
    {
      "names": ["production-*-apm"], <1>
      "privileges": ["read"]
    }
  ],
  "applications": [
    {
      "application" : "kibana-.kibana",
      "privileges" : [
        "feature_apm.read" <2>
      ],
      "resources" : [
        "space:production" <3>
      ]
    }
  ]
}
----
<1> This data view matches all of the production aliases created in step one.
<2> Assigns `read` privileges for the APM and User Experience apps.
<3> Provides access to the space named `production`.
====

[%collapsible]
.Create a `staging_apm_viewer` role
====
This request creates a `staging_apm_viewer` role:

[source, console]
----
POST /_security/role/staging_apm_viewer
{
  "cluster": [ ],
  "indices": [
    {
      "names": ["staging-*-apm"], <1>
      "privileges": ["read"]
    }
  ],
  "applications": [
    {
      "application" : "kibana-.kibana",
      "privileges" : [
        "feature_apm.read" <2>
      ],
      "resources" : [
        "space:staging" <3>
      ]
    }
  ]
}
----
<1> This data view matches all of the staging aliases created in step one.
<2> Assigns `read` privileges for the APM and User Experience apps.
<3> Provides access to the space named `staging`.
====

[float]
==== Step 5: Assign users to roles

The last thing to do is assign users to the newly created roles above.
Users will only have access to the data within the spaces that they are granted.

For information on how to create users and assign them roles with the {kib} UI,
see <<tutorial-secure-access-to-kibana>>.

Alternatively, you can use the
{es} {ref}/security-api-put-user.html[Create or update users API].

This example creates a new user and assigns them the `production_apm_viewer` role created in the previous step.
This user will only have access to the production space and data with a `service.environment` of `production`.
Remember to change the `password`, `full_name`, and `email` fields.

[source, console]
----
POST /_security/user/production-apm-user
{
  "password" : "l0ng-r4nd0m-p@ssw0rd",
  "roles" : [ "production_apm_viewer" ], <1>
  "full_name" : "Jane Production Smith",
  "email" : "janesmith@example.com"
}
----
<1> Assigns the previously created `production_apm_viewer` role.

This example creates a new user and assigns them the `staging_apm_viewer` role created in the previous step.
This user will only have access to the staging space and data with a `service.environment` of `staging`.
Remember to change the `password`, `full_name`, and `email` fields.

[source, console]
----
POST /_security/user/staging-apm-user
{
  "password" : "l0ng-r4nd0m-p@ssw0rd",
  "roles" : [ "staging_apm_viewer" ], <1>
  "full_name" : "John Staging Doe",
  "email" : "johndoe@example.com"
}
----
<1> Assigns the previously created `staging_apm_viewer` role.

[float]
==== Step 6: Marvel

That's it! Head back to the APM app and marvel at your space-specific data.
