-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Image signature verification worflow test
- Loading branch information
Showing
2 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package registry | ||
|
||
import ( | ||
"fmt" | ||
|
||
g "github.com/onsi/ginkgo" | ||
o "github.com/onsi/gomega" | ||
|
||
imagesutil "github.com/openshift/origin/test/extended/images" | ||
exutil "github.com/openshift/origin/test/extended/util" | ||
|
||
e2e "k8s.io/kubernetes/test/e2e/framework" | ||
) | ||
|
||
var _ = g.Describe("[imageapis] image signature workflow", func() { | ||
defer g.GinkgoRecover() | ||
var oc = exutil.NewCLI("registry-signing", exutil.KubeConfigPath()) | ||
|
||
g.It("can push a signed image to openshift registry and verify it", func() { | ||
g.By("building an signer image that know how to sign images") | ||
_, err := oc.Run("new-build").Args("--docker-image", "openshift/origin:latest", "--to", "signer:latest", "-D", "-").InputString(`FROM openshift/origin:latest | ||
RUN yum install -y skopeo && yum clean all && mkdir -p gnupg && chmod -R 0777 /var/lib/origin && \ | ||
echo $'%echo Generating a basic OpenPGP key ...\n\ | ||
Key-Type: DSA \n\ | ||
Key-Length: 1024 \n\ | ||
Subkey-Type: ELG-E \n\ | ||
Subkey-Length: 1024 \n\ | ||
Name-Real: Joe Tester \n\ | ||
Name-Comment: with stupid passphrase \n\ | ||
Name-Email: joe@foo.bar \n\ | ||
Expire-Date: 0 \n\ | ||
Creation-Date: 2017-01-01 \n\ | ||
%commit \n\ | ||
%echo done \n'\ | ||
>> dummy_key.conf`).Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
err = exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "signer", "latest") | ||
containerLog, _ := oc.Run("logs").Args("builds/signer-1").Output() | ||
e2e.Logf("signer build logs:\n%s\n", containerLog) | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
g.By("looking up the openshift registry URL") | ||
registryURL, err := imagesutil.GetDockerRegistryURL(oc) | ||
signerImage := fmt.Sprintf("%s/%s/signer:latest", registryURL, oc.Namespace()) | ||
signedImage := fmt.Sprintf("%s/%s/signed:latest", registryURL, oc.Namespace()) | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
g.By("obtaining bearer token for the test user") | ||
user := oc.Username() | ||
token, err := oc.Run("whoami").Args("-t").Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
g.By("granting the image-signer role to test user") | ||
_, err = oc.AsAdmin().Run("adm").Args("policy", "add-cluster-role-to-user", "system:image-signer", oc.Username()).Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
// TODO: The test user needs to be able to unlink the /dev/random which is owned by a | ||
// root. This cannot be done during image build time because the /dev is plugged into | ||
// container after it starts. This SCC could be avoided in the future when /dev/random | ||
// issue is fixed in Docker. | ||
g.By("granting the anyuid scc to test user") | ||
_, err = oc.AsAdmin().Run("adm").Args("policy", "add-scc-to-user", "anyuid", oc.Username()).Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
g.By("preparing the image stream where the signed image will be pushed") | ||
_, err = oc.Run("create").Args("imagestream", "signed").Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
g.By("granting the image-auditor role to test user") | ||
_, err = oc.AsAdmin().Run("adm").Args("policy", "add-cluster-role-to-user", "system:image-auditor", oc.Username()).Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
pod, err := exutil.NewPodExecutor(oc, "sign-and-push", signerImage) | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
// Generate GPG key | ||
// Note that we need to replace the /dev/random with /dev/urandom to get more entropy | ||
// into container so we can successfully generate the GPG keypair. | ||
g.By("creating dummy GPG key") | ||
out, err := pod.Exec("rm -f /dev/random; ln -sf /dev/urandom /dev/random && " + | ||
"GNUPGHOME=/var/lib/origin/gnupg gpg2 --batch --gen-key dummy_key.conf") | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
o.Expect(out).To(o.ContainSubstring("keyring `/var/lib/origin/gnupg/secring.gpg' created")) | ||
|
||
// Create kubeconfig for skopeo | ||
g.By("logging as a test user") | ||
out, err = pod.Exec("oc login https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT --token=" + token + " --certificate-authority=/run/secrets/kubernetes.io/serviceaccount/ca.crt") | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
o.Expect(out).To(o.ContainSubstring("Logged in")) | ||
|
||
// Sign and copy the origin-pod image into targed image stream tag | ||
// TODO: Fix skopeo to pickup the Kubernetes environment variables (remove the $KUBERNETES_MASTER) | ||
g.By("signing the origin-pod:latest image and pushing it into openshift registry") | ||
_, err = pod.Exec("KUBERNETES_MASTER=https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT GNUPGHOME=/var/lib/origin/gnupg " + | ||
"skopeo --debug --tls-verify=false copy --sign-by joe@foo.bar --dest-creds " + user + ":" + token + " --dest-tls-verify=false docker://docker.io/openshift/origin-pod:latest atomic:" + signedImage) | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
err = exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "signed", "latest") | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
g.By("obtaining the signed:latest image name") | ||
imageName, err := oc.Run("get").Args("istag", "signed:latest", "-o", "jsonpath='{.image.metadata.name}'").Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
|
||
g.By("expecting the image to have unverified signature") | ||
out, err = oc.Run("describe").Args("istag", "signed:latest").Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
o.Expect(out).To(o.ContainSubstring("Unverified")) | ||
|
||
_, err = pod.Exec("GNUPGHOME=/var/lib/origin/gnupg " + | ||
"oc adm verify-image-signature " + imageName + " --expected-identity=" + signedImage + " --save") | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
o.Expect(out).To(o.ContainSubstring("identity is now confirmed")) | ||
|
||
g.By("checking the signature is present on the image and it is now verified") | ||
out, err = oc.Run("describe").Args("istag", "signed:latest").Output() | ||
o.Expect(err).NotTo(o.HaveOccurred()) | ||
o.Expect(out).To(o.ContainSubstring("Verified")) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters