Harden systemd unit

master
Edward Shen 2023-07-28 02:04:29 -07:00
parent 6c8298aeec
commit f138148581
Signed by: edward
GPG Key ID: 0A400FFE10097C30
2 changed files with 38 additions and 11 deletions

View File

@ -57,7 +57,7 @@ pub struct Args {
#[derive(Subcommand, Clone, Debug)] #[derive(Subcommand, Clone, Debug)]
pub enum Command { pub enum Command {
/// Fetch a reflected IP address and update A and AAAA entries in DNS. /// Fetch a reflected IP address and update A and AAAA entries in DNS.
Run, Run(Run),
/// List all A and AAAA entries in each zone in the config. /// List all A and AAAA entries in each zone in the config.
List(List), List(List),
} }
@ -107,6 +107,13 @@ impl Display for Color {
} }
} }
#[derive(Parser, Clone, Debug)]
pub struct Run {
/// The directory to store cache files.
#[clap(long)]
cache_dir: Option<PathBuf>,
}
fn main() -> ExitCode { fn main() -> ExitCode {
let runtime = Runtime::new().unwrap(); let runtime = Runtime::new().unwrap();
let result = runtime.block_on(real_main()); let result = runtime.block_on(real_main());
@ -149,12 +156,12 @@ async fn real_main() -> Result<()> {
let config = load_config(args.config_file).context("Failed to find a suitable config file")?; let config = load_config(args.config_file).context("Failed to find a suitable config file")?;
match args.cmd { match args.cmd {
Command::Run => handle_run(config).await, Command::Run(run) => handle_run(config, run).await,
Command::List(list) => handle_list(config, list).await, Command::List(list) => handle_list(config, list).await,
} }
} }
async fn handle_run(conf: Config) -> Result<()> { async fn handle_run(conf: Config, run: Run) -> Result<()> {
let ipv4 = if let Some(addr_to_req) = conf.ip_reflector.ipv4 { let ipv4 = if let Some(addr_to_req) = conf.ip_reflector.ipv4 {
let ip = get_ipv4(addr_to_req) let ip = get_ipv4(addr_to_req)
.await .await
@ -176,7 +183,7 @@ async fn handle_run(conf: Config) -> Result<()> {
None None
}; };
let ip_cache_path = ip_cache_path().context("while getting the ip cache path")?; let ip_cache_path = ip_cache_path(run.cache_dir).context("while getting the ip cache path")?;
let mut cache_file = load_ip_cache(&ip_cache_path).context("while loading the ip cache")?; let mut cache_file = load_ip_cache(&ip_cache_path).context("while loading the ip cache")?;
let mut rate_limit = time::interval(Duration::from_millis(250)); let mut rate_limit = time::interval(Duration::from_millis(250));
@ -293,8 +300,10 @@ fn load_ip_cache<P: AsRef<Path> + Debug>(path: P) -> Result<CacheFile> {
}) })
} }
fn ip_cache_path() -> Result<PathBuf> { #[instrument(level = "debug", ret)]
dirs::cache_dir() fn ip_cache_path(cache_dir: Option<PathBuf>) -> Result<PathBuf> {
cache_dir
.or(dirs::cache_dir())
.context("Failed to determine cache directory") .context("Failed to determine cache directory")
.map(|path| path.join("cloudflare-ddns.cache")) .map(|path| path.join("cloudflare-ddns.cache"))
} }

View File

@ -5,13 +5,16 @@ After=network-online.target
[Service] [Service]
Type=oneshot Type=oneshot
ExecStart=/usr/bin/cloudflare-ddns run ExecStart=/usr/bin/cloudflare-ddns run --config-file "${CREDENTIALS_DIRECTORY}/cloudflare-ddns.toml" --cache-dir "${CACHE_DIRECTORY}"
# Please modify the path after the : to point to a custom config location if you'd like
LoadCredential=cloudflare-ddns.toml:/etc/cloudflare-ddns.toml
# Security Hardening
# Run `systemd-analyze security cloudflare-ddns` for recommendations
# Security
NoNewPrivileges=true NoNewPrivileges=true
ProtectSystem=strict
# Sandboxing config
ProtectSystem=true
PrivateTmp=true PrivateTmp=true
PrivateDevices=true PrivateDevices=true
ProtectHostname=true ProtectHostname=true
@ -25,6 +28,21 @@ LockPersonality=true
MemoryDenyWriteExecute=true MemoryDenyWriteExecute=true
RestrictRealtime=true RestrictRealtime=true
RestrictSUIDSGID=true RestrictSUIDSGID=true
CapabilityBoundingSet=
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged
SystemCallFilter=~@resources
ProtectProc=invisible
ProcSubset=pid
RestrictAddressFamilies=AF_INET AF_INET6
UMask=066
DynamicUser=true
CacheDirectory=cloudflare-ddns
PrivateUsers=true
ProtectHome=true
# Refuse to execute any other binary
ExecPaths=/usr/bin/cloudflare-ddns
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target