Skip to content

Better attestations #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 19, 2025
Merged

Better attestations #186

merged 13 commits into from
Aug 19, 2025

Conversation

kpcyrd
Copy link
Owner

@kpcyrd kpcyrd commented Aug 18, 2025

This introduces:

  • a long-term in-toto key for the rebuilderd daemon itself
  • attestations submitted by workers get an additional signature from the long-term key
  • an http endpoint that can be used to query the set of public keys the daemon identifies with
  • Old attestations are getting signed with the new long-term key when fetched through the api
    • This can be disabled through the config file

This is related (but not blocked by) my patch in in-toto/in-toto-rs#111

@alexhulbert
Copy link

This is perfect! Thank you so much!

@kpcyrd kpcyrd requested a review from Copilot August 19, 2025 16:44
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces long-term cryptographic key management and attestation signing capabilities to the rebuilderd daemon. The changes establish a persistent identity for the daemon and enhance the integrity of attestations through additional signatures.

  • Introduces automatic generation and management of long-term Ed25519 signing keys for the daemon
  • Adds cryptographic attestation signing functionality using in-toto standards
  • Implements transparent re-signing of existing attestations with the daemon's key when fetched via API

Reviewed Changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
daemon/src/attestation.rs New module implementing cryptographic key management and attestation signing using in-toto
daemon/src/args.rs New command-line argument parser with key generation and signing key options
daemon/src/main.rs Refactored main function to support key generation commands and private key loading
daemon/src/lib.rs Updated to integrate attestation module and pass private key to web handlers
daemon/src/api.rs Enhanced with new public key endpoint and attestation signing in build reports
daemon/src/config.rs Added configuration option for transparent attestation signing
common/src/utils.rs New utility function for atomic file creation and key loading
tests/src/main.rs Comprehensive test suite additions for attestation verification and key management
worker/src/auth.rs Refactored to use shared utility function for key loading
Multiple config files Updated configuration templates and dependency specifications

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@@ -14,7 +14,7 @@ pub async fn download(url_str: &str, path: &Path) -> Result<PathBuf> {
let filename = url
.path_segments()
.ok_or_else(|| format_err!("Url doesn't seem to have a path"))?
.last()
.next_back()
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using next_back() instead of last() is unnecessary here. Both methods return the last element of the iterator, but last() is more idiomatic and clearly expresses the intent to get the final element.

Suggested change
.next_back()
.last()

Copilot uses AI. Check for mistakes.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clippy disagrees:

warning: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator

@@ -19,6 +19,7 @@ impl actix_web::error::ResponseError for Error {}

impl From<errors::Error> for Error {
fn from(err: errors::Error) -> Error {
errors::error!("error occurred in http handler: {err:#}");
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This error logging may create duplicate log entries since the error is likely already logged at the source. Consider using debug! or trace! level instead of error! to avoid log noise, or remove this logging if errors are handled appropriately elsewhere.

Suggested change
errors::error!("error occurred in http handler: {err:#}");

Copilot uses AI. Check for mistakes.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed because the web handlers simply use ? on Result's. Matching on Err(err) and calling error! on every function that may fail would be unnecessarily verbose.

@@ -91,6 +91,7 @@ pub fn setup_auth_cookie() -> Result<String> {
let mut file = OpenOptions::new()
.mode(0o640)
.write(true)
.truncate(true)
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding .truncate(true) to the auth cookie file creation could be problematic if the file already exists and contains valid data. This will overwrite existing auth cookies, potentially breaking active sessions. Consider checking if the file exists first or using a different approach to ensure atomic updates.

Copilot uses AI. Check for mistakes.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point we've already checked the file doesn't exist. This could be written differently to be race-free, but I think it's fine.

"signatures": [
{
"keyid": "c25d24c04760b6982de77736776edc6600d5f8e1e84d0bba2a7299959ce7d47f",
"sig": "8cd70318ea1b34c91bf7303e9c8811df43d1b4746aa9adf1d503ebb0241e0fbff9be28f36dac0318825782bf05dbbcea7171eb0ca9a89be3b02666f0f3c84301"
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using hardcoded cryptographic key IDs and signatures in tests makes the code brittle and harder to maintain. Consider generating test keys dynamically or using constants defined at the top of the file to make the relationship between test data clearer.

Suggested change
"sig": "8cd70318ea1b34c91bf7303e9c8811df43d1b4746aa9adf1d503ebb0241e0fbff9be28f36dac0318825782bf05dbbcea7171eb0ca9a89be3b02666f0f3c84301"
"keyid": TEST_KEY_ID,
"sig": TEST_SIGNATURE

Copilot uses AI. Check for mistakes.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is acceptable as-is.

@kpcyrd kpcyrd merged commit 6510947 into main Aug 19, 2025
10 checks passed
@kpcyrd kpcyrd deleted the better-attestation branch August 19, 2025 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants