Install voucher_server
by running:
$ go install github.com/grafeas/voucher/v2/cmd/voucher_server
This will download and install the voucher server binary into $GOPATH/bin
directory.
Note: omitting "v2" from the path will download Voucher Server v1.
See the Tutorial for more thorough setup instructions.
An example configuration file can be found in the config directory.
The configuration can be written as a toml, json, or yaml file, and you can specify the path to the configuration file using "-c".
Below are the configuration options for Voucher Server:
Group | Key | Description |
---|---|---|
dryrun |
When set, don't create attestations. | |
scanner |
The vulnerability scanner to use ("metadata"). | |
failon |
The minimum vulnerability to fail on. Discussed below. | |
valid_repos |
A list of repos that are owned by your team/organization. | |
trusted_builder_identities |
A list of email addresses. Owners of these emails are considered "trusted" (and will pass Provenance) | |
trusted_projects |
A list of projects that are considered "trusted" (and will pass Provenance) | |
binauth_project |
The project in the metadata server that the binauth information is stored. | |
checks |
(test name here) | A test that is active when running "all" tests. |
server |
port |
The port that the server can be reached on. |
server |
timeout |
The number of seconds to spend checking an image, before failing. |
server |
require_auth |
Require the use of Basic Auth, with the username and password from the configuration. |
server |
username |
The username that Voucher server users must use. |
server |
password |
A password hashed with the bcrypt algorithm, for use with the username. |
ejson |
dir |
The path to the ejson keys directory. |
ejson |
secrets |
The path to the ejson secrets. |
sops |
file |
The path to the SOPS secrets. |
repository.[alias] |
org-url |
The URL used to determine if a repository is owned by an organization. |
required.[env] |
(test name here) | A test that is active when running "env" tests. |
metrics |
backend |
The destination for reporting metrics, can be statsd for local aggregation, datadog for direct Datadog API, or opentelemetry for an otel collector. |
metrics |
tags |
List of tags in key:value format that apply to every metric. Example: env:production . |
statsd |
addr |
The UDP endpoint to use when metrics.backend == "statsd" |
statsd |
sample_rate |
Configurable sample rate to limit metrics overhead. |
opentelemetry |
interval |
The interval at which to flush metrics to the opentelemetry collector. |
opentelemetry |
addr |
The http:// , https:// or grpc:// address for the opentelemetry collector. |
opentelemetry |
insecure |
Disable transport security like HTTPS for the opentelemetry collector. |
Configuration options can be overridden at runtime by setting the appropriate flag. For example, if you set the "port" flag when running voucher_server
, that value will override whatever is in the configuration.
Note that Repositories can be set multiple times. This is discussed futher below.
Secret values are stored encrypted in an ejson or SOPS file, and can not be overwritten at the command line. Below are the configuration secrets for Voucher Server. Ejson and SOPS secrets follow the same schema:
Group | Key | Description |
---|---|---|
openpgpkeys |
(test name here) | The PGP key to use for signing attestations of a specific test. |
datadog |
api_key |
API key for direct submission when configuration statsd.backend == "datadog" . |
datadog |
app_key |
App key for direct submission when configuration statsd.backend == "datadog" . |
repositories |
(repository owner name here) | Credentials for repository authentication. |
The scanner
option in the configuration is used to select the Vulnerability scanner.
This option supports one value:
metadata
to use Google Container Analysis. (Note thatg
andgca
are being deprecated in favor ofmetadata
.)
The failon
option allows you to set the minimum vulnerability to consider an image insecure.
This option supports the following:
- "negligible"
- "low"
- "medium"
- "unknown"
- "high"
- "critical"
For example, if you set failon
to "high", only "high" and "critical" vulnerabilities will prevent the image from being attested. A value of "low" will cause "low", "medium", "unknown", "high", and "critical" vulnerabilities to prevent the image from being attested failure.
The valid_repos
option in the configuration is used to limit which repositories images must be from to pass the DIY check.
This option takes a list of repos, which are compared against the repos that images live in. An image will pass if it starts with any of the items in the list.
For example:
valid_repos = [
"gcr.io/team-images/",
"gcr.io/external-images/specific-project"
]
Will allow images that start with gcr.io/team-images/
and gcr.io/external-images/specific-project/
to pass the DIY check, while blocking other gcr.io/external-images/
.
The provenance check works by obtaining the build metadata for an image from the metadata service, and verifying that it both comes from a trusted project and was built by a trusted builder.
You can use this to ensure that only images built by your continuous integration pipeline can be deployed to the cloud, with exceptions for images built by trusted administrators.
For example:
trusted_builder_identities = [
"[email protected]",
"idcloudbuild.gserviceaccount.com"
]
trusted_projects = [
"team-images"
]
This would require that images be built in the team-images
project, by either [email protected]
or idcloudbuild.gserviceaccount.com
. Images not built in the team-images
project will fail Provenance regardless of who built them.
Repository Groups are used to determine which Repository client should be used to connect to a Repository.
They are defined as an alias (usually matching the name of the organization in the repository system) and a URL. Note that
the alias can contain only lower cases letters, dashes, and underscores ([a-z_-]
).
The URL is used to determine if a repository is owned by a repository group.
For example, a repository owned by Shopify
, it's URL should contain github.com/Shopify
. A repository owned by Grafeas
, should contain github.com/grafeas
, and so on.
Repository groups are required to use the Repository checks.
You can define repository groups as follows:
[repository.shopify]
org-url = "https://github.com/Shopify"
[repository.grafeas]
org-url = "https://github.com/grafeas"
For the repository groups to authenticate with a repository server, you will need to create secrets matching the alias name in your secrets file (ejson or SOPS).
For example, for the repository.shopify
block, you would need a repositories
block in your secrets with a shopify
block inside of it:
{
"repositories": {
"shopify": {
"token": "EJ[1:vt978NEKynsJhZlCvg5XdSE2S2PM1JBPK0tlC05cQAc=:4mDZCykfieedtHGoM0UT+Wr6zPO9J6XO:/AuGJ3I2QVnk52qOLo0sQ+EzEAk=]"
}
}
}
Note that like aliases, the name of the block must only contain lower cases
letters, dashes, and underscores ([a-z_-]
).
If your repository server supports personal access token, you can specify it
by setting the token
key (as in the example above).
If your repository server supports app based authentication (as Github does), you can specify the App ID, Installation ID, and the private key as follows:
{
"repositories": {
"shopify": {
"_id": "1234",
"_installation_id": "123456789",
"private_key": "EJ[1:vt978NEKynsJhZlCvg5XdSE2S2PM1JBPK0tlC05cQAc=:4mDZCykfieedtHGoM0UT+Wr6zPO9J6XO:/AuGJ3I2QVnk52qOLo0sQ+EzEAk=]"
}
}
}
The organization check is a dynamic check which uses the name of an organization to determine if code came from that organization.
For example, if you have defined an organization as follows:
[[repositories]]
alias = "Shopify"
org-url = "https://github.com/Shopify"
You can enable a check that verifies that an image came from that organization:
[checks]
is_shopify = true
The name of the check is is_
followed by the name of the organization, converted to lowercase.
This check works by:
- looking up the build metadata for an image from your metadata service
- getting the repository information from that metadata
- connecting to the API of that repository (in this example, Github)
- verifying that the source code is associated with the organization that it says it is
You can enable certain checks for the "all" option by updating the checks
block in the configuration.
For example:
[checks]
diy = true
nobody = true
provenance = false
snakeoil = true
is_shopify = true
With this configuration, the diy
, nobody
, snakeoil
, and is_shopify
checks would run when running all
checks. The provenance
check will be ignored unless called directly.
You can configure named groups of checks identically to how you would define an enable
checks block, by replacing the block heading with required.[env]
where [env]
is a name of your choosing.
For example:
[required.myenv]
diy = true
nobody = true
provenance = false
snakeoil = true
is_shopify = true
With this configuration, the diy
, nobody
, snakeoil
, and is_shopify
checks would run when running myenv
checks. The provenance
check will be
ignored unless called directly.
You can use OpenPGP keys by encrypting them in your secrets file (ejson or SOPS).
First, ensure the signer is set to pgp
in the configuration:
signer = "pgp"
Then add keys to your secrets file. This is documented more completely in the Tutorial.
You can use Google KMS signing keys by switching the signer in the configuration:
signer = "kms"
Then you would specify the KMS keys in the configuration file, by adding
[[kms_keys]]
blocks.
For example, to have the DIY Check use a KMS key in the project binauth
with
the name diy-attestor
, you would use the following:
[[kms_keys]]
check = "diy"
path = "projects/binauth-staging/locations/global/keyRings/binauthz-keys/cryptoKeys/diy-attestor/cryptoKeyVersions/1"
algo = "SHA512"
You can run Voucher in server mode by launching voucher_server
, using the following syntax:
$ voucher_server [--port <port number>]
voucher_server
supports the following flags:
Flag | Short Flag | Description |
---|---|---|
--config |
-c |
The path to a configuration file that should be used. |
--port |
-p |
Set the port to listen on. |
--timeout |
The number of seconds to spend checking an image, before failing. |
For example:
$ voucher_server --port 8000
This would launch the server, utilizing port 8000.
You can connect to Voucher over http.
For example, using curl
:
$ curl -X POST -H "Content-Type: application/json" -d "{\"image_url\": \"gcr.io/path/to/image@sha256:ab7524b7375fbf09b3784f0bbd9cb2505700dd05e03ce5f5e6d262bf2f5ac51c\"}" http://localhost:8000/all
The response will be something along the following lines:
{
"image": "gcr.io/path/to/image@sha256:ab7524b7375fbf09b3784f0bbd9cb2505700dd05e03ce5f5e6d262bf2f5ac51c",
"success": false,
"results": [
{
"name": "provenance",
"error": "no occurrences returned for image",
"success": false,
"attested": false
},
{
"name": "snakeoil",
"success": true,
"attested": true
},
{
"name": "diy",
"success": true,
"attested": true
},
{
"name": "nobody",
"success": true,
"attested": true
}
]
}
More details about Voucher server can be read in the API documentation.