The In-Toto Framework
Securing individual steps in a software supply chain is necessary, but it is not sufficient. You might secure your git server with MFA and your build server with strict firewalls, but if an attacker can intercept the code between those two steps, or inject a malicious artifact during the handoff, the system is compromised.
In-toto (Latin for âin totalâ or âoverallâ) is an open framework designed to solve this specific problem. It does not just look at the steps; it secures the entire chain of custody from the moment a developer commits code to the moment an end-user installs the software.
While DevGuard handles much of the complexity of in-toto automatically, understanding its underlying mechanics is crucial for grasping how we guarantee the integrity of your software.
The âWeakest Linkâ Problem
In a complex supply chain, trust is often fragmented.
- The developer trusts the IDE.
- The build server trusts the version control system.
- The package registry trusts the build server.
In-toto assumes that any step in this chain could be compromised. Instead of implicitly trusting that âStep B followed Step A,â in-toto requires cryptographic proof that:
- Step A was performed by an authorized entity.
- Step B was performed by an authorized entity.
- The output of Step A matches exactly the input of Step B.
This effectively closes the gaps between the silos of your development lifecycle.
Core Architecture
In-toto operates on a model of âtrust, but verify.â It separates the definition of what should happen from the evidence of what actually happened.
1. The Layout (The âMapâ)
The Layout is the heart of in-toto. It is a signed policy file, usually created by the project owner or security lead. Think of it as the âfloor planâ or the ârecipeâ for the software.
The Layout defines:
- Steps: The discrete actions that must occur (e.g., âclone-codeâ, âbuild-binaryâ, âpackage-dockerâ).
- Functionaries: The specific public keys authorized to perform each step. (e.g., âOnly Aliceâs key can sign the âclone-codeâ step,â âOnly the Build Serverâs key can sign the âbuild-binaryâ stepâ).
- Inspections: Rules to ensure the handoff between steps is correct (e.g., âThe files consumed by the âbuildâ step must match the files produced by the âcloneâ stepâ).
Because the Layout is signed by the âProject Ownerâ (the root of trust), an attacker cannot simply modify the pipeline definition to insert a malicious step without invalidating the signature.
2. The Links (The Evidence)
As the software moves through the pipeline, each Functionary (person or machine) performs their assigned Step. When they finish, they generate a piece of metadata called a Link.
A Link contains:
- Materials: The hashes of all files used as input (e.g., source code).
- Products: The hashes of all files produced as output (e.g., the compiled binary).
- Command: The exact command that was executed (e.g.,
go build -o app main.go). - Environment: Information about the machine running the step.
- Signature: The Functionaryâs cryptographic signature.
If the Build Server is compromised and tries to swap the source code for a malicious version before building, the âMaterialsâ hash in the Build Link will not match the âProductsâ hash from the previous Checkout Link. The chain is broken.
The Verification Workflow
The true power of in-toto comes during the verification phase. This happens before the software is deployed or installed. The verifier (which could be an Admission Controller in Kubernetes or the DevGuard platform itself) takes the Layout, the collection of Links, and the final Artifact.
The verification process follows this logic:
- Verify the Layout: Is the Layout signed by a trusted Project Owner key? If no, stop.
- Iterate through Steps: For every step defined in the Layout:
- Find the corresponding Link metadata.
- Check if the Link is signed by the authorized Functionary defined in the Layout.
- If a step is missing or signed by the wrong key (e.g., âBobâ signed the build, but only âJenkinsâ is allowed), the verification fails.
- Match Artifacts (Artifact Rules):
- The verifier checks that the Products of Step 1 match the Materials of Step 2.
- This ensures that what came out of the first machine is exactly what went into the second machine, byte-for-byte.
- Run Inspections: Any custom shell scripts or logic defined in the Layout are executed to perform deeper checks.
If all checks pass, the software is deemed trusted âin-toto.â
ITE-6: The Evolution to Attestations
The original in-toto specification focused heavily on the specific format of Links and Layouts. However, as the ecosystem evolved (with the rise of containers and cloud-native builds), the community introduced In-Toto Enhancements (ITEs).
ITE-6 is the most significant of these for modern users. It generalizes the âLinkâ concept into a broader Attestation model.
- Instead of just recording files and commands, ITE-6 allows the encapsulation of any type of metadata (like a vulnerability scan report, a test result summary, or a generic provenance statement) inside an in-toto envelope.
- This is the underlying format used by Cosign, SLSA, and DevGuard.
When DevGuard generates a âStatement of Provenance,â it is creating an in-toto ITE-6 attestation. This ensures that the data is interoperable with the wider ecosystem of supply chain tools.
How DevGuard Uses In-Toto
Implementing in-toto manually can be complex. It involves managing keys for every developer, configuring link generation for every script, and writing complex layout files. DevGuard abstracts this complexity while retaining the security benefits.
Automated Link Generation
DevGuard integrates with your CI/CD (via our GitHub Action or GitLab Component) to act as a Functionary.
- When a pipeline job starts, DevGuard captures the state of the workspace (Materials).
- When the job ends, DevGuard captures the state of the artifacts (Products).
- DevGuard signs this data with an ephemeral key (linked to the CI identity) to create a valid in-toto Link/Attestation.
Implicit Layouts vs. Explicit Policies
In many DevGuard configurations, we use an âImplicit Layoutâ model. Instead of writing a JSON Layout file manually, you define your policy in the DevGuard dashboard (e.g., âAll artifacts must be scannedâ). DevGuard translates this high-level policy into the verification logic that checks the underlying in-toto attestations.
Why This Matters: Defense in Depth
The in-toto framework provides resilience against sophisticated attacks that other tools miss.
- Compromise Resilience: If an attacker steals a developerâs GPG key, they can sign commits. But they cannot sign the Build Step because that requires the Build Serverâs key. In-toto catches this discrepancy.
- Tamper Evidence: If an attacker modifies the binary on the download mirror, the verification fails because the binaryâs hash wonât match the âProductâ hash recorded by the Build Server.
- Granular Authorization: You can enforce strict separation of duties. The team that writes the code (Developers) is cryptographically distinct from the entity that compiles it (Build Server), which is distinct from the entity that publishes it (Release Manager).
Conclusion
In-toto is the glue that binds the disparate parts of a software supply chain into a single, verifiable whole. By mathematically linking steps togetherâensuring inputs match outputs and authorized actors perform every actionâit eliminates the blind spots where attackers hide. While DevGuard manages the heavy lifting of generating and storing these links, understanding the in-toto framework helps clarify why we place such emphasis on provenance and signed metadata. It is not just about record-keeping; it is about proving the negative: proving that nothing happened to your software that you didnât authorize.
References
- In-Toto Specification
- ITE-6: Generalized Attestation Format
- In-Toto Website & Architecutre