Represent SSH distribution sync as a resource log
This commit is contained in:
parent
eec4c92145
commit
42d7301bdb
6 changed files with 247 additions and 52 deletions
|
|
@ -220,6 +220,79 @@ pub struct SshRevocationEntry {
|
|||
pub provenance: Option<SshRecordProvenance>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "kebab-case")]
|
||||
pub enum SshDistributionLogEntry {
|
||||
CertRequest {
|
||||
entry_id: String,
|
||||
resource: String,
|
||||
timestamp: UnixMillis,
|
||||
request: SshCertRequest,
|
||||
},
|
||||
Certificate {
|
||||
entry_id: String,
|
||||
resource: String,
|
||||
timestamp: UnixMillis,
|
||||
certificate: SshCertificateRecord,
|
||||
},
|
||||
Revocation {
|
||||
entry_id: String,
|
||||
resource: String,
|
||||
timestamp: UnixMillis,
|
||||
revocation: SshRevocationEntry,
|
||||
},
|
||||
}
|
||||
|
||||
impl SshDistributionLogEntry {
|
||||
#[must_use]
|
||||
pub fn cert_request(request: SshCertRequest) -> Self {
|
||||
Self::CertRequest {
|
||||
entry_id: format!("ssh-log:cert-request:{}", request.id),
|
||||
resource: "resource:ssh:certs".to_owned(),
|
||||
timestamp: request.created_at,
|
||||
request,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn certificate(certificate: SshCertificateRecord) -> Self {
|
||||
Self::Certificate {
|
||||
entry_id: format!("ssh-log:certificate:{}", certificate.id),
|
||||
resource: "resource:ssh:certs".to_owned(),
|
||||
timestamp: certificate.imported_at,
|
||||
certificate,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn revocation(revocation: SshRevocationEntry) -> Self {
|
||||
Self::Revocation {
|
||||
entry_id: format!("ssh-log:revocation:{}", revocation.id),
|
||||
resource: "resource:ssh:revocations".to_owned(),
|
||||
timestamp: revocation.created_at,
|
||||
revocation,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn timestamp(&self) -> UnixMillis {
|
||||
match self {
|
||||
Self::CertRequest { timestamp, .. }
|
||||
| Self::Certificate { timestamp, .. }
|
||||
| Self::Revocation { timestamp, .. } => *timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn entry_id(&self) -> &str {
|
||||
match self {
|
||||
Self::CertRequest { entry_id, .. }
|
||||
| Self::Certificate { entry_id, .. }
|
||||
| Self::Revocation { entry_id, .. } => entry_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SshCertRequestSigningPayload {
|
||||
pub id: SshCertRequestId,
|
||||
|
|
@ -547,6 +620,31 @@ mod tests {
|
|||
assert_eq!(decoded, request);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ssh_distribution_log_entries_roundtrip_with_stable_ids() {
|
||||
let request = SshCertRequest {
|
||||
id: "ssh-cert-request:1".into(),
|
||||
requester_node: "node:laptop".into(),
|
||||
public_key: "ssh-ed25519 AAAA test".to_owned(),
|
||||
public_key_fingerprint: ssh_public_key_fingerprint("ssh-ed25519 AAAA test"),
|
||||
cert_kind: SshCertKind::User,
|
||||
principals: vec!["eric".to_owned()],
|
||||
requested_validity: Some("+52w".to_owned()),
|
||||
renewal_of: None,
|
||||
reason: Some("bootstrap".to_owned()),
|
||||
status: SshCertRequestStatus::Pending,
|
||||
created_at: UnixMillis(10),
|
||||
provenance: None,
|
||||
};
|
||||
let entry = SshDistributionLogEntry::cert_request(request);
|
||||
assert_eq!(entry.entry_id(), "ssh-log:cert-request:ssh-cert-request:1");
|
||||
assert_eq!(entry.timestamp(), UnixMillis(10));
|
||||
|
||||
let json = serde_json::to_string(&entry).expect("json");
|
||||
let decoded: SshDistributionLogEntry = serde_json::from_str(&json).expect("decode");
|
||||
assert_eq!(decoded, entry);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sign_command_includes_host_flag_for_host_certs() {
|
||||
let request = SshCertRequest {
|
||||
|
|
|
|||
Loading…
Reference in a new issue