GCR Kritis Signer is a service which creates attestations based on software vulnerabilities identified by the Google Container Analysis after scanning of container images stored in Google Container Registry.
The signer will attest whether the image conforms to the signer policy you defined.
The GCR signer only supports the Google Cloud KMS key.
The GCR Kritis signer follows the 12-factor application principles. It is configured via command options or one of the following environment variables:
name | equivalent option | description | required |
---|---|---|---|
ATTESTATION_NOTE_NAME | -note_name | name of the note to attest | yes |
ATTESTATION_KMS_KEY | -kms_key_name | KMS key version to use to sign | yes |
ATTESTATION_DIGEST_ALGORITHM | -kms_digest_alg | digest algorithm used | yes |
ATTESTATION_PROJECT | -attestation_project | GCP project to store attestation | no, default it uses the image project |
ATTESTATION_OVERWRITE | -overwrite | overwrite existing attestations | no, default false |
ATTESTATION_POLICY | NA | vulnerability policy document | yes, if -policy is missing |
The command line option takes precedence over the corresponding environment variable.
When running the signer in server mode, the following operations are available:
path | description |
---|---|
/check-only | checks the specified image against the policy |
/check-and-sign | checks and signs if the image passes the policy |
/event | if the event indicates the completion of a vulnerability scan, checks and signs the image |
Checkout the complete open API specification:
/check-only and /check-and-sign accept the following request message:
{
"image": "gcr.io/project/alpine@sha256:f86657a463e3de9e5176e4774640c76399b2480634af97f45354f1553e372cc9",
}
If the image passes the policy the response message will be:
{
"image": "gcr.io/project/alpine@sha256:f86657a463e3de9e5176e4774640c76399b2480634af97f45354f1553e372cc9",
"status": "ok"
}
If it does not pass the policy, the message will be.
{
"status": "failed",
"image": "gcr.io/speeltuin-mvanholsteijn/a27@sha256:f86657a463e3de9e5176e4774640c76399b2480634af97f45354f1553e372cc9",
"violations": [
"found unfixable CVE projects/goog-vulnz/notes/CVE-2018-18344 in gcr.io/project/alpine@sha256:f86657a463e3de9e5176e4774640c76399b2480634af97f45354f1553e372cc9, which has severity MEDIUM exceeding max unfixable severity LOW",
"found unfixable CVE projects/goog-vulnz/notes/CVE-2020-1751 in gcr.io/project/alpine@sha256:f86657a463e3de9e5176e4774640c76399b2480634af97f45354f1553e372cc9, which has severity MEDIUM exceeding max unfixable severity LOW",
]
}
/event accepts a normal pubsub event message:
{
"subscription": "vulnerability-attestor-container-analysis-occurrences",
"message": {
"data": "eyJuYW1lIjoicHJvamVjdHMvcHJvamVjdC9vY2N1cnJlbmNlcy9mNjJmMWU1MC1lMGUyLTQ3ZWYtOTI1ZC1iZDc5OTA1YWI4MmQiLCJraW5kIjoiRElTQ09WRVJZIiwibm90aWZpY2F0aW9uVGltZSI6IjIwMjAtMTEtMDZUMTU6MDM6NTAuNTMxMDgyWiJ9",
"id": "1681150847368976"
}
}
where the data will be provided by the container analysis service:
{
"name": "projects/project/occurrences/f62f1e50-e0e2-47ef-925d-bd79905ab82d",
"kind": "DISCOVERY",
"notificationTime": "2020-11-06T15:03:50.531082Z"
}
To install the kritis gcr signer:
-
Enable GCP services.
The signing tool needs to access a number of Google Cloud Platform (GCP) services. First we need to pick a GCP project and enable those services within the project.
-
Set the default GCP project used by
gcloud
.export PROJECT_ID=[PROJECT ID]
-
Set the default GCP project used by
gcloud
.gcloud config set project ${PROJECT_ID}
-
Run
gcloud
to enable services within a project.gcloud services enable \ run.googleapis.com \ binaryauthorization.googleapis.com \ cloudbuild.googleapis.com \ containerregistry.googleapis.com \ containeranalysis.googleapis.com \ containerscanning.googleapis.com \ cloudkms.googleapis.com # If using Cloud KMS
-
-
Build the grc signer container image.
gcloud builds submit --config deploy/gcr-kritis-signer/cloudbuild.yaml .
-
Enable Google Cloud service accounts and Cloud IAM roles.
-
Create a service account within the GCP project.
export SA_NAME=vulnerability-policy-attestor gcloud iam service-accounts create ${SA_NAME}
-
Add roles to the created service account.
# permission to create note gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ --role roles/containeranalysis.notes.editor # permission to view vulnerability and attestation occurrences gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ --role roles/containeranalysis.notes.occurrences.viewer # permission to upload attestation occurrences gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ --role roles/containeranalysis.occurrences.editor # (if using Cloud KMS) permission to cloud KMS signing service gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ --role roles/cloudkms.signer
-
-
Creating a signing key.
To create attestations for an image, the signer requires a private signing key. Run the following commands to create a keyring and an asymmetric signing key, and save the KMS key name.
gcloud kms keyrings create vulnerability-policy-attestors \ --location global gcloud --project=$PROJECT_ID kms keys create passed-vulnerability-policy \ --keyring vulnerability-policy-attestors \ --location global \ --purpose "asymmetric-signing" \ --default-algorithm "rsa-sign-pkcs1-2048-sha256"
Note down the digest algorithm “SHA256” and key name.
export KMS_DIGEST_ALG=SHA256 export KMS_KEY_NAME=projects/$PROJECT_ID/locations/global/keyRings/vulnerability-policy-attestors/cryptoKeys/passed-vulnerability-policy/cryptoKeyVersions/1
-
Create the attestor
Create the attestor for the note by adding its public key.
export NOTE_ID=passed-vulnerability-policy export NOTE_NAME=projects/${PROJECT_ID}/notes/${NOTE_ID} gcloud container binauthz attestors \ create vulnerability-policy \ --attestation-authority-note passed-vulnerability-policy \ --attestation-authority-note-project $PROJECT_ID gcloud container binauthz attestors public-keys add \ --attestor vulnerability-policy \ --keyversion-location global \ --keyversion-keyring vulnerability-policy-attestors \ --keyversion-key passed-vulnerability-policy \ --keyversion 1 \ --project $PROJECT_ID
-
Create vulnerability signing policy.
An example policy is in the samples.
cat samples/signer/policy.yaml apiVersion: kritis.grafeas.io/v1beta1 kind: VulnzSigningPolicy metadata: name: my-vsp spec: imageVulnerabilityRequirements: maximumFixableSeverity: MEDIUM maximumUnfixableSeverity: MEDIUM allowlistCVEs: - projects/goog-vulnz/notes/CVE-2020-10543 - projects/goog-vulnz/notes/CVE-2020-10878 - projects/goog-vulnz/notes/CVE-2020-14155
-
Run the kritis gcr signer as a service
-
Create the kritis-signer Cloud Run service:
gcloud run deploy gcr-kritis-signer \ --image gcr.io/${PROJECT_ID}/gcr-kritis-signer:latest \ --service-account ${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ --set-env-vars "ATTESTATION_POLICY=$(cat samples/signer/policy.yaml)" \ --timeout 2m \ --allow-unauthenticated \ --args="-vulnz_timeout=20s,-note_name=$NOTE_NAME,-kms_key_name=$KMS_KEY_NAME,-kms_digest_alg=$KMS_DIGEST_ALG" KRITIS_URL=$(gcloud run services describe gcr-kritis-signer --format 'value(status.url)')
Note that this service can now be invoked by unauthenticated users. We recommend to secure this for a production deployment.
-
subscribe to the container analysis occurrence notifications:
gcloud pubsub subscriptions create gcr-kritis-signer \ --topic container-analysis-occurrences-v1 \ --push-endpoint $KRITIS_URL/event
-
Now the signer will automatically sign images after the vulnerability scan completes.
-
Run signer on a built image (pass example).
-
Build and push an example good image.
docker build -t gcr.io/$PROJECT_ID/signer-test:good -f samples/signer/Dockerfile.good samples/signer docker push gcr.io/$PROJECT_ID/signer-test:good
-
Note down the image digest url.
export GOOD_IMG_URL=$(docker image inspect gcr.io/$PROJECT_ID/signer-test:good --format '{{index .RepoDigests 0}}')
-
wait until you see the attestation appear
gcloud container binauthz attestations list \ --artifact-url $GOOD_IMG_URL \ --attestor vulnerability-policy
-
you can also request a manual check by calling the service:
curl -d @- $KRITIS_URL/check-only <<! {"image": "$GOOD_IMG_URL"} !
-
or request a check-and-sign:
curl -d @- $KRITIS_URL/check-and-sign <<! {"image": "$GOOD_IMG_URL"} !
-
-
Run signer on a built image (fail example).
-
Build and push an example good image.
docker build -t gcr.io/$PROJECT_ID/signer-test:bad -f samples/signer/Dockerfile.bad samples/signer docker push gcr.io/$PROJECT_ID/signer-test:bad
-
Get the image digest url.
export BAD_IMG_URL=$(docker image inspect gcr.io/$PROJECT_ID/signer-test:bad --format '{{index .RepoDigests 0}}')
in this case, no attestation will appear.
gcloud container binauthz attestations list \ --artifact-url $BAD_IMG_URL \ --attestor vulnerability-policy
-
you can request a manual check to see the errors:
curl -d @- $KRITIS_URL/check-only <<! {"image": "$BAD_IMG_URL"} !
-
attempt to request a manual check-and-sign, will fail too:
curl -d @- $KRITIS_URL/check-and-sign <<! {"image": "$BAD_IMG_URL"} !
-