Update file permissions (#2499)
## Issue Addressed Resolves #2438 Resolves #2437 ## Proposed Changes Changes the permissions for validator client http server api token file and secret key to 600 from 644. Also changes the permission for logfiles generated using the `--logfile` cli option to 600. Logs the path to the api token instead of the actual api token. Updates docs to reflect the change.
This commit is contained in:
parent
50321c6671
commit
6f18f95893
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1747,6 +1747,7 @@ dependencies = [
|
|||||||
"eth2_config",
|
"eth2_config",
|
||||||
"eth2_network_config",
|
"eth2_network_config",
|
||||||
"exit-future",
|
"exit-future",
|
||||||
|
"filesystem",
|
||||||
"futures",
|
"futures",
|
||||||
"logging",
|
"logging",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
@ -17,10 +17,6 @@ Authorization Basic api-token-0x03eace4c98e8f77477bb99efb74f9af10d800bd3318f92c3
|
|||||||
|
|
||||||
## Obtaining the API token
|
## Obtaining the API token
|
||||||
|
|
||||||
The API token can be obtained via two methods:
|
|
||||||
|
|
||||||
### Method 1: Reading from a file
|
|
||||||
|
|
||||||
The API token is stored as a file in the `validators` directory. For most users
|
The API token is stored as a file in the `validators` directory. For most users
|
||||||
this is `~/.lighthouse/{network}/validators/api-token.txt`. Here's an
|
this is `~/.lighthouse/{network}/validators/api-token.txt`. Here's an
|
||||||
example using the `cat` command to print the token to the terminal, but any
|
example using the `cat` command to print the token to the terminal, but any
|
||||||
@ -31,13 +27,12 @@ $ cat api-token.txt
|
|||||||
api-token-0x03eace4c98e8f77477bb99efb74f9af10d800bd3318f92c33b719a4644254d4123
|
api-token-0x03eace4c98e8f77477bb99efb74f9af10d800bd3318f92c33b719a4644254d4123
|
||||||
```
|
```
|
||||||
|
|
||||||
### Method 2: Reading from logs
|
|
||||||
|
|
||||||
When starting the validator client it will output a log message containing an
|
When starting the validator client it will output a log message containing the path
|
||||||
`api-token` field:
|
to the file containing the api token.
|
||||||
|
|
||||||
```
|
```
|
||||||
Sep 28 19:17:52.615 INFO HTTP API started api_token: api-token-0x03eace4c98e8f77477bb99efb74f9af10d800bd3318f92c33b719a4644254d4123, listen_address: 127.0.0.1:5062
|
Sep 28 19:17:52.615 INFO HTTP API started api_token_file: "$HOME/prater/validators/api-token.txt", listen_address: 127.0.0.1:5062
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
@ -52,7 +52,7 @@ pub enum Error {
|
|||||||
UnableToRemoveACLEntry(String),
|
UnableToRemoveACLEntry(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a file with `600 (-rw-------)` permissions.
|
/// Creates a file with `600 (-rw-------)` permissions and writes the specified bytes to file.
|
||||||
pub fn create_with_600_perms<P: AsRef<Path>>(path: P, bytes: &[u8]) -> Result<(), Error> {
|
pub fn create_with_600_perms<P: AsRef<Path>>(path: P, bytes: &[u8]) -> Result<(), Error> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let mut file = File::create(&path).map_err(Error::UnableToCreateFile)?;
|
let mut file = File::create(&path).map_err(Error::UnableToCreateFile)?;
|
||||||
|
@ -19,6 +19,7 @@ futures = "0.3.7"
|
|||||||
parking_lot = "0.11.0"
|
parking_lot = "0.11.0"
|
||||||
slog-json = "2.3.0"
|
slog-json = "2.3.0"
|
||||||
exit-future = "0.2.0"
|
exit-future = "0.2.0"
|
||||||
|
filesystem = {"path" = "../../common/filesystem"}
|
||||||
|
|
||||||
[target.'cfg(not(target_family = "unix"))'.dependencies]
|
[target.'cfg(not(target_family = "unix"))'.dependencies]
|
||||||
ctrlc = { version = "3.1.6", features = ["termination"] }
|
ctrlc = { version = "3.1.6", features = ["termination"] }
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
use eth2_config::Eth2Config;
|
use eth2_config::Eth2Config;
|
||||||
use eth2_network_config::Eth2NetworkConfig;
|
use eth2_network_config::Eth2NetworkConfig;
|
||||||
|
use filesystem::restrict_file_permissions;
|
||||||
use futures::channel::mpsc::{channel, Receiver, Sender};
|
use futures::channel::mpsc::{channel, Receiver, Sender};
|
||||||
use futures::{future, StreamExt};
|
use futures::{future, StreamExt};
|
||||||
|
|
||||||
@ -169,6 +170,9 @@ impl<E: EthSpec> EnvironmentBuilder<E> {
|
|||||||
.open(&path)
|
.open(&path)
|
||||||
.map_err(|e| format!("Unable to open logfile: {:?}", e))?;
|
.map_err(|e| format!("Unable to open logfile: {:?}", e))?;
|
||||||
|
|
||||||
|
restrict_file_permissions(&path)
|
||||||
|
.map_err(|e| format!("Unable to set file permissions for {:?}: {:?}", path, e))?;
|
||||||
|
|
||||||
// Setting up the initial logger format and building it.
|
// Setting up the initial logger format and building it.
|
||||||
let drain = if let Some(format) = log_format {
|
let drain = if let Some(format) = log_format {
|
||||||
match format.to_uppercase().as_str() {
|
match format.to_uppercase().as_str() {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use eth2::lighthouse_vc::{PK_LEN, SECRET_PREFIX as PK_PREFIX};
|
use eth2::lighthouse_vc::{PK_LEN, SECRET_PREFIX as PK_PREFIX};
|
||||||
|
use filesystem::create_with_600_perms;
|
||||||
use libsecp256k1::{Message, PublicKey, SecretKey};
|
use libsecp256k1::{Message, PublicKey, SecretKey};
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use ring::digest::{digest, SHA256};
|
use ring::digest::{digest, SHA256};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
/// The name of the file which stores the secret key.
|
/// The name of the file which stores the secret key.
|
||||||
@ -37,6 +38,7 @@ pub const PK_FILENAME: &str = "api-token.txt";
|
|||||||
pub struct ApiSecret {
|
pub struct ApiSecret {
|
||||||
pk: PublicKey,
|
pk: PublicKey,
|
||||||
sk: SecretKey,
|
sk: SecretKey,
|
||||||
|
pk_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApiSecret {
|
impl ApiSecret {
|
||||||
@ -55,12 +57,20 @@ impl ApiSecret {
|
|||||||
let sk = SecretKey::random(&mut thread_rng());
|
let sk = SecretKey::random(&mut thread_rng());
|
||||||
let pk = PublicKey::from_secret_key(&sk);
|
let pk = PublicKey::from_secret_key(&sk);
|
||||||
|
|
||||||
fs::write(
|
// Create and write the secret key to file with appropriate permissions
|
||||||
|
create_with_600_perms(
|
||||||
&sk_path,
|
&sk_path,
|
||||||
eth2_serde_utils::hex::encode(&sk.serialize()).as_bytes(),
|
eth2_serde_utils::hex::encode(&sk.serialize()).as_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| {
|
||||||
fs::write(
|
format!(
|
||||||
|
"Unable to create file with permissions for {:?}: {:?}",
|
||||||
|
sk_path, e
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Create and write the public key to file with appropriate permissions
|
||||||
|
create_with_600_perms(
|
||||||
&pk_path,
|
&pk_path,
|
||||||
format!(
|
format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
@ -69,7 +79,12 @@ impl ApiSecret {
|
|||||||
)
|
)
|
||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
)
|
)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| {
|
||||||
|
format!(
|
||||||
|
"Unable to create file with permissions for {:?}: {:?}",
|
||||||
|
pk_path, e
|
||||||
|
)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sk = fs::read(&sk_path)
|
let sk = fs::read(&sk_path)
|
||||||
@ -133,7 +148,7 @@ impl ApiSecret {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { pk, sk })
|
Ok(Self { pk, sk, pk_path })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the public key of `self` as a 0x-prefixed hex string.
|
/// Returns the public key of `self` as a 0x-prefixed hex string.
|
||||||
@ -146,6 +161,11 @@ impl ApiSecret {
|
|||||||
format!("{}{}", PK_PREFIX, self.pubkey_string())
|
format!("{}{}", PK_PREFIX, self.pubkey_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the path for the API token file
|
||||||
|
pub fn api_token_path(&self) -> &PathBuf {
|
||||||
|
&self.pk_path
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the value of the `Authorization` header which is used for verifying incoming HTTP
|
/// Returns the value of the `Authorization` header which is used for verifying incoming HTTP
|
||||||
/// requests.
|
/// requests.
|
||||||
fn auth_header_value(&self) -> String {
|
fn auth_header_value(&self) -> String {
|
||||||
|
@ -125,7 +125,7 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let authorization_header_filter = ctx.api_secret.authorization_header_filter();
|
let authorization_header_filter = ctx.api_secret.authorization_header_filter();
|
||||||
let api_token = ctx.api_secret.api_token();
|
let api_token_path = ctx.api_secret.api_token_path();
|
||||||
let signer = ctx.api_secret.signer();
|
let signer = ctx.api_secret.signer();
|
||||||
let signer = warp::any().map(move || signer.clone());
|
let signer = warp::any().map(move || signer.clone());
|
||||||
|
|
||||||
@ -505,7 +505,7 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
|||||||
log,
|
log,
|
||||||
"HTTP API started";
|
"HTTP API started";
|
||||||
"listen_address" => listening_socket.to_string(),
|
"listen_address" => listening_socket.to_string(),
|
||||||
"api_token" => api_token,
|
"api_token_file" => ?api_token_path,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok((listening_socket, server))
|
Ok((listening_socket, server))
|
||||||
|
Loading…
Reference in New Issue
Block a user