Files
rustfs/protocol/agent/v1/fixtures/auth/certificate-profile.json
T
overtrue 3b5164032a feat(connect): add device identity store and registration proof
A RustFS cluster device needs a durable identity before it can exchange a
one-time registration token for a certificate. This adds the device-side
half of that exchange, which rustfs/connect already verifies.

`connect::identity` builds the canonical registration transcript frozen by
protocol/agent/v1/registration-proof.md, signs it as low-S ES256, and emits
the PKCS#10 certificate request Connect consumes for its SubjectPublicKeyInfo.
`connect::identity_store` seals the P-256 key at mode 0600 and publishes it
through a no-clobber link, so a retry or a concurrent start returns the
original identity rather than minting a second one, and a corrupt or widened
key is refused rather than silently replaced.

The protocol fixture set is copied here byte-identically because
fixture-sets.json names this repository as the consumer copy; the tests
verify it against its own manifests and cross-verify Connect-produced ECDSA
proofs against transcripts rebuilt locally.

Nothing starts a task or touches the S3 data path: an unenrolled deployment
generates no key and holds no identity.
2026-08-19 12:54:50 +08:00

83 lines
2.7 KiB
JSON

{
"protocolVersion": "v1",
"fixtureSet": "auth",
"fixture": "certificate-profile",
"description": "Frozen shape of the client certificate an online device presents and of the RFC 9440 header that conveys it.",
"certificate": {
"subject": {
"rdnCount": 1,
"commonName": "{clusterDeviceUid}",
"forbiddenAttributes": ["O", "OU", "C", "ST", "L", "emailAddress"]
},
"subjectAlternativeName": {
"entryCount": 1,
"type": "uniformResourceIdentifier",
"value": "urn:rustfs:connect:device:{clusterDeviceUid}",
"forbiddenTypes": ["dNSName", "iPAddress", "rfc822Name", "directoryName"],
"wildcardsAccepted": false
},
"clusterDeviceUid": {
"source": "cluster_devices.uid",
"format": "lowercase canonical UUIDv7",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
},
"keyAlgorithm": "EC",
"keyCurve": "P-256",
"signatureAlgorithm": "ES256",
"certificateSigningRequest": {
"format": "PKCS#10",
"signatureAlgorithm": "ES256",
"proofOfPossession": "self-signed with the device private key"
},
"lifetimeSeconds": 86400,
"maxRotationOverlapSeconds": 86400,
"recommendedRotationLeadSeconds": 28800,
"maxPresentableCredentialsPerDevice": 2,
"serial": {
"encoding": "lowercase-hex",
"length": 32,
"pattern": "^[0-9a-f]{32}$",
"entropyBits": 128
},
"certificateFingerprint": {
"algorithm": "SHA-256",
"over": "DER certificate",
"encoding": "lowercase-hex",
"pattern": "^[0-9a-f]{64}$"
},
"publicKeyFingerprint": {
"algorithm": "SHA-256",
"over": "DER SubjectPublicKeyInfo",
"encoding": "lowercase-hex",
"pattern": "^[0-9a-f]{64}$"
},
"keyId": {
"pattern": "^[a-z0-9][a-z0-9._-]{7,127}$"
},
"carriesOrganizationIdentifier": false,
"carriesClusterIdentifier": false,
"tenantBinding": {
"source": "device_credentials matched by certificate serial and certificate fingerprint",
"resolver": "ClusterDeviceIdentityPort::resolveOnlineCertificate"
}
},
"header": {
"name": "Client-Cert",
"specification": "RFC 9440",
"encoding": "sf-binary",
"valueTemplate": ":{base64(DER certificate)}:",
"example": ":MIIBkDCCATagAwIBAgIQZXhhbXBsZQ==:",
"chainHeader": {
"name": "Client-Cert-Chain",
"accepted": false,
"reason": "Chain validation belongs to the trusted ingress, which verifies against the Connect device CA before forwarding."
},
"setByTrustedIngressOnly": true,
"inboundHeaderStripped": true,
"appendAccepted": false,
"acceptedOnSurfaces": ["/agent"],
"ignoredOnSurfaces": ["/api"],
"backendPubliclyReachable": false
}
}