mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-11 22:49:54 +00:00
Fix teleport-investigate and teleport-access-review skill inaccuracies (#69309)
* docs: fix skill inaccuracies from v18 bp testing * fix: additional updates after another round of testing
This commit is contained in:
@@ -98,6 +98,10 @@ see [QUERY.md](references/QUERY.md).
|
|||||||
- **Level** is `standing`, `impersonate`, `request`, or `denied`, resolved by
|
- **Level** is `standing`, `impersonate`, `request`, or `denied`, resolved by
|
||||||
priority `denied > standing > impersonate > request`. A trailing `*` marks
|
priority `denied > standing > impersonate > request`. A trailing `*` marks
|
||||||
**temporary** access (granted by an access request; self-expiring).
|
**temporary** access (granted by an access request; self-expiring).
|
||||||
|
- **A level is a grant, not connectability.** Access Graph does not currently
|
||||||
|
resolve traits, so an identity that holds a grant but lacks the principals to
|
||||||
|
authenticate (`logins`, `db_users`, …) still shows `level: standing`, with no
|
||||||
|
field marking the gap. Report holding a grant, not the ability to exercise it.
|
||||||
- **Results are scoped to your query.** A query through an access list shows only
|
- **Results are scoped to your query.** A query through an access list shows only
|
||||||
paths that flow through that list — not every path each member has. To see a
|
paths that flow through that list — not every path each member has. To see a
|
||||||
user's _complete_ access to a resource, scope by the user and resource
|
user's _complete_ access to a resource, scope by the user and resource
|
||||||
|
|||||||
@@ -97,7 +97,7 @@
|
|||||||
{
|
{
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"prompt": "Who can access the staging-db database, and how is that access granted? Show me each grant. tctl is at evals/files/mock-tctl and tsh is at evals/files/mock-tsh.",
|
"prompt": "Who can access the staging-db database, and how is that access granted? Show me each grant. tctl is at evals/files/mock-tctl and tsh is at evals/files/mock-tsh.",
|
||||||
"expected_output": "[email protected] has standing access to staging-db. The access is backed by more than one grant: the primary grant (backing the resolved standing level) is the 'platform-admins' role, and a second, temporary/self-expiring path is granted by the 'jit-staging' access request at request level. The two grants are shown distinctly (e.g. via --detailed) with their own levels, and the primary grant is identified as the standing one \u2014 not the request one that happens to sort first by name. Because more than one grant backs the access, removing a single grant is not presented as a complete revocation. No write/mutating commands are run.",
|
"expected_output": "[email protected] has standing access to staging-db, backed by three grants (2 standing, 1 request) shown at their own levels, e.g. via --detailed. The primary grant is the permanent 'platform-admins' role. The other standing grant is an active access request \u2014 a synthetic, temporary ar_user_group_<uuid> node \u2014 reported as a live request rather than a role to fix. The request-level grant is the 'staging-db-jit' access list, named by its alias, which confers the ability to request. The pair is not called temporary overall, since a permanent grant also backs the standing level. Removing 'platform-admins' is therefore not an immediate revocation: the request keeps granting standing until it expires. No write/mutating commands are run.",
|
||||||
"files": [
|
"files": [
|
||||||
"evals/files/mock-tctl",
|
"evals/files/mock-tctl",
|
||||||
"evals/files/mock-tsh",
|
"evals/files/mock-tsh",
|
||||||
@@ -105,10 +105,12 @@
|
|||||||
"evals/files/tsh-status.txt"
|
"evals/files/tsh-status.txt"
|
||||||
],
|
],
|
||||||
"assertions": [
|
"assertions": [
|
||||||
"frank's resolved access to staging-db is reported as standing",
|
"frank's access to staging-db is reported as standing, with all three grants shown at their own levels",
|
||||||
"The primary grant backing the standing level is named as 'platform-admins' (granted_by[0]), i.e. the standing grant is treated as the one to act on",
|
"The grant to act on is named as the permanent 'platform-admins' role (granted_by[0]), not the one that sorts first by name",
|
||||||
"The 'jit-staging' access request is shown as a separate, temporary/request-level path (e.g. via --detailed), not conflated with the standing grant",
|
"The temporary standing grant is identified as an active access request (ar_user_group_<uuid>), not as a role to remediate",
|
||||||
"Because more than one grant backs the access, removing a single grant is not presented as a complete revocation",
|
"'staging-db-jit' is identified as an access list granting request-level access, referred to by its alias",
|
||||||
|
"The pair is not called temporary overall, since a permanent grant also backs the standing level",
|
||||||
|
"Removing 'platform-admins' is not presented as an immediate revocation, because the access request keeps granting standing until it expires",
|
||||||
"access-review is invoked with `--format json`; the skill parses JSON and does not rely on the default text-table output.",
|
"access-review is invoked with `--format json`; the skill parses JSON and does not rely on the default text-table output.",
|
||||||
"No write/mutating command is executed"
|
"No write/mutating command is executed"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
"id": "d0000000-0000-4000-8000-0000000000db",
|
"id": "d0000000-0000-4000-8000-0000000000db",
|
||||||
"name": "prod-db",
|
"name": "prod-db",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "standing",
|
"level": "standing",
|
||||||
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
||||||
@@ -67,9 +67,9 @@
|
|||||||
"id": "b6c00000-0000-4000-8000-000000000001",
|
"id": "b6c00000-0000-4000-8000-000000000001",
|
||||||
"name": "break-glass-prod",
|
"name": "break-glass-prod",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "standing",
|
"level": "standing",
|
||||||
"temporary": true,
|
"temporary": true,
|
||||||
@@ -78,9 +78,9 @@
|
|||||||
{
|
{
|
||||||
"node": {
|
"node": {
|
||||||
"id": "b6c0acc0-0000-4000-8000-000000000003",
|
"id": "b6c0acc0-0000-4000-8000-000000000003",
|
||||||
"name": "break-glass",
|
"name": "ar_user_group_019fc969-3cb3-77d5-b04a-7beb1a6ec1b2",
|
||||||
"kind": "identity_group",
|
"kind": "identity_group",
|
||||||
"sub_kind": "access_request",
|
"sub_kind": "role",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_access_request",
|
"origin": "teleport_access_request",
|
||||||
"temporary": true
|
"temporary": true
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
"id": "9a100db0-0000-4000-8000-000000000001",
|
"id": "9a100db0-0000-4000-8000-000000000001",
|
||||||
"name": "payments-db",
|
"name": "payments-db",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "standing",
|
"level": "standing",
|
||||||
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
"id": "57a91d00-1111-4111-8111-111111111111",
|
"id": "57a91d00-1111-4111-8111-111111111111",
|
||||||
"name": "staging-db",
|
"name": "staging-db",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "standing",
|
"level": "standing",
|
||||||
"grant_counts": {"standing": 1, "impersonate": 0, "request": 1},
|
"grant_counts": {"standing": 2, "impersonate": 0, "request": 1},
|
||||||
"granted_by": [
|
"granted_by": [
|
||||||
{
|
{
|
||||||
"node": {
|
"node": {
|
||||||
@@ -35,14 +35,26 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"node": {
|
"node": {
|
||||||
"id": "5f4e3d2c-1b0a-4987-8654-3210fedcba98",
|
"id": "2477c76d-d681-4b32-9055-51638cd285d9",
|
||||||
"name": "jit-staging",
|
"name": "ar_user_group_019fc969-3cb3-77d5-b04a-7beb1a6ec1b1",
|
||||||
"kind": "identity_group",
|
"kind": "identity_group",
|
||||||
"sub_kind": "access_request",
|
"sub_kind": "role",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_access_request",
|
"origin": "teleport_access_request",
|
||||||
"temporary": true
|
"temporary": true
|
||||||
},
|
},
|
||||||
|
"level": "standing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"id": "5f4e3d2c-1b0a-4987-8654-3210fedcba98",
|
||||||
|
"name": "staging-db-jit",
|
||||||
|
"alias": "Staging DB (just-in-time request)",
|
||||||
|
"kind": "identity_group",
|
||||||
|
"sub_kind": "access_list",
|
||||||
|
"source": "TELEPORT",
|
||||||
|
"origin": "teleport_access_list"
|
||||||
|
},
|
||||||
"level": "request"
|
"level": "request"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
"id": "d0000000-0000-4000-8000-0000000000db",
|
"id": "d0000000-0000-4000-8000-0000000000db",
|
||||||
"name": "prod-db",
|
"name": "prod-db",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "standing",
|
"level": "standing",
|
||||||
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
"id": "d0000000-0000-4000-8000-0000000000db",
|
"id": "d0000000-0000-4000-8000-0000000000db",
|
||||||
"name": "prod-db",
|
"name": "prod-db",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "standing",
|
"level": "standing",
|
||||||
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
"grant_counts": {"standing": 1, "impersonate": 0, "request": 0},
|
||||||
@@ -53,9 +53,9 @@
|
|||||||
"id": "d0000000-0000-4000-8000-0000000000db",
|
"id": "d0000000-0000-4000-8000-0000000000db",
|
||||||
"name": "prod-db",
|
"name": "prod-db",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "request",
|
"level": "request",
|
||||||
"grant_counts": {"standing": 0, "impersonate": 0, "request": 1},
|
"grant_counts": {"standing": 0, "impersonate": 0, "request": 1},
|
||||||
@@ -90,9 +90,9 @@
|
|||||||
"id": "d0000000-0000-4000-8000-0000000000db",
|
"id": "d0000000-0000-4000-8000-0000000000db",
|
||||||
"name": "prod-db",
|
"name": "prod-db",
|
||||||
"kind": "resource",
|
"kind": "resource",
|
||||||
"sub_kind": "db",
|
"sub_kind": "database",
|
||||||
"source": "TELEPORT",
|
"source": "TELEPORT",
|
||||||
"origin": "teleport_db"
|
"origin": "teleport_database"
|
||||||
},
|
},
|
||||||
"level": "denied",
|
"level": "denied",
|
||||||
"grant_counts": {"standing": 0, "impersonate": 0, "request": 0},
|
"grant_counts": {"standing": 0, "impersonate": 0, "request": 0},
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ object:
|
|||||||
| ---------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `resource` | Node | The resource reached. |
|
| `resource` | Node | The resource reached. |
|
||||||
| `level` | string | Resolved access level: `standing`, `impersonate`, `request`, or `denied` (see _Levels_). |
|
| `level` | string | Resolved access level: `standing`, `impersonate`, `request`, or `denied` (see _Levels_). |
|
||||||
| `temporary` | bool | `true` when the access is self-expiring (granted by an access request). Rendered as a `*` in text. |
|
| `temporary` | bool | `true` only when **every** grant at the resolved `level` is self-expiring. Omitted from JSON when `false`. Rendered as a `*` in text. |
|
||||||
| `grant_counts` | GrantCounts | How many grants back this access at each level (`standing`/`impersonate`/`request`). Denied grants are listed in `granted_by` but **not** counted here. |
|
| `grant_counts` | GrantCounts | How many grants back this access at each level (`standing`/`impersonate`/`request`). Denied grants are listed in `granted_by` but **not** counted here. |
|
||||||
| `granted_by` | Grant[] | The identity-group node(s) (access list / role / access request) that grant or deny the access. Ordered primary-first: `granted_by[0]` is the grant backing the resolved `level`. |
|
| `granted_by` | Grant[] | The identity-group node(s) (access list / role / access request) that grant or deny the access. Ordered primary-first: `granted_by[0]` is the grant backing the resolved `level`. |
|
||||||
| `activity` | Activity | Access count and last-access time over the window (default last 24h; widen with `--from`/`--to`). Omitted when `--no-activity` is passed or the activity lookup failed. |
|
| `activity` | Activity | Access count and last-access time over the window (default last 24h; widen with `--from`/`--to`). Omitted when `--no-activity` is passed or the activity lookup failed. |
|
||||||
@@ -33,8 +33,9 @@ object:
|
|||||||
`{ standing, impersonate, request }` — the number of grants backing the access
|
`{ standing, impersonate, request }` — the number of grants backing the access
|
||||||
at each level (denied grants excluded; they appear in `granted_by`). More than
|
at each level (denied grants excluded; they appear in `granted_by`). More than
|
||||||
one at a level means multiple grants back it, so removing a single grant won't
|
one at a level means multiple grants back it, so removing a single grant won't
|
||||||
revoke the access. In text, shown under the `Grants` column as e.g.
|
revoke the access — but temporary grants are counted too, so check
|
||||||
`3 standing, 1 request`.
|
`granted_by[].node.temporary` first. In text, shown under the `Grants` column as
|
||||||
|
e.g. `3 standing, 1 request`.
|
||||||
|
|
||||||
### Grant
|
### Grant
|
||||||
|
|
||||||
@@ -47,13 +48,18 @@ name, then `id` — so `granted_by[0]` is the strongest-priority grant, i.e. the
|
|||||||
one whose `level` equals the resolved `level`. Act on it when acting on the
|
one whose `level` equals the resolved `level`. Act on it when acting on the
|
||||||
resolved access.
|
resolved access.
|
||||||
|
|
||||||
|
An access-request grant is a synthetic node — `sub_kind: role`, `origin:
|
||||||
|
teleport_access_request`, `temporary: true`, named
|
||||||
|
`ar_user_group_<request-uuid>`. Don't report it as a role to remediate.
|
||||||
|
|
||||||
### Activity
|
### Activity
|
||||||
|
|
||||||
`{ count: number, last_access?: string (RFC3339) }`. Absent or null
|
`{ count: number, last_access?: string (RFC3339) }`. Unused pairs are omitted
|
||||||
`last_access` renders as `never`; a zero count renders as `0`. Requires Identity
|
from the JSON/YAML representation, so filter with `has("activity")`; text renders
|
||||||
Activity Center; if the activity lookup can't run, `activity` is omitted, the
|
them as `0` / `never`. Requires Identity Activity Center; if the activity lookup
|
||||||
top-level `activity_unavailable` field is set (shown in text as a note, with the
|
can't run, `activity` is dropped from **every** row, the top-level
|
||||||
activity columns omitted), and the access decisions are still returned.
|
`activity_unavailable` field is set (shown in text as a note, with the activity
|
||||||
|
columns omitted), and the access decisions are still returned.
|
||||||
|
|
||||||
Counts come from **session-start audit events**, so activity only covers
|
Counts come from **session-start audit events**, so activity only covers
|
||||||
resources reached through a Teleport session (SSH, database, Kubernetes, app,
|
resources reached through a Teleport session (SSH, database, Kubernetes, app,
|
||||||
@@ -71,7 +77,7 @@ Used for identities, resources, and grants.
|
|||||||
| `name` | string | The node's name **as stored** — what `=`/`IN` match against (exactly, case-sensitively). |
|
| `name` | string | The node's name **as stored** — what `=`/`IN` match against (exactly, case-sensitively). |
|
||||||
| `alias` | string | Optional friendly alias; also matched by name filters. |
|
| `alias` | string | Optional friendly alias; also matched by name filters. |
|
||||||
| `kind` | string | `identity`, `resource`, `identity_group`, `resource_group`, `sub_resource`, … |
|
| `kind` | string | `identity`, `resource`, `identity_group`, `resource_group`, `sub_resource`, … |
|
||||||
| `sub_kind` | string | e.g. identity → `user`/`bot`; resource → `ssh`/`database`/`kubernetes`/`app`/`desktop`; group → `role`/`access_list`/`access_request`. The text `Kind` columns show this. |
|
| `sub_kind` | string | e.g. identity → `user`/`bot`; resource → `ssh`/`database`/`kubernetes`/`app`/`desktop`; group → `role`/`access_list`. The text `Kind` columns show this. |
|
||||||
| `source` | string | Origin system, e.g. `TELEPORT`, `OKTA`. |
|
| `source` | string | Origin system, e.g. `TELEPORT`, `OKTA`. |
|
||||||
| `origin` | string | Finer origin, e.g. `teleport_user`. |
|
| `origin` | string | Finer origin, e.g. `teleport_user`. |
|
||||||
| `temporary` | bool | For a grant, `true` if created by an access request (self-expiring). |
|
| `temporary` | bool | For a grant, `true` if created by an access request (self-expiring). |
|
||||||
@@ -80,15 +86,19 @@ Used for identities, resources, and grants.
|
|||||||
|
|
||||||
| Level | Meaning |
|
| Level | Meaning |
|
||||||
| ------------- | --------------------------------------------------------------------------------------------- |
|
| ------------- | --------------------------------------------------------------------------------------------- |
|
||||||
| `standing` | The identity holds the access directly, no action required. |
|
| `standing` | The identity holds the grant directly, no request or impersonation needed. |
|
||||||
| `impersonate` | Reachable only by minting a certificate to impersonate another identity (no approval needed). |
|
| `impersonate` | Held only by minting a certificate to impersonate another identity (no approval needed). |
|
||||||
| `request` | Reachable only after an approved access request. |
|
| `request` | Held only after an approved access request. |
|
||||||
| `denied` | A deny rule blocks the access. Any denied path wins over everything else. |
|
| `denied` | A deny rule blocks the access. Any denied path wins over everything else. |
|
||||||
|
|
||||||
A trailing `*` on the level in text output marks `temporary` (self-expiring)
|
A trailing `*` on the level in text output marks `temporary` (self-expiring)
|
||||||
access — distinguish it from standing membership so you don't trim access that
|
access — distinguish it from standing membership so you don't trim access that
|
||||||
will lapse on its own.
|
will lapse on its own.
|
||||||
|
|
||||||
|
Every level is a **grant**, not connectability — Access Graph does not currently
|
||||||
|
resolve traits, so it can't tell whether the identity holds the principals to
|
||||||
|
authenticate.
|
||||||
|
|
||||||
## Empty rows
|
## Empty rows
|
||||||
|
|
||||||
An identity in the query's scope with **no qualifying access** is still
|
An identity in the query's scope with **no qualifying access** is still
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ carry the activity, then filter to all of them:
|
|||||||
```sh
|
```sh
|
||||||
$TCTL investigate --status failure --from 7d --facets-only --format json \
|
$TCTL investigate --status failure --from 7d --facets-only --format json \
|
||||||
| jq '[.facets[] | select(.name=="event-type").values[]]'
|
| jq '[.facets[] | select(.name=="event-type").values[]]'
|
||||||
# failed "logins" surface as BOTH user.login and auth — so filter on both.
|
# e.g. "database access" spans db.session.start, db.session.end, db.session.query.
|
||||||
```
|
```
|
||||||
|
|
||||||
The sweep cuts both ways: a bare `--status failure` also catches failures that
|
The sweep cuts both ways: a bare `--status failure` also catches failures that
|
||||||
@@ -82,12 +82,12 @@ abbreviated.
|
|||||||
|
|
||||||
### "Were there any failed authentications from India in the last 7 days?"
|
### "Were there any failed authentications from India in the last 7 days?"
|
||||||
|
|
||||||
Failed logins span two event types — `user.login` and `auth`, both with
|
Login failures are `user.login` with `status:failure`, whatever the method
|
||||||
`status:failure` — so query both (see happy path 4). From India →
|
(local, SSO, `client.cert`, `headless`). From India → `--country India`. Facets
|
||||||
`--country India`. Facets answer it without pulling events:
|
answer it without pulling events:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$TCTL investigate --event-type auth --event-type user.login --status failure --country India \
|
$TCTL investigate --event-type user.login --status failure --country India \
|
||||||
--from 7d --facets-only --format json \
|
--from 7d --facets-only --format json \
|
||||||
| jq '{total, who: [.facets[] | select(.name=="user").values[]]}'
|
| jq '{total, who: [.facets[] | select(.name=="user").values[]]}'
|
||||||
```
|
```
|
||||||
@@ -96,6 +96,10 @@ $TCTL investigate --event-type auth --event-type user.login --status failure --c
|
|||||||
{ "total": 1, "who": [{ "value": "alice", "count": 1 }] }
|
{ "total": 1, "who": [{ "value": "alice", "count": 1 }] }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Don't add `--event-type auth`: `auth` is usually an **authorization**-attempt
|
||||||
|
failure — most often an SSH certificate lacking the requested principal — rather
|
||||||
|
than a failed authentication. Mixing the two inflates any brute-force signal.
|
||||||
|
|
||||||
### "What did bot CI-deployer do yesterday?"
|
### "What did bot CI-deployer do yesterday?"
|
||||||
|
|
||||||
Bots are non-human identities; filter by the bot's name (optionally narrow with
|
Bots are non-human identities; filter by the bot's name (optionally narrow with
|
||||||
@@ -144,9 +148,13 @@ $TCTL investigate --resource production-database --event-type db.session.end \
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Manually exclude Teleport automation from the `who` facet — `system` (e.g.
|
The `who` facet lists `identity.id` values, and several of them aren't people.
|
||||||
`session.summarized`), `Instance` (`instance.join`), and `UNKNOWN` are not human
|
Drop `system` (`session.summarized`), `Instance` (`instance.join`), `UNKNOWN`,
|
||||||
accessors.
|
and any agent's `<host-uuid>.<cluster-name>` before reporting accessors.
|
||||||
|
|
||||||
|
Exclude them by name, **not** with `--exclude-user-kind system`: `identity.kind`
|
||||||
|
is derived per **event**, so the same human is `system` on `mfa.add` and `user`
|
||||||
|
on `mfa_auth_challenge.*`, and excluding the kind drops real human activity.
|
||||||
|
|
||||||
### "Show me what activity was performed during the following access request `<uuid>`"
|
### "Show me what activity was performed during the following access request `<uuid>`"
|
||||||
|
|
||||||
@@ -269,9 +277,10 @@ start with low-cost searches and refine until the result set is narrow.
|
|||||||
- **Empty `data`** — broaden the time window, or add `--show-unmatched` to a
|
- **Empty `data`** — broaden the time window, or add `--show-unmatched` to a
|
||||||
`--facets-only` run to discover which filter values actually exist in the
|
`--facets-only` run to discover which filter values actually exist in the
|
||||||
window, then adjust the filter.
|
window, then adjust the filter.
|
||||||
- **Negative coordinates need the equals form.** A negative `--latitude` or
|
- **Geo filters come as a set, and negatives need the equals form.**
|
||||||
`--longitude` is misread as a flag (`expected argument for flag '--latitude'`);
|
`--latitude`, `--longitude` and `--radius` (km) must all be passed. A negative
|
||||||
pass it as `--latitude=-26.2309 --longitude=28.0583`.
|
coordinate is misread as a flag (`expected argument for flag '--latitude'`), so
|
||||||
|
write it as `--latitude=-26.2309 --longitude=28.0583 --radius=50`.
|
||||||
- **`user_agent` is sparse.** For Teleport events it's only populated on some
|
- **`user_agent` is sparse.** For Teleport events it's only populated on some
|
||||||
event types (login, cert issue, db session start, SCIM list/get); treat a
|
event types (login, cert issue, db session start, SCIM list/get); treat a
|
||||||
missing `user_agent` as absent data, not a signal.
|
missing `user_agent` as absent data, not a signal.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ event type. These are always present, so you can rely on them when projecting:
|
|||||||
| `event_source` | string | Source of the event. |
|
| `event_source` | string | Source of the event. |
|
||||||
| `action` | string | Action performed; mirrors `event_type` for Teleport-native events. |
|
| `action` | string | Action performed; mirrors `event_type` for Teleport-native events. |
|
||||||
| `status` | string | Outcome, e.g. `success`, `failure`. |
|
| `status` | string | Outcome, e.g. `success`, `failure`. |
|
||||||
| `origin` | string | Event origin, e.g. `example.teleport.com`. |
|
| `origin` | string | Event origin — the cluster name, e.g. `acme-prod`. |
|
||||||
| `identity` | object | Actor: `{id, kind, name, token_id, user_agent}`. |
|
| `identity` | object | Actor: `{id, kind, name, token_id, user_agent}`. |
|
||||||
| `target` | object | Object acted on: `{id, kind, location, resource}`. |
|
| `target` | object | Object acted on: `{id, kind, location, resource}`. |
|
||||||
| `location_details` | object | Geo from IP: `{ip, city, region, country, latitude, longitude}`. |
|
| `location_details` | object | Geo from IP: `{ip, city, region, country, latitude, longitude}`. |
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ func TestBuildAccessReviewOutput(t *testing.T) {
|
|||||||
|
|
||||||
nodes := []accessgraph.IdentityAccessNode{
|
nodes := []accessgraph.IdentityAccessNode{
|
||||||
{Id: idID, Name: "alice@corp", Kind: "identity", SubKind: new("user")},
|
{Id: idID, Name: "alice@corp", Kind: "identity", SubKind: new("user")},
|
||||||
{Id: resID, Name: "prod-db", Kind: "resource", SubKind: new("db"), Alias: new("Production DB")},
|
{Id: resID, Name: "prod-db", Kind: "resource", SubKind: new("database"), Alias: new("Production DB")},
|
||||||
{Id: grStanding, Name: "admins", Kind: "identity_group", SubKind: new("role")},
|
{Id: grStanding, Name: "admins", Kind: "identity_group", SubKind: new("role")},
|
||||||
{Id: grRequest, Name: "oncall", Kind: "identity_group", SubKind: new("access_request"), Temporary: new(true)},
|
{Id: grRequest, Name: "oncall", Kind: "identity_group", SubKind: new("role"), Temporary: new(true)},
|
||||||
}
|
}
|
||||||
resp := &accessgraph.IdentityAccessResponse{
|
resp := &accessgraph.IdentityAccessResponse{
|
||||||
Nodes: nodes,
|
Nodes: nodes,
|
||||||
|
|||||||
Reference in New Issue
Block a user