NK-WP-0054: security review; standard draft-3 as a SecurityCanon profile; agent security quickstart
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Review against security-canon (Mode of Authority, SEC-DSM 1.0.0) showed the draft
restated canon rules and invented a parallel taxonomy. Draft-3 imports principal_type
and MODE @ SCOPE grants, treats break-glass as an activation, cites SEC-DSM per rule,
states the estate identities in canon terms and adds SI-15 (accountable automation:
prepare, admit, execute, verify, retain). Founder decisions and rule ids are kept.

For agents: tools/security-tools.json and make security-tools list each security tool,
the question it answers and whether an agent may run it; a test keeps the index
complete. AGENTS.md and CLAUDE.md carry the same quickstart block. Validator migration
to grants is T03b. Review record in history/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 328925@bnt-lap001
Assistant-Session: 14b795fd-c632-4c01-8d28-e7e490c7b0ed
This commit is contained in:
tegwick 2026-10-24 23:12:37 +02:00
parent a3bab9210b
commit b7749277fd
10 changed files with 492 additions and 206 deletions

View file

@ -283,3 +283,20 @@ do not silently download or execute a replacement.
This pilot adds situational knowledge, not authority, live readiness or a change
to this repository's owner contracts. Work: `emergent-security/EMERGENT-WP-0002`.
<!-- END EMERGENT-SECURITY-PILOT -->
<!-- BEGIN NETKINGDOM-SECURITY-QUICKSTART -->
## Security quickstart for agents (Claude Code, Codex, Grok)
1. **Find the tool:** `make security-tools` lists every security tool, the question it answers, how to run
it and whether an agent may run it (`tools/security-tools.json` is the machine-readable form).
Tool availability is not permission.
2. **Know the rules:** `SECURITY-COMPANION.md` section 7 ("If you are an agent").
3. **Credentials:** `warden route find "<need>" --json`. Never ask for, print or store a secret value.
4. **Accounts and accountable automation:** `canon/standards/service-identity-privilege_v0.1.md`, rules
SI-14 (agents) and SI-15 (prepare, admit, execute, verify, retain).
5. **Your effective authority is everything your tools can reach** (SEC-DSM DSM-AGENT-008). Live changes,
private keys and production credentials belong to the person: prepare and test on synthetic fixtures,
and give them the exact command to run.
6. **Leave a trail:** commits get assistant trailers from the hook; log State Hub progress with your agent
name and session.
<!-- END NETKINGDOM-SECURITY-QUICKSTART -->

View file

@ -32,3 +32,20 @@ do not silently download or execute a replacement.
This pilot adds situational knowledge, not authority, live readiness or a change
to this repository's owner contracts. Work: `emergent-security/EMERGENT-WP-0002`.
<!-- END EMERGENT-SECURITY-PILOT -->
<!-- BEGIN NETKINGDOM-SECURITY-QUICKSTART -->
## Security quickstart for agents (Claude Code, Codex, Grok)
1. **Find the tool:** `make security-tools` lists every security tool, the question it answers, how to run
it and whether an agent may run it (`tools/security-tools.json` is the machine-readable form).
Tool availability is not permission.
2. **Know the rules:** `SECURITY-COMPANION.md` section 7 ("If you are an agent").
3. **Credentials:** `warden route find "<need>" --json`. Never ask for, print or store a secret value.
4. **Accounts and accountable automation:** `canon/standards/service-identity-privilege_v0.1.md`, rules
SI-14 (agents) and SI-15 (prepare, admit, execute, verify, retain).
5. **Your effective authority is everything your tools can reach** (SEC-DSM DSM-AGENT-008). Live changes,
private keys and production credentials belong to the person: prepare and test on synthetic fixtures,
and give them the exact command to run.
6. **Leave a trail:** commits get assistant trailers from the hook; log State Hub progress with your agent
name and session.
<!-- END NETKINGDOM-SECURITY-QUICKSTART -->

View file

@ -203,6 +203,9 @@ service-identity-test: ## Run service-identity schema/validator tests (NK-WP-005
service-identity-check: ## Evaluate the checked-in service identity declarations (read-only, offline)
python3 tools/service-identity/validate.py tools/service-identity/declarations/*.yaml
security-tools: ## List the security tools, what each answers, and whether an agent may run it
python3 tools/security_tools.py
posture-feedback-reference: ## Emit the proposal-only reference report at its fixed example time
python3 tools/posture-feedback/posture_feedback.py \
--as-of 2026-08-23T12:00:00Z \
@ -371,7 +374,7 @@ security-bootstrap-ui: security-bootstrap-metadata-init ## Serve local custody a
creds-agent-init creds-agent-status creds-emergency-reprint \
openbao-init-unseal openbao-init-unseal-dry-run \
iam-profile-conformance-test playbook-contract-test posture-feedback-test \
custody-record-test service-identity-test service-identity-check \
custody-record-test service-identity-test service-identity-check security-tools \
emission-cadence-profile-test \
posture-feedback-reference security-scenario-compose-lightweight \
security-bootstrap-console-test security-bootstrap-scripts-syntax \

View file

@ -311,6 +311,7 @@
| task | NK-WP-0054-T01 | done | — | workplans/NK-WP-0054-service-identity-policy.md |
| task | NK-WP-0054-T02 | wait | — | workplans/NK-WP-0054-service-identity-policy.md |
| task | NK-WP-0054-T03 | done | — | workplans/NK-WP-0054-service-identity-policy.md |
| task | NK-WP-0054-T03b | todo | — | workplans/NK-WP-0054-service-identity-policy.md |
| task | NK-WP-0054-T04 | wait | — | workplans/NK-WP-0054-service-identity-policy.md |
| task | NK-WP-0054-T05 | wait | — | workplans/NK-WP-0054-service-identity-policy.md |
| task | NK-WP-0054-T06 | wait | — | workplans/NK-WP-0054-service-identity-policy.md |

View file

@ -8,16 +8,19 @@ version: "0.1"
created: "2026-10-24"
updated: "2026-10-24"
scope: service-account-governance
revision: "draft-2"
revision: "draft-3"
owner: net-kingdom
last_reviewed: "2026-10-24"
review_interval: 3m
standard_token: service-identity-privilege_v0.1
profiles:
- security-canon/infospace/standards/devops-secrets-management/SecurityCanonDevOpsSecretsManagementStandard.md
- security-canon/infospace/vocabulary/mode-of-authority/SecurityCanonModeOfAuthority.md
related:
- SECURITY-COMPANION.md
- canon/standards/iam-profile_v0.3.md
- canon/standards/credential-management_v0.2.md
- canon/standards/tenancy-posture_v0.1.md
- canon/standards/security-zones_v0.1.md
- canon/standards/posture-feedback_v0.1.md
- docs/service-identity-inventory.md
- docs/crisis-custody-list.md
@ -27,251 +30,264 @@ related:
## 0. Status
**Proposed, draft-2.** It binds nothing until the founder ratifies it and each owner adopts it.
It was started on 2026-10-24 from the founder's direction and from the first inventory
(`docs/service-identity-inventory.md`, NK-WP-0054-T01).
**Proposed, draft-3.** It binds nothing until the founder ratifies it and each owner adopts it.
- **draft-1** (2026-10-24): thirteen rules, naming, five initial exceptions, seven open questions.
- **draft-2** (2026-10-24): the founder's review answered four questions and two clarifications (§10). Added the `agent` class and
SI-14; SI-8 now requires the assurance claim for admin-policy roles; the human administrator keeps
directory admin rights through group membership; declarations start in this repository and move to each
service. Building the offline validator (NK-WP-0054-T03) also made custody a list and broadened SI-X1.
- **draft-2** (2026-10-24): the founder's review decided six points (§10), added the agent class and SI-14.
- **draft-3** (2026-10-24): realigned as NetKingdom's **estate profile of SecurityCanon**, after a comparison
with the canon showed that drafts 1 and 2 restated SEC-DSM rules and invented a taxonomy beside the canon's.
Classes are replaced by the imported `principal_type` and **authority grants** written `MODE @ SCOPE` with
the canon's dimensions. Break-glass is an *activation*, not a kind of identity. Every rule now names the SEC-DSM
rules it profiles and states only what NetKingdom adds. New: the estate identities in canon terms (§3) and
SI-15, accountable automation. All founder decisions and every rule id from draft-2 are kept.
The offline validator exists (`tools/service-identity`, provisional). The live health check (T04) does not.
The offline validator (`tools/service-identity`) still implements the draft-2 field model. Its migration to
grants is NK-WP-0054-T03b. The live health check (T04) does not exist yet.
The finding behind it: one LLDAP account, `uid=admin`, is at the same time the human platform
administrator, the directory super-admin and the bind credential of Authelia, KeyCape, the
privacyIDEA resolver and the identity-provisioner. One account has one password, so the human
login, four services and every backup bundle share one secret. The Credential Management
Standard §6 already calls rotating it "3-way coordinated"; the inventory found five consumers.
## 1. Purpose, scope and authority
## 1. Purpose and scope
This standard says which accounts, with which authority, may exist inside the services that make up
NetKingdom, and how that is declared and checked.
This standard says which identities, and which privileges, may exist inside the services that
are part of NetKingdom. It governs the **accounts** in a service's own store, directory or
policy engine. It does not replace:
It is a **profile**, not a second rulebook. Per SecurityCanon SEC-ADR-001, the identity model belongs to
InfoTechCanon and security concept definitions to SecurityCanon; NetKingdom holds the security architecture and
standards of record for the estate. So this standard:
- the **token profile**: human, service and agent principals in tokens belong to
[IAM Profile v0.3](iam-profile_v0.3.md);
- **credential storage and rotation procedure**: [Credential Management v0.2](credential-management_v0.2.md);
- **tenant isolation**: [Tenancy Posture](tenancy-posture_v0.1.md) and
[Security Zones](security-zones_v0.1.md).
- **imports** the vocabulary: `principal_type` (InfoTechCanon, via SecurityCanon) and the Mode of Authority
grant notation with its dimensions (SecurityCanon, draft 0.2.0);
- **profiles** the DevOps Secrets Management Standard (`SEC-DSM` 1.0.0): it names the rules that apply to
NetKingdom accounts and, where NetKingdom is stricter, says so;
- **adds** only what is estate-specific: which identities exist, their names, the declarations, the link to
crisis custody, and how conformance is checked.
In scope: LLDAP, Authelia, KeyCape, privacyIDEA, the identity-provisioner, user-engine and
tenant-engine at their boundary, OpenBao authentication roles and policies, and the platform
consumers of these services. Out of scope: accounts that a tenant creates inside its own
workloads, except where they cross into a NetKingdom service.
Out of scope: tokens (IAM Profile v0.3), custody procedure (Credential Management v0.2), tenant isolation
(Tenancy Posture, Security Zones), and accounts a tenant creates inside its own workloads.
## 2. Vocabulary
## 2. Vocabulary (imported)
An **identity** is any account, role, client or principal held in a service's own store. A
**credential** is what proves an identity. A **consumer** is a person or system that presents
the credential. Every identity has exactly one **class**.
**Principal type** (`principal_type`): `HUMAN`, `WORKLOAD`, `SERVICE`, `AGENT`, `CONTROLLER`, `DEVICE`. IAM
Profile v0.3 carries the same distinction in tokens in lower case.
| Class | Meaning | Examples today |
**Authority grant:** `MODE @ SCOPE`, where the mode is one of `USE`, `OBSERVE`, `OPERATE`, `ADMINISTER`,
`GOVERN`, `CONSTRUCT`, `SOVEREIGN`. A grant may state `activation` (`STANDING`, `JUST_IN_TIME`, `SCHEDULED`,
`APPROVED`, `INCIDENT`, `BREAK_GLASS`, `RECOVERY`), `provenance`, `environment` (`DEVELOPMENT`, `TEST`,
`STAGING`, `PRODUCTION`, `RECOVERY`), `evidence` and `relation` (`DELEGATED`, `IMPERSONATED`). Modes classify the
*kind* of authority, not its amount.
**Account** (NetKingdom term): an identity held in a service's own store, with or without a stored credential.
**Credential** and **standing authority** are used as in SEC-DSM §4.
Estate conventions, which are names for recurring grant shapes and not new canon terms:
| Convention | Canon expression |
| --- | --- |
| Bind account `svc-<service>` | a `SERVICE` principal with `USE @ directory`, read-only operations, one consumer |
| Service-admin account `<short>-admin` | an account held by a `HUMAN`, `ADMINISTER @ <that service>` |
| Break-glass | any grant with `activation = BREAK_GLASS` |
| Agent | an `AGENT` principal with `relation = DELEGATED` and the person it acts for as authority context |
Draft-2's classes map as follows: `human` → `HUMAN`; `break-glass` → `activation = BREAK_GLASS`; `bind` and
`infrastructure` → `SERVICE` with the matching grant; `service-admin` → the convention above; `workload` →
`WORKLOAD` or `SERVICE`; `agent` → `AGENT`.
## 3. The estate identities
The founder's model, written in canon terms. This is what the declarations must express.
| Account | Principal | Grants | Activation | Environment |
| --- | --- | --- | --- | --- |
| `platform-root` | `HUMAN` | `SOVEREIGN @ platform`; `CONSTRUCT @ platform` (build mode) | `BREAK_GLASS` in production; standing only outside it | `RECOVERY`; `DEVELOPMENT` and `TEST` for build mode, never `PRODUCTION` |
| `admin` | `HUMAN` | `OPERATE @ platform`; `OPERATE @ backup-system`; `ADMINISTER @ directory` through an admin group | `STANDING` | `PRODUCTION` |
| `tegwick` | `HUMAN` | `CONSTRUCT @ product` | `STANDING` | `DEVELOPMENT`, `TEST` |
| `ld-admin` | account held by a `HUMAN` | `ADMINISTER @ lldap` | `BREAK_GLASS` (sealed fallback) | `PRODUCTION` |
| `pi-admin` | account held by a `HUMAN` | `ADMINISTER @ privacyidea` | `STANDING` (exception SI-X5: only a local admin exists) | `PRODUCTION` |
| `svc-authelia`, `svc-keycape`, `svc-privacyidea` | `SERVICE` | `USE @ directory`, read-only | `STANDING` | `PRODUCTION` |
| provisioner account | `SERVICE` | `ADMINISTER @ directory/people,groups`, narrowest working scope | `STANDING` | `PRODUCTION` |
| Claude Code, Codex, Grok sessions | `AGENT` | what the tools they can reach allow (SI-14) | per task | that of the person they act for |
`backup operator → OPERATE @ backup-system` and `developer → CONSTRUCT @ product` are the canon's own
translations, and match the founder's intent that `admin` operates backups and `tegwick` builds.
## 4. Rules
Each rule keeps its draft-2 id. **Profiles** names the SEC-DSM rules it applies; **NetKingdom adds** states
what is stricter or estate-specific. Where nothing is added, the SEC-DSM rule governs as written.
**SI-1 One account, one principal type, one purpose.** Profiles DSM-ID-004, DSM-AP-003. NetKingdom adds: an
account presented by a `HUMAN` and by a `SERVICE` is non-conformant, whatever its privileges.
**SI-2 People and services never share a credential.** Profiles DSM-ID-004 (MUST). NetKingdom adds: a human's
password MUST NOT be stored where a service reads it, including a Kubernetes Secret.
**SI-3 Bind accounts.** Profiles DSM-ID-001 and DSM-AUTH-001. NetKingdom adds: DSM-ID-001's SHOULD becomes MUST.
Each consuming service has its own bind account with read-only `USE @ directory`, never used interactively. A
service that must write gets its own `SERVICE` account with the narrowest working `ADMINISTER` scope, never the
service-admin account.
**SI-4 One local admin per service.** Profiles DSM-AUTH-001. NetKingdom adds: the account is named
`<short>-admin`, the short form belongs to that one service, and its grant is `ADMINISTER @ that service` only.
**SI-5 Attributed administration first.** Profiles DSM-AUDIT-003 and the reduction of standing authority (SEC-DSM
§4.12). NetKingdom adds: day-to-day administration uses the administrator's own `HUMAN` account through group
membership. The local service-admin account is a sealed fallback listed in the crisis custody list.
**SI-6 Break-glass is an activation.** Profiles DSM-HUM-003, DSM-ROOT-001 to DSM-ROOT-005. NetKingdom adds:
`platform-root` holds `SOVEREIGN @ platform` with `activation = BREAK_GLASS` in production, held offline. It
authorizes and does not operate, and it is never used for routine work, validation or as a drill's test
subject. Its `CONSTRUCT` authority (build mode) is not available in `PRODUCTION`.
**SI-7 The developer identity.** Profiles DSM-AP-012. NetKingdom adds: `tegwick` holds `CONSTRUCT @ product` in
`DEVELOPMENT` and `TEST`, no production credential and no recovery custody item.
**SI-8 Assurance.** NetKingdom rule, with IAM Profile v0.3 assurance claims. Every `HUMAN` account and every
service-admin account requires a second factor where the service can enforce one. A role that grants
`ADMINISTER` or higher MUST bind the assurance claim itself (for example `aal2` in an OpenBao role); relying on an
upstream check needs an exception. Decided 2026-10-24 for OpenBao `platform-admin`.
**SI-9 Every place a credential lives is declared.** Profiles DSM-INV-002, DSM-STORE-002. NetKingdom adds: a
person's password safe MUST NOT hold a `SERVICE`, `WORKLOAD` or `AGENT` credential.
**SI-10 Owner, rotation and coupling.** Profiles DSM-INV-003, DSM-ROT-001, DSM-ROT-003; static binds are governed
residual secrets under DSM-ARCH-002 and DSM-TRANS-002. NetKingdom adds: the coupling (everything that must change
together) is part of the declaration.
**SI-11 Declared or it is a finding.** Profiles DSM-INV-005 to DSM-INV-007. NetKingdom adds: an account that exists
and is not declared is `unknown`; a legacy account has a disposition with owner and date.
**SI-12 Recovery identities are in the crisis custody list.** Profiles DSM-ROOT-001, DSM-ROOT-004. NetKingdom adds:
each recovery item answers "does it work with SSO and OpenBao down?". An account that cannot be used while its
own service is down is never the only recovery path.
**SI-13 Validation is operated by the operator identity.** NetKingdom rule. Restore drills and backup validation
are `OPERATE @ backup-system`, run by `admin` with `admin`'s own token as the test subject, and record which
identity ran each stage.
**SI-14 Agents.** Profiles DSM-AGENT-001 to DSM-AGENT-008, DSM-AP-016, DSM-AP-017 and the companion §7.
NetKingdom adds: an agent presents as `AGENT` with its mode (IAM Profile v0.3); its tokens last at most 60
minutes (3600 seconds; decided 2026-10-24); it is bounded by a named boundary policy; and its **effective
authority includes everything reachable through its tools** (DSM-AGENT-008). An agent running in a person's
terminal therefore holds that person's tool-reachable authority, and declarations say so.
**SI-15 Accountable automation.** Profiles DSM-AUDIT-001, DSM-AUDIT-003, DSM-DX-002 and companion §7.4. Every
state-changing action by an `AGENT` or `WORKLOAD` is reconstructable: actor, on whose authority, run or session,
operation, result and where the evidence is kept. High-impact actions follow the NetKingdom golden path:
1. **Prepare.** The agent writes source-reviewed tooling and tests it on synthetic fixtures. No live effect.
2. **Admit.** A person authorizes the exact action: a signed admission or a recorded decision.
3. **Execute.** The person, or a bounded executor under the admission, runs it, isolated where possible.
4. **Verify.** An independent verifier checks the receipt against the source it names.
5. **Retain.** The receipt is kept by hash, with no secret values.
Evidence available today: commit trailers (`Assistant`, `Assistant-Session`, `Assistant-Process`), safe receipts
with source hashes, signed admissions, and State Hub progress events. Hub authorship is a free-text field that
nothing authenticates; that is a declared gap (§10).
## 5. Naming
| Convention | Pattern | Notes |
| --- | --- | --- |
| `human` | A person's attributable login | `tegwick`, `admin` |
| `break-glass` | Final authority held offline, not routine | `platform-root` (king credential) |
| `bind` | A service's own lookup in another service's directory | planned `svc-authelia` |
| `service-admin` | The administrative account of one service | `pi-admin`, planned `ld-admin` |
| `workload` | A service that obtains tokens or secrets | KeyCape clients, `secrets-engine-openbao` |
| `agent` | Automation that acts autonomously or under delegated authority; IAM Profile v0.3 agent principal | the coding agent |
| `infrastructure` | A role below the application | database role `privacyidea` |
| Bind account | `svc-<service>` | one per consuming service; `svc-<service>-<function>` if one needs several |
| Service-admin account | `<short>-admin` | the short form belongs to one service: `pi-admin` (privacyIDEA), `ld-admin` (LLDAP only) |
| Break-glass | `platform-root` | the king credential |
| Human | the person's own login | `admin`, `tegwick` |
| Workload, service, agent | the token subject form in use | for example `service:secrets-engine`; IAM Profile v0.3 governs the token |
## 3. Rules
Each rule has a stable id so that findings, exceptions and the health check can cite it.
**SI-1 One identity, one class.** An identity MUST have exactly one class. An account that is
both a person and a service is non-conformant.
**SI-2 People and services do not share credentials.** A person MUST NOT use a service
credential, and a service MUST NOT use a person's credential. A human's password MUST NOT be
stored in a Secret that a service reads.
**SI-3 Bind identities.** A `bind` identity MUST be read-only, limited to the least subtree and
operations its consumer needs, unable to sign in interactively, and used by exactly one
consuming service. Two services MUST NOT share a bind credential. Where a service must write
(for example the identity-provisioner creating users), it gets its own `workload` identity with
the narrowest working write scope and is never given the service-admin account.
**SI-4 Service-admin identities.** A service SHOULD have exactly one local administrative
identity, separate from every bind and every human. It MUST be named for its service (§4),
MUST require a second factor where the service can enforce one, and MUST NOT be used by
automation unless the declaration says so.
**SI-5 Attributed administration first.** Where a service supports administrative roles granted
to an attributed human identity (for example OpenBao policies bound to a group), day-to-day
administration SHOULD use that route. The human platform administrator holds directory and policy administration rights through membership
of an administrative group on their own account, with their own password and second factor. The local
`service-admin` is the sealed fallback and is listed in the crisis custody list. A service that has only a local administrator (privacyIDEA
today) records that as an exception, not as a norm.
**SI-6 Break-glass.** There MUST be a break-glass identity, held offline. Using it is an event
that MUST be recorded. It MUST NOT be used for routine operation, for backup validation or as the
test subject of a drill. It authorizes; it does not operate.
**SI-7 The developer identity.** The developer identity MUST NOT hold break-glass or recovery
custody items and MUST NOT hold a production service credential. It builds and tests.
**SI-8 Assurance.** Every `human` and `service-admin` identity MUST require a second factor
where the service can enforce one. A role that grants administrative policy MUST require the
assurance level itself (for example an `aal2` claim bound in the OpenBao role), not only rely on
an upstream service having checked. A role that does not MUST record why in an exception.
Decided 2026-10-24: OpenBao `platform-admin` binds `aal2`.
**SI-9 Custody class.** Every credential MUST declare a custody class: `offline-key`,
`personal-safe`, `openbao-lease`, `delivered-secret` (delivered into the workload by the
platform), or `none` (federated, no stored credential). A credential used by more than one
consumer is non-conformant under SI-3.
**SI-10 Ownership and rotation.** Every identity MUST name an owner, its consumers and a
rotation path with its coupling (what must change together). Static long-lived binds are a
stated gap under Tenancy Posture §9 (Decision 9.1 and 9.2), not a silent exclusion; their
compensating controls are SI-3 and a restricted network path.
**SI-11 Declaration and legacy.** Every identity that exists in a service MUST be declared.
An identity that exists and is not declared is non-conformant (`unknown`). A legacy identity
MUST have a disposition (retire, accept, or defer) with an owner and a date.
**SI-12 Recovery.** Every identity needed to recover a service MUST appear in the crisis custody
list with the answer to "does using it work when SSO and OpenBao are down?". An identity that
cannot be used while its own service is down MUST NOT be the only recovery path.
**SI-13 Validation is operated by the operator identity.** Restore drills and backup validation
MUST be run by the production operator identity, with that identity's own token as the test
subject, and MUST record which identity ran each stage.
**SI-14 Agents.** An agent identity MUST present as an agent: its tokens carry `principal_type: agent` and
name the agent's mode, autonomous or delegated (IAM Profile v0.3). It MUST NOT use a human's credential, MUST
have short-lived tokens (ceiling 3600 seconds, 60 minutes; decided 2026-10-24) and MUST be bounded by a named
boundary policy. A delegated agent names the delegating actor in its tokens.
## 4. Naming
| Class | Pattern | Notes |
| --- | --- | --- |
| `bind` | `svc-<service>` | One per consuming service; `svc-<service>-<function>` if one service needs several |
| `service-admin` | `<short>-admin` | A short form belongs to exactly one service (see §9): `pi-admin` for privacyIDEA; `ld-admin` for LLDAP only |
| `break-glass` | `platform-root` | The king credential |
| `human` | the person's own login | `tegwick`, `admin` |
| `workload` | the token subject form already in use | for example `service:secrets-engine`; IAM Profile v0.3 governs the token |
| `agent` | the agent's own subject | for example `service:codex:railiance-platform` today; the tokens must carry `principal_type: agent` (SI-14) |
Names are reserved for their class. The name `admin` is the human platform administrator's name wherever it
appears (decided 2026-10-24); no service-admin account is called `admin`. A `svc-` or `-admin` name MUST NOT
be used for a human account. A
federated role that holds no credential (custody `none`), such as an OpenBao role that maps a group to a
policy, is not an account and is not bound by this rule (see §10, question 7).
## 5. Target shape for today's services (informative)
This table shows where the rules lead. The authoritative state is the inventory, and the
steps are NK-WP-0054-T05 and T06.
| Service | `service-admin` | `bind` and write identities | Human route |
| --- | --- | --- | --- |
| LLDAP | `ld-admin` (the directory's configured super-admin, for LLDAP only; `admin` stays the human's account) | `svc-authelia`, `svc-keycape`, `svc-privacyidea` read-only; a scoped provisioner identity | `admin` with directory admin rights through the admin group, own password and OTP |
| Authelia | none (LDAP backend only) | uses `svc-authelia` | none |
| privacyIDEA | `pi-admin` | resolver uses `svc-privacyidea` | none (local administrator only: exception) |
| KeyCape | none | uses `svc-keycape` | none |
| OpenBao | per its own policy | n/a | `net-kingdom-admins` group to `platform-admin` |
The name `admin` is the human platform administrator's name wherever it appears (decided 2026-10-24); no
service-admin account is called `admin`. A `svc-` or `-admin` name MUST NOT be used for a human account. A
federated role that holds no credential, such as an OpenBao role mapping a group to a policy, is not an account
and is not bound by this rule.
## 6. Declaration
Each service publishes one declaration of every identity it holds, in a machine-readable form
defined by NK-WP-0054-T03. Decided 2026-10-24: declarations start in this repository
(`tools/service-identity/declarations/`) and move to each service's repository as its owner confirms them.
The owner's confirmation is recorded in the declaration (`owner_confirmed`). For each identity: name, class, purpose, privileges, custody class,
consumers, owner, rotation path and coupling, second-factor requirement, status
(`active`, `legacy`, `planned`) and any exception id. A declaration holds no credential and no
Each service declares every account it holds: name, `principal_type`, purpose, grants (`MODE @ SCOPE` with
activation and environment), operations, where the credential lives, consumers, owner, rotation and coupling,
second-factor requirement, status (`active`, `legacy`, `planned`) and exceptions. The canon's ten questions are
the checklist for a complete entry: who is the actor, on whose authority, what mode, over what scope, which
operations, where the authority originates, how it is activated, which realm enforces it, who keeps the evidence,
and who can override enforcement.
Declarations start in this repository (`tools/service-identity/declarations/`) and move to each service's
repository as its owner confirms them (decided 2026-10-24). A declaration holds no credential and no
secret-shaped value.
## 7. Conformance and the health check
For each identity the result is one of `conformant`, `non-conformant` (with the rule ids),
`excepted` (with the exception id) or `unknown`. Unknown is a finding, not a pass.
Per account the result is `conformant`, `non-conformant`, `excepted`, `unknown` or `planned`. Unknown is a
finding, not a pass. These match the companion's conformance states: `excepted` is a declared gap,
`non-conformant` is an undeclared violation.
The offline validator `tools/service-identity/validate.py` (NK-WP-0054-T03, provisional) evaluates the
rules that a declaration alone can decide: SI-1, SI-2, SI-3, SI-6, SI-8, SI-9, SI-11, SI-12, SI-14 and the
naming rules. SI-4, SI-5, SI-7, SI-10 and SI-13 are advisory or process rules and are not decided offline; SI-4
appears as an advisory. Unknown facts are reported as `unknown` for every class. Dates are explicit: the
validator takes `--as-of`.
The offline validator decides from a declaration alone: SI-1, SI-2, SI-3, SI-6, SI-8, SI-9, SI-11, SI-12, SI-14
and naming. SI-4 is an advisory. SI-5, SI-7, SI-10, SI-13 and SI-15 are process rules, checked by evidence rather
than by declaration. Dates are explicit (`--as-of`).
The health check (NK-WP-0054-T04) compares declared against observed state: for example,
which DN each service binds as, which groups the bind identities belong to, and which policies
an admin role carries. It uses read-only metadata that each owner provides and repository
manifests. It MUST NOT read a Secret. Its findings are proposals routed to the identity's owner
through [Posture Feedback](posture-feedback_v0.1.md), with an evidence-freshness bound. It
The health check (T04) is SEC-DSM's automated discovery (DSM-INV-004) applied to accounts. It compares declared
against observed state from owner-provided read-only metadata and repository manifests. It MUST NOT read a Secret.
Its findings are proposals routed to the owner through Posture Feedback, with an evidence-freshness bound. It
changes nothing.
## 8. Exceptions
An exception is time-boxed and records: the rule, the identity, the reason, the owner, an expiry
date and the compensating control. It is reviewed at the standard's review interval. A rule
without a recorded exception that is broken is non-conformant.
Exceptions follow DSM-EXC-001 to DSM-EXC-004: explicit, recorded (rule, account, reason, owner, compensating
control), expiring or revalidated, and carrying an **elimination path**: what change ends the exception.
Initial exceptions at adoption:
| Id | Rule | Identity | Reason | Until |
| Id | Rules | Account | Reason | Elimination path |
| --- | --- | --- | --- | --- |
| SI-X1 | SI-1, SI-2, SI-3, SI-9, NAMING | LLDAP `admin` | One account is the human, the super-admin and the shared bind of four services, and its password is in a person's safe and in a Kubernetes Secret | NK-WP-0054-T05 completes |
| SI-X2 | SI-10 | LDAP binds | Static long-lived credential; LDAP has no lease | Tenancy Posture §9 gap review |
| SI-X3 | NAMING, SI-11 | `trigger-admin` (privacyIDEA) | Legacy account, not named in the admin form, with uninventoried consumers; its disposition is tracked | NK-WP-0049-T22 disposition |
| SI-X4 | SI-8 | OpenBao `netkingdom-platform-admin` | Role binds on the group claim only in the repository file; decided 2026-10-24 to bind `aal2`, change owned by railiance-platform | The role binds `aal2` |
| SI-X5 | SI-5 | privacyIDEA | Only a local administrator is supported | Upstream capability |
| SI-X1 | SI-1, SI-2, SI-3, SI-9, naming | LLDAP `admin` | The human, the super-admin and the shared bind of four services in one account; password in a person's safe and a Kubernetes Secret | NK-WP-0054-T05: `svc-*` binds, provisioner account, `ld-admin`, `admin` human-only |
| SI-X2 | SI-10 | LDAP bind accounts | Static long-lived credential; LDAP has no lease | Governed residual secret (DSM-TRANS-002) until a federated directory lookup exists |
| SI-X3 | naming, SI-11 | `trigger-admin` (privacyIDEA) | Legacy account, consumers uninventoried | NK-WP-0049-T22 disposition |
| SI-X4 | SI-8 | OpenBao `netkingdom-platform-admin` | Role binds the group claim only | railiance-platform binds `aal2` (decided 2026-10-24) |
| SI-X5 | SI-4, SI-5 | privacyIDEA | Only a local administrator is supported | Upstream support for attributed administrators |
**Finding at adoption, not excepted:** F-1. The coding-agent role in OpenBao binds `principal_type: service`, so
the agent presents as a service against IAM Profile v0.3 (SI-14). The validator reports it as non-conformant
until railiance-platform changes the role or records an exception with a compensating control.
SI-X2 and SI-X5 concern SI-10 and SI-5, which cannot be decided from a declaration. They are recorded
here and are not encoded in the declarations; the offline validator would call them stale. The
declarations carry the exceptions the validator can evaluate (SI-X1, SI-X3, SI-X4).
**Findings at adoption, not excepted:** F-1, the OpenBao coding-agent role binds `principal_type: service`, so the
agent presents as a service against IAM Profile v0.3 (SI-14). It stays non-conformant until railiance-platform
changes the role or records an exception with a compensating control.
## 9. Relationship to other documents
- **IAM Profile v0.3** defines the principal types in tokens. This standard governs the
accounts that exist behind them and does not change the token profile. KeyCape's confidential clients
stay governed by the profile plus a declaration (settled 2026-10-24).
- **Credential Management v0.2 §6** lists `LLDAP_LDAP_USER_PASS` as a three-way coupling.
On adoption that row is corrected and replaced by the per-service bind accounts.
- **Tenancy Posture §9** treats long-lived credentials as a gap; SI-10 applies it to binds.
- **Security Layer Model v0.9** should be checked for an identity-layer statement this standard
must match; that reconciliation is part of ratification.
- **Crisis custody list** (`docs/crisis-custody-list.md`) is the recovery companion to SI-9 and SI-12.
- The registry of `<short>-admin` forms lives with the declarations (T03) and starts with
`pi-admin` and `ld-admin`; each form belongs to one service.
- **SecurityCanon:** vocabulary from Mode of Authority (draft 0.2.0); rules profiled from SEC-DSM 1.0.0. A
disagreement between this profile and the canon is a finding for the canon's owner, not a local override.
- **InfoTechCanon:** owns the identity model and `principal_type`.
- **Security Companion** (`SECURITY-COMPANION.md`, operative form of the security layer model): its §7 rules for
agents ("no standing credential", "tool availability is not permission", "every action is reconstructable as the
caller's action") are the basis of SI-14 and SI-15. Its four conformance states map to §7 here.
- **IAM Profile v0.3:** governs tokens, including the agent principal. KeyCape's confidential clients stay governed
by the profile plus a declaration (settled 2026-10-24).
- **Credential Management v0.2 §6** lists `LLDAP_LDAP_USER_PASS` as a three-way coupling; the inventory found five
consumers. That row is corrected when SI-X1 is eliminated.
- **Crisis custody list** (`docs/crisis-custody-list.md`) is the recovery companion to SI-9 and SI-12, and the
enumeration of roots that DSM-ROOT-001 asks for.
## 10. Decisions and open items
**Decided by the founder, 2026-10-24 (review of draft-1):**
**Decided by the founder, 2026-10-24:**
1. OpenBao `platform-admin` binds the `aal2` claim itself (SI-8). The change is railiance-platform's.
2. The human administrator keeps directory admin rights through an administrative group on their own
account (SI-5); the service-admin account is a sealed fallback.
3. Declarations start in this repository and move to each service repository as owners confirm them (§6).
4. Agents get their own class, with SI-14, and the token-lifetime ceiling is 60 minutes (3600 seconds).
5. `ld-admin` is for LLDAP only. `admin` stays the human's account on every service, including LLDAP, where the
directory's configured super-admin becomes `ld-admin` and `admin` keeps its administrative rights through
an admin group on its own password and OTP.
2. The human administrator administers through a group on their own account (SI-5); service-admin accounts are
sealed fallbacks.
3. Declarations start here and move to each service repository as owners confirm them (§6).
4. Agents are a distinct principal with SI-14; their token ceiling is 60 minutes.
5. `ld-admin` is for LLDAP only; `admin` stays the human's name on every service.
**Settled unless the founder objects:** KeyCape's confidential clients are governed by IAM Profile v0.3 plus a
declaration; the reserved-name rule applies to credential-holding accounts, not to federated roles (§4).
declaration; the reserved-name rule applies to credential-holding accounts, not to federated roles.
**To be rehearsed in isolation, not decided:**
**New in draft-3, for the founder and the canon owners:**
- Introducing `ld-admin` as the configured super-admin on an existing directory and demoting `admin` to an
administrative-group member with its own password. This replaces the earlier idea of renaming (NK-WP-0054-T06).
- The provisioner's narrowest working privilege against the pinned LLDAP image (T05).
- Whether a read-only bind account can be prevented from signing in interactively. If not, SI-3's
"unable to sign in" becomes "has a long random password that nobody uses and a read-only group".
- The mode readings in §3 are NetKingdom's. In particular: is a directory lookup `USE @ directory` (the directory's
purpose) rather than `OBSERVE`? The SecurityCanon owner should confirm.
- **Hub authorship is unauthenticated.** Progress events and decisions carry a free-text `author`. For SI-15 they
need an attributable actor and session, as commits already have.
- **Agents act under the person's ambient authority.** There is no per-run agent identity yet (DSM-AGENT-002). Until
there is, each agent session's effective authority is the person's tool-reachable authority, and that is a
declared gap, not conformance.
**Open:** nothing is open beyond the rehearsals and the owners' review.
**To be rehearsed in isolation, not decided:** introducing `ld-admin` as the configured super-admin and demoting
`admin` (T06); the provisioner's narrowest scope (T05); whether a bind account can be kept from signing in
interactively (SI-3).
## 11. Adoption
Structure first, tooling second, as with Tenancy Posture. The order is: ratify the vocabulary and
rules; confirm the declarations with their owners (T03); run the health check read-only (T04) and publish the
first report; then retire the exceptions one by one, starting with SI-X1 (T05). No exception is
closed by writing a declaration. Each is closed by the live change and an evidence run.
Structure first, tooling second. Ratify the vocabulary and rules; migrate the declarations and validator to
grants (T03b); confirm the declarations with their owners; run the health check read-only (T04) and publish the
first report; then eliminate the exceptions one by one, starting with SI-X1 (T05). No exception is closed by
writing a declaration. Each is closed by the live change and an evidence run.

View file

@ -0,0 +1,72 @@
# Security identity, accountable automation and agent orientation review — 2026-10-24
Requested by the founder during NK-WP-0054: review the NetKingdom security infrastructure, optimize the
Service Identity and Privilege standard against the security canon, optimize automation with
accountability, and make the security architecture easy for agents (Claude Code, Codex, Grok) to pick up.
## Method and sources
- Emergent Security orientation: package 0.2.6, digest `8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02`,
card `start` **withheld** (12 of 14 sources changed since review), so its sources were read directly.
- `security-canon`: README, SCOPE, the Mode of Authority vocabulary card, and the DevOps Secrets Management
Standard `SEC-DSM` 1.0.0 (sections 4, 9, 20 to 25 read; the rest by heading).
- This repository: `SECURITY-COMPANION.md` (operative form of the accepted security layer model v0.8),
`canon/standards/`, `AGENTS.md`, `CLAUDE.md`, `tools/`, the `Makefile` and the NK-WP-0054 work.
- Commit history for attribution trailers. No live service, Secret or credential was touched.
## Findings
**R1. The standard restated the canon.** Drafts 1 and 2 of the Service Identity and Privilege standard repeated
SEC-DSM rules (DSM-ID-001/004, DSM-AUTH-001, DSM-HUM-003, DSM-ROOT, DSM-INV, DSM-EXC, DSM-AGENT) and invented
identity "classes" beside the canon's `principal_type` and Mode of Authority. The canon's own translations
contradict one class: "break-glass" is an `activation`, not a kind of identity. They confirm the founder's model:
`backup operator → OPERATE @ backup-system`, `developer → CONSTRUCT @ product`.
**R2. Accountability is present for commits and receipts, absent for hub writes.** Commits carry `Assistant`,
`Assistant-Session` and `Assistant-Process` trailers under the human author. Recovery receipts carry source hashes
and are checked by independent verifiers; admissions are SSH-signed. State Hub progress events and decisions carry a
free-text `author` that nothing authenticates.
**R3. Agents act under the person's ambient authority.** A Claude Code, Codex or Grok session in the founder's
terminal can reach everything the founder's tools reach. SEC-DSM DSM-AGENT-008 counts that as the agent's
authority. There is no per-run agent identity (DSM-AGENT-002). The working practice that kept this safe in
NK-WP-0049 (the agent prepares and tests on fixtures; the person admits and runs; an independent verifier checks)
was not written down as a rule.
**R4. The OpenBao coding-agent role presents as a service.** It binds `principal_type: service`; IAM Profile v0.3
requires `principal_type: agent`. Recorded as finding F-1 in the standard.
**R5. Agents could not find the security tools.** Eleven security tools exist under `tools/`. They were reachable
only through `make help` (over a hundred targets) and per-tool READMEs, with nothing saying which question each
answers or whether an agent may run it. The automatic orientation card is withheld, so a new agent session got no
guided entry. Grok has no dedicated instruction file here; `AGENTS.md` is the shared cross-agent file.
**R6. Overlapping custody material.** `make security-bootstrap-custody-roster-template` prints a two-of-three custody
roster template, and `docs/crisis-custody-list.md` now lists custody items. They should converge rather than drift.
## Changes made
1. **Standard draft-3** (`canon/standards/service-identity-privilege_v0.1.md`, still proposed): an estate profile of
SecurityCanon. It imports `principal_type` and `MODE @ SCOPE` grants, maps draft-2's classes onto them, states the
estate identities in canon terms, and gives every rule its SEC-DSM references with only NetKingdom's additions.
New SI-15, accountable automation, with the golden path prepare, admit, execute, verify, retain. Exceptions now
carry an elimination path (DSM-EXC-004). Every founder decision and rule id is kept.
2. **Security tools index** (`tools/security-tools.json`, `make security-tools`): every security tool with the
question it answers, its run and test commands, its governing standard and whether an agent may run it (`yes`,
`fixtures-only`, `no-attended`, `no-live`). A test fails when a new tool directory is not indexed, or when a path,
standard or make target in the index does not exist.
3. **Agent quickstart** in `AGENTS.md` and `CLAUDE.md`, identical, in its own marked block beside the managed
emergent-security pilot block: find the tool, know the rules, route credentials, effective authority, leave a trail.
## Recommendations, with owners
| Item | Owner |
| --- | --- |
| Migrate declarations and validator to grants (NK-WP-0054-T03b) | net-kingdom |
| Authenticate State Hub authorship for agents (actor, session) to meet SI-15 | state-hub |
| Per-run agent identity (DSM-AGENT-002), for example short-lived agent tokens from KeyCape | key-cape, glas-harness |
| Coding-agent role presents as `agent` (F-1) | railiance-platform |
| Refresh the withheld orientation cards; consider a card pointing at `make security-tools` | emergent-security (EMERGENT-WP-0002) |
| Confirm the mode readings in the standard §3, in particular `USE @ directory` for binds | security-canon |
| Converge the custody roster template with the crisis custody list | net-kingdom |
| Confirm which instruction file Grok reads; if not `AGENTS.md`, point it there | founder |

View file

@ -0,0 +1,34 @@
"""The security tools index stays complete and points at things that exist."""
import json
import pathlib
import re
ROOT = pathlib.Path(__file__).resolve().parents[1]
INDEX = json.loads((ROOT / "tools/security-tools.json").read_text())
MAKEFILE = (ROOT / "Makefile").read_text()
TARGETS = set(re.findall(r"^([a-z0-9-]+):", MAKEFILE, re.M))
def test_every_tool_directory_is_indexed_or_explicitly_excluded():
dirs = {p.name for p in (ROOT / "tools").iterdir() if p.is_dir() and not p.name.startswith(("_", "."))}
listed = {t["id"] for t in INDEX["tools"]} | set(INDEX["not_security_tools"])
assert dirs - listed == set(), f"add to tools/security-tools.json: {sorted(dirs - listed)}"
def test_paths_and_standards_exist():
for tool in INDEX["tools"]:
assert (ROOT / tool["path"]).is_dir(), tool["id"]
assert (ROOT / tool["standard"]).is_file(), (tool["id"], tool["standard"])
def test_make_targets_named_in_the_index_exist():
for tool in INDEX["tools"]:
for field in ("run", "test"):
command = tool[field]
if command.startswith("make "):
assert command.split()[1] in TARGETS, (tool["id"], command)
def test_agent_permission_is_always_stated():
allowed = set(INDEX["agent_may_run_values"])
assert all(tool["agent_may_run"] in allowed for tool in INDEX["tools"])

58
tools/security-tools.json Normal file
View file

@ -0,0 +1,58 @@
{
"schema": "netkingdom.security-tools-index.v1",
"purpose": "One place for any agent (Claude Code, Codex, Grok) or person to find NetKingdom's security tools, what question each answers, how to run it, and whether an agent may run it. Tool availability is not permission (SECURITY-COMPANION.md section 7).",
"agent_may_run_values": {
"yes": "offline and read-only; any agent may run it",
"fixtures-only": "an agent may run it on synthetic fixtures; real inputs are the owner's",
"no-attended": "needs a person's private input or authority; an agent prepares and the person runs it",
"no-live": "contacts a live service; only under the owner's admitted procedure"
},
"orientation": [
{"what": "Security rules, operative form", "where": "SECURITY-COMPANION.md"},
{"what": "Credential and access routing (who owns a credential)", "command": "warden route find \"<need>\" --json", "where": "~/ops-warden"},
{"what": "Shared security orientation cards", "command": "PYTHONPATH=../emergent-security/src python3 -m emergent_security.knowledge --repositories .. show start --audience generic", "note": "A withheld card means: read its listed sources instead."},
{"what": "Standards of record", "where": "canon/standards/"},
{"what": "Upstream security vocabulary and secrets standard", "where": "../security-canon (Mode of Authority, SEC-DSM 1.0.0)"},
{"what": "Accounts, authority and accountable automation", "where": "canon/standards/service-identity-privilege_v0.1.md"},
{"what": "Who and what unlocks recovery", "where": "docs/crisis-custody-list.md"}
],
"tools": [
{"id": "service-identity", "path": "tools/service-identity", "answers": "Do the declared service accounts conform to the identity and privilege standard?",
"run": "make service-identity-check", "test": "make service-identity-test", "agent_may_run": "yes",
"standard": "canon/standards/service-identity-privilege_v0.1.md"},
{"id": "custody-record", "path": "tools/custody-record", "answers": "Is a platform-root custody record valid, and may a root grant be observed from it?",
"run": "uv run tools/custody-record/validate.py <record.json>", "test": "make custody-record-test", "agent_may_run": "yes",
"standard": "docs/adr/ADR-0017-root-grant-custody-and-account-authority.md"},
{"id": "tenancy-posture", "path": "tools/tenancy-posture", "answers": "Is a tenancy.yaml declaration valid against the tenancy posture standard?",
"run": "python3 tools/tenancy-posture/validate.py <tenancy.yaml>", "test": "make posture-feedback-test", "agent_may_run": "yes",
"standard": "canon/standards/tenancy-posture_v0.1.md"},
{"id": "posture-feedback", "path": "tools/posture-feedback", "answers": "Which owner should get which remediation proposal for a posture finding?",
"run": "make posture-feedback-reference", "test": "make posture-feedback-test", "agent_may_run": "yes",
"standard": "canon/standards/posture-feedback_v0.1.md", "note": "Proposal-only: never writes State Hub or policy."},
{"id": "iam-profile-conformance", "path": "tools/iam-profile-conformance", "answers": "Does an OIDC issuer conform to the NetKingdom IAM Profile?",
"run": "see tools/iam-profile-conformance/README.md", "test": "make iam-profile-conformance-test", "agent_may_run": "fixtures-only",
"standard": "canon/standards/iam-profile_v0.3.md", "note": "A live check needs a freshly minted access token from the issuer's owner."},
{"id": "playbook-capability-contract", "path": "tools/playbook-capability-contract", "answers": "Is a Railiance playbook capability declaration valid?",
"run": "see tools/playbook-capability-contract/README.md", "test": "make playbook-contract-test", "agent_may_run": "yes",
"standard": "canon/standards/playbook-capability-contract_v0.1.md"},
{"id": "security-scenario-composer", "path": "tools/security-scenario-composer", "answers": "Which providers, trust transitions and responsibilities does a security scenario need?",
"run": "make security-scenario-compose-lightweight", "test": "make security-scenario-composer-test", "agent_may_run": "yes",
"standard": "canon/standards/security-scenario-composition_v0.1.md", "note": "Plan-only; executes nothing."},
{"id": "security-case-types", "path": "tools/security-case-types", "answers": "Are a SecurityCaseType and a SecurityCase valid?",
"run": "see tools/security-case-types/README.md", "test": "python3 -m pytest tools/security-case-types/tests", "agent_may_run": "yes",
"standard": "canon/standards/security-case-types_v0.1.md"},
{"id": "emission-cadence-profile", "path": "tools/emission-cadence-profile", "answers": "Does an emission-cadence declaration meet the NetKingdom security overlay?",
"run": "see tools/emission-cadence-profile/README.md", "test": "make emission-cadence-profile-test", "agent_may_run": "yes",
"standard": "canon/standards/emission-cadence-security-profile_v0.1.md"},
{"id": "security-bootstrap-console", "path": "tools/security-bootstrap-console", "answers": "Where is the guided security bootstrap, and what is the next safe action?",
"run": "make security-bootstrap-console", "test": "make security-bootstrap-console-test", "agent_may_run": "fixtures-only",
"standard": "docs/smooth-bootstrap-guide.md", "note": "Can write an explicit custody-mode approval record; that is the person's act."},
{"id": "bootstrap-recovery", "path": "tools/bootstrap-recovery", "answers": "Can the identity backup be retrieved and each service restored in isolation?",
"run": "tools/bootstrap-recovery/run-isolated-*.sh <transfer receipt>", "test": "NK49_RUN_ISOLATED_*_TEST=1 python3 -m pytest tests/test_isolated_*", "agent_may_run": "no-attended",
"standard": "docs/identity-restore-drill.md", "note": "Needs the backup age key and private test inputs. Agents prepare and test on fixtures; the operator (admin) runs the real stages (standard SI-13)."}
],
"not_security_tools": {
"coordination-frame": "Renders the coordination receiver from staged sources; repository maintenance.",
"tutorial-verify": "Verifies runbook tutorial packs."
}
}

46
tools/security_tools.py Normal file
View file

@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Print the NetKingdom security tools index (tools/security-tools.json) for people and agents.
Offline and read-only. `--json` prints the index unchanged for machine use.
"""
from __future__ import annotations
import argparse
import json
import pathlib
import sys
INDEX = pathlib.Path(__file__).resolve().parent / "security-tools.json"
def load() -> dict:
return json.loads(INDEX.read_text(encoding="utf-8"))
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
parser.add_argument("--json", action="store_true")
args = parser.parse_args(argv)
index = load()
if args.json:
print(json.dumps(index, indent=2))
return 0
print("NetKingdom security tools. Tool availability is not permission (SECURITY-COMPANION.md section 7).\n")
print("Start here:")
for item in index["orientation"]:
target = item.get("command") or item.get("where")
print(f" - {item['what']}: {target}")
print("\nTools (agent may run: " + ", ".join(index["agent_may_run_values"]) + "):")
for tool in index["tools"]:
print(f"\n {tool['id']} [agent may run: {tool['agent_may_run']}]")
print(f" answers: {tool['answers']}")
print(f" run: {tool['run']}")
print(f" test: {tool['test']}")
print(f" rules: {tool['standard']}")
if tool.get("note"):
print(f" note: {tool['note']}")
return 0
if __name__ == "__main__":
sys.exit(main())

View file

@ -93,6 +93,9 @@ Profile v0.3, Credential Management v0.2 and the Security Zones standard.
**Done when:** the draft is reviewed by the founder and the service owners it names.
Draft-3 (2026-10-24): realigned as an estate profile of SecurityCanon after a review against the canon
(`history/2026-10-24-security-identity-and-agent-review.md`): imported vocabulary, SEC-DSM references per rule,
estate identities in canon terms, new SI-15 (accountable automation). Validator migration is T03b.
Draft-2 (2026-10-24, after the founder's review): decisions applied are OpenBao `platform-admin` binds
`aal2`; the human administrator keeps directory admin rights through an admin group; declarations start here
and move to the services; agents get their own class and rule SI-14. Rehearsals still to do (not decisions):
@ -135,6 +138,25 @@ Secret and a person's safe), the SI-X1 exception grew to include SI-9 and NAMING
rule was scoped to credential-holding identities (standard section 10, question 7). SI-4, SI-5, SI-7,
SI-10 and SI-13 are not decidable from a declaration.
## Migrate declarations and validator to canon grants (draft-3)
```task
id: NK-WP-0054-T03b
status: todo
priority: medium
assignee: claude-code
depends_on: [NK-WP-0054-T03]
```
Draft-3 of the standard is an estate profile of SecurityCanon: accounts carry an imported `principal_type`
and authority grants written `MODE @ SCOPE` with activation and environment, and break-glass is an
activation. The schema, validator and declarations still use draft-2's classes. Migrate them, keeping the
rule ids, the exception ids and the current results comparable (the first run under grants should report the
same non-conformant, excepted and unknown accounts unless a difference is explained).
**Done when:** the schema expresses principal type and grants, the declarations follow §3 of the standard,
the tests pass, and a before/after comparison is recorded.
## Live conformance health check
```task