pub struct PersistState {
pub machine_key: MachinePrivateKey,
pub network_lock_key: NetworkLockPrivateKey,
pub node_key: NodePrivateKey,
pub old_node_key: Option<NodePublicKey>,
pub acme_account_key: Option<Zeroizing<Vec<u8>>>,
}Expand description
The portion of the key state that should be retained between runs of the same device.
Disco keys are ephemeral and should be generated anew each time a device runs, so are excluded from this state.
§At-rest protection is the embedder’s responsibility
The secret-bearing fields here are zeroized in memory on drop (the dedicated key types and the
Zeroizing-wrapped ACME account key), but that is an in-process hygiene
measure only. Protecting this state at rest — restrictive file permissions (e.g. 0o600),
full-disk or filesystem encryption, secure-enclave/keyring storage — is entirely the
responsibility of the embedding application that serializes and writes it to durable storage.
This crate neither reads nor writes files and makes no at-rest guarantee (see SECURITY.md).
Fields§
§machine_key: MachinePrivateKeyThe MachinePrivateKey for the hardware this Tailnet peer runs on.
network_lock_key: NetworkLockPrivateKeyThe NetworkLockPrivateKey for this Tailnet peer, for use with Tailnet Lock.
node_key: NodePrivateKeyThe NodePrivateKey for this Tailnet peer.
old_node_key: Option<NodePublicKey>The node’s PREVIOUS node public key, recorded during a node-key rotation so the next
registration sends it as RegisterRequest.OldNodeKey for key continuity (Go’s regen flow).
None outside a rotation (the default). Reactive / embedder-driven — matching Go, this fork
does NOT auto-rotate the node key before expiry (Go deliberately doesn’t either; key expiry is
a human-re-auth control). See PersistState::rotate_node_key.
acme_account_key: Option<Zeroizing<Vec<u8>>>The persisted ACME account key (PKCS#8 DER of an ECDSA P-256 key), or None if no ACME
account has been provisioned for this node. The acme cert-issuance path loads this to keep
the same Let’s Encrypt account identity across renewals; absent, the runtime generates an
ephemeral per-call key (a new ACME account each issuance). #[serde(default)] so key files
written before this field load as None (mirrors old_node_key).
Wrapped in Zeroizing so the DER private-key bytes are wiped from
memory on drop. Zeroizing<Vec<u8>> serializes transparently via its inner Vec, so the
persisted JSON shape is identical to a bare Vec<u8> (a byte array).
Implementations§
Source§impl PersistState
impl PersistState
Sourcepub fn rotate_node_key(&mut self)
pub fn rotate_node_key(&mut self)
Rotate the node key for re-registration, mirroring Go’s regen flow: record the current
node public key as old_node_key and replace the node key with
a freshly-generated one. The next registration that uses this state will send the prior key
as RegisterRequest.OldNodeKey, so control links the new node key to the node’s existing
identity instead of treating it as a brand-new node.
This is the embedder-driven rotation primitive (re-create the device with the returned state). It is reactive, NOT a pre-expiry auto-rotator: Go has no such timer, because node-key expiry is a deliberate periodic human/IdP re-attestation control. Re-registration still requires a valid auth credential, exactly as a fresh registration does.
Trait Implementations§
Source§impl Clone for PersistState
impl Clone for PersistState
Source§fn clone(&self) -> PersistState
fn clone(&self) -> PersistState
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for PersistState
impl Debug for PersistState
Source§impl Default for PersistState
impl Default for PersistState
Source§fn default() -> PersistState
fn default() -> PersistState
Source§impl<'de> Deserialize<'de> for PersistState
impl<'de> Deserialize<'de> for PersistState
Source§fn deserialize<__D>(
__deserializer: __D,
) -> Result<PersistState, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(
__deserializer: __D,
) -> Result<PersistState, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
Source§impl From<&NodeState> for PersistState
impl From<&NodeState> for PersistState
Source§fn from(value: &NodeState) -> PersistState
fn from(value: &NodeState) -> PersistState
Source§impl From<&PersistState> for NodeState
impl From<&PersistState> for NodeState
Source§fn from(value: &PersistState) -> NodeState
fn from(value: &PersistState) -> NodeState
Source§impl From<NodeState> for PersistState
impl From<NodeState> for PersistState
Source§fn from(value: NodeState) -> PersistState
fn from(value: NodeState) -> PersistState
Source§impl From<PersistState> for NodeState
impl From<PersistState> for NodeState
Source§fn from(value: PersistState) -> NodeState
fn from(value: PersistState) -> NodeState
Source§impl Serialize for PersistState
impl Serialize for PersistState
Source§fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
Auto Trait Implementations§
impl Freeze for PersistState
impl RefUnwindSafe for PersistState
impl Send for PersistState
impl Sync for PersistState
impl Unpin for PersistState
impl UnsafeUnpin for PersistState
impl UnwindSafe for PersistState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<A, T> DynMessage<A> for T
impl<A, T> DynMessage<A> for T
Source§fn handle_dyn<'a>(
self: Box<T>,
state: &'a mut A,
actor_ref: ActorRef<A>,
tx: Option<Sender<Result<Box<dyn Any + Send>, SendError<Box<dyn Any + Send>, Box<dyn Any + Send>>>>>,
stop: &'a mut bool,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn ReplyError>>> + Send + 'a>>
fn handle_dyn<'a>( self: Box<T>, state: &'a mut A, actor_ref: ActorRef<A>, tx: Option<Sender<Result<Box<dyn Any + Send>, SendError<Box<dyn Any + Send>, Box<dyn Any + Send>>>>>, stop: &'a mut bool, ) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn ReplyError>>> + Send + 'a>>
impl<T> ErasedDestructor for Twhere
T: 'static,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more