linux_keyutils_keyring_store/
lib.rs

1/*!
2# Credential store for the keyring crate
3
4This module implements a credential store for the keyring crate that uses keyutils as its back end.
5
6## Usage
7
8If you are trying to use the keyring crate on a headless linux box, or one that doesn't come with
9gnome-keyring, it's strongly recommended that you use this credential store, because (as part of the kernel)
10it's always available on Linux.
11
12To make this keystore the default for creation of keyring entries, execute this code:
13```
14keyring_core::set_default_store(linux_keyutils_keyring_store::Store::new().unwrap())
15```
16
17# Mapping service and user values to credentials
18
19Entries in keyutils are identified by a string `description`.  If a keyring entry is created with
20an explicit `description` modifier, that value is used as the keyutils description.
21Otherwise, a description is generated by concatenating a prefix string, the `service`,
22a delimiter string, the `user`, and a suffix string.  The prefix, delimiter, and suffix strings
23are part of the store configuration.  Their default values are: `keyring:` for the prefix,
24'@' for the delimiter, and an empty string for the suffix.
25
26Note that service and user strings, by default, can contain the delimiter
27string, so it is possible for entries with different service and user strings to
28map to the same description (and thus the same credential in the store). If you
29are worried about this, you can avoid it by configuring your store to forbid the
30delimiter string in the service string.
31
32# Attributes
33
34There is no notion of attribute other than the description supported by keyutils,
35so the [get_attributes](keyring::Entry::get_attributes)
36and [update_attributes](keyring::Entry::update_attributes)
37calls are both no-ops for this credential store.
38
39# Persistence
40
41The key management facility provided by the kernel is completely in-memory and will not persist
42across reboots. Consider the keyring a secure cache and plan for your application to handle
43cases where the entry is no longer available in-memory.
44
45In other words, you should prepare for `Entry::get_password` to fail and have a fallback to re-load
46the credential into memory.
47
48Potential options to re-load the credential into memory are:
49
50- Re-prompt the user (most common/effective for CLI applications)
51- Create a PAM module or use `pam_exec` to load a credential securely when the user logs in.
52- If you're running as a systemd service you can use `systemd-ask-password` to prompt the user
53  when your service starts.
54
55```
56use std::error::Error;
57use keyring_core::Entry;
58
59/// Simple user code that handles retrieving a credential regardless
60/// of the credential state.
61struct CredentialManager {
62    entry: Entry,
63}
64
65impl CredentialManager {
66    /// Init the service as normal
67    pub fn new(service: &str, user: &str) -> Result<Self, Box<dyn Error>> {
68        Ok(Self {
69            entry: Entry::new(service, user)?
70        })
71    }
72
73    /// Method that first attempts to retrieve the credential from memory
74    /// and falls back to prompting the user.
75    pub fn get(&self) -> Result<String, Box<dyn Error>> {
76        self.entry.get_password().or_else(|_| self.prompt())
77    }
78
79    /// Internal method to prompt the user and cache the credential
80    /// in memory for subsequent lookups.
81    fn prompt(&self) -> Result<String, Box<dyn Error>> {
82        let password = rpassword::read_password()?;
83        self.entry.set_password(&password)?;
84        Ok(password)
85    }
86}
87```
88
89A single entry in keyutils can be on multiple "keyrings", each of which has a subtly
90different lifetime.  The core storage for keyring keys is provided by the user-specific
91[persistent keyring](https://www.man7.org/linux/man-pages/man7/persistent-keyring.7.html),
92whose lifetime defaults to a few days (and is controllable by
93administrators).  But whenever an entry's credential is used,
94it is also added to the user's
95[session keyring](https://www.man7.org/linux/man-pages/man7/session-keyring.7.html):
96this ensures that the credential will persist as long as the user session exists, and when the user
97logs out the credential will persist as long as the persistent keyring doesn't expire while the user is
98logged out.
99
100Each time the `Entry::new()` operation is performed, the persistent keyring's expiration timer
101is reset to the value configured in:
102
103```no_run,no_test,ignore
104proc/sys/kernel/keys/persistent_keyring_expiry
105```
106
107| Persistent Keyring State | Session Keyring State | User Key State |
108| -------------            | -------------         | -------------  |
109| Active                   | Active                | Active         |
110| Expired                  | Active                | Active         |
111| Active                   | Logged Out            | Active (Accessible on next login)        |
112| Expired                  | Logged Out            | Expired        |
113
114**Note**: As mentioned above, a reboot clears all keyrings.
115*/
116mod error;
117
118mod cred;
119pub use cred::Cred;
120
121mod store;
122pub use store::Store;
123
124#[cfg(test)]
125mod tests;