From fef561517117505bca3693ad6e1415a9ec7a4203 Mon Sep 17 00:00:00 2001 From: Toshi Yamamoto Date: Fri, 15 May 2020 18:59:44 -0400 Subject: [PATCH 1/3] initial drop --- signature-server/sample/.gitignore | 77 +++++++ signature-server/sample/README.md | 159 ++++++++++++++ .../deploy/signature-server-combined.yaml | 201 ++++++++++++++++++ signature-server/sample/image/build.sh | 17 ++ .../sample/image/init-server/Dockerfile | 4 + .../sample/image/init-server/build.sh | 9 + .../image/init-server/init-server-bc.yaml | 23 ++ .../image/init-server/init-server-stream.yaml | 12 ++ .../sample/image/server/Dockerfile | 24 +++ signature-server/sample/image/server/build.sh | 13 ++ .../image/server/signature-server-bc.yaml | 28 +++ .../image/server/signature-server-stream.yaml | 12 ++ .../sample/image/server/store.php | 135 ++++++++++++ .../sample/sample/sample-pod.yaml | 11 + .../sample/sample/sample-sigstore-ca.yaml | 17 ++ 15 files changed, 742 insertions(+) create mode 100644 signature-server/sample/.gitignore create mode 100644 signature-server/sample/README.md create mode 100644 signature-server/sample/deploy/signature-server-combined.yaml create mode 100755 signature-server/sample/image/build.sh create mode 100644 signature-server/sample/image/init-server/Dockerfile create mode 100755 signature-server/sample/image/init-server/build.sh create mode 100644 signature-server/sample/image/init-server/init-server-bc.yaml create mode 100644 signature-server/sample/image/init-server/init-server-stream.yaml create mode 100644 signature-server/sample/image/server/Dockerfile create mode 100755 signature-server/sample/image/server/build.sh create mode 100644 signature-server/sample/image/server/signature-server-bc.yaml create mode 100644 signature-server/sample/image/server/signature-server-stream.yaml create mode 100644 signature-server/sample/image/server/store.php create mode 100644 signature-server/sample/sample/sample-pod.yaml create mode 100644 signature-server/sample/sample/sample-sigstore-ca.yaml diff --git a/signature-server/sample/.gitignore b/signature-server/sample/.gitignore new file mode 100644 index 0000000..7c50470 --- /dev/null +++ b/signature-server/sample/.gitignore @@ -0,0 +1,77 @@ +# Temporary Build Files +build/_output +build/_test +# Created by https://www.gitignore.io/api/go,vim,emacs,visualstudiocode +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* +# Org-mode +.org-id-locations +*_archive +# flymake-mode +*_flymake.* +# eshell files +/eshell/history +/eshell/lastdir +# elpa packages +/elpa/ +# reftex files +*.rel +# AUCTeX auto folder +/auto/ +# cask packages +.cask/ +dist/ +# Flycheck +flycheck_*.el +# server auth directory +/server/ +# projectiles files +.projectile +projectile-bookmarks.eld +# directory configuration +.dir-locals.el +# saveplace +places +# url cache +url/cache/ +# cedet +ede-projects.el +# smex +smex-items +# company-statistics +company-statistics-cache.el +# anaconda-mode +anaconda-mode/ +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +# Test binary, build with 'go test -c' +*.test +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +### Vim ### +# swap +.sw[a-p] +.*.sw[a-p] +# session +Session.vim +# temporary +.netrwhist +# auto-generated tag files +tags +### VisualStudioCode ### +.vscode/* +.history +# End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode diff --git a/signature-server/sample/README.md b/signature-server/sample/README.md new file mode 100644 index 0000000..bf7d9e4 --- /dev/null +++ b/signature-server/sample/README.md @@ -0,0 +1,159 @@ +# Welcome to the Kabanero look aside signature server and related files. + +# Table of Contents +1. [About Look aside signature server](#About-look-aside-signature-server) +1. [Prerequisite](#Prerequisite) +1. [Build](#Build) + 1. [Copy kabanero-security Git repository](#Copy-kabanero-security-Git-repository) + 1. [Building the images](#Building-the-images) +1. [Deploy](#Deploy) +1. [Configuration](#Configuration) + 1. [Signature data backup](#Signature-data-backup) + 1. [Persistent storage](#Persistent-storage) +1. [Accessing the server](#Accessing-the-server) + 1. [Storing signatures](#Storing-signatures) + 1. [Getting signatures](#Getting-signatures) + + +# About look aside signature server +This server can be used as an augmenting server for any existing image registry to support the image signing and verification which is defined by [signature data](https://github.com/containers/image/blob/master/docs/containers-signature.5.md) and [access protocol](https://github.com/containers/image/blob/master/docs/signature-protocols.md). + +This server is not designed for the production environment, but for development and evaluation purposes. +In order to provide zero configuration experience, it uses a k8s secret as a backup storage, thus the maximum number of signatures which can be stored is about 500. +In order to secure the data, it is recommended to use a persistent storage for storing the signatures. + +This server consists of three container images. +* **initialize server** - The image for initializing the pod. It restores the back up data from the k8s secret named `signature-data` +* **signature server** - The image of the signature server which is a PHP server with apache http server. It is a simple http server which takes signatures by PUT request and returns signatures by GET request. When, a new signature is stored, it creates a zip file which contains entire signature storage and places the zip data to teh secret `signature-data` in a namespace where this server is deployed. +* **oauth proxy** - The OpenShift oauth proxy server which protects PUT requests by enforcing RBAC. +The PUT request is granted if an account is allowed creating secret resource. + +# Prerequisite + +This sample uses ImageStream of OpenShift, therefore OpenShift CLI environment of OpenShift Cluster 4.x is required. And all of instruction is described by using oc commands. + +# Build +## Copy kabanero-security Git repository + +After [download](https://github.com/kabanero-io/kabanero-security/archive/master.zip) and unzip the file, or [clone](https://github.com/kabanero-io/kabanero-security.git) the repository, change the current directory to `kabanero-security`. + +## Building the images + +Since the build is done by the image stream on OpenShift, login to a cluster prior to run the build script. + +(example) +``` +oc login -u admin -p security https://openshift.my.com:8443/ +``` + +Run the `signature-server/sample/image/build.sh` to build two servers. + +The build creates the image in kabanero-security namespace and push the image to the OCP internal image registry. Note that the namespace can be changed by modifying `signature-server/sample/image/build.sh`. + +Verify the servers have been created as ImageStream. + +(example output) +``` +[admin@openshift imagestream]# oc get is -n kabanero-security +NAME IMAGE REPOSITORY TAGS UPDATED +signatures-init-server image-registry.openshift-image-registry.svc:5000/kabanero-security/signatures-init-server latest 3 minutes ago +signatures-server image-registry.openshift-image-registry.svc:5000/kabanero-security/signatures-server latest 2 minutes ago +``` + +# Deploy +Deploy a pod which hosts the images for the look aside signature server with required resources. + +``` +oc apply -n kabanero-security -f signature-server/sample/deploy/signature-server-combined.yaml +``` +(example output) +``` +[admin@openshift deploy]# oc apply -n kabanero-security -f signature-server/sample/deploy/signature-server-combined.yaml +configmap/signature-server-config created +serviceaccount/signature-server created +clusterrole.rbac.authorization.k8s.io/signature-server created +clusterrolebinding.rbac.authorization.k8s.io/signature-server created +route.route.openshift.io/signature-server created +service/signature-server created +deployment.apps/signature-server created +``` + +Verify that the pod is up and running +``` +oc get pod -n kabanero-security +``` +(example output) +``` +[admin@openshift deploy]# oc get pod -n kabanero-security +NAME READY STATUS RESTARTS AGE +signature-init-server-1-build 0/1 Completed 0 10m +signature-server-1-build 0/1 Completed 0 8m24s +signature-server-5549cfd69b-mq8hc 2/2 Running 0 98s +``` +# Configuration + +There is not any configuration prior to use the server.However, it is recommended to use a persistent storage for preventing a potential of data loss. + +## Signature data backup +By default, the look aside signature server does not require any persistent storage, instead, it stores the whole signature data to a secret resource named `signature-data`, in this secret, the zipped data is stored as `stored.zip` file. +This file is restored during the initialization when a pod which contains the look aside signature store server is started. + +## Persistent storage +In order to use persistent storage, mount any persistent storage to `/var/www/sigstore/html/signatures/`. The original configuration mounts an emptyDir. +At the same time, set `sigstore-save-secret` data in `signature-server-config' config map as `false` in order to disable storing the signatures as a secret. + + +# Accessing the server + +## Storing signatures +To store a signature, a HTTP PUT method is used. The target URI is the form + +> `/staging/`_registry_`/`_namespaces_`/`_name_`@`_digest-algo_`=`_digest-value_`/signature-`_index_ + +The target is protected by OpenShift OAuth proxy. A bearer token is required to authenticate and authorize a request. The token needs to be granted accessing a secret and web resources. For Kabanero either using kabanero-operator service account or use image-signer sample service account which is available in this repository. + +The following shows an example by using curl when a signature of which name is signature-1 is for the image `mynamespace/busybox@sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e` which is stored in a registry `registry.example.com:5000` and a url of a look aside signature store is `signatures-server-icp4app-security.apps.myocp.example.com` +You need to modify existing Tekton tasks to add the code to put a generated signature to the signature server. +``` +TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token` + +curl -X PUT -H "Authorization: Bearer $TOKEN" -T "@signature-1" https://signatures-server-icp4app-security.apps.myocp.example.com/signatures/registry.example.com=5000/mynamespace/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-1 +``` + +When a signature stored without any error, HTTP response code 201 is returned along with a text. Otherwise it returns HTTP response code other than 201. + +The expected error codes include: + +* _302_ - Authorization error +* _400_ - invalid path +* _507_ - failiure while storing a signature +Other error codes might be returned by oauth server, http server or php server. + +Example of success case: + +`Result:Success: stored to secret` + + +## Getting signatures + +Signatures are accessed by HTTP GET method using URLs of the form. This is done by the application which supports the image verification. The target is not protected, so as far as the a signature is available for the specified URL, the contents are returned. + +> `/signatures/`_registry_`/`_namespaces_`/`_name_`@`_digest-algo_`=`_digest-value_`/signature-`_index_ + +where _registry_ is the container image registry hostname and port. _=_ is used as a delimitor between host and port. (i.e., registry.example.com=5000). The rest of the values are documented [here](https://github.com/containers/image/blob/master/docs/signature-protocols.md#path-structure). +For example, if an image is available as `mynamespace/busybox@sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e` which is stored in a registry `registry.example.com:5000` and a url of a look aside signature store is `signatures-server-icp4app-security.apps.myocp.example.com`, the URL is + +`https://signatures-server-icp4app-security.apps.myocp.example.com/signatures/registry.example.com=5000/mynamespace/busybox@sha256=817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e/signature-1` + +The target root URL need to be placed in a specific docker configuration file. Please refer to [this documentation](https://github.com/containers/image/blob/master/docs/containers-registries.d.5.md) +For example, if the target image registry is `registry.example.com:5000` and a url of a look aside signature store is `signatures-server-icp4app-security.apps.myocp.example.com`, the file need to have the following entry. Also make sure `/etc/containers/policy.json` file is configured to set the public key which is used for verification. + +``` +docker: + registry.example.com:5000: + sigstore: https://signatures-server-icp4app-security.apps.myocp.example.com/signatures/registry.example.com=5000 +``` + +#### Signature data backup +By default, the look aside signature store server does not require any persistent storage, instead, it stores the whole signature data to a secret resource named _signature-data_, in this secret, the zipped data is stored as _stored.zip_ file. +This file is restored during the initialization when a pod which contains the look aside signature store servr is started. \ No newline at end of file diff --git a/signature-server/sample/deploy/signature-server-combined.yaml b/signature-server/sample/deploy/signature-server-combined.yaml new file mode 100644 index 0000000..d278029 --- /dev/null +++ b/signature-server/sample/deploy/signature-server-combined.yaml @@ -0,0 +1,201 @@ +kind: List +apiVersion: v1 +items: +# ConfigMap for enabling storing segnatures data to a secret. +- apiVersion: v1 + kind: ConfigMap + metadata: + name: signature-server-config + data: + sigstore-save-secret: "true" +# Service Account +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: signature-server + annotations: + serviceaccounts.openshift.io/oauth-redirectreference.primary: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"signature-server"}}' +# ClusterRole +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: signature-server + rules: + - apiGroups: + - '' + resources: + - secrets + - serviceaccounts + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch + - apiGroups: + - 'image.openshift.io' + resources: + - '*' + verbs: + - '*' + - apiGroups: + - 'authentication.k8s.io' + resources: + - tokenreviews + verbs: + - '*' + - apiGroups: + - 'authorization.k8s.io' + resources: + - subjectaccessreviews + verbs: + - '*' +# Role binding +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: signature-server + subjects: + - kind: ServiceAccount + name: signature-server + namespace: kabanero-security + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: signature-server +# Route a connection to the proxy. +- apiVersion: v1 + kind: Route + metadata: + name: signature-server + spec: + to: + kind: Service + name: signature-server + tls: + termination: reencrypt +- apiVersion: v1 + kind: Service + metadata: + name: signature-server + annotations: + service.alpha.openshift.io/serving-cert-secret-name: proxy-tls + spec: + ports: + - name: http + port: 443 + targetPort: 8443 + selector: + app: signature-server + +# Launch a proxy as a sidecar +- apiVersion: apps/v1 + kind: Deployment + metadata: + name: signature-server + spec: + replicas: 1 + selector: + matchLabels: + app: signature-server + template: + metadata: + labels: + app: signature-server + spec: + serviceAccountName: signature-server + restartPolicy: Always + triggers: + - type: ConfigChange + initContainers: + - name: signature-init-server + image: image-registry.openshift-image-registry.svc:5000/kabanero-security/signature-init-server + env: + - name: SIGSTORE_SAVE_SECRET + valueFrom: + configMapKeyRef: + name: signature-server-config + key: sigstore-save-secret + command: ['/bin/bash'] + args: + - -c + - | + shopt -s nocasematch + if [[ $SIGSTORE_SAVE_SECRET == "true" ]] + then + STORED="/tmp/signature-data/stored.zip" + if [[ -f $STORED ]] + then + echo "Restore signature data from backup." + unzip $STORED -d /tmp/signatures + echo "Restored." + else + echo "The backup does not exist." + fi + else + echo "No need to restore signature data." + fi + + volumeMounts: + - name: signatures + mountPath: /tmp/signatures/ + - name: signature-data + mountPath: /tmp/signature-data/ + containers: + - name: oauth-proxy + image: openshift/oauth-proxy:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8443 + name: public + args: + - --https-address=:8443 + - --provider=openshift + - --openshift-service-account=signature-server + - --upstream=http://localhost:8080 + - --tls-cert=/etc/tls/private/tls.crt + - --tls-key=/etc/tls/private/tls.key + - --cookie-secret=SECRET + - --openshift-sar={"group":"","resource":"secrets","verb":"create"} + - --openshift-delegate-urls={"/":{"group":"","resource":"secrets","verb":"create"}} + - --skip-auth-regex=^/signatures/.* + - --skip-provider-button + volumeMounts: + - mountPath: /etc/tls/private + name: proxy-tls + - name: signature-server + image: image-registry.openshift-image-registry.svc:5000/kabanero-security/signature-server:latest + imagePullPolicy: Always + ports: + - containerPort: 8080 + protocol: TCP + resources: {} + env: + - name: SIGSTORE_SAVE_SECRET + valueFrom: + configMapKeyRef: + name: signature-server-config + key: sigstore-save-secret + volumeMounts: + - name: signatures + mountPath: /var/www/sigstore/html/signatures/ + volumes: + - name: proxy-tls + secret: + secretName: proxy-tls + - name: signature-data + secret: + secretName: signature-data + optional: true + - name: signatures + emptyDir: {} + + + + + + + diff --git a/signature-server/sample/image/build.sh b/signature-server/sample/image/build.sh new file mode 100755 index 0000000..033231a --- /dev/null +++ b/signature-server/sample/image/build.sh @@ -0,0 +1,17 @@ +#!/bin/bash +NAMESPACE=kabanero-security +# Create a namespace to store the signed image +oc get namespace $NAMESPACE +if [ $? -ne 0 ]; then + echo "Creating namespace $NAMESPACE" + oc create namespace $NAMESPACE +fi +BASE_DIR="$(cd $(dirname $0) && pwd)" +cd $BASE_DIR +echo "Building signature-init-server" +init-server/build.sh $NAMESPACE +if [ $? -ne 0 ]; then +exit 1 +fi +echo "Building signature-server" +server/build.sh $NAMESPACE diff --git a/signature-server/sample/image/init-server/Dockerfile b/signature-server/sample/image/init-server/Dockerfile new file mode 100644 index 0000000..2313cfe --- /dev/null +++ b/signature-server/sample/image/init-server/Dockerfile @@ -0,0 +1,4 @@ +FROM registry.access.redhat.com/ubi8:latest + +RUN yum --disableplugin=subscription-manager install -y unzip + diff --git a/signature-server/sample/image/init-server/build.sh b/signature-server/sample/image/init-server/build.sh new file mode 100755 index 0000000..f80fa08 --- /dev/null +++ b/signature-server/sample/image/init-server/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e +NAMESPACE=$1 + +BASE_DIR="$(cd $(dirname $0) && pwd)" +cd $BASE_DIR +oc apply -f init-server-bc.yaml -f init-server-stream.yaml -n $NAMESPACE +oc start-build signature-init-server --from-file=Dockerfile --follow -n $NAMESPACE diff --git a/signature-server/sample/image/init-server/init-server-bc.yaml b/signature-server/sample/image/init-server/init-server-bc.yaml new file mode 100644 index 0000000..e790b90 --- /dev/null +++ b/signature-server/sample/image/init-server/init-server-bc.yaml @@ -0,0 +1,23 @@ +# BuildConfig for creating the image containing the image signing initializing server. +apiVersion: build.openshift.io/v1 +kind: BuildConfig +metadata: + labels: + build: signature-init-server + name: signature-init-server +spec: + failedBuildsHistoryLimit: 5 + nodeSelector: null + output: + to: + kind: ImageStreamTag + name: signature-init-server:latest + postCommit: {} + resources: {} + runPolicy: Serial + source: + binary: {} + strategy: + dockerStrategy: {} + type: Docker + successfulBuildsHistoryLimit: 5 diff --git a/signature-server/sample/image/init-server/init-server-stream.yaml b/signature-server/sample/image/init-server/init-server-stream.yaml new file mode 100644 index 0000000..0598339 --- /dev/null +++ b/signature-server/sample/image/init-server/init-server-stream.yaml @@ -0,0 +1,12 @@ +#ImageStream for creating the image containing the image signing lookaside initialization server +apiVersion: image.openshift.io/v1 +kind: ImageStream +metadata: + labels: + build: signature-init-server + name: signature-init-server +spec: + lookupPolicy: + local: false +status: + dockerImageRepository: "" diff --git a/signature-server/sample/image/server/Dockerfile b/signature-server/sample/image/server/Dockerfile new file mode 100644 index 0000000..44d7345 --- /dev/null +++ b/signature-server/sample/image/server/Dockerfile @@ -0,0 +1,24 @@ +FROM registry.access.redhat.com/ubi8:latest + +RUN yum --disableplugin=subscription-manager module -y enable php:7.2 \ +# && yum --disableplugin=subscription-manager install -y httpd php libzip php-pecl-zip mod_ssl\ + && yum --disableplugin=subscription-manager install -y httpd php libzip php-pecl-zip\ + && yum --disableplugin=subscription-manager install -y zip unzip + +RUN mkdir -p /var/www/sigstore/html/staging/ \ + && rm -f /etc/httpd/conf.d/welcome.conf + +COPY phpfile/store.php /var/www/sigstore/html/staging/ + +RUN sed -i 's/Listen 80/Listen 8080/' /etc/httpd/conf/httpd.conf \ + && sed -i 's/DocumentRoot "\/var\/www\/html"/DocumentRoot "\/var\/www\/sigstore\/html"/' /etc/httpd/conf/httpd.conf \ + && echo -e "\n\n\tOptions -Indexes\n" >> /etc/httpd/conf/httpd.conf \ + && echo -e "\nRewriteEngine On\nRewriteCond %{REQUEST_METHOD} !^(GET|PUT|HEAD)\nRewriteRule .* - [R=405,L]\n" >> /etc/httpd/conf/httpd.conf \ + && echo -e "\nScript PUT /staging/store.php\n" >> /etc/httpd/conf/httpd.conf \ + && sed -i 's/;clear_env = no/clear_env = no/' /etc/php-fpm.d/www.conf \ + && mkdir /run/php-fpm \ + && chgrp -R 0 /var/log/httpd /var/run/httpd /run/php-fpm /var/www/sigstore \ + && chmod -R g=u /var/log/httpd /var/run/httpd /run/php-fpm /var/www/sigstore + +EXPOSE 8080 +CMD php-fpm & httpd -D FOREGROUND diff --git a/signature-server/sample/image/server/build.sh b/signature-server/sample/image/server/build.sh new file mode 100755 index 0000000..3f66039 --- /dev/null +++ b/signature-server/sample/image/server/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e +NAMESPACE=$1 +BASE_DIR="$(cd $(dirname $0) && pwd)" +echo $BASE_DIR +cd $BASE_DIR + +oc delete configmap phpfile -n $NAMESPACE | true +oc create configmap phpfile --from-file store.php -n $NAMESPACE +oc apply -f signature-server-bc.yaml -f signature-server-stream.yaml -n $NAMESPACE +oc start-build signature-server --from-file=Dockerfile --follow -n $NAMESPACE +oc delete configmap phpfile -n $NAMESPACE diff --git a/signature-server/sample/image/server/signature-server-bc.yaml b/signature-server/sample/image/server/signature-server-bc.yaml new file mode 100644 index 0000000..9a01275 --- /dev/null +++ b/signature-server/sample/image/server/signature-server-bc.yaml @@ -0,0 +1,28 @@ +# BuildConfig for creating the image containing the image signing lookaside server. +apiVersion: build.openshift.io/v1 +kind: BuildConfig +metadata: + labels: + build: signature-server + name: signature-server +spec: + failedBuildsHistoryLimit: 5 + nodeSelector: null + output: + to: + kind: ImageStreamTag + name: signature-server:latest + postCommit: {} + resources: {} + runPolicy: Serial + source: + binary: {} + configMaps: + - configMap: + name: phpfile + destinationDir: phpfile + type: Binary + strategy: + dockerStrategy: {} + type: Docker + successfulBuildsHistoryLimit: 5 diff --git a/signature-server/sample/image/server/signature-server-stream.yaml b/signature-server/sample/image/server/signature-server-stream.yaml new file mode 100644 index 0000000..649be08 --- /dev/null +++ b/signature-server/sample/image/server/signature-server-stream.yaml @@ -0,0 +1,12 @@ +#ImageStream for creating the image containing the image signing lookaside server +apiVersion: image.openshift.io/v1 +kind: ImageStream +metadata: + labels: + build: signature-server + name: signature-server +spec: + lookupPolicy: + local: false +status: + dockerImageRepository: "" diff --git a/signature-server/sample/image/server/store.php b/signature-server/sample/image/server/store.php new file mode 100644 index 0000000..0b9f1a1 --- /dev/null +++ b/signature-server/sample/image/server/store.php @@ -0,0 +1,135 @@ +open($zipfile, ZipArchive::CREATE | ZipArchive::OVERWRITE); + $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($rootpath), RecursiveIteratorIterator::LEAVES_ONLY); + + foreach ($files as $name => $file) { + // no need to zip directories. + if (!$file->isDir()) { + $filepath = $file->getRealPath(); + $relativepath = substr($filepath, strlen($rootpath) + 1); + $zip->addFile($filepath, $relativepath); + } + } + $zip->close(); + return true; + } + + function createSecretJson($zipfile, $jsonfile) { + $data = file_get_contents($zipfile); + if (strlen($data) > 0) { + $encoded = base64_encode($data); + $contents = '{"apiVersion": "v1","kind": "Secret","metadata":{"name": "signature-data"},"data": {"stored.zip": '; + $len = file_put_contents($jsonfile, $contents . '"' . $encoded . '"}}', LOCK_EX); + if ($len == 0) { + error_log("error: failed to create a secret. file creation error"); + return false; + } elseif ($len > 1000000) { + error_log("error: failed to create a secret. data is too large to store."); + return false; + } + return true; + } + error_log("failed to create a secret. zip file read error"); + return false; + } + + function setSecret($jsonfile) { + $server="https://" . getenv("KUBERNETES_SERVICE_HOST") . ":" . getenv("KUBERNETES_SERVICE_PORT"); + $token=file_get_contents("/var/run/secrets/kubernetes.io/serviceaccount/token"); + $namespace=file_get_contents("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); + $name="signature-data"; + if (existSecret($server, $namespace, $token, $name)) { + $command='curl -k -X PUT -d "@'. $jsonfile . '" -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer ' . $token . '" ' . $server . '/api/v1/namespaces/' . $namespace . '/secrets/' . $name; + } else { + $command='curl -k -X POST -d "@'. $jsonfile . '" -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer ' . $token . '" ' . $server . '/api/v1/namespaces/' . $namespace . '/secrets'; + } + exec($command, $output, $return_var); + if ($return_var==0) { + if (isSuccess($output)) { + return true; + } + // error case + error_log("error: failed to set secret in a REST call."); + return false; + } + // fail curl + error_log("error: failed to set secret in cURL call."); + return false; + } + + function existSecret($server, $namespace, $token, $name) { + $command='curl -k -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer ' . $token . '" ' . $server . '/api/v1/namespaces/' . $namespace . '/secrets/' . $name; + exec($command, $output, $return_var); + if ($return_var ==0) { + if (isSuccess($output)) { + return true; + } + } + return false; + } + + function isSuccess($output) { + foreach($output as $value) { + if ((strpos($value, '"status"') !== false) && (strpos($value, ':') !== false) && (strpos($value, '"Failure"') !== false)) { + return false; + } + } + return true; + } + + function startsWith($src, $dest) { + return (substr($src, 0, strlen($dest)) === $dest); + } +?> diff --git a/signature-server/sample/sample/sample-pod.yaml b/signature-server/sample/sample/sample-pod.yaml new file mode 100644 index 0000000..4e61d9e --- /dev/null +++ b/signature-server/sample/sample/sample-pod.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Pod +metadata: + name: private-reg +spec: + containers: + - name: private-reg-container + image: mtcub4.rtp.raleigh.ibm.com:443/kabanero-signed/httpd:v0.1.0 + imagePullPolicy: Always + imagePullSecrets: + - name: regcred-mtcub4 diff --git a/signature-server/sample/sample/sample-sigstore-ca.yaml b/signature-server/sample/sample/sample-sigstore-ca.yaml new file mode 100644 index 0000000..608add9 --- /dev/null +++ b/signature-server/sample/sample/sample-sigstore-ca.yaml @@ -0,0 +1,17 @@ +apiVersion: machineconfiguration.openshift.io/v1 +kind: MachineConfig +metadata: + labels: + machineconfiguration.openshift.io/role: worker + name: 89-sigstore-ca +spec: + config: + ignition: + version: 2.2.0 + storage: + files: + - contents: + source: data:,-----BEGIN%20CERTIFICATE-----%0AMIIDLzCCAhegAwIBAgIIGK40fS%2B0ZOswDQYJKoZIhvcNAQELBQAwJjEkMCIGA1UE%0AAwwbaW5ncmVzcy1vcGVyYXRvckAxNTg1NTIyNjI3MB4XDTIwMDMyOTIyNTcxMVoX%0ADTIyMDMyOTIyNTcxMlowKDEmMCQGA1UEAwwdKi5hcHBzLm10Y29jcC5vcy5meXJl%0ALmlibS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDISuMUKm6N%0AMuucZT0mckUYQzFprhQDHpnJUAaDKNM8gk%2FLzOfLxGkiiWD7A8yJhnVW506IjFHe%0AH6Setg0bcvw0TTRT7HuOglZmMWhQR7uplLMw3e5gZ8krZXJCH5wosy9PKYPhyJS7%0AeNKqJ2FFZUG9lbddosp8EET5IIa5R%2BghBI6ZPimMdPEV%2BRrE4Mmoyq%2BKutPIcMt4%0AO1%2F8Fr72%2F15KPjONefREHtLGZRtSZZPd89ja7BTDgRkblNbSoBbehBL2jcAuadJF%0AFaV5wlub0dHh805wnxFHnxOROm5MUCFhV6%2FdnitKAPuqWn3Xhp1UiQXI6ao8xH1B%0AVlZWdRRGByz5AgMBAAGjXzBdMA4GA1UdDwEB%2FwQEAwIFoDATBgNVHSUEDDAKBggr%0ABgEFBQcDATAMBgNVHRMBAf8EAjAAMCgGA1UdEQQhMB%2BCHSouYXBwcy5tdGNvY3Au%0Ab3MuZnlyZS5pYm0uY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCQ9ZxYTVEWuc8%2FjFvj%0A%2BUkLWfKC%2BOKmOsdDNVLQDP55gjqFFVpvckiHPfPQooYhf476mKFoRNqZv3RqSuwF%0AKWx%2BC2TabloFSXzU1KsjNn1jNlsFnmu4Tqs2W3dhlFl01rJubKPwzqt6TQLLkFZk%0ApqnIPjquwui1GFWnlj%2FNY7VvKSSYJQYRt6KpuwarlFQpwA7ylvOq0IQi9kaPckRS%0AK6QwHkQjE7Gc%2FQ%2F1Trglt3bPbFtbWGNJN7CAaRathyym9m0VqmPGvYxqVo6ZU6eg%0Acm5XDVU6Dgcz%2BAmEsrfAHpU8okgEp8kUZME5bsTXS4BSAJ9Ycx5g3Npf81B0BTbj%0A2%2BLb%0A-----END%20CERTIFICATE-----%0A-----BEGIN%20CERTIFICATE-----%0AMIIC7TCCAdWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtpbmdy%0AZXNzLW9wZXJhdG9yQDE1ODU1MjI2MjcwHhcNMjAwMzI5MjI1NzA2WhcNMjIwMzI5%0AMjI1NzA3WjAmMSQwIgYDVQQDDBtpbmdyZXNzLW9wZXJhdG9yQDE1ODU1MjI2Mjcw%0AggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5tPXe9geVQgLDlUt3dCjL%0Ad3J0FT%2FMRv07Bz6x%2FQ%2ByUsluTw3B%2BbBJyVvYzSFDXMrXk4YpsCPS743HQeVxSsiQ%0AZUpQQxSLu6z3qxj80XPBwyyB7%2BRkjSwvl1VhH05Q87agOMS1VuHSXZkUv8F99OHI%0Acjy4fWKgi5hnhUUyzivSMfTYOUCTR5hkqhtRHD%2FEu5wpHkD4NaHY7C7qq6tPx4f1%0A07028sh1DAbBUXbw5Qf18tOmsD431%2FIFCThM6otH%2FrW%2FKm%2BPJBI1Ok7oA1EK0f8h%0A%2BochW720UrQZXUkpqwYCezeqItfvOFxP%2FW%2B%2FXE2aW48HfOWvi3uEhILNyD3sPcTp%0AAgMBAAGjJjAkMA4GA1UdDwEB%2FwQEAwICpDASBgNVHRMBAf8ECDAGAQH%2FAgEAMA0G%0ACSqGSIb3DQEBCwUAA4IBAQB%2FrHbevw%2FZ3zK1qwmmg%2Ba7UvzjlNf8azb0NrSMwACL%0AaWh0tOYhgHJq6bS6f2VphkNVxFnlXJPSSa6RjYQ%2FwWHSulL58L%2Fmn1XP1s1dd5z5%0AY0bG4Num6oOdLBrvZGDYNO0s3Jut1sNUx7X2Y3ofMeR%2BFojLAI7gUg6XV%2FP3w042%0Au7ej0N5jImGZojiVLsulqWtwlHHQVC%2FN7lXSAFW54Bt53bpoEOqfcVkH3961Yuqu%0AsHWCp2Nem9y30e3pPGZe9%2F0pYUg5q8%2BdJ7E%2FdCww580BAB4Tu%2BVhTeN0NVsbKbDw%0AX6MUm2lQMhdyHrXNRYTnss8EOcMDcMh%2BloZzT3pp8QfX%0A-----END%20CERTIFICATE-----%0A + filesystem: root + mode: 0644 + path: /etc/pki/ca-trust/source/anchors/sigstore.crt From e2a0d026b27b49d662c04d6206a983a8aa30ca58 Mon Sep 17 00:00:00 2001 From: Toshi Yamamoto Date: Sat, 30 May 2020 08:15:17 -0400 Subject: [PATCH 2/3] change RBAC required role --- signature-server/sample/deploy/signature-server-combined.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/signature-server/sample/deploy/signature-server-combined.yaml b/signature-server/sample/deploy/signature-server-combined.yaml index d278029..3172ad0 100644 --- a/signature-server/sample/deploy/signature-server-combined.yaml +++ b/signature-server/sample/deploy/signature-server-combined.yaml @@ -159,8 +159,8 @@ items: - --tls-cert=/etc/tls/private/tls.crt - --tls-key=/etc/tls/private/tls.key - --cookie-secret=SECRET - - --openshift-sar={"group":"","resource":"secrets","verb":"create"} - - --openshift-delegate-urls={"/":{"group":"","resource":"secrets","verb":"create"}} + - --openshift-sar={"group":"","resource":"imagesignatures","verb":"create"} + - --openshift-delegate-urls={"/":{"group":"","resource":"imagesignatures","verb":"create"}} - --skip-auth-regex=^/signatures/.* - --skip-provider-button volumeMounts: From 81245499e058b44944e14105ae3766fdb85f2522 Mon Sep 17 00:00:00 2001 From: Toshi Yamamoto Date: Sun, 31 May 2020 18:25:28 -0400 Subject: [PATCH 3/3] update readme --- signature-server/sample/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/signature-server/sample/README.md b/signature-server/sample/README.md index bf7d9e4..3c3cee3 100644 --- a/signature-server/sample/README.md +++ b/signature-server/sample/README.md @@ -110,7 +110,19 @@ To store a signature, a HTTP PUT method is used. The target URI is the form > `/staging/`_registry_`/`_namespaces_`/`_name_`@`_digest-algo_`=`_digest-value_`/signature-`_index_ -The target is protected by OpenShift OAuth proxy. A bearer token is required to authenticate and authorize a request. The token needs to be granted accessing a secret and web resources. For Kabanero either using kabanero-operator service account or use image-signer sample service account which is available in this repository. +The target is protected by OpenShift OAuth proxy. A bearer token is required to authenticate and authorize requests. The token needs to be granted to store ImageSignature. Following shows the required role. +``` +- apiGroups: + - '' + - image.openshift.io + resources: + - imagesignatures + verbs: + - create + - delete +``` + +For Kabanero either using kabanero-operator service account or use image-signer sample service account which is available in this repository. The following shows an example by using curl when a signature of which name is signature-1 is for the image `mynamespace/busybox@sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e` which is stored in a registry `registry.example.com:5000` and a url of a look aside signature store is `signatures-server-icp4app-security.apps.myocp.example.com` You need to modify existing Tekton tasks to add the code to put a generated signature to the signature server.