NK-WP-0054: security review; standard draft-3 as a SecurityCanon profile; agent security quickstart
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:
parent
a3bab9210b
commit
b7749277fd
10 changed files with 492 additions and 206 deletions
17
AGENTS.md
17
AGENTS.md
|
|
@ -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 -->
|
||||
|
|
|
|||
17
CLAUDE.md
17
CLAUDE.md
|
|
@ -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 -->
|
||||
|
|
|
|||
5
Makefile
5
Makefile
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
72
history/2026-10-24-security-identity-and-agent-review.md
Normal file
72
history/2026-10-24-security-identity-and-agent-review.md
Normal 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 |
|
||||
34
tests/test_security_tools_index.py
Normal file
34
tests/test_security_tools_index.py
Normal 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
58
tools/security-tools.json
Normal 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
46
tools/security_tools.py
Normal 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())
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue