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:
Pawan Dhananjay 2021-09-03 02:41:10 +00:00
parent 50321c6671
commit 6f18f95893
7 changed files with 38 additions and 17 deletions

1
Cargo.lock generated
View File

@ -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",

View File

@ -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

View File

@ -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)?;

View File

@ -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"] }

View File

@ -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() {

View File

@ -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 {

View File

@ -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))