Skip to content

Commit

Permalink
feat: Make vault + cloudflare calls only on update
Browse files Browse the repository at this point in the history
  • Loading branch information
pabrahamsson committed Nov 1, 2022
1 parent bf553a6 commit 387126b
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 117 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "cf-dns-record-update"
version = "0.2.3"
edition = "2018"
version = "0.3.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
180 changes: 66 additions & 114 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use vaultrs::{
auth::kubernetes::login,
client::{Client as VCClient, VaultClient, VaultClientSettingsBuilder},
error::ClientError,
token,
};

const JWT_TOKEN_PATH: &str = "/var/run/secrets/kubernetes.io/serviceaccount/token";
Expand Down Expand Up @@ -106,12 +105,6 @@ fn print_type_of<T>(_: &T) {
}
*/

async fn set_default_env_var(key: &str, value: &str) {
if env::var(key).is_err() {
env::set_var(key, value);
}
}

async fn handle_cf_error(api_failure: &ApiFailure) {
match api_failure {
ApiFailure::Error(status, errors) => {
Expand All @@ -136,27 +129,26 @@ async fn get_zone_id(zone_name: &str, api_client: &CFClient) -> Option<String> {
span.set_attribute(KeyValue::new("dns.zone", zone_name.to_string()));
let cx = Context::current_with_span(span);

let response = api_client
match api_client
.request_handle(&zone::ListZones {
params: zone::ListZonesParams {
name: Some(zone_name.to_string()),
..Default::default()
},
})
.with_context(cx)
.await;
match response {
Ok(records) => {
if records.result.len() == 1 {
Some(records.result[0].id.clone())
} else {
panic!("No zone found for: {}", zone_name)
.await {
Ok(records) => {
if records.result.len() == 1 {
Some(records.result[0].id.clone())
} else {
panic!("No zone found for: {zone_name}")
}
}
Err(e) => {
handle_cf_error(&e).await;
None
}
}
Err(e) => {
handle_cf_error(&e).await;
None
}
}
}

Expand All @@ -171,7 +163,7 @@ async fn get_current_record(
span.set_attribute(KeyValue::new("dns.zone", zone_identifier.to_string()));
let cx = Context::current_with_span(span);

let response = api_client
match api_client
.request_handle(&dns::ListDnsRecords {
zone_identifier,
params: dns::ListDnsRecordsParams {
Expand All @@ -180,19 +172,18 @@ async fn get_current_record(
},
})
.with_context(cx)
.await;
match response {
Ok(records) => {
if records.result.len() == 1 {
Some(records.result[0].id.clone())
} else {
panic!("Unable to lookup address for: {}", record_name)
.await {
Ok(records) => {
if records.result.len() == 1 {
Some(records.result[0].id.clone())
} else {
panic!("Unable to lookup address for: {}", record_name)
}
}
Err(e) => {
handle_cf_error(&e).await;
None
}
}
Err(e) => {
handle_cf_error(&e).await;
None
}
}
}

Expand All @@ -209,32 +200,40 @@ async fn update_record(
span.set_attribute(KeyValue::new("dns.name", name.to_string()));
let cx = Context::current_with_span(span);

let response = api_client
match api_client
.request_handle(&dns::UpdateDnsRecord {
zone_identifier,
identifier: record_identifier,
params: dns::UpdateDnsRecordParams {
ttl: Some(60),
proxied: None,
name,
content: dns::DnsContent::A { content: *address },
content: dns::DnsContent::A {
content: *address,
},
},
})
.with_context(cx)
.await;
match response {
Ok(_) => Some(()),
Err(e) => {
handle_cf_error(&e).await;
None
}
.await {
Ok(_) => Some(()),
Err(e) => {
handle_cf_error(&e).await;
None
}
}
}

async fn create_cf_api_client(credentials: Credentials) -> CFClient {
async fn create_cf_api_client(client: &VaultClient) -> CFClient {
let tracer = global::tracer("create_cf_api_client");
let mut span = tracer.start("Create CF API Client...");

let response: VaultKV2 = vaultrs::kv2::read(client, "ocp/cf-dyn-dns", "cf-api")
//.with_context(Context::current_with_span(span))
.await
.unwrap();
let credentials: Credentials = Credentials::UserAuthToken {
token: response.key.trim_matches('"').to_string(),
};
let api_client = CFClient::new(
credentials,
HttpApiClientConfig::default(),
Expand All @@ -245,7 +244,7 @@ async fn create_cf_api_client(credentials: Credentials) -> CFClient {
api_client
}

async fn dns(zone_name: &str, record_name: &str, vault_client: &mut VaultClient) {
async fn dns(zone_name: &str, record_name: &str) {
let tracer = global::tracer("dns");
let span = tracer.start("Dns logic...");
let cx = Context::current_with_span(span);
Expand All @@ -267,11 +266,7 @@ async fn dns(zone_name: &str, record_name: &str, vault_client: &mut VaultClient)
"DNS record for {} ({} ==> {}) will be updated",
record_name, &lookup_ip, &current_ip
);
let cf_credentials = create_cf_credential(vault_client)
.with_context(cx.clone())
.await
.expect("Failed to create CF credentials");
let api_client = create_cf_api_client(cf_credentials)
let api_client = create_cf_api_client(&create_vault_client().await.unwrap())
.with_context(cx.clone())
.await;
let zone_identifier = get_zone_id(zone_name, &api_client)
Expand Down Expand Up @@ -313,64 +308,35 @@ async fn dns_lookup(resolver: IpAddr, hostname: &str) -> Ipv4Addr {
rrset.rdata[0].address
}

async fn get_vault_client_with_token(
client: &mut VaultClient,
) -> Result<&mut VaultClient, ClientError> {
let tracer = global::tracer("vault_token_with_client");
let span = tracer.start("Getting vault client...");
async fn create_vault_client() -> Result<VaultClient, ClientError> {
let tracer = global::tracer("create_vault_client");
let span = tracer.start("Creating vault client...");
let cx = Context::current_with_span(span);

if client.settings.token.is_empty()
|| (get_token_ttl(client).with_context(cx.clone()).await.unwrap() < 120)
{
info!("Creating Vault client with token");

set_default_env_var("JWT_TOKEN_PATH", JWT_TOKEN_PATH).await;
let jwt_token_path = env::var("JWT_TOKEN_PATH").unwrap();
let jwt = fs::read_to_string(jwt_token_path).unwrap();
let mount = "ocp/cf-dyn-dns-k8s";
let role = "cf-dyn-dns-secret-reader";
match login(client, mount, role, &jwt).with_context(cx.clone()).await {
let vault_addr = env::var("VAULT_ADDR").unwrap_or_else(|_| VAULT_ADDR.to_string());
let mut vault_client = VaultClient::new(
VaultClientSettingsBuilder::default()
.address(&vault_addr)
.verify(true)
.build()
.unwrap(),
)
.unwrap();
let jwt_token_path = env::var("JWT_TOKEN_PATH").unwrap_or_else(|_| JWT_TOKEN_PATH.to_string());
let jwt = fs::read_to_string(jwt_token_path).unwrap();
let mount = "ocp/cf-dyn-dns-k8s";
let role = "cf-dyn-dns-secret-reader";
match login(&vault_client, mount, role, &jwt)
.with_context(cx.clone())
.await {
Ok(response) => {
client.set_token(&response.client_token);
Ok(client)
vault_client.set_token(&response.client_token);
Ok(vault_client)
}
Err(e) => Err(e),
}
} else {
Ok(client)
}
}

async fn get_token_ttl(client: &VaultClient) -> Result<u64, vaultrs::error::ClientError> {
let tracer = global::tracer("get_token_ttl");
let span = tracer.start("Getting vault token ttl...");
let cx = Context::current_with_span(span);

match token::lookup_self(client).with_context(cx).await {
Ok(self_token) => Ok(self_token.ttl),
Err(e) => {
warn!("renew_vault_lease: {}", e);
Err(e)
}
}
}

async fn create_cf_credential(client: &VaultClient) -> Result<Credentials, ClientError> {
let tracer = global::tracer("create_cf_credential");
let span = tracer.start("Creating CF api credentials...");
let cx = Context::current_with_span(span);

let response: VaultKV2 = vaultrs::kv2::read(client, "ocp/cf-dyn-dns", "cf-api")
.with_context(cx)
.await
.unwrap();
let credentials: Credentials = Credentials::UserAuthToken {
token: response.key.trim_matches('"').to_string(),
};
Ok(credentials)
}

fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
opentelemetry_jaeger::new_agent_pipeline()
.with_service_name("cf-dyn-dns")
Expand All @@ -386,27 +352,13 @@ fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
pub async fn run(
config: Config<'_>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
set_default_env_var("VAULT_ADDR", VAULT_ADDR).await;
let vault_addr = env::var("VAULT_ADDR").unwrap();
let mut vault_client = VaultClient::new(
VaultClientSettingsBuilder::default()
.address(&vault_addr)
.verify(true)
.build()
.unwrap(),
)
.unwrap();

loop {
let tracer = init_tracer()?;
let span = tracer.start("root");
let cx = Context::current_with_span(span);
let vault_client_with_token = get_vault_client_with_token(&mut vault_client)
.with_context(cx.clone())
.await
.expect("Failed to get Vault client");

dns(config.zone, config.record, vault_client_with_token)
dns(config.zone, config.record)
.with_context(cx)
.await;

Expand Down

0 comments on commit 387126b

Please sign in to comment.