Signing Chalk artifacts
Chalk can automatically sign (or attest) chalked artifacts.
Configure
To configure attestation, use the setup command. This will create an
attestation key and will print out the password used to encrypt the
private key:
$ chalk setup
------------------------------------------
CHALK_PASSWORD=91-qmuffjZlKOWSh-5T2RA==
------------------------------------------
Write this down. In future chalk commands, you will need
to provide it via CHALK_PASSWORD environment variable.
$ ls chalk.{key,pub}
chalk.key chalk.pub
Save this password as well as the key. We recommend to save it as a secret in your CI/CD.
Use standalone
Once you’ve run chalk setup, running chalk insert will
automatically sign the artifact if the CHALK_PASSWORD environment
variable is set.
Use in CI/CD
In order to use attestation in CI/CD, you will need to reference the secrets created earlier.
GitHub Actions
- name: Set up Chalk
uses: crashappsec/setup-chalk-action@main
with:
password: ${{ secrets.CHALK_PASSWORD }}
public_key: ${{ secrets.CHALK_PUBLIC_KEY }} # content of chalk.pub
private_key: ${{ secrets.CHALK_PRIVATE_KEY }} # content of chalk.key
Other
Similarly attestation can be enabled via setup.sh:
$ CHALK_PASSWORD=<password> \
sh <(curl -fsSL https://crashoverride.run/setup.sh) \
--public-key=./chalk.pub \
--private-key=./chalk.key
Verifying Attestation
Once an artifact is chalked, the extract command will verify its
attestation. Chalk will report whether the artifact attestation
signature was successfully validated. This works for both files and
docker images:
$ chalk extract ./myapp # file
$ chalk extract docker.io/example/image # docker image
Here’s an example of signing a binary with Chalk (where the password
and signature will differ based on your run of chalk setup).
$ unalias ls
$ cp $(which ls) ls
$ CHALK_PASSWORD=91-qmuffjZlKOWSh-5T2RA== chalk insert ./ls 2>/dev/null | jq -r '.[]|._CHALKS[]|.SIGNATURE'
MEYCIQCz8IUfWOgjhMVjdsmkE2T/u83UIu5Y8ZJszmReanodjgIhAN62niXkNYYwnHdluKwUeMnp1V6pW4ys1syyXmZZFKMb
$ chalk extract ./ls 2>/dev/null | jq -r '.[]|._CHALKS[]|._VALIDATED_SIGNATURE'
And if we omitted the CHALK_PASSWORD (or we didn’t run chalk setup) neither of these fields will exist:
$ unalias ls
$ cp $(which ls) ls
$ chalk insert ./ls 2>/dev/null | jq -r '.[]|._CHALKS[]|.SIGNATURE'
null
./chalk extract ./ls 2>/dev/null | jq -r '.[]|._CHALKS[]|._VALIDATED_SIGNATURE'
null
How does this differ from gpg?
You can always sign your own binaries yourself, whether you chalk mark them or not. In that scenario you will manage and distributed and verify the signature separately, or not at all.
When signing with Chalk (when dealing with binaries) the signature
gets baked into the binary itself and is then validated every time you
chalk extract.
(Separately, note that even if Chalk is set up with signing keys it
doesn’t do anything with chalk exec-ed binaries that have not been
marked by Chalk.)