Skip to content

Commit

Permalink
certdog: Adjust certdog to use a generated configuration file
Browse files Browse the repository at this point in the history
  • Loading branch information
jmt-lab committed Feb 2, 2024
1 parent 2b1a787 commit 8dd9b5c
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 37 deletions.
6 changes: 5 additions & 1 deletion Release.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = "1.19.0"
version = "1.20.0"

[migrations]
"(0.3.1, 0.3.2)" = ["migrate_v0.3.2_admin-container-v0-5-0.lz4"]
Expand Down Expand Up @@ -264,3 +264,7 @@ version = "1.19.0"
"(1.18.0, 1.19.0)" = [
"migrate_v1.19.0_add-additional-ecs-settings.lz4",
]
"(1.19.0, 1.20.0)" = [
"migrate_v1.20.0_certdog-config-file-v0-1-0.lz4",
"migrate_v1.20.0_certdog-service-cfg-v0-1-0.lz4",
]
2 changes: 1 addition & 1 deletion Twoliter.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
schema-version = 1
release-version = "1.19.0"
release-version = "1.20.0"

[sdk]
registry = "public.ecr.aws/bottlerocket"
Expand Down
11 changes: 11 additions & 0 deletions packages/os/certdog-toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[required-extensions]
std = { version = "v1", helpers = ["default"]}
pki = "v1"
+++
{{#if settings.pki}}
{{#each settings.pki}}
["{{@key}}"]
trusted = {{this.trusted}}
data = "{{this.data}}"
{{/each}}
{{/if}}
4 changes: 3 additions & 1 deletion packages/os/os.spec
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Source12: 00-resolved.conf
%if %{with k8s_runtime}
Source13: cis-checks-k8s-metadata-json
%endif
Source14: certdog-toml

# 1xx sources: systemd units
Source100: apiserver.service
Expand Down Expand Up @@ -472,7 +473,7 @@ install -d %{buildroot}%{_cross_datadir}/updog
install -p -m 0644 %{_cross_repo_root_json} %{buildroot}%{_cross_datadir}/updog

install -d %{buildroot}%{_cross_templatedir}
install -p -m 0644 %{S:5} %{S:6} %{S:7} %{S:8} %{buildroot}%{_cross_templatedir}
install -p -m 0644 %{S:5} %{S:6} %{S:7} %{S:8} %{S:14} %{buildroot}%{_cross_templatedir}

install -d %{buildroot}%{_cross_unitdir}
install -p -m 0644 \
Expand Down Expand Up @@ -684,6 +685,7 @@ install -p -m 0644 %{S:400} %{S:401} %{S:402} %{buildroot}%{_cross_licensedir}

%files -n %{_cross_os}certdog
%{_cross_bindir}/certdog
%{_cross_templatedir}/certdog-toml

%files -n %{_cross_os}bootstrap-containers
%{_cross_bindir}/bootstrap-containers
Expand Down
15 changes: 15 additions & 0 deletions sources/Cargo.lock

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

2 changes: 2 additions & 0 deletions sources/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ members = [
"api/migration/migrations/v1.18.0/aws-control-container-v0-7-7",
"api/migration/migrations/v1.18.0/public-control-container-v0-7-7",
"api/migration/migrations/v1.19.0/add-additional-ecs-settings",
"api/migration/migrations/v1.20.0/certdog-config-file-v0-1-0",
"api/migration/migrations/v1.20.0/certdog-service-cfg-v0-1-0",

"bloodhound",

Expand Down
1 change: 1 addition & 0 deletions sources/api/certdog/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ serde_json = "1"
simplelog = "0.12"
snafu = "0.7"
tokio = { version = "~1.32", default-features = false, features = ["macros", "rt-multi-thread"] } # LTS
toml = "0.8"
x509-parser = "0.15"

[dev-dependencies]
Expand Down
69 changes: 36 additions & 33 deletions sources/api/certdog/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ use std::fmt::Write;
use std::fs;
use std::io::BufReader;
use std::io::{BufRead, Seek};
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process;

use model::modeled_types::Identifier;
use model::PemCertificate;

// Default location of the config file
const DEFAULT_CONFIG_FILE: &str = "/etc/certdog.toml";
// Read from the source in `/usr/share/factory` not the copy in `/etc`
const DEFAULT_SOURCE_BUNDLE: &str = "/usr/share/factory/etc/pki/tls/certs/ca-bundle.crt";
// This file is first created with tmpfilesd configurations
Expand All @@ -36,9 +39,9 @@ struct Args {
#[argh(option, default = "LevelFilter::Info", short = 'l')]
/// log-level trace|debug|info|warn|error
log_level: LevelFilter,
#[argh(option, default = "constants::API_SOCKET.to_string()", short = 's')]
/// socket-path path to apiserver socket
socket_path: String,
#[argh(option, default = "PathBuf::from(DEFAULT_CONFIG_FILE)", short = 'c')]
/// config-path path to apiserver socket
config_path: PathBuf,
#[argh(option, default = "DEFAULT_TRUSTED_STORE.to_string()", short = 't')]
/// trusted-store path to the trusted store
trusted_store: String,
Expand All @@ -47,37 +50,37 @@ struct Args {
source_bundle: String,
}

#[derive(Default)]
struct CertBundle {
trusted_certs: Vec<x509_parser::pem::Pem>,
distrusted_certs: Vec<x509_parser::pem::Pem>,
}

/// Query the API for the certificate bundles, returns a tuple with trusted
/// and distrusted PEM certificates
async fn get_certificate_bundles<P>(socket_path: P) -> Result<CertBundle>
async fn get_certificate_bundles<P>(config_path: P) -> Result<CertBundle>
where
P: AsRef<Path>,
{
debug!("Querying the API for settings");

let method = "GET";
let uri = constants::API_SETTINGS_URI;
let (_code, response_body) = apiclient::raw_request(&socket_path, uri, method, None)
.await
.context(error::APIRequestSnafu { method, uri })?;
debug!("Loading certdog configuration");
let config_path = config_path.as_ref();
if !config_path.exists() {
return Ok(CertBundle::default());
}

// Build a Settings struct from the response string
debug!("Deserializing response");
let settings: model::Settings =
serde_json::from_str(&response_body).context(error::ResponseJsonSnafu { uri })?;
let config_str = fs::read_to_string(config_path).context(error::ConfigReadSnafu {
config: format!("{:?}", config_path),
})?;
let pki: HashMap<Identifier, PemCertificate> =
toml::from_str(config_str.as_str()).context(error::ConfigDeserializationSnafu {
config: format!("{:?}", config_path),
})?;

split_bundles(settings.pki.unwrap_or_default())
split_bundles(pki)
}

/// Returns a tuple with two lists, for trusted and distrusted certificates
fn split_bundles(
certificates_bundle: HashMap<Identifier, model::PemCertificate>,
) -> Result<CertBundle> {
fn split_bundles(certificates_bundle: HashMap<Identifier, PemCertificate>) -> Result<CertBundle> {
let mut trusted_certs: Vec<x509_parser::pem::Pem> = Vec::new();
let mut distrusted_certs: Vec<x509_parser::pem::Pem> = Vec::new();

Expand Down Expand Up @@ -210,7 +213,7 @@ async fn run() -> Result<()> {
SimpleLogger::init(args.log_level, LogConfig::default()).context(error::LoggerSnafu)?;

info!("certdog started");
let certificate_bundles = get_certificate_bundles(&args.socket_path).await?;
let certificate_bundles = get_certificate_bundles(&args.config_path).await?;
info!("Got certificate bundles from API");
update_trusted_store(certificate_bundles, args.trusted_store, args.source_bundle)?;
info!("Updated trusted store");
Expand Down Expand Up @@ -238,12 +241,18 @@ mod error {
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(super)))]
pub(super) enum Error {
#[snafu(display("Error sending {} to {}: {}", method, uri, source))]
APIRequest {
method: String,
uri: String,
#[snafu(source(from(apiclient::Error, Box::new)))]
source: Box<apiclient::Error>,
#[snafu(display("Error reading data from configuration at {}: {}", config, source))]
ConfigRead {
config: String,
#[snafu(source(from(std::io::Error, Box::new)))]
source: Box<std::io::Error>,
},

#[snafu(display("Error deserializing pki from configuration at {}: {}", config, source))]
ConfigDeserialization {
config: String,
#[snafu(source(from(toml::de::Error, Box::new)))]
source: Box<toml::de::Error>,
},

#[snafu(display("Unable to decode base64 from certificate '{}': {}", name, source))]
Expand Down Expand Up @@ -274,12 +283,6 @@ mod error {
#[snafu(display("Error while reading bundle from file '{}': {}", path.display(), source))]
ReadSourceBundle { path: PathBuf, source: io::Error },

#[snafu(display("Error deserializing response from '{}': {}", uri, source))]
ResponseJson {
uri: String,
source: serde_json::Error,
},

#[snafu(display("Failed to update trust store: {}", source))]
UpdateTrustedStore { source: io::Error },

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "certdog-config-file-v0-1-0"
version = "0.1.0"
authors = ["Jarrett Tierney <[email protected]>"]
license = "Apache-2.0 OR MIT"
edition = "2021"
publish = false
# Don't rebuild crate just because of changes to README.
exclude = ["README.md"]

[dependencies]
migration-helpers = { path = "../../../migration-helpers", version = "0.1.0" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use migration_helpers::common_migrations::{
AddPrefixesMigration, ListReplacement, ReplaceListsMigration,
};
use migration_helpers::{migrate, Result};
use std::process;

/// Add settings for the new certdog-toml config file
fn run() -> Result<()> {
migrate(AddPrefixesMigration(vec![
"services.pki",
"configuration-files.certdog-toml",
]))
}

fn main() {
if let Err(e) = run() {
eprintln!("{}", e);
process::exit(1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "certdog-service-cfg-v0-1-0"
version = "0.1.0"
authors = ["Jarrett Tierney <[email protected]>"]
license = "Apache-2.0 OR MIT"
edition = "2021"
publish = false
# Don't rebuild crate just because of changes to README.
exclude = ["README.md"]

[dependencies]
migration-helpers = { path = "../../../migration-helpers", version = "0.1.0" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use migration_helpers::common_migrations::{
AddPrefixesMigration, ListReplacement, ReplaceListsMigration,
};
use migration_helpers::{migrate, Result};
use std::process;

/// Add settings for the new certdog-toml config file
fn run() -> Result<()> {
migrate(ReplaceListsMigration(vec![ListReplacement {
setting: "services.pki.configuration-files",
old_vals: &[],
new_vals: &["certdog-toml"],
}]))
}

fn main() {
if let Err(e) = run() {
eprintln!("{}", e);
process::exit(1);
}
}
6 changes: 5 additions & 1 deletion sources/models/shared-defaults/defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ affected-services = ["bootstrap-containers"]
# Certdog

[services.pki]
configuration-files = []
configuration-files = ["certdog-toml"]
restart-commands = ["/usr/bin/certdog"]

# DNS
Expand All @@ -176,3 +176,7 @@ restart-commands = ["netdog write-resolv-conf"]
[configuration-files.netdog-toml]
path = "/etc/netdog.toml"
template-path = "/usr/share/templates/netdog-toml"

[configuration-files.certdog-toml]
path = "/etc/certdog.toml"
template-path = "/usr/share/templates/certdog-toml"

0 comments on commit 8dd9b5c

Please sign in to comment.