-
Notifications
You must be signed in to change notification settings - Fork 519
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
dogtag: implement imds and reverse dns hostname tools
- Loading branch information
Showing
9 changed files
with
231 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -89,6 +89,8 @@ members = [ | |
|
||
"imdsclient", | ||
|
||
"dogtag", | ||
|
||
"driverdog", | ||
|
||
"early-boot-config/early-boot-config", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "dogtag" | ||
version = "0.1.0" | ||
authors = ["Jarrett Tierney <[email protected]>"] | ||
license = "Apache-2.0 OR MIT" | ||
edition = "2021" | ||
publish = false | ||
exclude = ["README.md"] | ||
|
||
[[bin]] | ||
name = "20-imds" | ||
path = "bin/imds.rs" | ||
|
||
[[bin]] | ||
name = "10-reverse-dns" | ||
path = "bin/reverse.rs" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
argh = "0.1" | ||
dns-lookup = "2" | ||
imdsclient = { version = "0.1", path = "../imdsclient" } | ||
log = "0.4" | ||
snafu = "0.8" | ||
tokio = { version = "1.32", features = ["full"]} | ||
walkdir = "2.4" | ||
|
||
[build-dependencies] | ||
generate-readme = { version = "0.1", path = "../generate-readme" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# dogtag | ||
|
||
Current version: 0.1.0 | ||
|
||
dogtag resolves the hostname of a bottlerocket server/instance. It's used to generate settings.network.hostname. To accomplish this, it uses a set of standalone binaries in /var/bottlerocket/dogtag that resolve the hostname via different methods. | ||
|
||
Currently, bottlerocket ships with two hostname resolver binaries: | ||
|
||
20-imds - Fetches hostname from EC2 Instance Metadata Service | ||
10-reverse-dns - Uses reverse DNS lookup to resolve the hostname | ||
|
||
dogtag runs the resolvers in /var/bottlerocket/dogtag in reverse alphanumerical order until one of them returns a hostname, at which point it will exit early and print the returned hostname to stdout. | ||
|
||
## Colophon | ||
|
||
This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/main.rs`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# {{crate}} | ||
|
||
Current version: {{version}} | ||
|
||
{{readme}} | ||
|
||
## Colophon | ||
|
||
This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/main.rs`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
use dogtag::Cli; | ||
use imdsclient::ImdsClient; | ||
use snafu::{OptionExt, ResultExt}; | ||
|
||
type Result<T> = std::result::Result<T, error::Error>; | ||
|
||
/// Implements a hostname lookup tool by fetching the public hostname | ||
/// from the instance metadata via IMDS. It will interface with IMDS | ||
/// via: | ||
/// | ||
/// * Check for IPv6, default to IPv4 if not available | ||
/// * Check for IMDSv2, fallback to IMDSv1 if not enabled | ||
#[tokio::main] | ||
async fn main() -> Result<()> { | ||
// Even though for this helper we do not need any arguments | ||
// still validate to ensure the helper follows standards. | ||
let _: Cli = argh::from_env(); | ||
let mut imds = ImdsClient::new(); | ||
let hostname = imds | ||
.fetch_hostname() | ||
.await | ||
.context(error::ImdsSnafu)? | ||
.context(error::NoHostnameSnafu)?; | ||
println!("{}", hostname); | ||
Ok(()) | ||
} | ||
|
||
mod error { | ||
use snafu::Snafu; | ||
|
||
#[derive(Debug, Snafu)] | ||
#[snafu(visibility(pub(super)))] | ||
pub(super) enum Error { | ||
#[snafu(display("failed to fetch hostname from IMDS: {}", source))] | ||
Imds { source: imdsclient::Error }, | ||
#[snafu(display("no hostname returned by imds"))] | ||
NoHostname, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use dns_lookup::lookup_addr; | ||
use dogtag::Cli; | ||
use snafu::ResultExt; | ||
|
||
type Result<T> = std::result::Result<T, error::Error>; | ||
|
||
/// Looks up the public hostname by using dns-lookup to | ||
/// resolve it from the ip address provided | ||
fn main() -> Result<()> { | ||
let cli: Cli = argh::from_env(); | ||
let ip: std::net::IpAddr = cli.ip_address.parse().context(error::InvalidIpSnafu)?; | ||
let hostname = lookup_addr(&ip).context(error::LookupSnafu)?; | ||
println!("{}", hostname); | ||
Ok(()) | ||
} | ||
|
||
mod error { | ||
use snafu::Snafu; | ||
|
||
#[derive(Debug, Snafu)] | ||
#[snafu(visibility(pub(super)))] | ||
pub(super) enum Error { | ||
#[snafu(display("Invalid ip address passed to tool {}", source))] | ||
InvalidIp { | ||
#[snafu(source(from(std::net::AddrParseError, Box::new)))] | ||
source: Box<std::net::AddrParseError>, | ||
}, | ||
#[snafu(display("Failed to lookup hostname via dns {}", source))] | ||
Lookup { | ||
#[snafu(source(from(std::io::Error, Box::new)))] | ||
source: Box<std::io::Error>, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
generate_readme::from_lib().unwrap() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/*! | ||
dogtag resolves the hostname of a bottlerocket server/instance. It's used to generate settings.network.hostname. To accomplish this, it uses a set of standalone binaries in /var/bottlerocket/dogtag that resolve the hostname via different methods. | ||
Currently, bottlerocket ships with two hostname resolver binaries: | ||
20-imds - Fetches hostname from EC2 Instance Metadata Service | ||
10-reverse-dns - Uses reverse DNS lookup to resolve the hostname | ||
dogtag runs the resolvers in /var/bottlerocket/dogtag in reverse alphanumerical order until one of them returns a hostname, at which point it will exit early and print the returned hostname to stdout. | ||
*/ | ||
use argh::FromArgs; | ||
use log::debug; | ||
use snafu::ResultExt; | ||
use std::{path::PathBuf, process}; | ||
use walkdir::WalkDir; | ||
|
||
const DOGTAG_BIN_PATH: &str = "/var/bottlerocket/dogtag"; | ||
|
||
/// Cli defines the standard cmdline interface for all hostname handlers | ||
#[derive(FromArgs)] | ||
#[argh(description = "hostname resolution tool")] | ||
pub struct Cli { | ||
#[argh(option)] | ||
#[argh(description = "ip_address of the host")] | ||
pub ip_address: String, | ||
} | ||
|
||
pub type Result<T> = std::result::Result<T, error::Error>; | ||
|
||
/// find_hostname will utilize the helpers located in /var/bottlerocket/dogtag/ to try and discover the hostname | ||
pub async fn find_hostname() -> Result<String> { | ||
debug!( | ||
"attempting to discover hostname helpers in {}", | ||
DOGTAG_BIN_PATH | ||
); | ||
// We want to do reverse sort as we want to prioritize higher numbers first | ||
// this is because it makes it easier to add more of these and not have to worry about | ||
// bumping the binary name for existing ones | ||
let mut hostname_helpers: Vec<PathBuf> = WalkDir::new(DOGTAG_BIN_PATH) | ||
.max_depth(1) | ||
.min_depth(1) | ||
.sort_by_file_name() | ||
.into_iter() | ||
.collect::<std::result::Result<Vec<_>, _>>() | ||
.context(error::WalkdirSnafu)? | ||
.into_iter() | ||
.map(|x| x.into_path()) | ||
.collect(); | ||
hostname_helpers.reverse(); | ||
|
||
for helper in hostname_helpers.iter() { | ||
let output = process::Command::new(helper) | ||
.output() | ||
.map(Some) | ||
.unwrap_or(None); | ||
if let Some(output) = output.as_ref() { | ||
// Read the std output | ||
if output.status.success() { | ||
let hostname = String::from_utf8_lossy(output.stdout.as_slice()).to_string(); | ||
return Ok(hostname.trim().to_string()); | ||
} | ||
} | ||
} | ||
Err(error::Error::NoHelper {}) | ||
} | ||
|
||
pub mod error { | ||
use snafu::Snafu; | ||
|
||
#[derive(Snafu, Debug)] | ||
#[snafu(visibility(pub))] | ||
pub enum Error { | ||
#[snafu(display("Failed to detect hostname due to an io error: {}", source))] | ||
Walkdir { source: walkdir::Error }, | ||
#[snafu(display( | ||
"Failed to detect hostname, no helpers are installed in path or io error occurred" | ||
))] | ||
NoHelper, | ||
#[snafu(display( | ||
"Failed to detect hostname, no helper installed was able to resolve the hostname" | ||
))] | ||
FailHostname, | ||
} | ||
} |