Files
mesh-contracts/identity-and-access/seats/mesh-node-enroller/seat.json
T

341 lines
10 KiB
JSON

{
"format": 1,
"seat": "mesh-node-enroller",
"scope": "mesh",
"grain": "whole",
"domain": "Identity and access",
"decision": "novox/hq ADR 0587, ADR 0634, ADR 0635",
"description": "The seat that enrols a new machine on the operator's Approve and a one-time token (ADR 0587). Renamed from mesh-enrolment (ADR 0634 §9).",
"verbs": [
{
"name": "issue",
"description": "Issue a one-time token for a new machine, on the operator's Approve: refused at once, naming every finding, for a name that is not a node name or that a node record, a placement key or an open enrolment holds, and for every call before the controller's lease is handed away. Otherwise reserves the lowest free private-network address, asks the operator under the seat's own name and, on the warrant, adds the node to placement with its tunnel key, asks the vault for the token and says enrolment-issued. The token itself is read only through tokens.",
"input": {
"properties": {
"expires": {
"description": "how long the token lasts, a duration such as 1h or 24h: one hour when not given, at most 24 hours",
"type": "string"
},
"node": {
"description": "the new machine's name in the mesh",
"type": "string"
},
"overlay_key": {
"description": "the new machine's private network (tunnel) public key, as `nox-mesh-host key` prints it",
"type": "string"
},
"why": {
"description": "why it joins, shown to the operator with the ask",
"type": "string"
}
},
"required": [
"node",
"why",
"overlay_key"
],
"type": "object"
},
"answer": {
"type": "object",
"description": "the enrolment's stage, address and ask, or every finding refused at once"
}
},
{
"name": "redeem",
"description": "Spend a token: asked by a joining node-engine dialled as enrol.<node> alone, with the public halves of its keys and its identity key's proof over them. Spends the token, asks the vault for the node's account and certificate, writes the node into placement, and answers the account sealed to the node, its certificate and the vault's public half, signed by the vault. Asked again with the same keys it finishes what is not done and answers the same; with other keys it is refused.",
"input": {
"additionalProperties": false,
"properties": {
"node": {
"description": "the node the token was issued for",
"type": "string"
},
"overlay_key": {
"description": "the private network key's public half",
"type": "string"
},
"profile": {
"description": "what the machine is, as its record says it",
"type": "object"
},
"proof": {
"description": "the identity key's signature over the redeem's proof bytes (delivery.RedeemProof), base64",
"type": "string"
},
"public_key": {
"description": "the identity key's public half, base64",
"type": "string"
},
"sealing_key": {
"description": "the sealing key's public half, which the account is sealed to",
"type": "string"
},
"serving_key": {
"description": "the serving key's public half, which the certificate binds",
"type": "string"
},
"tunnel": {
"description": "a tunnel found on the machine: everything but its private key",
"type": "object"
}
},
"required": [
"node",
"public_key",
"sealing_key",
"proof"
],
"type": "object"
},
"answer": {
"type": "object",
"description": "the account sealed to the node, its certificate and the vault's public half, signed by the vault",
"properties": {
"node": {
"type": "string",
"description": "the node"
},
"login": {
"type": "string",
"description": "the login it dials as next"
},
"account": {
"type": "string",
"description": "its account sealed to the sealing key it presented, base64"
},
"certificate": {
"type": "string",
"description": "its certificate, PEM"
},
"signer": {
"type": "string",
"description": "the vault's public signing half, base64"
},
"signature": {
"type": "string",
"description": "the vault's signature over the answer without it, under the context of the enrolment kind, base64"
}
},
"required": [
"node",
"login",
"account",
"certificate",
"signer"
]
}
},
{
"name": "confirm",
"description": "Confirm an enrolment: asked by the node-engine dialled as its own node login alone, the runtime's proof of that caller being the confirmation. Says node-enrolled and ends the enrolment.",
"input": {
"properties": {},
"type": "object"
},
"answer": {
"type": "object",
"description": "the enrolment ended"
}
},
{
"name": "revoke",
"description": "End an enrolment at any stage, with why, without an Approve: withdraws an open ask, deletes the node's key and its address, has the vault retire an account it already minted for it, records the act as a hand act and says enrolment-revoked.",
"input": {
"properties": {
"node": {
"description": "the node",
"type": "string"
},
"why": {
"description": "why, recorded with the hand act",
"type": "string"
}
},
"required": [
"node",
"why"
],
"type": "object"
},
"answer": {
"type": "object",
"description": "the enrolment ended"
}
},
{
"name": "tokens",
"description": "Read every open enrolment, or one: its stage, expiry, ask and revision, the bucket's fill against its cap. For a node at live, its token sealed to the operator key, asked of the vault at that moment and relayed as the vault sealed it. With history, the ended enrolments from the seat's events, as far back as the events are kept.",
"input": {
"properties": {
"history": {
"description": "\"true\": the ended enrolments too",
"enum": [
"true",
"false"
],
"type": "string"
},
"node": {
"description": "one node",
"type": "string"
}
},
"type": "object"
},
"answer": {
"type": "object",
"description": "every open enrolment, or one"
}
},
{
"name": "again",
"description": "Raise an issue's ask again when the operator's channel does not hold it, and nothing more.",
"input": {
"properties": {
"node": {
"description": "the node whose ask is raised again",
"type": "string"
}
},
"required": [
"node"
],
"type": "object"
},
"answer": {
"type": "object",
"description": "the ask raised again"
}
}
],
"events": [
{
"name": "enrolment-issued",
"body": {
"$ref": "#/defs/Enrolment"
}
},
{
"name": "node-enrolled",
"body": {
"$ref": "#/defs/Enrolment"
}
},
{
"name": "enrolment-refused",
"body": {
"$ref": "#/defs/Enrolment"
}
},
{
"name": "enrolment-revoked",
"body": {
"$ref": "#/defs/Enrolment"
}
},
{
"name": "enrolment-expired",
"body": {
"$ref": "#/defs/Enrolment"
}
}
],
"family": {
"name": "mesh-node-enroller.events",
"max-age-days": 7
},
"states": [
{
"name": "enrolments",
"template": "state",
"key-forms": [
{
"key": "node.<node>",
"value": {
"$ref": "#/defs/Enrolment"
},
"description": "a node's enrolment, living until the token expires while live"
},
{
"key": "address.<address>",
"value": {
"type": "object",
"description": "the private-network address reserved at issue",
"properties": {
"v": {
"type": "integer"
},
"node": {
"type": "string"
},
"ask": {
"type": "string"
},
"issued": {
"type": "string",
"format": "date-time"
}
},
"required": [
"node"
]
},
"description": "an address reserved for a node"
}
],
"history": 5,
"description": "open enrolments and the addresses reserved for them"
}
],
"defs": {
"Enrolment": {
"type": "object",
"description": "one open enrolment",
"properties": {
"v": {
"type": "integer"
},
"node": {
"type": "string"
},
"address": {
"type": "string"
},
"why": {
"type": "string"
},
"caller": {
"type": "string"
},
"ask": {
"type": "string"
},
"stage": {
"type": "string",
"description": "asked, live or redeeming"
},
"issued": {
"type": "string",
"format": "date-time"
},
"expires": {
"type": "string",
"format": "date-time"
},
"keys-digest": {
"type": "string"
},
"overlay-key": {
"type": "string"
}
},
"required": [
"node",
"address",
"stage"
]
}
}
}