Before using salt make sure you have a valid Xygeni account as well as a Xygeni token. Please see Generate Xygeni Token for further info.
Once you have a valid Xygeni Token, provide the token as an env variable named XYGENI_TOKEN. Salt will read and use it to authenticate against Xygeni platform.
Salt Command-Line Reference
Salt provides a command-line interface (Salt CLI) with commands for creating the attestation document from the inputs, interacting with the attestations registry, and verifying an attestation with respect to the referenced software product.
salt CMD, with CMD = attestation | keygen | registry | contract | verify.
The Salt CLI has two levels (command + subcommand), and -h | --help will show the help at the command or subcommand level.
The main commands are:
salt keygen: Generate key pairs for signing
salt attestation init|add|run|status|commit|reset: Incremental attestation build
salt attestation provenance: Provenance for pipeline, in a single shot
salt registry search | get | put: Operations with Attestation Registry
salt verify: Verify contract / attestation for SW artifact
Software attestations are typically created in the same pipeline that builds and/or deploys the software. One or more steps can run Salt CLI commands to either build the attestation either in one shot (salt attestation provenance) or incrementally at different steps along the pipeline (salt attestation init|add|run|commit).
These commands may be invoked from CI/CD-specific plugins (like GitHub Custom Action or Jenkins Step), instead of calling directly the command executable.
The attestation is always a JSON file following a standard format, that could be distributed along with the software products, or registered in a specific Attestation Registry.
The -h | --help could be used with any command / subcommand:
$ salt -h
oooo .
`888 .o8
.oooo.o .oooo. 888 .o888oo
d88( "8 `P )88b 888 888
`"Y88b. .oP"888 888 888
o. )88b d8( 888 888 888 .
8""888P' `Y888""8o o888o "888"
Software Attestations Layer for Trust, by Xygeni Security.
Usage:
salt [-hqvV] [--config=<config>] [@<filename>...] [COMMAND]
Parameters:
[@<filename>...] One or more argument files containing options.
-v, --verbose Verbose output?
-q, --quiet Quiet mode: do not generate output at console
--config=<config> config file (default $HOME/.salt/salt.yaml or
$SALT_HOME/conf/salt.yaml)
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
Commands:
attestation, at
Create software attestation: incrementally using init / add / run
/ commit|reset, or SLSA build provenance in a single shot.
keygen, kg Generate and save signing keys to disk. These keys may be used
later in attestation commands.
registry, reg Operations on Attestations Registry (store, retrieve, search)
verify, v, check download and verify an attestation for an artifact
generate-completion Generate bash/zsh completion script for salt.
Key Generation
Keys need to be generated before generating attestations (unless you use the keyless mode with --keyless). You may use your own tooling like openssl
$ salt --no-banner keygen -h
Usage:
salt keygen [-hV] [-b=<bits>] [--config=<config>] [-d=<path>] [-f=NAME] [-t=<type>]
[@<filename>...]
Generate and save signing keys to disk.
These keys may be used later in attestation commands.
Parameters:
[@<filename>...] One or more argument files containing options.
-f, --file-prefix=NAME Name for generated .key / .pub files (default: salt).
-t, --type=<type> key type, one of rsa, ed25519, ecdsa (default: rsa).
-b, --bits=<bits> key size, in bits.
RSA defaults to 3072. Use values between 2048 and 4096.
ECDSA curve will be P-192 up to P-521 depending on bits
(defaults to 384).
Not applicable to Ed25519.
-d, --basedir=<path> directory for key files.
Default is current working dir.
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
--config=<config> config file (default $HOME/.salt/salt.yaml or
$SALT_HOME/conf/salt.yaml)
Examples:
# generate key-pair and write to salt.key and salt.pub files
salt keygen
# generate key-pair and write to my-signer.key and my-signer.pub files
salt keygen --file-prefix my-signer
NOTE:
The command interactively prompts for a password.
You may use SALT_PRIVATE_KEY_PASSWORD environment variable to provide one.
Example: To generate an Ed25519 keypair and store in my_key.pub (public key) and my_key.key (private key), use the following:
$ salt -nb kg -t ed25519 -f my_key
# with long options:
# salt --no-banner keygen --type ed25519 --file my_key
Enter password for private key:
Repeat password:
2023-11-29 05:15:15 INFO Salt - Generating ed25519 key-pair...
2023-11-29 05:15:15 INFO Salt - Private key stored in my_key.key
2023-11-29 05:15:15 INFO Salt - Public key stored in my_key.pub
The command generates the keypair of the requested type and stores its parts in two files. Please note that, unless the password should be written from the console unless it is passed in the SALT_PRIVATE_KEY_PASSWORD env var.
For generating on-the-fly, single-use keys, and if you have an OIDC provider available, it could be more convenient to use keyless signing.
Protect the private key and private key password as important secrets, otherwise the digital signature has no value, losing its ability for source authentication and for protecting the integrity of the signed attestations.
Remember that doing encryption right is tough, managing secrets is even harder if doing it yourself. You may use CI/CD secrets for storing the private key and the private key password. You may use instead a Secrets Vault.
Notes on the supported cryptographic algorithms:
(1) Salt supports RSA, ECDSA and Ed25519 key pairs.
(2) Signature formats currently supported are raw signatures (DER-encoded). Keys are often encoded in PEM (key content in base64 between PEM delimiters).
(3) Signing with external tools like openssl or PGP is not currently supported. This is planned for future versions.
(4) Cloud-provided Key Management Systems (KMS) will be also supported in future versions.
The command salt attestation is used for creating software attestations:
$ salt attestation --help
Usage: salt attestation [-hV] [--never-fail] [--config=<config>] -p=<pipeline>
[@<filename>...] CMD
Create software attestation: incrementally using init / add / run / commit|reset, or SLSA
build provenance in a single shot.
[@<filename>...] One or more argument files containing options.
-p, --pipeline=<pipeline>
name of the pipeline/workflow being run.
--never-fail Always return 0, even with errors, to keep the pipeline
running. Default: false
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
--config=<config> config file (default $HOME/.salt/salt.yaml or
$SALT_HOME/conf/salt.yaml)
Commands:
init start attestation drafting process
run run a command and add attestation for the command execution
add add element (material, subject, product or statement) to draft
attestation
status show the current draft attestation
commit complete and store the attestation in draft
reset reset attestation in draft
provenance, slsa generate and sign SLSA provenance
There are two modes: incremental (init … commit) and one-shot (provenance).
Notes:
(1) The working directory used for resolving file / directory paths is the -d | --basedir option, or the current working directory when not given.
(2) Key material is typically encoded in PEM format, and can be passed as an environment variable, local file path, or the PEM value itself. You may use also prefix-based syntax like env:YOUR_VARNAME_HERE or file:YOUR_PATH_HERE. File paths are resolved against the current working directory.
Please note that using env:VAR_NAME could be more convenient than passing $VAR_NAME substitution to the command option directly, as the value will not be shown in logfiles.
Generate Provenance
For generating attestation during the build of software in a single shot, you may use the attestation provenance command (alias: attestation slsa). SLSA Provenance is a common attestation format.
Usage:
salt attestation provenance [-hV] [--config=<config>] [-d=<basedir>] -p=<pipeline>
([-n=<name>] (-v=<value> | -f=<file> | -i=<image> |
--digest=<digest>))... [[-k=<key>] [-pk=<publicKey>]
[-cert=<certificate>] [-kpass=<keyPassword>]
[--pki-format=pkiFormat] [--keyless]] [[-o=<output>]
[--output-unsigned=<outputStatement>] [--pretty-print]
[--project=<project>] [--[no-]upload] [--[no-]result-upload]]
[@<filename>...]
generate and sign SLSA provenance
Parameters:
[@<filename>...] One or more argument files containing options.
-d, --basedir=<basedir> base directory where source files are located
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
-p, --pipeline=<pipeline> name of the pipeline/workflow being run.
--config=<config> config file (default $HOME/.salt/salt.yaml or
$SALT_HOME/conf/salt.yaml)
Subject content, choose one:
-v, --value=<value> value (string) to add to attestation
-f, --file=<file> file to add to attestation
-i, --image=<image> published container image, [REG/]NAME[:TAG]
Example: index.docker.io/my_org/my_image:latest or
my_org/my_image
--digest=<digest> digest, prefixed by the digest function
Example: sha256:d82938...8e62
Signer configuration:
-k, --key=<key> reference (path, env-var name) to the private key for
signing the attestation.
Alternatively uses SALT_PRIVATE_KEY env-var when provided.
-pk, --public-key=<publicKey>
reference (path, env-var name or value) to the public key
for signing the attestation.
Alternatively uses SALT_PUBLIC_KEY env-var when provided.
-cert, --certificate=<certificate>
optional reference (path, env-var name or value) to the
signer's certificate.
Alternatively uses SALT_CERTIFICATE env-var when provided.
-kpass, --key-password=<keyPassword>
reference (path or env-var name) to the private key password
Alternatively uses SALT_PRIVATE_KEY_PASSWORD env-var when
provided.
If '-', the password will be prompted (DO NOT USE in CI/CD)
--pki-format=pkiFormat format for signature and private key: One of pgp, x509,
minisign, ssh, pkcs7, tuf (default null)
--keyless Sign using an ephemeral keypair and a short-lived
certificate with OIDC identity.
Uses OIDC identity token to obtain a 10' public-key
certificate from Fulcio CA.
Attestation options:
-o, --output=<output> file for the signed attestation. Use '-' for stdout.
--output-unsigned=<outputStatement>
file for the unsigned attestation. Use '-' for stdout.
--pretty-print pretty-print the attestation. Default: false.
--project=<project> The software name (project), default: git repository.
--[no-]upload Do not upload the attestation, useful for testing or using
your own storage.
--[no-]result-upload Do not upload the result of the attestation forging to
Xygeni.
Subjects to add:
-n, --name=<name> name for the subject (if under contract, use the contract's
field name)
Example: Generate SLSA provenance for a container image.
With REPO_DIR = path to the software repository, and OUT_DIR = directory where the output files will be written.
$ salt -nb attestation provenance --basedir $REPO_DIR --pipeline my_pipeline \
--name sources --file src \
--name my_tool_cli --file build/my_cli \
--image myorg/myimage:latest \
--keyless --certificate=$OUT_DIR/ephemeral_cert.crt \
-o $OUT_DIR/provenance.signed.json --output-unsigned=$OUT_DIR/provenance.json \
--pretty-print
Generating ephemeral ecdsa keypair of 256 bits
Authenticating using OIDC provider https://oauth2.sigstore.dev/auth
Opening in existing browser session.
Retrieving ephemeral certificate chain from fulcio
Ephemeral fulcio certificate:
-----BEGIN CERTIFICATE-----
MIIC0TCCAligAwIBAgIUJcAbnJyHfrPM7CHQvXZjuEOoyKwwCgYIKoZIzj0EAwMw
...
2nhi3BU=
-----END CERTIFICATE-----
IntotoEnvelope written to provenance.signed.json
Statement https://slsa.dev/provenance/v1 written to provenance.json
Ephemeral certificate saved in file ephemeral_cert.crt
Chain (length 2) for ephemeral certificate saved in file ephemeral_cert.crt.chain
Created entry in the attestations registry with id: 8a...c5b0
Entry may be downloaded from: https://salt.xygeni.io/download/8a...c5b0
The above command will:
compute the gitoid:sha256 digest on the $REPO_DIR/src directory as a subject named 'sources', the sha256 digest on the $REPO_DIR/build/my_cli executable (one product of the build), and the docker sha256 digest on the container image (as a second product).
use keyless signing to generate and certify on-the-fly keys,
produce a signed SLSA v1 Provenance in $OUT_DIR/provenance.signed.json and the unsigned in-toto Statement (easier to see the attestation contents) into $OUT_DIR/provenance.json.
upload the signed attestation to the configured attestations registry, and the result from the build and attestation drafting to Xygeni platform.
Computing the relevant image digest needs the docker client installed locally.You may pass a full image name, including the reference to the OCI container where it was pushed.The default image registry is the Docker Hub (docker.io), but you may use another, including a cloud, SCM or private registry.Just use the qualified image name, like registry/namespace/image:tag, as with any docker / podman command.
You may pass the --no-upload to do not upload signed provenance to the configured attestations registry, and --no-result-upload to do not upload build and provenance results to Xygeni platform. The generated signed attestation could be uploaded to your registry of choice.
Generate Custom Attestation
As an alternative to the attestation provenance command, you may incrementally generate a fully customized attestation using the attestation init | add | run | commit/reset subcommands. If you need to create a customized attestation.
You may consider different attestation formats, for different use cases:
"Know your container" - Feed into automated policy engines, like Google Cloud’s Binary Authorization.
Generate SBOM (Cyclone DX or SPDX formats) and include it as part of a software attestation for protecting the integrity and authenticate source of origin. SPDX or CycloneDX can be inserted as predicates for an In-Toto Statement.
Add statements about the current security position of the software: Typically, the statement reads like "I hereby certify that, to the best of my knowledge, the software does not have any critical security flaw…"
The idea is to integrate the usual software product security reports like static analysis' detected flaws, software composition and vulnerabilities in components, results from dynamic vulnerability scans. Formats like SCAI or the Vulnerabilities Predicate allow for this.
Attestation drafting
Attestation could be built incrementally, using multiple steps kept in a context, and a final step that signs the attestation and publishes it. This incremental process is called attestation drafting. The drafting process follows the commands in the developer’s possibly favorite tool, git: init / add / commit. An attestation run subcommand is added to capture the execution of a build command.
Example of attestation drafting: Assume that PIPELINE is the reference to the running pipeline where the commands are inserted, and that REPO_DIR points to the software repo directory.
# Initialize attestation
salt -nb attestation init -p $PIPELINE -d $REPO_DIR \
--attestor git --attestor environment
# Add material (src directory) and products
# (command-line executable tool built, and OCI image)
salt -nb attestation add -p $PIPELINE -d $REPO_DIR \
--type material --file src
--type product --file path/to/cli_tool \
--type product --image myorg/my_image:my_tag
# Add an attestation predicate,
# for example issues from your favorite Xygeni scan
# in the in-toto Vulnerabilities predicate format:
salt -nb attestatation add -p $PIPELINE -d $REPO_DIR \
-n xygeni-scan -t predicate -f path/to/xygeni_scan.json \
--predicate-type https://in-toto.io/attestation/vulns
# Capture a build step to be included in the attestation
# In the example the current Go package is built and installed:
salt -nb attestation run -p $PIPELINE -d $REPO_DIR \
--step compile -- \
go install
# ... more attestation add commands may follow ...
salt -nb attestation commit -p $PIPELINE -d $REPO_DIR \
-k env:MY_KEY -kpass env:MY_KEY_PASS -pk env:MY_PUB \
-o attestation.json --output-unsigned
Use your CI/CD variables for creating a value for --pipeline that it is unique to the pipeline run. For example, $GITHUB_WORKFLOW_REF/$GITHUB_RUN_ID could be used in GitHub Actions.
attestation init creates the initial draft with initial information (like system environment and git data) extracted by one or more predefined 'attestors'. Available attestors are currently git and environment. Materials (inputs) may also be added as files or directories.
attestation add adds elements (material, subject, product or statement) to the current draft attestation. Typically, a digest (SHA-256) is computed on the element. Container images may be added.
The image digest is the 'official' from the manifest, as extracted from docker manifest inspect IMAGE -v or gcrane digest IMAGE
attestation run runs a command and add an attestation predicate for the command execution. Cryptographic digests for input artifacts (materials) will be computed before running the command, and for output artifacts (by-products) at the end of the command. This could be used to link the inputs and outputs of the step with other steps in the pipeline. The predicate has a type URI of xygeni.io/attestations/command-run/v1, and includes the following information:
attestation commit builds the final attestation as in-toto Statement, serializes it as JSON, signs it with the passed key material, creates an in-toto Envelope with the statement as payload, the signature and the reference for the signing key, and publishes it in the attestation registry
The final statement is composed using the added predicates, input artifacts ('materials'), run command predicates, init attestors, and output artifacts ('products'), and then signed using the key materials passed as options.
As multiple predicates are typically added, a special collection predicate (with type URI xygeni.io/attestations/collection-predicates/v1) is used to compound multiple predicates in the single predicate that goes as the predicate for the in-toto statement to be signed.
Publishing in the configured Attestations Registry, and report upload to Xygeni platform is done by default. They may be disabled with the --no-upload and --no-result-upload options, respectively.
For full command syntax, use the --help | -h option on the attestation subcommand:
salt attestation init -h
salt attestation add -h
salt attestation run -h
salt attestation commit -h
Attestation Status
You may use the attestation status subcommand in the drafting process to show the current context for the drafted attestation. Example:
If the attestation drafting process should be aborted, due to an failure ini the build, the attestation reset command should be invoked for cleaning up the attestation context:
Run salt attestation reset -h for full command reference.
Verify Attestation
Attestation verification can be performed by the user of the software the attestation refers to. The verification process:
(1) Computes the digests of the subjects that are passed to the command, following the same syntax as with the attestation add | provenance commands. Emits a verification failure if any digest do not match with the digests present in the attestation. This could help with detecting post-build tampering.
(2) Verifies the signature of the attestation payload (statement included in the attestation envelope) with the public key or certificate passed.
(3) If certificate available, verifies the certificate and certificate chain. For ephemeral certificates used with --keyless, it checks that the certificate was valid at the moment when the attestation was signed, and checks that certificate issuance was registered in the transparency log at the given timestamp.
The attestation verify performs this validation:
$ salt -nb verify \
--image=myorg/myimage:my_tag \
--attestation=attestation.json \
--public-key=ephemeral_cert.crt
Verifying in-toto envelope with type = https://in-toto.io/Statement/v1
Attestations passed OK
When there is a failure in validation, the result shows what failed:
Use salt verify -h to display the full syntax of the command.
Further 'semantic' validation is not supported in the current version. In future releases, additional checks based on a contract (sort of policy specifying the steps in the build process and the expected results for each step), signed by the attestor, will be added to salt.
Registry Operations
Attestation generation and verification may connect with the Attestations Registry to fetch the attestation. The registry command allows you to upload, search for, and download attestations.
Attestation entries in the registry have a digest (64 hexadecimal digits) for downloading.
Search typically use the digest value of a subject in the attestation to list the attestations that refer to it (there could be multiple).
salt -nb registry search --digest $IMAGE_SHA
29 attestations found containing digest sha256:0c8a...df3a0f:
---
Attestation #1: 3a7062b...d6a3
Download URL: https://salt.xygeni.io/download/3a7062b...d6a3
Payload type: application/vnd.in-toto+json
Signature #1: MEUCI...+tE=
Public Key ID #1: d0a3e...b63
---
Attestation #2: 5f6b....3c89
...
Use salt reg -h for the full syntax of the commands.
$ salt reg -h
Usage: salt registry [-hV] [--never-fail] [--config=<config>] [--format=<format>]
[@<filename>...] CMD
Operations on Attestations Registry (store, retrieve, search)
[@<filename>...] One or more argument files containing options.
--format=<format> Output format, one of json, text (default: text)
--never-fail Always return 0, even with errors, to keep the pipeline running.
Default: false
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
--config=<config> config file (default $HOME/.salt/salt.yaml or
$SALT_HOME/conf/salt.yaml)
Commands:
store, put, upload store an attestation in the registry
retrieve, get, download get an attestation from registry
search, find, query search for attestations in the registry