Skip to content
Image Signing and Scanning as a Service
Go Groovy Shell Dockerfile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
ci
cmd/image-scanning-signing-service
config
docs/images
examples
files
images
inventory
pkg
vendor
version
.gitignore
Gopkg.lock
Gopkg.toml
LICENSE
README.md
requirements.yml

README.md

Image Scanning and Signing Service

This repository is currently undergoing active development. Functionality may be in flux

Services to support image scanning and signing on the OpenShift Container Platform

Overview

The OpenShift Container Platform ecosystem contains mechanisms for securely managing container images. This includes but is not limited to image signing and image scanning. In addition, the platform also provides users with methods for specifying their intent for actions to be completed. A typical use case includes the creation of applications with certain replica counts. It can also include a desire to have actions, such as a desire to have an image signed or scanned.

The contents within this repository provide a service for which users declare their intent to scan and sign container images and the service facilitating this process on their behalf.

Concepts

Image Signing

Image signing is a way to apply a digital signature to a container image. This guide describes how an automated process can be created an implemented within OpenShift. The goal is to produce an environment that allows for only the execution of signed images from trusted sources (Red Hat Container Catalog [RHCC]) along with assets that are created within an organization or group.

Image Scanning

Image scanning is a process for inspecting the composition of a container image for vulnerabilities or threats. While there are a number of tools on the market today, this guide will describe how image scanning can be utilized to verify the content of images prior to their deployment into a production environment.

Self Service Model

One of the key traits of OpenShift is that the platform provides the ability for users to request and provision resources. The ability for a user to declare their intent to scan and sign images is consistent with the capabilities provided by the platform.

Architecture

The image scanning and signing service takes advantage of two key concepts in the OpenShift ecosystem:

  • Operators - Method of packaging, deploying, and managing Kubernetes Applications. This application leverages the Operator SDK to streamline the development of Operators.
  • Custom Resource Definitions - An extension of the OpenShift/Kubernetes API that allows users to interact with API objects in a similar manner as Pods

When combined with the a Custom Resource Definition, a custom controller can react upon the intents specified by the user and perform a set of actions, such as triggering the scanning and signing of an image.

Provisioning

The process for building and deploying the infrastructure to support the tooling contained within this repository has been declaratively described through a set of OpenShift configurations and templates. These objects can be applied to an OpenShift environment through the openshift-applier.

Prerequisites

The following prerequisites must be met in order to deploy the components through the openshift-applier:

  • Ansible
  • OpenShift Command Line tool
  • An OpenShift environment with the ability to create cluster level resources

For disconnected and Satellite installation, below repo must be enabled:

  • rhel-7-server-optional-rpms

Deployment

Currently, there are two types of deployments:

  • Core infrastructure
  • Continuous Integration/Continuous Delivery demonstration (in subsequent section)

Depending on the type of deployment that you are targeting, filter_tags as part of the openshift-applier can be specified as described below.

Complete the following steps to deploy the Image Scanning and Signing Service.

  1. Clone this repository to your local machine and navigate into the repository

     git clone https://github.com/sabre1041/image-scanning-signing-service
     cd image-scanning-signing-service
    
  2. Run Ansible Galaxy to pull in required Ansible dependencies

     ansible-galaxy install -r requirements.yml -p galaxy
    
  3. Login to OpenShift cluster as a user with cluster-admin rights

     oc login -u <username> https://<openshift-server>
    
  4. Execute provisioning

To deploy the core infrastructure, specify the Ansible environment variable -e filter_tags=core as shown below

	ansible-playbook -i inventory/ galaxy/openshift-applier/playbooks/openshift-cluster-seed.yml -e filter_tags=core

Confirm the ansible run was successful. A series of builds and deployments will occur within OpenShift. Provisioning will be successful when a pod starting with image-scanning-signing-service from the command oc get pods -n image-management

Demonstrations

There are multiple ways to demonstrate image scanning and image signing inaction.

Simple Workflow

To facilitate Image Signing, the image-scanning-signing-service makes use of a ImageSigningRequest Custom Resource Definition which allows users to declare their intent to have an image signed. This section will walk through the process of signing an image after a new image has been built.

OpenShift provides a number of quickstart templates. One of these templates contains a simple .NET Core web application application. This is an ideal use case to showcase image signing in action.

Build an Application

First, create a new project called dotnet-example

oc new-project dotnet-example

Instantiate the dotnet-example template within the project using the default values specified in the template

oc new-app --template=dotnet-example

Monitor the status of the build triggered by the template instantiation

oc get builds

When the build completes, the image has been pushed to the OpenShift internal registry and the latest tag is updated on the ImageStream. This can be verified by running oc get is

Declare an Intent to Sign the Image

To declare your intent to sign the previously built image, a new ImageSigningRequest can be created within the project. A typical request is shown below

apiVersion: cop.redhat.com/v1alpha2
kind: ImageSigningRequest
metadata:
  name: dotnet-app
spec:
  imageStreamTag: dotnet-example:latest

As seen in the example above, the key field of note is the name of the object (dotnet-example) and the imageStreamTag (dotnet-example:latest).

A template is available to streamline generating an ImageSigningRequest in the examples/image-signing-request-template.yml file. Two parameters are required:

  • Name of the object to be created
  • ImageStreamTag of the image that should be signed in the current project

To create a new ImageSigningRequest with the name dotnet-example and the ImageStreamTag dotnet-example:latest, execute the following command:

oc process -f examples/image-signing-request-template.yml -p IMAGE_SIGNING_REQUEST_NAME=dotnet-example IMAGE_STREAM_TAG=dotnet-example:latest | oc apply -f-

Confirm the new ImageSigningRequest was successfully created by running oc get imagesigningrequests

As soon as the object is created, the controller will create a new signing pod in the image-management project. This can be seen by running oc get pods -n image-management. Feel free to track the status of the signing action by viewing the logs from the signing pod.

Once the pod signing pod completes successfully, the ImageSigningRequest will be updated and contain the name of the signed image in the Status section. Confirm this by running oc get imagesigningrequest dotnet-example -o yaml.

Finally, the newly created Image will contain the signatures associated with the signing action. This can be confirmed by running the following command:

oc get image $(oc get imagesigningrequest dotnet-example --template='{{ .status.signedImage }}') -o yaml

Confirm the response contains a signatures section similar to the following:

signatures:
- content: owGbwMvMwMRo/+eUg2nAWlHG0we6khiiuks1q5WSizJLMpMTc5SsqpUyU1LzSjJLKkHslPzk7NQi3aLUtNSi1LzkVCUrhFB6ZnFJUaVeSmpaYmlOiV5xWbKVqYGBgX5KfkleaoluYkEBjJlakZhbkJNqlZNYklpcolSro5SZm5ieimRBbmJeZhpQTjclMx2kxEqpOCPRyNTMKik5JckyMcXAwsLQ2CjJwCLFIjnJLM00zdzYMC0x2dLCINXcNMnQwMLc3DQl1dzcyNDc3NwESBskWxoYGpskgiwrqSwAOTyxJD83M1khOT+vJDEzL7VIoTgzPS+xpLQoFaQov6AkMz8PEgLJRalAxUUIPQZ6hnoGuimpZUpA0zJzgS4EekjJytDU0BLoMktj89raTkYZFgZGJgY2ViZQkDJwcQrAAnrvPfb/zjP7ytTT7u1oP/AgZnFN1tuPe3vVjSza18gw/Nx7obY8cmXj/f0rmpR2rX+x7rbf+Un/bzz32vtae76e1vfOQIOCrVZmlfOs09XF31tL5N9qCL4owhHBpRauqyxYMK1oS71OTlVPXf9XHTbf0g1Lmr8u3W+r81y12uM27xbl/mjXi7evdKw8toztsqrmtUqLx1E7aqf/MU959ezao09yvmebY/mYF4Ssq9sga2PkHDi9zjG+N05vsbLDrvP1q6fUTbaxE1JU7t796dll4x5m8Qf1Dy0MFVYwskeJVBtz9Md8eF+fVZkXvHBvxPY7ZWJbP3Vp3wnk2nvcae/Gm6dWLrtnHMs4J3lRrvC/G7cA
  metadata:
    creationTimestamp: 2018-02-20T01:08:57Z
    name: sha256:bcdb9ad088132b08d8cb6f5f731fac980e75b108775de772177747720c90134a@81f1f60851e175e008bba542f3cd443b
    uid: a08ed947-15da-11e8-ae24-fa163e6706b0
  type: atomic

Specifying a custom GPG key to utilize

Instead of leveraging the default gpg key that is configured within the cluster, users can specify a separate GPG key to use to sign the image. The GPG key is stored within a secret and injected into the signing pod at runtime.

First, create a new secret within the current project containing the GPG key:

oc create secret mygpgkey <directory_containing_gpg_key>

Create a new ImageSigningRequest which specifies the secret and signer address:

apiVersion: "cop.redhat.com/v1alpha2"
kind: ImageSigningRequest
metadata:
  name: dotnet-app-mygpgkey
spec:
  imageStreamTag: "dotnet-example:latest"
  signingKeySecretName: mygpgkey
  signingKeySignBy: custom-openshift@example.com

Declare an Intent to Scan The Image

To declare your intent to scan the previously built image, a new ImageScanningRequest can be created within the project. A typical request is shown below

apiVersion: cop.redhat.com/v1alpha2
kind: ImageScanningRequest
metadata:
  name: dotnet-app
spec:
  imageStreamTag: dotnet-example:latest

As seen in the example above, the key field of note is the name of the object (dotnet-example) and the imageStreamTag (dotnet-example:latest).

A template is available to streamline generating an ImageScanningRequest in the examples/image-scanning-request-template.yml file. Two parameters are required:

  • Name of the object to be created
  • ImageStreamTag of the image that should be scanned in the current project

To create a new ImageScanningRequest with the name dotnet-example and the ImageStreamTag dotnet-example:latest, execute the following command:

oc process -f examples/image-scanning-request-template.yml -p IMAGE_SCANNING_REQUEST_NAME=dotnet-example IMAGE_STREAM_TAG=dotnet-example:latest | oc apply -f-

Confirm the new ImageScanningRequest was successfully created by running oc get imagescanningrequests

As soon as the object is created, the controller will create a new scanning pod in the image-management project. This can be seen by running oc get pods -n image-management. Feel free to track the status of the scanning action by viewing the logs from the scanning pod.

Once the scan completes, a WebDav server is started within the pod to host the reports. The controller will communicate with the pod and retrieve the results. The ImageSigningRequest will be updated and contain the statistics from the scan in the scanResult section of the Status section. Confirm this by running oc get imagescanningrequest dotnet-example -o yaml.

Finally, the newly created Image will contain the results associated with the scanning action. This can be confirmed by running the following command:

oc get imagescanningrequest dotnet-example -o yaml

Confirm the response contains a signatures section similar to the following:

status:
  conditions:
  - lastTransitionTime: 2018-07-16T14:34:20Z
    message: Scanning Pod Launched 'image-management/42b15f17-8905-11e8-961e-fa163e236d0f'
    status: "True"
    type: Initialization
  - lastTransitionTime: 2018-07-16T14:35:04Z
    message: Image Scanned
    status: "True"
    type: Finished
  endTime: 2018-07-16T14:35:04Z
  phase: Completed
  scanResult:
    failedRules: 2
    passedRules: 659
    totalRules: 661
  startTime: 2018-07-16T14:34:20Z

Notice the scanResult field which contains the results of the scan.

Continuous Integration and Continuous Delivery

This example demonstrates how to leverage image scanning and signing as part of a Continuous Integration and Continuous Delivery pipeline.

Provisioning

Similar to the deployment of the core infrastructure, this demonstration can be provisioned using the OpenShift applier by specifying the -e filter_tags=pipeline Ansible environment variable.

Execute the following command to provision the components:

	ansible-playbook -i inventory/ galaxy/openshift-applier/playbooks/openshift-cluster-seed.yml -e filter_tags=pipeline

Once complete, a new project called image-scanning-signing-pipeline which will contain a Jenkins server along with application build (JenkinsPipeline and Binary S2I) along with deployment objects.

Triggers have been enabled on the Jenkins pipeline so a build will be triggered automatically.

Login to the OpenShift web console and select the Image Scanning and Signing Pipeline project. View running pipelines by hovering over Builds on the lefthand navigation bar and select Pipelines.

Under Build #1, select View Log which will redirect to the Jenkins instance which was deployed.

You can view the progress of the build log. Otherwise, select Back to Project on the lefthand navigation links to view the overall state of the builds.

As it progresses through the pipeline, the following actions will occur:

  • Code build
  • Image build
  • Image scanning and signing actions
  • Application deployments

Once successful, the stage view will appear similar to the following:

CICD  PIpeline

Back within the OpenShift web console, locate the address of the exposed Route to access the application by hovering over Applications on the lefthand navigation bar and selecting Routes. Click on the URL provided underneath Hostname.

To learn more about the underlying steps that are executed within the pipeline, browse through the included Jenkinsfile.

Known Issues

  • Currently, the latest version of the image-inspector binary suffers from a bug causing reduced functionality. The --openscap-html-report option mishandles the parsing of the results-arf.xml in image-sign-scan-base This casues the execution of image scans to fail. A workaround has been applied to the image-sign-scan-base image to ignore this flag. Reduced functionality of no HTML report generation for all image scan requests is expected until the upstream image-inspector is fixed. Please see https://github.com/openshift/image-inspector/issues/105
You can’t perform that action at this time.