Distroless Builds Are Now SLSA 2

Posted by Priya Wadhwa and Appu Goundan, Google Open Source Security TeamA few months ago we announced that we started signing all distroless images with cosign, which allows users to verify that they have the correct image before starting the build process. Signing our images was our first step towards fully securing the distroless supply chain. Since then, we’ve implemented even more accountability in our supply chain and are excited to announce that distroless builds have achieved SLSA 2. SLSA is a security framework for increasing supply chain security, and Level 2 ensures that the build service is tamper resistant.This means that in addition to a signature, each distroless image now has an associated signed provenance. This provenance is an in-toto attestation and includes information around how each image was built, what command was run, and what build system was used. It also includes any special parameters that were passed in, the exact commit the images were built at, and more. This provenance is a useful tool for builds that need to be audited in the future.SLSA 2 RequirementDistrolessSource – Version controlledSource code in GithubBuild – Scripted buildBuild script exists as a Tekton Pipeline, invoked as a Google Cloud Build stepBuild – Build serviceAll steps run on Kubernetes with TektonProvenance – AvailableProvenance is available in the rekor transparency log as an in-toto attestationProvenance – AuthenticatedProvenance is signed with the distroless GCP KMS keyProvenance – Service generatedProvenance is generated by Tekton Chains from a Tekton TaskRunAchieving SLSA 2 required some changes to the distroless build pipeline: we set up Tekton Pipelines and Tekton Chains in a GKE cluster to automate building images and generating provenance. Every time a pull request is merged to the distroless Github repo, a Tekton Pipeline is triggered. This Pipeline builds the distroless images, and Tekton Chains is responsible for generating signed provenance for each image. Tekton Chains stores the signed provenance alongside the image in an OCI registry and also stores a record of the provenance in the rekor transparency log.Don’t trust us? You can try the build yourself. Because distroless builds are reproducible, all the information to replicate the build is in the provenance, and you or a trusted third party can build the image yourselves and verify the build is correct by matching image digests.You can verify an attestation for a distroless image with cosign and the distroless public key:$ cosign verify-attestation -key cosign.pub gcr.io/distroless/base@sha256:4f8aa0aba190e375a5a53bb71a303c89d9734c817714aeaca9bb23b82135ed91Verification for gcr.io/distroless/base@sha256:4f8aa0aba190e375a5a53bb71a303c89d9734c817714aeaca9bb23b82135ed91 –The following checks were performed on each of these signatures:  – The cosign claims were validated  – The signatures were verified against the specified public key  – Any certificates were verified against the Fulcio roots….And you can find the provenance for the image in the rekor transparency log with the rekor-cli tool. For example, you could find the provenance for the above image by using the image’s digest and running:$ rekor-cli search –sha sha256:4f8aa0aba190e375a5a53bb71a303c89d9734c817714aeaca9bb23b82135ed91af7a9687d263504ccdb2759169c9903d8760775045c6e7554e365ec2bf29f6f8$ rekor-cli get –uuid af7a9687d263504ccdb2759169c9903d8760775045c6e7554e365ec2bf29f6f8 –format json | jq -r .Attestation | base64 –decode | jq{  “_type”: “distroless-provenance”,  “predicateType”: “https://tekton.dev/chains/provenance”,  “subject”: [    {      “name”: “gcr.io/distroless/base”,      “digest”: {        “sha256”: “703a4726aedc9ec7a7e32251087565246db117bb9a141a7993d1c4bb4036660d”      }    },    {      “name”: “gcr.io/distroless/base”,      “digest”: {        “sha256”: “d322ed16d530596c37eee3eb57a039677502aa71f0e4739b0272b1ebd8be9bce”      }    },    {      “name”: “gcr.io/distroless/base”,      “digest”: {        “sha256”: “2dfdd5bf591d0da3f67a25f3fc96d929b256d5be3e0af084db10952e5da2c661”      }    },    {      “name”: “gcr.io/distroless/base”,      “digest”: {        “sha256”: “4f8aa0aba190e375a5a53bb71a303c89d9734c817714aeaca9bb23b82135ed91”      }    },    {      “name”: “gcr.io/distroless/base”,      “digest”: {        “sha256”: “dc0a793d83196a239abf3ba035b3d1a0c7a24184856c2649666e84bc82fc5980”      }    },    {      “name”: “gcr.io/distroless/base-debian10”,      “digest”: {        “sha256”: “2dfdd5bf591d0da3f67a25f3fc96d929b256d5be3e0af084db10952e5da2c661”      }    },    {      “name”: “gcr.io/distroless/base-debian10”,      “digest”: {        “sha256”: “703a4726aedc9ec7a7e32251087565246db117bb9a141a7993d1c4bb4036660d”      }    },    {      “name”: “gcr.io/distroless/base-debian10”,      “digest”: {        “sha256”: “4f8aa0aba190e375a5a53bb71a303c89d9734c817714aeaca9bb23b82135ed91”      }    },    {      “name”: “gcr.io/distroless/base-debian10”,      “digest”: {        “sha256”: “d322ed16d530596c37eee3eb57a039677502aa71f0e4739b0272b1ebd8be9bce”      }    },    {      “name”: “gcr.io/distroless/base-debian10”,      “digest”: {        “sha256”: “dc0a793d83196a239abf3ba035b3d1a0c7a24184856c2649666e84bc82fc5980”      }    },    {      “name”: “gcr.io/distroless/base-debian11”,      “digest”: {        “sha256”: “c9507268813f235b11e63a7ae01526b180c94858bd718d6b4746c9c0e8425f7a”      }    },    {      “name”: “gcr.io/distroless/cc”,      “digest”: {        “sha256”: “4af613acf571a1b86b1d3c50682caada0b82024e566c1c4c2fe485a70f3af47d”      }    },    {      “name”: “gcr.io/distroless/cc”,      “digest”: {        “sha256”: “2c4bb6b7236db0a55ec54ba8845e4031f5db2be957ac61867872bf42e56c4deb”      }    },    {      “name”: “gcr.io/distroless/cc”,      “digest”: {        “sha256”: “2c4bb6b7236db0a55ec54ba8845e4031f5db2be957ac61867872bf42e56c4deb”      }    },    {      “name”: “gcr.io/distroless/cc-debian10”,      “digest”: {        “sha256”: “4af613acf571a1b86b1d3c50682caada0b82024e566c1c4c2fe485a70f3af47d”      }    },    {      “name”: “gcr.io/distroless/cc-debian10”,      “digest”: {        “sha256”: “2c4bb6b7236db0a55ec54ba8845e4031f5db2be957ac61867872bf42e56c4deb”      }    },    {      “name”: “gcr.io/distroless/cc-debian10”,      “digest”: {        “sha256”: “2c4bb6b7236db0a55ec54ba8845e4031f5db2be957ac61867872bf42e56c4deb”      }    },    {      “name”: “gcr.io/distroless/java”,      “digest”: {        “sha256”: “deb41661be772c6256194eb1df6b526cc95a6f60e5f5b740dda2769b20778c51”      }    },    {      “name”: “gcr.io/distroless/nodejs”,      “digest”: {        “sha256”: “927dd07e7373e1883469c95f4ecb31fe63c3acd104aac1655e15cfa9ae0899bf”      }    },    {      “name”: “gcr.io/distroless/nodejs”,      “digest”: {        “sha256”: “927dd07e7373e1883469c95f4ecb31fe63c3acd104aac1655e15cfa9ae0899bf”      }    },    {      “name”: “gcr.io/distroless/nodejs”,      “digest”: {        “sha256”: “f106757268ab4e650b032e78df0372a35914ed346c219359b58b3d863ad9fb58”      }    },    {      “name”: “gcr.io/distroless/nodejs-debian10”,      “digest”: {        “sha256”: “927dd07e7373e1883469c95f4ecb31fe63c3acd104aac1655e15cfa9ae0899bf”      }    },    {      “name”: “gcr.io/distroless/nodejs-debian10”,      “digest”: {        “sha256”: “f106757268ab4e650b032e78df0372a35914ed346c219359b58b3d863ad9fb58”      }    },    {      “name”: “gcr.io/distroless/nodejs-debian10”,      “digest”: {        “sha256”: “927dd07e7373e1883469c95f4ecb31fe63c3acd104aac1655e15cfa9ae0899bf”      }    },    {      “name”: “gcr.io/distroless/python3”,      “digest”: {        “sha256”: “aa8a0358b2813e8b48a54c7504316c7dcea59d6ae50daa0228847de852c83878”      }    },    {      “name”: “gcr.io/distroless/python3-debian10”,      “digest”: {        “sha256”: “aa8a0358b2813e8b48a54c7504316c7dcea59d6ae50daa0228847de852c83878”      }    },    {      “name”: “gcr.io/distroless/static”,      “digest”: {        “sha256”: “9acfd1fdf62b26cbd4f3c31422cf1edf3b7b01a9ecee00a499ef8b7e3536914d”      }    },    {      “name”: “gcr.io/distroless/static”,      “digest”: {        “sha256”: “e50641dbb871f78831f9aa7ffa59ec8f44d4cc33ae4ee992c9f4b046040e97f2”      }    },    {      “name”: “gcr.io/distroless/static-debian10”,      “digest”: {        “sha256”: “9acfd1fdf62b26cbd4f3c31422cf1edf3b7b01a9ecee00a499ef8b7e3536914d”      }    },    {      “name”: “gcr.io/distroless/static-debian10”,      “digest”: {        “sha256”: “e50641dbb871f78831f9aa7ffa59ec8f44d4cc33ae4ee992c9f4b046040e97f2”      }    }  ],  “predicate”: {    “invocation”: {      “parameters”: [        “MANIFEST_SUBSECTION={string 0 []}”,        “CHAINS-GIT_COMMIT={string 976c1c9bc178ac0371d8888d69893145c3df09f0 []}”,        “CHAINS-GIT_URL={string https://github.com/GoogleContainerTools/distroless []}”      ],      “recipe_uri”: “task://distroless-provenance”,      “event_id”: “531c282f-806e-41e4-b3ad-b596c4283381”,      “builder.id”: “tekton-chains”    },    “recipe”: {      “steps”: [        {          “entryPoint”: “#!/bin/shnset -exnn# get the digests for a subset of images built, and store in the IMAGES resultngo run provenance/provenance.go images $(params.MANIFEST_SUBSECTION) > $(results.IMAGES.path)n”,          “arguments”: null,          “environment”: {            “container”: “provenance”,            “image”: “docker.io/library/golang@sha256:cb1a7482cb5cfc52527c5cdea5159419292360087d5249e3fe5472f3477be642”          },          “annotations”: null        }      ]    },    “metadata”: {      “buildStartedOn”: “2021-09-16T00:03:04Z”,      “buildFinishedOn”: “2021-09-16T00:04:36Z”    },    “materials”: [      {        “uri”: “https://github.com/GoogleContainerTools/distroless”,        “digest”: {          “revision”: “976c1c9bc178ac0371d8888d69893145c3df09f0”        }      }    ]  }}As you might guess, our next step is getting distroless to SLSA 3, which will require adding non-falsifiable provenance and isolated builds to the distroless supply chain. Stay tuned for more!

—————
Free Unlimited, Encrypted, Anti Snoop & Ad Free Email
Boost Aviation Internet Speeds – Cuts tracking and Junk at source
Register UK names for just £2.99 a year
Check our Premium Domains and Freebies