@openauditmodel/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +215 -0
- package/README.md +647 -0
- package/dist/conformance/src/cli.d.ts +20 -0
- package/dist/conformance/src/cli.js +560 -0
- package/dist/conformance/src/cli.js.map +1 -0
- package/dist/conformance/src/format-errors.d.ts +20 -0
- package/dist/conformance/src/format-errors.js +116 -0
- package/dist/conformance/src/format-errors.js.map +1 -0
- package/dist/conformance/src/integrity/canonicalize.d.ts +25 -0
- package/dist/conformance/src/integrity/canonicalize.js +100 -0
- package/dist/conformance/src/integrity/canonicalize.js.map +1 -0
- package/dist/conformance/src/integrity/digest.d.ts +54 -0
- package/dist/conformance/src/integrity/digest.js +126 -0
- package/dist/conformance/src/integrity/digest.js.map +1 -0
- package/dist/conformance/src/integrity/types.d.ts +86 -0
- package/dist/conformance/src/integrity/types.js +36 -0
- package/dist/conformance/src/integrity/types.js.map +1 -0
- package/dist/conformance/src/integrity/verify-chain.d.ts +23 -0
- package/dist/conformance/src/integrity/verify-chain.js +235 -0
- package/dist/conformance/src/integrity/verify-chain.js.map +1 -0
- package/dist/conformance/src/integrity/verify-event.d.ts +29 -0
- package/dist/conformance/src/integrity/verify-event.js +140 -0
- package/dist/conformance/src/integrity/verify-event.js.map +1 -0
- package/dist/conformance/src/privacy/entropy.d.ts +14 -0
- package/dist/conformance/src/privacy/entropy.js +86 -0
- package/dist/conformance/src/privacy/entropy.js.map +1 -0
- package/dist/conformance/src/privacy/field-names.d.ts +36 -0
- package/dist/conformance/src/privacy/field-names.js +121 -0
- package/dist/conformance/src/privacy/field-names.js.map +1 -0
- package/dist/conformance/src/privacy/lint-event.d.ts +18 -0
- package/dist/conformance/src/privacy/lint-event.js +272 -0
- package/dist/conformance/src/privacy/lint-event.js.map +1 -0
- package/dist/conformance/src/privacy/rules.d.ts +44 -0
- package/dist/conformance/src/privacy/rules.js +161 -0
- package/dist/conformance/src/privacy/rules.js.map +1 -0
- package/dist/conformance/src/privacy/safe-formats.d.ts +32 -0
- package/dist/conformance/src/privacy/safe-formats.js +118 -0
- package/dist/conformance/src/privacy/safe-formats.js.map +1 -0
- package/dist/conformance/src/privacy/size-analysis.d.ts +36 -0
- package/dist/conformance/src/privacy/size-analysis.js +87 -0
- package/dist/conformance/src/privacy/size-analysis.js.map +1 -0
- package/dist/conformance/src/privacy/token-patterns.d.ts +24 -0
- package/dist/conformance/src/privacy/token-patterns.js +126 -0
- package/dist/conformance/src/privacy/token-patterns.js.map +1 -0
- package/dist/conformance/src/privacy/traverse.d.ts +33 -0
- package/dist/conformance/src/privacy/traverse.js +61 -0
- package/dist/conformance/src/privacy/traverse.js.map +1 -0
- package/dist/conformance/src/privacy/types.d.ts +58 -0
- package/dist/conformance/src/privacy/types.js +32 -0
- package/dist/conformance/src/privacy/types.js.map +1 -0
- package/dist/conformance/src/privacy/url-analysis.d.ts +40 -0
- package/dist/conformance/src/privacy/url-analysis.js +148 -0
- package/dist/conformance/src/privacy/url-analysis.js.map +1 -0
- package/dist/conformance/src/profiles/check-profile.d.ts +22 -0
- package/dist/conformance/src/profiles/check-profile.js +72 -0
- package/dist/conformance/src/profiles/check-profile.js.map +1 -0
- package/dist/conformance/src/profiles/evaluate-rule.d.ts +27 -0
- package/dist/conformance/src/profiles/evaluate-rule.js +87 -0
- package/dist/conformance/src/profiles/evaluate-rule.js.map +1 -0
- package/dist/conformance/src/profiles/load-profile.d.ts +30 -0
- package/dist/conformance/src/profiles/load-profile.js +95 -0
- package/dist/conformance/src/profiles/load-profile.js.map +1 -0
- package/dist/conformance/src/profiles/resolve-pointer.d.ts +44 -0
- package/dist/conformance/src/profiles/resolve-pointer.js +123 -0
- package/dist/conformance/src/profiles/resolve-pointer.js.map +1 -0
- package/dist/conformance/src/profiles/select-rules.d.ts +13 -0
- package/dist/conformance/src/profiles/select-rules.js +42 -0
- package/dist/conformance/src/profiles/select-rules.js.map +1 -0
- package/dist/conformance/src/profiles/types.d.ts +101 -0
- package/dist/conformance/src/profiles/types.js +31 -0
- package/dist/conformance/src/profiles/types.js.map +1 -0
- package/dist/conformance/src/profiles/validate-profile-definition.d.ts +12 -0
- package/dist/conformance/src/profiles/validate-profile-definition.js +47 -0
- package/dist/conformance/src/profiles/validate-profile-definition.js.map +1 -0
- package/dist/conformance/src/sources.d.ts +53 -0
- package/dist/conformance/src/sources.js +153 -0
- package/dist/conformance/src/sources.js.map +1 -0
- package/dist/conformance/src/validate-core.d.ts +30 -0
- package/dist/conformance/src/validate-core.js +62 -0
- package/dist/conformance/src/validate-core.js.map +1 -0
- package/dist/conformance/src/validate.d.ts +34 -0
- package/dist/conformance/src/validate.js +62 -0
- package/dist/conformance/src/validate.js.map +1 -0
- package/dist/conformance/src/validator-interface.d.ts +35 -0
- package/dist/conformance/src/validator-interface.js +19 -0
- package/dist/conformance/src/validator-interface.js.map +1 -0
- package/package.json +85 -0
- package/profiles/README.md +201 -0
- package/profiles/api-and-integration-management/README.md +271 -0
- package/profiles/api-and-integration-management/profile.json +258 -0
- package/profiles/backup-and-recovery/README.md +318 -0
- package/profiles/backup-and-recovery/profile.json +178 -0
- package/profiles/customer-and-account-management/README.md +340 -0
- package/profiles/customer-and-account-management/profile.json +237 -0
- package/profiles/deployment-and-change-management/README.md +359 -0
- package/profiles/deployment-and-change-management/profile.json +298 -0
- package/profiles/document-management/README.md +120 -0
- package/profiles/document-management/profile.json +170 -0
- package/profiles/financial-transaction-management/README.md +339 -0
- package/profiles/financial-transaction-management/profile.json +247 -0
- package/profiles/identity-and-access-management/README.md +112 -0
- package/profiles/identity-and-access-management/profile.json +120 -0
- package/profiles/incident-management/README.md +338 -0
- package/profiles/incident-management/profile.json +256 -0
- package/profiles/message-broker-management/README.md +344 -0
- package/profiles/message-broker-management/profile.json +399 -0
- package/profiles/profile-definition.schema.json +213 -0
- package/profiles/secrets-and-key-management/README.md +331 -0
- package/profiles/secrets-and-key-management/profile.json +219 -0
- package/schemas/v0.1/audit-event.schema.json +911 -0
- package/semantic-conventions/README.md +52 -0
- package/semantic-conventions/authentication.md +111 -0
- package/semantic-conventions/configuration-and-change.md +122 -0
- package/semantic-conventions/correlation-and-tracing.md +387 -0
- package/semantic-conventions/data-access.md +115 -0
- package/semantic-conventions/event-naming.md +114 -0
- package/semantic-conventions/identity-and-access.md +112 -0
- package/semantic-conventions/privileged-operations.md +110 -0
- package/semantic-conventions/workflow-and-approval.md +109 -0
- package/specification/actor-model.md +135 -0
- package/specification/approval-and-delegation.md +150 -0
- package/specification/authentication.md +116 -0
- package/specification/authorization.md +117 -0
- package/specification/change-model.md +134 -0
- package/specification/delivery.md +136 -0
- package/specification/design-principles.md +137 -0
- package/specification/event-model.md +387 -0
- package/specification/evidence-model.md +109 -0
- package/specification/extension-model.md +159 -0
- package/specification/integrity.md +314 -0
- package/specification/overview.md +172 -0
- package/specification/privacy.md +386 -0
- package/specification/resource-model.md +116 -0
- package/specification/terminology.md +135 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Data Access Events
|
|
2
|
+
|
|
3
|
+
**Specification version: 0.1 · Status: Experimental**
|
|
4
|
+
|
|
5
|
+
Categories: `data-access`, `data-modification`
|
|
6
|
+
|
|
7
|
+
## 1. Recommended event names
|
|
8
|
+
|
|
9
|
+
### Reading
|
|
10
|
+
|
|
11
|
+
| Name | Operation |
|
|
12
|
+
| ------------------------ | ------------------------------ |
|
|
13
|
+
| `data.record.read` | A record was read individually |
|
|
14
|
+
| `data.record.search` | A search returned records |
|
|
15
|
+
| `data.report.generate` | A report was produced |
|
|
16
|
+
| `data.export.create` | An export was produced |
|
|
17
|
+
| `data.export.download` | An export was retrieved |
|
|
18
|
+
| `document.file.view` | A document was viewed |
|
|
19
|
+
| `document.file.download` | A document was downloaded |
|
|
20
|
+
|
|
21
|
+
### Writing
|
|
22
|
+
|
|
23
|
+
| Name | Operation |
|
|
24
|
+
| --------------------- | ----------------------------- |
|
|
25
|
+
| `data.record.create` | A record was created |
|
|
26
|
+
| `data.record.update` | A record was modified |
|
|
27
|
+
| `data.record.delete` | A record was deleted |
|
|
28
|
+
| `data.record.restore` | A deleted record was restored |
|
|
29
|
+
| `data.import.create` | Data was imported |
|
|
30
|
+
|
|
31
|
+
### Sharing
|
|
32
|
+
|
|
33
|
+
| Name | Operation |
|
|
34
|
+
| ---------------------------- | ---------------------------------------------------- |
|
|
35
|
+
| `document.share.create` | Access was granted to a recipient |
|
|
36
|
+
| `document.share.revoke` | A share was withdrawn |
|
|
37
|
+
| `document.permission.grant` | A permission was granted on a resource |
|
|
38
|
+
| `document.permission.revoke` | A permission was removed |
|
|
39
|
+
| `data.transfer.external` | Data was transmitted outside the operator's boundary |
|
|
40
|
+
|
|
41
|
+
## 2. Not everything is worth auditing
|
|
42
|
+
|
|
43
|
+
Read events are the highest-volume category in most systems and the least useful by default. An audit
|
|
44
|
+
trail that records every list view is expensive, hard to search, and hides the events that matter.
|
|
45
|
+
|
|
46
|
+
Producers SHOULD audit reads where at least one of these holds:
|
|
47
|
+
|
|
48
|
+
- The resource is classified above `internal`.
|
|
49
|
+
- The read crosses a tenant, organization or customer boundary.
|
|
50
|
+
- The actor is privileged, or is acting for someone else.
|
|
51
|
+
- The volume is unusual: an export, a bulk search, a full extract.
|
|
52
|
+
- The data is personal data and the operator has committed to access transparency.
|
|
53
|
+
|
|
54
|
+
Producers SHOULD NOT audit ordinary reads of unclassified data by their owner. That is what
|
|
55
|
+
application logs are for.
|
|
56
|
+
|
|
57
|
+
## 3. Context to populate
|
|
58
|
+
|
|
59
|
+
| Field | Guidance |
|
|
60
|
+
| ------------------------- | ----------------------------------------------------------------- |
|
|
61
|
+
| `resource.classification` | Frequently the reason the event is being recorded at all |
|
|
62
|
+
| `resource.ownerId` | Who the data belongs to, where it differs from the actor |
|
|
63
|
+
| `privacy` | `containsPersonalData`, `dataCategories`, `processing`, `purpose` |
|
|
64
|
+
| `authorization` | The decision that permitted the access |
|
|
65
|
+
| `reason` | For support access and any access to another party's data |
|
|
66
|
+
| `request.route` | The route template, never a resolved URL with a query string |
|
|
67
|
+
| `metadata` | `recordCount`, `exportFormat`, `scope`, `filterName` |
|
|
68
|
+
| `controlCategories` | `data-access-logging`, `external-data-sharing` |
|
|
69
|
+
|
|
70
|
+
## 4. Search and bulk reads
|
|
71
|
+
|
|
72
|
+
A search returns an unknown number of records. Recording each one is usually infeasible and often
|
|
73
|
+
undesirable. Recommended handling:
|
|
74
|
+
|
|
75
|
+
- Record one `data.record.search` event with `resource` set to the collection searched.
|
|
76
|
+
- Record `metadata.recordCount`, and the **name** of the filter applied, not its values.
|
|
77
|
+
- MUST NOT record the query string or the search terms. Search terms routinely contain personal data
|
|
78
|
+
and are among the most sensitive values a system holds. See
|
|
79
|
+
[privacy.md](../specification/privacy.md).
|
|
80
|
+
|
|
81
|
+
## 5. External sharing
|
|
82
|
+
|
|
83
|
+
Sharing outside the operator's boundary is a distinct control, and SHOULD be recorded as such:
|
|
84
|
+
|
|
85
|
+
- Include `external-data-sharing` in `controlCategories`.
|
|
86
|
+
- Record the recipient **type** and **domain**, not the recipient's address, unless the audit purpose
|
|
87
|
+
specifically requires identifying the individual.
|
|
88
|
+
- Record share constraints — expiry, password protection, watermarking, download permission — in
|
|
89
|
+
`metadata`, because they are what a reviewer assesses.
|
|
90
|
+
- Emit a matching `document.share.revoke` when the share ends, so that the trail shows exposure
|
|
91
|
+
windows rather than only their beginning.
|
|
92
|
+
|
|
93
|
+
See [examples/valid/document-external-share.json](../examples/valid/document-external-share.json).
|
|
94
|
+
|
|
95
|
+
## 6. Exports
|
|
96
|
+
|
|
97
|
+
Exports concentrate risk: one operation moves a large volume of data out of the controlled system.
|
|
98
|
+
|
|
99
|
+
- `data.export.create` records production of the export; `data.export.download` records retrieval.
|
|
100
|
+
Both are worth recording, because they can be separated by days and performed by different
|
|
101
|
+
principals.
|
|
102
|
+
- Record `metadata.recordCount` and `metadata.exportFormat`.
|
|
103
|
+
- Record `privacy` fully. An export is the event most likely to be reviewed under a data protection
|
|
104
|
+
question.
|
|
105
|
+
- Where the export is produced by a service for a user, record the `subject` and `delegation`. See
|
|
106
|
+
[examples/valid/service-account-data-export.json](../examples/valid/service-account-data-export.json).
|
|
107
|
+
|
|
108
|
+
## 7. Modification
|
|
109
|
+
|
|
110
|
+
For data modification, `change` carries the substance. Prefer `changedFields` over values; see
|
|
111
|
+
[change-model.md](../specification/change-model.md).
|
|
112
|
+
|
|
113
|
+
`data-modification` is the category for business data. Changes to application or platform settings
|
|
114
|
+
belong in `configuration`; see
|
|
115
|
+
[configuration-and-change.md](configuration-and-change.md).
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Event Naming
|
|
2
|
+
|
|
3
|
+
**Specification version: 0.1 · Status: Experimental**
|
|
4
|
+
|
|
5
|
+
The normative naming rules are in [event-model.md](../specification/event-model.md) §7. This document
|
|
6
|
+
gives the recommended vocabularies and the reasoning behind them.
|
|
7
|
+
|
|
8
|
+
## 1. The shape
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
domain.resource.action
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Segment | Answers | Examples |
|
|
15
|
+
| ---------- | ------------------------- | ---------------------------------------- |
|
|
16
|
+
| `domain` | Which area of the system? | `authentication`, `identity`, `document` |
|
|
17
|
+
| `resource` | Which kind of thing? | `role`, `share`, `case`, `setting` |
|
|
18
|
+
| `action` | What was done to it? | `assign`, `create`, `close`, `update` |
|
|
19
|
+
|
|
20
|
+
Two segments are permitted where a resource segment would be artificial:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
authentication.login
|
|
24
|
+
authentication.logout
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Action segments may be hyphenated where the action is genuinely two words:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
queue.consumer.offset-reset
|
|
31
|
+
identity.credential.self-service-reset
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 2. Recommended categories
|
|
35
|
+
|
|
36
|
+
`event.category` groups names for filtering and routing. It is an open vocabulary; these values cover
|
|
37
|
+
the domains this model targets:
|
|
38
|
+
|
|
39
|
+
| Category | Covers |
|
|
40
|
+
| ---------------------- | -------------------------------------------------------- |
|
|
41
|
+
| `authentication` | Proving identity, sessions, factors, credentials |
|
|
42
|
+
| `identity` | Accounts, roles, permissions, service accounts |
|
|
43
|
+
| `data-access` | Reading, exporting, sharing, downloading |
|
|
44
|
+
| `data-modification` | Creating, updating, deleting business data |
|
|
45
|
+
| `configuration` | Application and platform settings, secrets |
|
|
46
|
+
| `deployment` | Releases, rollouts, rollbacks |
|
|
47
|
+
| `workflow` | Requests, approvals, case and incident lifecycle |
|
|
48
|
+
| `privileged-operation` | Administrative and break-glass operations |
|
|
49
|
+
| `data-infrastructure` | Brokers, topics, queues, caches, database administration |
|
|
50
|
+
| `security` | Security-relevant events that fit no other category |
|
|
51
|
+
| `resource-lifecycle` | Provisioning and decommissioning of resources |
|
|
52
|
+
|
|
53
|
+
A category is a coarse label. When an event fits two, choose the one a reviewer would filter on.
|
|
54
|
+
|
|
55
|
+
## 3. Recommended activity types
|
|
56
|
+
|
|
57
|
+
`event.type` is an OPTIONAL, domain-independent classifier. It exists so that a consumer can ask
|
|
58
|
+
"show me every deletion" without knowing every domain's vocabulary.
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
create read update delete execute
|
|
62
|
+
approve reject share grant revoke
|
|
63
|
+
login logout export import rotate
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`event.type` never replaces `event.name`. `identity.role.revoke` and `document.permission.revoke` are
|
|
67
|
+
different operations that share `type: revoke`.
|
|
68
|
+
|
|
69
|
+
## 4. Rules, restated
|
|
70
|
+
|
|
71
|
+
1. **Stable.** A published name keeps its meaning. If the meaning changes, the name changes.
|
|
72
|
+
2. **No product names.** `document.share.create`, not `sharepointish.share.create`.
|
|
73
|
+
3. **No company names.** The audit trail outlives the vendor relationship.
|
|
74
|
+
4. **No jurisdiction names.** `data.export.create`, not `data.export.create-eu`.
|
|
75
|
+
5. **Describe the operation, not the mechanism.** `identity.role.assign` is right whether the role was
|
|
76
|
+
assigned through a console, an API, a sync job or a script. Names that encode the mechanism
|
|
77
|
+
fragment the trail and break when the mechanism changes.
|
|
78
|
+
6. **Same name for success and failure.** Use `outcome`, not a different name.
|
|
79
|
+
|
|
80
|
+
## 5. The failure-name anti-pattern
|
|
81
|
+
|
|
82
|
+
This is the most common naming mistake, and it is worth stating twice:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
authentication.login outcome: success ← RECOMMENDED
|
|
86
|
+
authentication.login outcome: failure ← RECOMMENDED
|
|
87
|
+
|
|
88
|
+
authentication.login-success ← NOT RECOMMENDED
|
|
89
|
+
authentication.login-failed ← NOT RECOMMENDED
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Encoding the outcome in the name doubles the vocabulary, makes "how often does this operation fail?"
|
|
93
|
+
a string-matching problem, and guarantees that some operations get a failure name and others do not.
|
|
94
|
+
|
|
95
|
+
## 6. Granularity
|
|
96
|
+
|
|
97
|
+
Prefer the granularity a reviewer would ask about.
|
|
98
|
+
|
|
99
|
+
| Too coarse | Too fine | Recommended |
|
|
100
|
+
| --------------------- | ----------------------------------------------- | ------------------------------ |
|
|
101
|
+
| `document.update` | `document.metadata.title.update` | `document.version.create` |
|
|
102
|
+
| `identity.change` | `identity.role.assign.via-bulk-import` | `identity.role.assign` |
|
|
103
|
+
| `configuration.write` | `configuration.setting.session-lifetime.update` | `configuration.setting.update` |
|
|
104
|
+
|
|
105
|
+
Detail that varies per operation belongs in `resource`, `change.changedFields` and `metadata`, not in
|
|
106
|
+
the name. A name is a category; a category with one member is not a category.
|
|
107
|
+
|
|
108
|
+
## 7. Naming new events
|
|
109
|
+
|
|
110
|
+
1. Find the closest existing convention document and follow its pattern.
|
|
111
|
+
2. Use the resource type you already use in `resource.type` as the resource segment where possible.
|
|
112
|
+
3. Use a verb in the imperative for the action: `assign`, not `assigned` or `assignment`.
|
|
113
|
+
4. Check the name does not encode outcome, mechanism, product, company or jurisdiction.
|
|
114
|
+
5. Check that a reviewer who has never seen your system can guess what it means.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Identity and Access Events
|
|
2
|
+
|
|
3
|
+
**Specification version: 0.1 · Status: Experimental**
|
|
4
|
+
|
|
5
|
+
Category: `identity`
|
|
6
|
+
|
|
7
|
+
## 1. Recommended event names
|
|
8
|
+
|
|
9
|
+
### Accounts
|
|
10
|
+
|
|
11
|
+
| Name | Operation |
|
|
12
|
+
| ----------------------- | --------------------------------- |
|
|
13
|
+
| `identity.user.create` | An account was created |
|
|
14
|
+
| `identity.user.update` | Account attributes changed |
|
|
15
|
+
| `identity.user.disable` | An account was disabled |
|
|
16
|
+
| `identity.user.enable` | A disabled account was re-enabled |
|
|
17
|
+
| `identity.user.delete` | An account was deleted |
|
|
18
|
+
|
|
19
|
+
### Roles and permissions
|
|
20
|
+
|
|
21
|
+
| Name | Operation |
|
|
22
|
+
| ------------------------------ | ----------------------------------- |
|
|
23
|
+
| `identity.role.create` | A role was defined |
|
|
24
|
+
| `identity.role.update` | A role definition changed |
|
|
25
|
+
| `identity.role.delete` | A role was removed |
|
|
26
|
+
| `identity.role.assign` | A role was granted to a principal |
|
|
27
|
+
| `identity.role.revoke` | A role was removed from a principal |
|
|
28
|
+
| `identity.permission.grant` | A permission was granted directly |
|
|
29
|
+
| `identity.permission.revoke` | A permission was removed |
|
|
30
|
+
| `identity.group.member-add` | A principal joined a group |
|
|
31
|
+
| `identity.group.member-remove` | A principal left a group |
|
|
32
|
+
|
|
33
|
+
### Machine identities and sessions
|
|
34
|
+
|
|
35
|
+
| Name | Operation |
|
|
36
|
+
| ---------------------------------- | -------------------------------------- |
|
|
37
|
+
| `identity.service-account.create` | A machine identity was created |
|
|
38
|
+
| `identity.service-account.disable` | A machine identity was disabled |
|
|
39
|
+
| `identity.credential.rotate` | A machine credential was replaced |
|
|
40
|
+
| `identity.session.impersonate` | A principal began acting as another |
|
|
41
|
+
| `identity.delegation.grant` | Authority was delegated to a principal |
|
|
42
|
+
| `identity.delegation.revoke` | A delegation was withdrawn |
|
|
43
|
+
|
|
44
|
+
## 2. Which principal goes where
|
|
45
|
+
|
|
46
|
+
This is the most error-prone area in the whole model.
|
|
47
|
+
|
|
48
|
+
| Operation | `actor` | `resource` | `subject` |
|
|
49
|
+
| ------------------------------------------ | ----------------- | ---------------------- | --------- |
|
|
50
|
+
| Administrator assigns a role to a user | the administrator | the **user** | absent |
|
|
51
|
+
| User accepts an invitation | the user | the user's own account | absent |
|
|
52
|
+
| Service provisions an account from HR data | the service | the new account | absent |
|
|
53
|
+
| Administrator impersonates a user | the administrator | the session | the user |
|
|
54
|
+
| Delegated administrator acts for an owner | the delegate | the affected resource | the owner |
|
|
55
|
+
|
|
56
|
+
The target of an identity operation is a `resource`, not a `subject`. `subject` appears only when
|
|
57
|
+
someone's authority was borrowed. See [actor-model.md](../specification/actor-model.md).
|
|
58
|
+
|
|
59
|
+
The role or permission being granted is a **related resource** or `metadata`, not the primary
|
|
60
|
+
resource — the primary resource is what changed, and what changed is the principal's access.
|
|
61
|
+
|
|
62
|
+
## 3. Context to populate
|
|
63
|
+
|
|
64
|
+
| Field | Guidance |
|
|
65
|
+
| ------------------- | ----------------------------------------------------------------------- |
|
|
66
|
+
| `relatedResources` | The role, permission, group or scope involved |
|
|
67
|
+
| `change` | `changedFields`, and before/after where the values are safe to record |
|
|
68
|
+
| `authorization` | The decision that permitted the change |
|
|
69
|
+
| `approval` | Where access requires approval, including `not-required` when evaluated |
|
|
70
|
+
| `reason` | The access request or ticket that justifies the grant |
|
|
71
|
+
| `metadata` | `assignedRole`, `assignmentScope`, `effectiveFrom`, `expiresAt` |
|
|
72
|
+
| `controlCategories` | `privileged-access`, `separation-of-duties`, `change-approval` |
|
|
73
|
+
|
|
74
|
+
## 4. Privileged grants
|
|
75
|
+
|
|
76
|
+
An event that grants administrative access SHOULD:
|
|
77
|
+
|
|
78
|
+
- Set `event.severity` to `high` or `critical`.
|
|
79
|
+
- Include `privileged-access` in `controlCategories`.
|
|
80
|
+
- Populate `approval` where the operator requires approval for privileged grants.
|
|
81
|
+
- Record `metadata.expiresAt` for time-bound grants, so that a reviewer can distinguish standing
|
|
82
|
+
privilege from just-in-time access.
|
|
83
|
+
|
|
84
|
+
## 5. Effective time
|
|
85
|
+
|
|
86
|
+
Access changes are often scheduled. `time` is when the **change was recorded**, not when it takes
|
|
87
|
+
effect. Where they differ, record the effective window in `metadata`:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"metadata": {
|
|
92
|
+
"assignedRole": "support-agent",
|
|
93
|
+
"effectiveFrom": "2026-03-16T00:00:00Z",
|
|
94
|
+
"expiresAt": "2026-06-16T00:00:00Z"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
A separate event SHOULD be emitted when a time-bound grant actually expires, so that the trail shows
|
|
100
|
+
the access ending rather than only the intention that it would.
|
|
101
|
+
|
|
102
|
+
## 6. Bulk changes
|
|
103
|
+
|
|
104
|
+
Access changes are frequently bulk operations. Producers SHOULD emit one event per affected principal
|
|
105
|
+
where the principals are individually significant — which, for access, they usually are. Where a bulk
|
|
106
|
+
operation is recorded as one event, the count and scope MUST be recorded in `metadata`, and the
|
|
107
|
+
producer MUST document the choice. See [resource-model.md](../specification/resource-model.md) §6.
|
|
108
|
+
|
|
109
|
+
## 7. Example
|
|
110
|
+
|
|
111
|
+
See [examples/valid/user-role-assignment.json](../examples/valid/user-role-assignment.json) for a
|
|
112
|
+
complete role assignment with authorization, approval, reason and change context.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Privileged Operations
|
|
2
|
+
|
|
3
|
+
**Specification version: 0.1 · Status: Experimental**
|
|
4
|
+
|
|
5
|
+
Category: `privileged-operation`
|
|
6
|
+
|
|
7
|
+
## 1. What counts as privileged
|
|
8
|
+
|
|
9
|
+
An operation is privileged when it can affect data or controls beyond the actor's ordinary scope.
|
|
10
|
+
Concretely, when at least one of these holds:
|
|
11
|
+
|
|
12
|
+
- It uses administrative authority rather than the actor's own entitlements.
|
|
13
|
+
- It bypasses or disables a control.
|
|
14
|
+
- It reaches across a tenant, customer or organization boundary.
|
|
15
|
+
- It acts on another principal's data or identity.
|
|
16
|
+
- It changes security-relevant configuration.
|
|
17
|
+
- It operates directly on infrastructure rather than through the application.
|
|
18
|
+
|
|
19
|
+
Privilege is a property of **the operation**, not of the account. The same account performs ordinary
|
|
20
|
+
and privileged operations, and the audit trail should distinguish them.
|
|
21
|
+
|
|
22
|
+
## 2. Recommended event names
|
|
23
|
+
|
|
24
|
+
| Name | Operation |
|
|
25
|
+
| ----------------------------------- | --------------------------------------------------- |
|
|
26
|
+
| `identity.session.impersonate` | A principal began acting as another |
|
|
27
|
+
| `privileged.access.request` | Elevated access was requested |
|
|
28
|
+
| `privileged.access.grant` | Elevated access was granted |
|
|
29
|
+
| `privileged.access.revoke` | Elevated access was withdrawn |
|
|
30
|
+
| `privileged.break-glass.activate` | An emergency access path was used |
|
|
31
|
+
| `privileged.break-glass.close` | An emergency access episode was closed |
|
|
32
|
+
| `privileged.control.disable` | A control was switched off |
|
|
33
|
+
| `privileged.control.enable` | A control was switched back on |
|
|
34
|
+
| `privileged.database.query-execute` | A direct data store query was run |
|
|
35
|
+
| `privileged.maintenance.execute` | A maintenance operation was performed on production |
|
|
36
|
+
|
|
37
|
+
Domain-specific privileged operations keep their domain name and are marked privileged through
|
|
38
|
+
`controlCategories` and `severity`, rather than being renamed. `configuration.setting.update` on
|
|
39
|
+
production security configuration is a privileged operation with the name it already has.
|
|
40
|
+
|
|
41
|
+
## 3. Required signals
|
|
42
|
+
|
|
43
|
+
For an operation the producer considers privileged, it SHOULD:
|
|
44
|
+
|
|
45
|
+
1. Set `event.severity` to `high` or `critical`.
|
|
46
|
+
2. Include `privileged-access` in `controlCategories`.
|
|
47
|
+
3. Populate `authorization` with the decision that permitted it.
|
|
48
|
+
4. Populate `reason` with a business justification.
|
|
49
|
+
5. Populate `approval` where the operator requires approval, including `not-required` when that was
|
|
50
|
+
evaluated.
|
|
51
|
+
6. Populate `authentication`, including `mfa`, where the operator requires re-authentication for
|
|
52
|
+
privileged actions.
|
|
53
|
+
7. Populate `subject` and `delegation` where the operation was performed for someone else.
|
|
54
|
+
|
|
55
|
+
The value of a privileged-operation trail is that a reviewer can answer "was this justified?" without
|
|
56
|
+
asking the person who did it. An event with none of the fields above cannot answer that.
|
|
57
|
+
|
|
58
|
+
## 4. Break-glass access
|
|
59
|
+
|
|
60
|
+
Emergency access exists because controls sometimes have to be bypassed. The audit trail is what makes
|
|
61
|
+
that acceptable.
|
|
62
|
+
|
|
63
|
+
Producers SHOULD:
|
|
64
|
+
|
|
65
|
+
- Emit `privileged.break-glass.activate` at the start and `privileged.break-glass.close` at the end,
|
|
66
|
+
so the episode has a duration rather than a single moment.
|
|
67
|
+
- Share one `request.correlationId` across every operation performed during the episode, so the
|
|
68
|
+
entire episode can be reviewed as a unit.
|
|
69
|
+
- Record `reason` with a real justification, and `reason.reference` pointing at the incident.
|
|
70
|
+
- Set `event.severity` to `critical`.
|
|
71
|
+
- Record `approval` even when it was retrospective, using `approvedAt` to make the sequence visible.
|
|
72
|
+
|
|
73
|
+
## 5. Direct data store access
|
|
74
|
+
|
|
75
|
+
Running queries directly against a production data store bypasses every application-level control,
|
|
76
|
+
including the application's own audit trail.
|
|
77
|
+
|
|
78
|
+
Producers that support it SHOULD record:
|
|
79
|
+
|
|
80
|
+
- The store as `resource`, and the affected tables or collections in `relatedResources` where known.
|
|
81
|
+
- `metadata.statementType` — `select`, `update`, `delete` — and `metadata.affectedRowCount`.
|
|
82
|
+
- `metadata.queryHash` where a query needs to be identifiable across events.
|
|
83
|
+
|
|
84
|
+
Producers MUST NOT record query text or parameters automatically. Both routinely contain personal
|
|
85
|
+
data, and parameters in particular are the values of the very records being accessed. See
|
|
86
|
+
[privacy.md](../specification/privacy.md) §2.
|
|
87
|
+
|
|
88
|
+
## 6. Message broker and infrastructure operations
|
|
89
|
+
|
|
90
|
+
Operations on brokers, queues and caches are administrative operations on data-carrying
|
|
91
|
+
infrastructure, and are privileged when performed against production.
|
|
92
|
+
|
|
93
|
+
- Use the broker family as the domain segment: `kafka.consumer.offset-reset`,
|
|
94
|
+
`rabbitmq.queue.purge`, `redis.key.delete`.
|
|
95
|
+
- Record the affected topic, queue or key space in `relatedResources`.
|
|
96
|
+
- Record offsets, partitions and counts in `metadata`.
|
|
97
|
+
- MUST NOT record message payloads. See
|
|
98
|
+
[profiles/message-broker-management/](../profiles/message-broker-management/).
|
|
99
|
+
|
|
100
|
+
See
|
|
101
|
+
[examples/valid/kafka-consumer-offset-reset.json](../examples/valid/kafka-consumer-offset-reset.json).
|
|
102
|
+
|
|
103
|
+
## 7. Control changes
|
|
104
|
+
|
|
105
|
+
Disabling a control is the operation most worth auditing and the one most likely to go unaudited,
|
|
106
|
+
because it is often performed on the system that does the auditing.
|
|
107
|
+
|
|
108
|
+
Producers SHOULD emit `privileged.control.disable` and `privileged.control.enable` as a pair, record
|
|
109
|
+
the control in `resource`, and record the window in `metadata`. A control that was disabled and never
|
|
110
|
+
re-enabled should be visible as an open pair, not inferred from silence.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Workflow and Approval Events
|
|
2
|
+
|
|
3
|
+
**Specification version: 0.1 · Status: Experimental**
|
|
4
|
+
|
|
5
|
+
Category: `workflow`
|
|
6
|
+
|
|
7
|
+
## 1. Recommended event names
|
|
8
|
+
|
|
9
|
+
### Requests and approvals
|
|
10
|
+
|
|
11
|
+
| Name | Operation |
|
|
12
|
+
| ---------------------------- | -------------------------------------------------- |
|
|
13
|
+
| `workflow.request.create` | A request entered a workflow |
|
|
14
|
+
| `workflow.request.submit` | A request was submitted for decision |
|
|
15
|
+
| `workflow.approval.request` | Approval was requested from one or more principals |
|
|
16
|
+
| `workflow.approval.grant` | An approver approved |
|
|
17
|
+
| `workflow.approval.reject` | An approver refused |
|
|
18
|
+
| `workflow.approval.expire` | An approval request lapsed undecided |
|
|
19
|
+
| `workflow.approval.delegate` | Approval authority was passed to another principal |
|
|
20
|
+
| `workflow.stage.advance` | A workflow moved to the next stage |
|
|
21
|
+
| `workflow.request.cancel` | A request was withdrawn |
|
|
22
|
+
| `workflow.request.close` | A request reached a terminal state |
|
|
23
|
+
|
|
24
|
+
### Case and incident lifecycle
|
|
25
|
+
|
|
26
|
+
| Name | Operation |
|
|
27
|
+
| ---------------------------- | ------------------------------------- |
|
|
28
|
+
| `incident.case.create` | An incident was raised |
|
|
29
|
+
| `incident.priority.change` | Priority was reassessed |
|
|
30
|
+
| `incident.assignment.change` | Ownership changed |
|
|
31
|
+
| `incident.major.declare` | An incident was escalated to major |
|
|
32
|
+
| `incident.case.resolve` | An incident was resolved |
|
|
33
|
+
| `incident.case.close` | An incident was closed |
|
|
34
|
+
| `incident.case.reopen` | A closed incident was reopened |
|
|
35
|
+
| `incident.rca.create` | A root cause analysis was recorded |
|
|
36
|
+
| `incident.rca.approve` | A root cause analysis was approved |
|
|
37
|
+
| `incident.sla.breach` | A service level commitment was missed |
|
|
38
|
+
|
|
39
|
+
## 2. The approval object versus approval events
|
|
40
|
+
|
|
41
|
+
Both exist, and they answer different questions.
|
|
42
|
+
|
|
43
|
+
| Question | Where it is answered |
|
|
44
|
+
| ----------------------------------------------- | ------------------------------------- |
|
|
45
|
+
| Was this operation approved? | `approval` on the **operated** event |
|
|
46
|
+
| Who approved what, when, and did anyone refuse? | Separate `workflow.approval.*` events |
|
|
47
|
+
|
|
48
|
+
A configuration change carries `approval` describing the state of its approval. The approval decisions
|
|
49
|
+
themselves — each approver, each timestamp, each rejection — are their own events, because they are
|
|
50
|
+
separate auditable operations performed by different principals at different times.
|
|
51
|
+
|
|
52
|
+
Producers SHOULD emit both. Recording only the summary loses who decided; recording only the decisions
|
|
53
|
+
makes it impossible to tell what they authorized.
|
|
54
|
+
|
|
55
|
+
## 3. Approval status transitions
|
|
56
|
+
|
|
57
|
+
Recommended transitions, and the event that records each:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
not-required (no approval event; recorded on the operated event)
|
|
61
|
+
pending → approved workflow.approval.grant
|
|
62
|
+
pending → rejected workflow.approval.reject
|
|
63
|
+
pending → expired workflow.approval.expire
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
An operated event whose `approval.status` is `pending`, `rejected` or `expired` and whose outcome is
|
|
67
|
+
`success` describes a control bypass. Producers MUST record it accurately.
|
|
68
|
+
|
|
69
|
+
## 4. Context to populate
|
|
70
|
+
|
|
71
|
+
| Field | Guidance |
|
|
72
|
+
| ---------------------------- | ------------------------------------------------------------------ |
|
|
73
|
+
| `resource` | The request, case or workflow instance |
|
|
74
|
+
| `relatedResources` | The resource the workflow governs, and any affected services |
|
|
75
|
+
| `approval.approvers` | Only the principals whose decisions counted |
|
|
76
|
+
| `approval.requiredApprovals` | The policy threshold, so a reviewer can see whether it was met |
|
|
77
|
+
| `change` | Status transitions, as `changedFields` with before and after |
|
|
78
|
+
| `evidence` | The approval record, the analysis document, the ticket |
|
|
79
|
+
| `reason` | Why the decision was made, where a justification is required |
|
|
80
|
+
| `request.correlationId` | Shared across the whole workflow, so its events can be assembled |
|
|
81
|
+
| `controlCategories` | `change-approval`, `separation-of-duties`, `incident-traceability` |
|
|
82
|
+
|
|
83
|
+
## 5. Correlation across a workflow
|
|
84
|
+
|
|
85
|
+
A workflow produces many events over hours or weeks, from different applications and principals. They
|
|
86
|
+
are assembled by correlation, not by timestamp.
|
|
87
|
+
|
|
88
|
+
Producers SHOULD:
|
|
89
|
+
|
|
90
|
+
- Use one `request.correlationId` for the life of the workflow instance.
|
|
91
|
+
- Use the workflow instance identifier consistently in `approval.workflowId`.
|
|
92
|
+
- Reference the same case identifier in `change.incidentId` or `reason.reference`.
|
|
93
|
+
|
|
94
|
+
## 6. Separation of duties
|
|
95
|
+
|
|
96
|
+
Where policy requires that the approver differ from the requester, the audit trail must make the
|
|
97
|
+
comparison possible. Producers SHOULD:
|
|
98
|
+
|
|
99
|
+
- Record `actor` on the operated event and `approval.approvers` such that both are identifiable.
|
|
100
|
+
- Include `separation-of-duties` in `controlCategories`.
|
|
101
|
+
- Emit the event even when the check **passes**. A control that only produces evidence when it fails
|
|
102
|
+
cannot be shown to have been operating.
|
|
103
|
+
|
|
104
|
+
The model records the facts. It does not evaluate the rule: OpenAuditModel is not a policy engine.
|
|
105
|
+
|
|
106
|
+
## 7. Example
|
|
107
|
+
|
|
108
|
+
See [examples/valid/incident-case-close.json](../examples/valid/incident-case-close.json) for an
|
|
109
|
+
incident closure with approvals, evidence references, status transition and trace correlation.
|