From 28d2ed9e5903a59f58d6a12703b0f8cd9b16ed06 Mon Sep 17 00:00:00 2001 From: salaxander Date: Wed, 27 Sep 2023 14:43:37 +0000 Subject: [PATCH] deploy: 28191f15f934eaeee898a05dafc768be4d206d4e --- website/404.html | 4 ++-- website/assets/js/72e14192.3a58b2b1.js | 1 - website/assets/js/72e14192.caf3f8a8.js | 1 + .../{runtime~main.f1c526f2.js => runtime~main.fcaf8288.js} | 2 +- website/code-of-conduct.html | 4 ++-- website/contributing.html | 4 ++-- website/design.html | 4 ++-- website/faq.html | 4 ++-- website/index.html | 4 ++-- website/installation.html | 4 ++-- website/next.html | 4 ++-- website/next/code-of-conduct.html | 4 ++-- website/next/contributing.html | 4 ++-- website/next/design.html | 4 ++-- website/next/faq.html | 4 ++-- website/next/installation.html | 4 ++-- website/next/output.html | 4 ++-- website/next/quick-start.html | 6 +++--- website/next/troubleshooting.html | 4 ++-- website/quick-start.html | 4 ++-- website/troubleshooting.html | 4 ++-- website/v0.1.x.html | 4 ++-- website/v0.1.x/code-of-conduct.html | 4 ++-- website/v0.1.x/contributing.html | 4 ++-- website/v0.1.x/design.html | 4 ++-- website/v0.1.x/faq.html | 4 ++-- website/v0.1.x/installation.html | 4 ++-- website/v0.1.x/quick-start.html | 4 ++-- website/v0.2.x.html | 4 ++-- website/v0.2.x/code-of-conduct.html | 4 ++-- website/v0.2.x/contributing.html | 4 ++-- website/v0.2.x/design.html | 4 ++-- website/v0.2.x/faq.html | 4 ++-- website/v0.2.x/installation.html | 4 ++-- website/v0.2.x/quick-start.html | 4 ++-- website/v0.3.x.html | 4 ++-- website/v0.3.x/code-of-conduct.html | 4 ++-- website/v0.3.x/contributing.html | 4 ++-- website/v0.3.x/design.html | 4 ++-- website/v0.3.x/faq.html | 4 ++-- website/v0.3.x/installation.html | 4 ++-- website/v0.3.x/quick-start.html | 4 ++-- 42 files changed, 81 insertions(+), 81 deletions(-) delete mode 100644 website/assets/js/72e14192.3a58b2b1.js create mode 100644 website/assets/js/72e14192.caf3f8a8.js rename website/assets/js/{runtime~main.f1c526f2.js => runtime~main.fcaf8288.js} (98%) diff --git a/website/404.html b/website/404.html index 30a0d93c..e0516b1e 100644 --- a/website/404.html +++ b/website/404.html @@ -7,13 +7,13 @@ - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/website/assets/js/72e14192.3a58b2b1.js b/website/assets/js/72e14192.3a58b2b1.js deleted file mode 100644 index 955701b2..00000000 --- a/website/assets/js/72e14192.3a58b2b1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[239],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),c=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=a,k=d["".concat(s,".").concat(m)]||d[m]||u[m]||r;return n?i.createElement(k,o(o({ref:t},p),{},{components:n})):i.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var i=n(7462),a=(n(7294),n(3905));const r={title:"Quick Start"},o=void 0,l={unversionedId:"quick-start",id:"quick-start",title:"Quick Start",description:"This sample illustrates how to patch containers using vulnerability reports with copa.",source:"@site/docs/quick-start.md",sourceDirName:".",slug:"/quick-start",permalink:"/copacetic/website/next/quick-start",draft:!1,tags:[],version:"current",frontMatter:{title:"Quick Start"},sidebar:"sidebar",previous:{title:"Installation",permalink:"/copacetic/website/next/installation"},next:{title:"Output",permalink:"/copacetic/website/next/output"}},s={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Sample Steps",id:"sample-steps",level:2}],p={toc:c};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"This sample illustrates how to patch containers using vulnerability reports with ",(0,a.kt)("inlineCode",{parentName:"p"},"copa"),"."),(0,a.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"An Ubuntu 22.04 VM configured through the ",(0,a.kt)("a",{parentName:"li",href:"/copacetic/website/next/installation"},"setup instructions"),". This includes:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"copa")," tool ",(0,a.kt)("a",{parentName:"li",href:"/copacetic/website/next/installation"},"built & pathed"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/moby/buildkit/#quick-start"},"buildkit")," daemon installed & pathed. ",(0,a.kt)("a",{parentName:"li",href:"#buildkit-connection-examples"},"Examples")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.docker.com/desktop/linux/install/#generic-installation-steps"},"docker")," daemon running and CLI installed & pathed."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://aquasecurity.github.io/trivy/latest/getting-started/installation/"},"trivy CLI")," installed & pathed.")))),(0,a.kt)("h2",{id:"sample-steps"},"Sample Steps"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Scan the container image for patchable OS vulnerabilities, outputting the results to a JSON file:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"trivy image --vuln-type os --ignore-unfixed -f json -o nginx.1.21.6.json docker.io/library/nginx:1.21.6\n")),(0,a.kt)("p",{parentName:"li"},"You can also see the existing patchable vulnerabilities in table form on the shell with:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6\n\n"))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"To patch the image, use the Trivy report and specify a buildkit instance to connect to:"),(0,a.kt)("p",{parentName:"li"},"By default copa will attempt to auto-connect to an instance in order:"),(0,a.kt)("ol",{parentName:"li"},(0,a.kt)("li",{parentName:"ol"},"Default docker buildkit endpoint (requires at least docker v24.0 with ",(0,a.kt)("a",{parentName:"li",href:"https://docs.docker.com/storage/containerd/#enable-containerd-image-store-on-docker-engine"},"containerd snapshotter")," support enabled)"),(0,a.kt)("li",{parentName:"ol"},"Currently selected buildx builder (see: ",(0,a.kt)("inlineCode",{parentName:"li"},"docker buildx --help"),")"),(0,a.kt)("li",{parentName:"ol"},"buildkit daemon at the default address ",(0,a.kt)("inlineCode",{parentName:"li"},"/run/buildkit/buildkitd.sock"))),(0,a.kt)("p",{parentName:"li"},"If an instance doesn't exist or that instance doesn't support all the features copa needs the next will be attempted.\nYou may need to specify a custom address using the ",(0,a.kt)("inlineCode",{parentName:"p"},"--addr")," flag. Here are the supported formats:"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unix:///path/to/buildkit.sock")," - Connect to buildkit over unix socket."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"tcp://$BUILDKIT_ADDR:$PORT")," - Connec to buildkit over TCP. (not recommended for security reasons)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"docker://")," - Connect to docker, currently only unix sockets are supported, e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"docker://unix:///var/run/docker.sock")," (or just ",(0,a.kt)("inlineCode",{parentName:"li"},"docker://"),")."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"docker-container://my-buildkit-container")," - Connect to a buildkitd running in a docker container."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"buildx://my-builder")," - Connect to a buildx builder (or ",(0,a.kt)("inlineCode",{parentName:"li"},"buildx://")," for the currently selected builder). ",(0,a.kt)("em",{parentName:"li"},"Note: only container-backed buildx instances are currently supported")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"nerdctl-container://my-container-name")," - Similar to ",(0,a.kt)("inlineCode",{parentName:"li"},"docker-container")," but uses ",(0,a.kt)("inlineCode",{parentName:"li"},"nerdctl"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"podman-container://my-container-name")," - Similar to ",(0,a.kt)("inlineCode",{parentName:"li"},"docker-container")," but uses ",(0,a.kt)("inlineCode",{parentName:"li"},"podman"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ssh://myhost")," - Connect to a buildkit instance over SSH. Format of the host spec should mimic the SSH command."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"kubepod://mypod")," - Connect to buildkit running in a Kubernetes pod. Can also specify kubectl context and pod namespace (",(0,a.kt)("inlineCode",{parentName:"li"},"kubepod://mypod?context=foo&namespace=notdefault"),").")),(0,a.kt)("h4",{parentName:"li",id:"buildkit-connection-examples"},"Buildkit Connection Examples"),(0,a.kt)("p",{parentName:"li"},"Example: Connect using defaults:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched\n")),(0,a.kt)("p",{parentName:"li"},"Example: Connect to buildx"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"},"docker buildx create --name demo\ncopa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr buildx://demo\n")),(0,a.kt)("p",{parentName:"li"},"Example: Buildkit in a container"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"},'export BUILDKIT_VERSION=v0.12.0\ndocker run \\\n --detach \\\n --rm \\\n --privileged \\\n --name buildkitd \\\n --entrypoint buildkitd \\\n "moby/buildkit:$BUILDKIT_VERSION"\n\ncopa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr docker-container://buildkitd\n')),(0,a.kt)("p",{parentName:"li"},"Example: Buildkit over TCP"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"},'export BUILDKIT_VERSION=v0.12.0\n export BUILDKIT_PORT=8888\n docker run \\\n --detach \\\n --rm \\\n --privileged \\\n -p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \\\n --name buildkitd \\\n --entrypoint buildkitd \\\n "moby/buildkit:$BUILDKIT_VERSION" \\\n --addr tcp://0.0.0.0:$BUILDKIT_PORT\n copa patch \\\n -i docker.io/library/nginx:1.21.6 \\\n -r nginx.1.21.6.json \\\n -t 1.21.6-patched \\\n -a tcp://0.0.0.0:$BUILDKIT_PORT\n')),(0,a.kt)("p",{parentName:"li"},"In either case, ",(0,a.kt)("inlineCode",{parentName:"p"},"copa")," is non-destructive and exports a new image with the specified ",(0,a.kt)("inlineCode",{parentName:"p"},"1.21.6-patched")," label to the local Docker daemon."),(0,a.kt)("blockquote",{parentName:"li"},(0,a.kt)("p",{parentName:"blockquote"},(0,a.kt)("strong",{parentName:"p"},"NOTE:")," if you're running this sample against an image from a private registry instead,\nensure that the credentials are configured in the default Docker config.json before running ",(0,a.kt)("inlineCode",{parentName:"p"},"copa patch"),",\nfor example, via ",(0,a.kt)("inlineCode",{parentName:"p"},"sudo docker login -u -p "),"."))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Scan the patched image and verify that the vulnerabilities have been patched:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6-patched\n")),(0,a.kt)("p",{parentName:"li"},"You can also inspect the structure of the patched image with ",(0,a.kt)("inlineCode",{parentName:"p"},"docker history")," to see the new patch layer appended to the image:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker history docker.io/library/nginx:1.21.6-patched\nIMAGE CREATED CREATED BY SIZE COMMENT\na372df41e06d 1 minute ago mount / from exec sh -c apt install --no-ins\u2026 26.1MB buildkit.exporter.image.v0\n 3 months ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0\n 3 months ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0\n 3 months ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0\n 3 months ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0\n 3 months ago COPY 30-tune-worker-processes.sh /docker-ent\u2026 4.61kB buildkit.dockerfile.v0\n 3 months ago COPY 20-envsubst-on-templates.sh /docker-ent\u2026 1.04kB buildkit.dockerfile.v0\n 3 months ago COPY 10-listen-on-ipv6-by-default.sh /docker\u2026 1.96kB buildkit.dockerfile.v0\n 3 months ago COPY docker-entrypoint.sh / # buildkit 1.2kB buildkit.dockerfile.v0\n 3 months ago RUN /bin/sh -c set -x && addgroup --syst\u2026 61.1MB buildkit.dockerfile.v0\n 3 months ago ENV PKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0\n 3 months ago ENV NJS_VERSION=0.7.0 0B buildkit.dockerfile.v0\n 3 months ago ENV NGINX_VERSION=1.20.2 0B buildkit.dockerfile.v0\n 3 months ago LABEL maintainer=NGINX Docker Maintainers 4 months ago /bin/sh -c #(nop) CMD ["bash"] 0B\n 4 months ago /bin/sh -c #(nop) ADD file:09675d11695f65c55\u2026 80.4MB\n'))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Run the container to verify that the image has no regressions:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker run -it --rm --name nginx-test docker.io/library/nginx:1.21.6-patched\n/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\n/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\n/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\n10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf\n10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf\n/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\n/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh\n/docker-entrypoint.sh: Configuration complete; ready for start up\n2022/05/16 18:00:17 [notice] 1#1: using the "epoll" event method\n2022/05/16 18:00:17 [notice] 1#1: nginx/1.20.2\n2022/05/16 18:00:17 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)\n2022/05/16 18:00:17 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2\n2022/05/16 18:00:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576\n2022/05/16 18:00:17 [notice] 1#1: start worker processes\n2022/05/16 18:00:17 [notice] 1#1: start worker process 31\n2022/05/16 18:00:17 [notice] 1#1: start worker process 32\n2022/05/16 18:00:17 [notice] 1#1: start worker process 33\n2022/05/16 18:00:17 [notice] 1#1: start worker process 34\n2022/05/16 18:00:17 [notice] 1#1: start worker process 35\n2022/05/16 18:00:17 [notice] 1#1: start worker process 36\n2022/05/16 18:00:17 [notice] 1#1: start worker process 37\n2022/05/16 18:00:17 [notice] 1#1: start worker process 38\n2022/05/16 18:00:17 [notice] 38#38: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 36#36: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 33#33: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 32#32: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 34#34: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 35#35: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 37#37: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 1#1: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 31#31: signal 28 (SIGWINCH) received\n')),(0,a.kt)("p",{parentName:"li"},"You can stop the container by opening a new shell instance and running: ",(0,a.kt)("inlineCode",{parentName:"p"},"docker stop nginx-test")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/website/assets/js/72e14192.caf3f8a8.js b/website/assets/js/72e14192.caf3f8a8.js new file mode 100644 index 00000000..62e54a53 --- /dev/null +++ b/website/assets/js/72e14192.caf3f8a8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[239],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),c=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=a,k=d["".concat(s,".").concat(m)]||d[m]||u[m]||r;return n?i.createElement(k,o(o({ref:t},p),{},{components:n})):i.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var i=n(7462),a=(n(7294),n(3905));const r={title:"Quick Start"},o=void 0,l={unversionedId:"quick-start",id:"quick-start",title:"Quick Start",description:"This sample illustrates how to patch containers using vulnerability reports with copa.",source:"@site/docs/quick-start.md",sourceDirName:".",slug:"/quick-start",permalink:"/copacetic/website/next/quick-start",draft:!1,tags:[],version:"current",frontMatter:{title:"Quick Start"},sidebar:"sidebar",previous:{title:"Installation",permalink:"/copacetic/website/next/installation"},next:{title:"Output",permalink:"/copacetic/website/next/output"}},s={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Sample Steps",id:"sample-steps",level:2}],p={toc:c};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"This sample illustrates how to patch containers using vulnerability reports with ",(0,a.kt)("inlineCode",{parentName:"p"},"copa"),"."),(0,a.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"An Ubuntu 22.04 VM configured through the ",(0,a.kt)("a",{parentName:"li",href:"/copacetic/website/next/installation"},"setup instructions"),". This includes:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"copa")," tool ",(0,a.kt)("a",{parentName:"li",href:"/copacetic/website/next/installation"},"built & pathed"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/moby/buildkit/#quick-start"},"buildkit")," daemon installed & pathed. ",(0,a.kt)("a",{parentName:"li",href:"#buildkit-connection-examples"},"Examples")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.docker.com/desktop/linux/install/#generic-installation-steps"},"docker")," daemon running and CLI installed & pathed."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://aquasecurity.github.io/trivy/latest/getting-started/installation/"},"trivy CLI")," installed & pathed.")))),(0,a.kt)("h2",{id:"sample-steps"},"Sample Steps"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Scan the container image for patchable OS vulnerabilities, outputting the results to a JSON file:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"trivy image --vuln-type os --ignore-unfixed -f json -o nginx.1.21.6.json docker.io/library/nginx:1.21.6\n")),(0,a.kt)("p",{parentName:"li"},"You can also see the existing patchable vulnerabilities in table form on the shell with:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6\n\n"))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"To patch the image, use the Trivy report and specify a buildkit instance to connect to:"),(0,a.kt)("p",{parentName:"li"},"By default copa will attempt to auto-connect to an instance in order:"),(0,a.kt)("ol",{parentName:"li"},(0,a.kt)("li",{parentName:"ol"},"Default docker buildkit endpoint (requires at least docker v24.0 with ",(0,a.kt)("a",{parentName:"li",href:"https://docs.docker.com/storage/containerd/#enable-containerd-image-store-on-docker-engine"},"containerd snapshotter")," support enabled)"),(0,a.kt)("li",{parentName:"ol"},"Currently selected buildx builder (see: ",(0,a.kt)("inlineCode",{parentName:"li"},"docker buildx --help"),")"),(0,a.kt)("li",{parentName:"ol"},"buildkit daemon at the default address ",(0,a.kt)("inlineCode",{parentName:"li"},"/run/buildkit/buildkitd.sock"))),(0,a.kt)("p",{parentName:"li"},"If an instance doesn't exist or that instance doesn't support all the features copa needs the next will be attempted.\nYou may need to specify a custom address using the ",(0,a.kt)("inlineCode",{parentName:"p"},"--addr")," flag. Here are the supported formats:"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unix:///path/to/buildkit.sock")," - Connect to buildkit over unix socket."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"tcp://$BUILDKIT_ADDR:$PORT")," - Connect to buildkit over TCP. (not recommended for security reasons)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"docker://")," - Connect to docker, currently only unix sockets are supported, e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"docker://unix:///var/run/docker.sock")," (or just ",(0,a.kt)("inlineCode",{parentName:"li"},"docker://"),")."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"docker-container://my-buildkit-container")," - Connect to a buildkitd running in a docker container."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"buildx://my-builder")," - Connect to a buildx builder (or ",(0,a.kt)("inlineCode",{parentName:"li"},"buildx://")," for the currently selected builder). ",(0,a.kt)("em",{parentName:"li"},"Note: only container-backed buildx instances are currently supported")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"nerdctl-container://my-container-name")," - Similar to ",(0,a.kt)("inlineCode",{parentName:"li"},"docker-container")," but uses ",(0,a.kt)("inlineCode",{parentName:"li"},"nerdctl"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"podman-container://my-container-name")," - Similar to ",(0,a.kt)("inlineCode",{parentName:"li"},"docker-container")," but uses ",(0,a.kt)("inlineCode",{parentName:"li"},"podman"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"ssh://myhost")," - Connect to a buildkit instance over SSH. Format of the host spec should mimic the SSH command."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"kubepod://mypod")," - Connect to buildkit running in a Kubernetes pod. Can also specify kubectl context and pod namespace (",(0,a.kt)("inlineCode",{parentName:"li"},"kubepod://mypod?context=foo&namespace=notdefault"),").")),(0,a.kt)("h4",{parentName:"li",id:"buildkit-connection-examples"},"Buildkit Connection Examples"),(0,a.kt)("p",{parentName:"li"},"Example: Connect using defaults:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched\n")),(0,a.kt)("p",{parentName:"li"},"Example: Connect to buildx"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"},"docker buildx create --name demo\ncopa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr buildx://demo\n")),(0,a.kt)("p",{parentName:"li"},"Example: Buildkit in a container"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"},'export BUILDKIT_VERSION=v0.12.0\ndocker run \\\n --detach \\\n --rm \\\n --privileged \\\n --name buildkitd \\\n --entrypoint buildkitd \\\n "moby/buildkit:$BUILDKIT_VERSION"\n\ncopa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr docker-container://buildkitd\n')),(0,a.kt)("p",{parentName:"li"},"Example: Buildkit over TCP"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"},'export BUILDKIT_VERSION=v0.12.0\n export BUILDKIT_PORT=8888\n docker run \\\n --detach \\\n --rm \\\n --privileged \\\n -p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \\\n --name buildkitd \\\n --entrypoint buildkitd \\\n "moby/buildkit:$BUILDKIT_VERSION" \\\n --addr tcp://0.0.0.0:$BUILDKIT_PORT\n copa patch \\\n -i docker.io/library/nginx:1.21.6 \\\n -r nginx.1.21.6.json \\\n -t 1.21.6-patched \\\n -a tcp://0.0.0.0:$BUILDKIT_PORT\n')),(0,a.kt)("p",{parentName:"li"},"In either case, ",(0,a.kt)("inlineCode",{parentName:"p"},"copa")," is non-destructive and exports a new image with the specified ",(0,a.kt)("inlineCode",{parentName:"p"},"1.21.6-patched")," label to the local Docker daemon."),(0,a.kt)("blockquote",{parentName:"li"},(0,a.kt)("p",{parentName:"blockquote"},(0,a.kt)("strong",{parentName:"p"},"NOTE:")," if you're running this sample against an image from a private registry instead,\nensure that the credentials are configured in the default Docker config.json before running ",(0,a.kt)("inlineCode",{parentName:"p"},"copa patch"),",\nfor example, via ",(0,a.kt)("inlineCode",{parentName:"p"},"sudo docker login -u -p "),"."))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Scan the patched image and verify that the vulnerabilities have been patched:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6-patched\n")),(0,a.kt)("p",{parentName:"li"},"You can also inspect the structure of the patched image with ",(0,a.kt)("inlineCode",{parentName:"p"},"docker history")," to see the new patch layer appended to the image:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker history docker.io/library/nginx:1.21.6-patched\nIMAGE CREATED CREATED BY SIZE COMMENT\na372df41e06d 1 minute ago mount / from exec sh -c apt install --no-ins\u2026 26.1MB buildkit.exporter.image.v0\n 3 months ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0\n 3 months ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0\n 3 months ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0\n 3 months ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0\n 3 months ago COPY 30-tune-worker-processes.sh /docker-ent\u2026 4.61kB buildkit.dockerfile.v0\n 3 months ago COPY 20-envsubst-on-templates.sh /docker-ent\u2026 1.04kB buildkit.dockerfile.v0\n 3 months ago COPY 10-listen-on-ipv6-by-default.sh /docker\u2026 1.96kB buildkit.dockerfile.v0\n 3 months ago COPY docker-entrypoint.sh / # buildkit 1.2kB buildkit.dockerfile.v0\n 3 months ago RUN /bin/sh -c set -x && addgroup --syst\u2026 61.1MB buildkit.dockerfile.v0\n 3 months ago ENV PKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0\n 3 months ago ENV NJS_VERSION=0.7.0 0B buildkit.dockerfile.v0\n 3 months ago ENV NGINX_VERSION=1.20.2 0B buildkit.dockerfile.v0\n 3 months ago LABEL maintainer=NGINX Docker Maintainers 4 months ago /bin/sh -c #(nop) CMD ["bash"] 0B\n 4 months ago /bin/sh -c #(nop) ADD file:09675d11695f65c55\u2026 80.4MB\n'))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Run the container to verify that the image has no regressions:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'$ docker run -it --rm --name nginx-test docker.io/library/nginx:1.21.6-patched\n/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration\n/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/\n/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh\n10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf\n10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf\n/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh\n/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh\n/docker-entrypoint.sh: Configuration complete; ready for start up\n2022/05/16 18:00:17 [notice] 1#1: using the "epoll" event method\n2022/05/16 18:00:17 [notice] 1#1: nginx/1.20.2\n2022/05/16 18:00:17 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)\n2022/05/16 18:00:17 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2\n2022/05/16 18:00:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576\n2022/05/16 18:00:17 [notice] 1#1: start worker processes\n2022/05/16 18:00:17 [notice] 1#1: start worker process 31\n2022/05/16 18:00:17 [notice] 1#1: start worker process 32\n2022/05/16 18:00:17 [notice] 1#1: start worker process 33\n2022/05/16 18:00:17 [notice] 1#1: start worker process 34\n2022/05/16 18:00:17 [notice] 1#1: start worker process 35\n2022/05/16 18:00:17 [notice] 1#1: start worker process 36\n2022/05/16 18:00:17 [notice] 1#1: start worker process 37\n2022/05/16 18:00:17 [notice] 1#1: start worker process 38\n2022/05/16 18:00:17 [notice] 38#38: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 36#36: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 33#33: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 32#32: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 34#34: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 35#35: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 37#37: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 1#1: signal 28 (SIGWINCH) received\n2022/05/16 18:00:17 [notice] 31#31: signal 28 (SIGWINCH) received\n')),(0,a.kt)("p",{parentName:"li"},"You can stop the container by opening a new shell instance and running: ",(0,a.kt)("inlineCode",{parentName:"p"},"docker stop nginx-test")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/website/assets/js/runtime~main.f1c526f2.js b/website/assets/js/runtime~main.fcaf8288.js similarity index 98% rename from website/assets/js/runtime~main.f1c526f2.js rename to website/assets/js/runtime~main.fcaf8288.js index 0605ad96..663ca642 100644 --- a/website/assets/js/runtime~main.f1c526f2.js +++ b/website/assets/js/runtime~main.fcaf8288.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,t,r,c,b={},f={};function d(e){var a=f[e];if(void 0!==a)return a.exports;var t=f[e]={id:e,loaded:!1,exports:{}};return b[e].call(t.exports,t,t.exports,d),t.loaded=!0,t.exports}d.m=b,d.c=f,e=[],d.O=(a,t,r,c)=>{if(!t){var b=1/0;for(i=0;i=c)&&Object.keys(d.O).every((e=>d.O[e](t[o])))?t.splice(o--,1):(f=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[t,r,c]},d.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return d.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var c=Object.create(null);d.r(c);var b={};a=a||[null,t({}),t([]),t(t)];for(var f=2&r&&e;"object"==typeof f&&!~a.indexOf(f);f=t(f))Object.getOwnPropertyNames(f).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,d.d(c,b),c},d.d=(e,a)=>{for(var t in a)d.o(a,t)&&!d.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((a,t)=>(d.f[t](e,a),a)),[])),d.u=e=>"assets/js/"+({4:"d9461b6c",53:"935f2afb",59:"b5d5e16b",71:"804a5934",80:"4d54d076",87:"fcc13998",88:"4cb9f763",114:"b9421f89",128:"a09c2993",145:"299b5310",163:"934782ba",200:"bab6f5ab",201:"040fbf97",212:"48ae5635",217:"3b8c55ea",220:"f9459e94",239:"72e14192",242:"3fcb412e",262:"9e350ec0",267:"86b9c768",296:"e8c0720c",325:"c12dc9fd",335:"053b5658",352:"dea0f9ea",360:"9d9f8394",414:"0aeccac2",451:"6173fde8",480:"9f65b58a",514:"1be78505",644:"d2339658",691:"0a7bb60d",702:"2a636ef6",705:"c5934ffc",722:"7e72de0f",737:"2133a534",765:"57b2432c",835:"ea9eabff",836:"0480b142",838:"6bd0979b",845:"c13ba925",865:"b407a98a",918:"17896441",925:"89eebbd3",948:"0c380bb3",964:"22539a87",993:"c698fe77"}[e]||e)+"."+{4:"cfb2e633",53:"28c78675",59:"671619da",71:"94dc2f49",80:"b42a6d95",87:"60932360",88:"7b7193b5",114:"2569d45d",128:"d7d5958b",145:"edc4e810",163:"38219ecf",200:"75d4fe2d",201:"2f4e975a",212:"06d4c7cd",217:"7fbcd779",220:"a9a17024",239:"3a58b2b1",242:"48bc29de",262:"2124b2d5",267:"6a1c76ae",296:"806b237d",325:"026b82ae",335:"14dee349",352:"41975f45",360:"aca5ea48",414:"008fdaae",451:"9aae5469",480:"52d92de7",514:"af84a9b6",644:"5d019890",691:"ac142ed8",702:"51de8e98",705:"3a06677d",722:"46d6e17a",737:"156e8b1f",765:"97404563",835:"fb82e175",836:"cad65f4e",838:"6c0a2130",845:"811c1f7b",865:"944ebdbf",918:"561afd72",925:"266b07ac",948:"f493fbf1",964:"29d1b817",972:"b43202c5",993:"c274d15b"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},c="website:",d.l=(e,a,t,b)=>{if(r[e])r[e].push(a);else{var f,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{f.onerror=f.onload=null,clearTimeout(s);var c=r[e];if(delete r[e],f.parentNode&&f.parentNode.removeChild(f),c&&c.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:f}),12e4);f.onerror=l.bind(null,f.onerror),f.onload=l.bind(null,f.onload),o&&document.head.appendChild(f)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/copacetic/website/",d.gca=function(e){return e={17896441:"918",d9461b6c:"4","935f2afb":"53",b5d5e16b:"59","804a5934":"71","4d54d076":"80",fcc13998:"87","4cb9f763":"88",b9421f89:"114",a09c2993:"128","299b5310":"145","934782ba":"163",bab6f5ab:"200","040fbf97":"201","48ae5635":"212","3b8c55ea":"217",f9459e94:"220","72e14192":"239","3fcb412e":"242","9e350ec0":"262","86b9c768":"267",e8c0720c:"296",c12dc9fd:"325","053b5658":"335",dea0f9ea:"352","9d9f8394":"360","0aeccac2":"414","6173fde8":"451","9f65b58a":"480","1be78505":"514",d2339658:"644","0a7bb60d":"691","2a636ef6":"702",c5934ffc:"705","7e72de0f":"722","2133a534":"737","57b2432c":"765",ea9eabff:"835","0480b142":"836","6bd0979b":"838",c13ba925:"845",b407a98a:"865","89eebbd3":"925","0c380bb3":"948","22539a87":"964",c698fe77:"993"}[e]||e,d.p+d.u(e)},(()=>{var e={303:0,532:0};d.f.j=(a,t)=>{var r=d.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(303|532)$/.test(a))e[a]=0;else{var c=new Promise(((t,c)=>r=e[a]=[t,c]));t.push(r[2]=c);var b=d.p+d.u(a),f=new Error;d.l(b,(t=>{if(d.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var c=t&&("load"===t.type?"missing":t.type),b=t&&t.target&&t.target.src;f.message="Loading chunk "+a+" failed.\n("+c+": "+b+")",f.name="ChunkLoadError",f.type=c,f.request=b,r[1](f)}}),"chunk-"+a,a)}},d.O.j=a=>0===e[a];var a=(a,t)=>{var r,c,b=t[0],f=t[1],o=t[2],n=0;if(b.some((a=>0!==e[a]))){for(r in f)d.o(f,r)&&(d.m[r]=f[r]);if(o)var i=o(d)}for(a&&a(t);n{"use strict";var e,a,t,r,c,b={},f={};function d(e){var a=f[e];if(void 0!==a)return a.exports;var t=f[e]={id:e,loaded:!1,exports:{}};return b[e].call(t.exports,t,t.exports,d),t.loaded=!0,t.exports}d.m=b,d.c=f,e=[],d.O=(a,t,r,c)=>{if(!t){var b=1/0;for(i=0;i=c)&&Object.keys(d.O).every((e=>d.O[e](t[o])))?t.splice(o--,1):(f=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[t,r,c]},d.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return d.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var c=Object.create(null);d.r(c);var b={};a=a||[null,t({}),t([]),t(t)];for(var f=2&r&&e;"object"==typeof f&&!~a.indexOf(f);f=t(f))Object.getOwnPropertyNames(f).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,d.d(c,b),c},d.d=(e,a)=>{for(var t in a)d.o(a,t)&&!d.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((a,t)=>(d.f[t](e,a),a)),[])),d.u=e=>"assets/js/"+({4:"d9461b6c",53:"935f2afb",59:"b5d5e16b",71:"804a5934",80:"4d54d076",87:"fcc13998",88:"4cb9f763",114:"b9421f89",128:"a09c2993",145:"299b5310",163:"934782ba",200:"bab6f5ab",201:"040fbf97",212:"48ae5635",217:"3b8c55ea",220:"f9459e94",239:"72e14192",242:"3fcb412e",262:"9e350ec0",267:"86b9c768",296:"e8c0720c",325:"c12dc9fd",335:"053b5658",352:"dea0f9ea",360:"9d9f8394",414:"0aeccac2",451:"6173fde8",480:"9f65b58a",514:"1be78505",644:"d2339658",691:"0a7bb60d",702:"2a636ef6",705:"c5934ffc",722:"7e72de0f",737:"2133a534",765:"57b2432c",835:"ea9eabff",836:"0480b142",838:"6bd0979b",845:"c13ba925",865:"b407a98a",918:"17896441",925:"89eebbd3",948:"0c380bb3",964:"22539a87",993:"c698fe77"}[e]||e)+"."+{4:"cfb2e633",53:"28c78675",59:"671619da",71:"94dc2f49",80:"b42a6d95",87:"60932360",88:"7b7193b5",114:"2569d45d",128:"d7d5958b",145:"edc4e810",163:"38219ecf",200:"75d4fe2d",201:"2f4e975a",212:"06d4c7cd",217:"7fbcd779",220:"a9a17024",239:"caf3f8a8",242:"48bc29de",262:"2124b2d5",267:"6a1c76ae",296:"806b237d",325:"026b82ae",335:"14dee349",352:"41975f45",360:"aca5ea48",414:"008fdaae",451:"9aae5469",480:"52d92de7",514:"af84a9b6",644:"5d019890",691:"ac142ed8",702:"51de8e98",705:"3a06677d",722:"46d6e17a",737:"156e8b1f",765:"97404563",835:"fb82e175",836:"cad65f4e",838:"6c0a2130",845:"811c1f7b",865:"944ebdbf",918:"561afd72",925:"266b07ac",948:"f493fbf1",964:"29d1b817",972:"b43202c5",993:"c274d15b"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},c="website:",d.l=(e,a,t,b)=>{if(r[e])r[e].push(a);else{var f,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{f.onerror=f.onload=null,clearTimeout(s);var c=r[e];if(delete r[e],f.parentNode&&f.parentNode.removeChild(f),c&&c.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:f}),12e4);f.onerror=l.bind(null,f.onerror),f.onload=l.bind(null,f.onload),o&&document.head.appendChild(f)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/copacetic/website/",d.gca=function(e){return e={17896441:"918",d9461b6c:"4","935f2afb":"53",b5d5e16b:"59","804a5934":"71","4d54d076":"80",fcc13998:"87","4cb9f763":"88",b9421f89:"114",a09c2993:"128","299b5310":"145","934782ba":"163",bab6f5ab:"200","040fbf97":"201","48ae5635":"212","3b8c55ea":"217",f9459e94:"220","72e14192":"239","3fcb412e":"242","9e350ec0":"262","86b9c768":"267",e8c0720c:"296",c12dc9fd:"325","053b5658":"335",dea0f9ea:"352","9d9f8394":"360","0aeccac2":"414","6173fde8":"451","9f65b58a":"480","1be78505":"514",d2339658:"644","0a7bb60d":"691","2a636ef6":"702",c5934ffc:"705","7e72de0f":"722","2133a534":"737","57b2432c":"765",ea9eabff:"835","0480b142":"836","6bd0979b":"838",c13ba925:"845",b407a98a:"865","89eebbd3":"925","0c380bb3":"948","22539a87":"964",c698fe77:"993"}[e]||e,d.p+d.u(e)},(()=>{var e={303:0,532:0};d.f.j=(a,t)=>{var r=d.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(303|532)$/.test(a))e[a]=0;else{var c=new Promise(((t,c)=>r=e[a]=[t,c]));t.push(r[2]=c);var b=d.p+d.u(a),f=new Error;d.l(b,(t=>{if(d.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var c=t&&("load"===t.type?"missing":t.type),b=t&&t.target&&t.target.src;f.message="Loading chunk "+a+" failed.\n("+c+": "+b+")",f.name="ChunkLoadError",f.type=c,f.request=b,r[1](f)}}),"chunk-"+a,a)}},d.O.j=a=>0===e[a];var a=(a,t)=>{var r,c,b=t[0],f=t[1],o=t[2],n=0;if(b.some((a=>0!==e[a]))){for(r in f)d.o(f,r)&&(d.m[r]=f[r]);if(o)var i=o(d)}for(a&&a(t);n - + @@ -62,7 +62,7 @@ Mozilla's code of conduct enforcement ladder.

For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.

- + \ No newline at end of file diff --git a/website/contributing.html b/website/contributing.html index d0749d6d..d3a1cf78 100644 --- a/website/contributing.html +++ b/website/contributing.html @@ -7,7 +7,7 @@ - + @@ -27,7 +27,7 @@ personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.

Contributors sign-off that they adhere to these requirements by adding a Signed-off-by line to commit messages.

This is my commit message

Signed-off-by: Random J Developer <random@developer.example.org>

Git even has a -s command line option to append this automatically to your commit message:

git commit -s -m 'This is my commit message'

Pull requests that do not contain a valid Signed-off-by line cannot be merged.

I didn't sign my commit, now what?

No worries - You can easily amend your commit with a sign-off and force push the change to your submitting branch:

git switch <branch-name>
git commit --amend --no-edit --signoff
git push --force-with-lease <remote-name> <branch-name>

Code of Conduct

This project has adopted the Contributor Covenant Code of Conduct.

- + \ No newline at end of file diff --git a/website/design.html b/website/design.html index b268fa2a..18c8fbde 100644 --- a/website/design.html +++ b/website/design.html @@ -7,13 +7,13 @@ - +
Version: v0.4.x

Design

Design Tenets

  • Copa is intended to accelerate container patching by eliminating waiting on base image dependency chains to update. This is a raison d’etre for the Copa project, so if we figured out a different way to patch containers that still relied on waiting for base images to be rebuilt and republished, we would consider spinning that off into a different project instead of making it part of Copa.

  • Copa is intended to work with the existing ecosystem of container images. The project should have a strong preference for solutions that do not require image producers to create or modify their images in special ways to use Copa.

  • Copa is intended to allow parties other than the image authors to address container vulnerabilities. Copa should require a minimum of special knowledge about the lineage and construction of an image from the user to patch it successfully.

  • Copa is intended to do one thing well and be composable with other tools and processes. Copa does not have to be a universal multitool for container patching. For example, it is preferable that it integrates with popular container scanning tools rather than incorporating custom container scanning into the project itself. Similarly, it does not need to become a general container manipulation tool in the vein of crane.

Design Reasoning

The design of copa arises from the application of those tenets to the observed issues in previous efforts directly update container images via rebasing, for example, the experimental crane rebase:

  • Rebasing requires that all actors involved in creation of the image are coordinated so that some layers can be switched out without breaking the image. Attempting to switch out layers in the container overlay structure is brittle because most existing containers are created by writing over shared configuration files and data stores in base images. For example, an apt install during image creation will overwrite the dpkg status file in the base image, which will mask any package updates in a rebased layer. Since many existing container scanners rely on the reported package status to find vulnerable package versions, this can cause new vulnerabilities to not be reported or for patched binaries not to be recognized by the scanners.

    To avoid breaking integration with the existing container ecosystem, copa patches the filesystem bundle as a whole instead of as a collection of layers so that the resulting image state is consistent. This strategy also allows copa to patch vulnerabilties introduced at any layer in the image, including OS packages added in the app layers that is not addressed by a simple rebase. It also supports the core tenet of supporting patching without requiring coordination with all the publishers of the base images that a given image transitively depends on.

  • Rebasing also requires that the user knows a priori what base image (or transitive base image) is in the target image to determine which appropriate rebase image to use. This makes it very difficult for anyone not intimately involved with authoring the image from being able to remediate it, which is one of our tenets.

    While it is possible to embed extra metadata or annotations into the target image to facilitate this base image (or transitive base image) lookup, that would require that the images to be patched be modified or created especially to support updates, which goes against another of our tenets to be able to patch images without requiring them to be customized explicitly for that purpose.

    The design of copa addresses this by reframing the problem of updating containers and understanding the structure or lineage of a container image to the more specific problem of what packages in a given container image need to be updated. This allows copa to tap into the expertise embedded in the much more robust ecosystem for detecting and remediating vulnerabilities at the package level that already exists today. By making copa an additional remediation step that can be run after a container scan in existing workflows, we avoid both of those issues with an additional benefit: it incurs no additional work on the part of base image publishers to support patching of images based on their base images, the existing channels for publishing update packages is sufficient to service those container images as well.

Architecture

The requirements presented encourage an extensible model in order to support broad applicability. Specifically, there are two areas that the tool will need to accommodate multiple implementations to support more use cases:

  • The data schema of various vulnerability scanners producing the input vulnerability report.
  • The state management of various package managers and process for applying patches appropriately through them.

Effectively, copa patch can be considered a command that bridges an extensible Parse action with an extensible Apply action as illustrated in the diagram; the implementation can be thought of as an engine that uses this abstract Go interface to apply security update packages:

type UpdatePackage struct {
Name string
Version string
}

type UpdateManifest struct {
OSType string
OSVersion string
Arch string
Updates []UpdatePackage
}

type ScanReportParser interface {
Parse(reportPath string) (*UpdateManifest, error)
}

type PackageManager interface {
Apply(imagePath string, report *UpdateManifest) error
}

Implementation

copa is a pseudo-frontend to buildkit implemented as a CLI tool. Effectively, instead of taking a container definition to create from scratch, it takes the reference to the target image to patch and a container scan report and builds a series of LLB graphs for buildkit to execute:

  1. Actions to probe the image as a filesystem bundle, for example, retrieving the package manager status in the image.
    • Within each distribution type identified by the scanner report (e.g. Debian) there can be different ways of applying patches to the target image (e.g. distroless), which can be differentiated through these actions.
  2. Actions to fetch and deploy tools that can be injected into the target image to perform the patching.
    • In cases where the package tools are not available in the target image, a standard version of the OS container matching the target image's is used to stage the necessary tooling for patches.
    • In the case of distroless images for example, where there is no valid package status file in the target image, the tooling container is also used to pull down and process the necessary package updates for copy to the target image.
    • Although not pictured, this can also be used to obtain tools (e.g. busybox) to be used in the image probing stage as well.
  3. Actions to deploy the required patch packages to the target image.
    • copa integrates with buildkit at the API level because it uses the diff and merge graph operations directly so that it can stage all the necessary tooling in the target image while producing a resulting image that only contains the original image plus a new layer with all the deployed patches.

Tradeoffs

  • The core architectural choice of relying on packages as the unit of patching creates a couple of constraints:
    • By relying on existing vulnerability scanner behavior that only detects vulnerabilities via presence/absence of vulnerable packages, copa is limited in the kinds of vulnerabilities it can address and false positive/negatives from scanners flow downstream to copa.
    • copa depends on individual package manager adapters to correctly deploy patches to the target images, but there is a long tail of compatibility issues that arise depending on the target image itself (e.g. outdated package manager config/keys, invalid/missing package graph, etc.). Overall, the maintenance cost of the project is expected to be non-trivial to address this.
  • No support for windows containers given the dependency on buildkit.
- + \ No newline at end of file diff --git a/website/faq.html b/website/faq.html index f0ddd0c5..d597cab1 100644 --- a/website/faq.html +++ b/website/faq.html @@ -7,13 +7,13 @@ - +
Version: v0.4.x

FAQ

What kind of vulnerabilities can Copa patch?

Copa is capable of patching "OS level" vulnerabilities. This includes packages (like openssl) in the image that are managed by a package manager such as apt or yum. Copa is not currently capable of patching vulnerabilities at the "application level" such as Python packages or Go modules.

- + \ No newline at end of file diff --git a/website/index.html b/website/index.html index 009d8ea2..fdfb122c 100644 --- a/website/index.html +++ b/website/index.html @@ -7,13 +7,13 @@ - +
Version: v0.4.x

Project Copacetic: Directly patch container image vulnerabilities

copa is a CLI tool written in Go and based on buildkit that can be used to directly patch container images given the vulnerability scanning results from popular tools like Trivy.

Why?

We needed the ability to patch containers quickly without going upstream for a full rebuild. As the window between vulnerability disclosure and active exploitation continues to narrow, there is a growing operational need to patch critical security vulnerabilities in container images so they can be quickly redeployed into production. The need is especially acute when those vulnerabilities are:

  • inherited from base images several levels deep and waiting on updated releases to percolate through the supply chain is not an option
  • found in 3rd party app images you don't maintain with update cadences that don't meet your security SLAs.

In addition to filling the operational gap not met by left-shift security practices and tools, the ability of copa to patch a container without requiring a rebuild of the container image provides other benefits:

  • Allows users other than the image publishers to also patch container images, such as DevSecOps engineers.
  • Reduces the storage and transmission costs of redistributing patched images by only creating an additional patch layer, instead of rebuilding the entire image which usually results in different layer hashes that break layer caching.
  • Reduces the turnaround time for patching a container image by not having to wait for base image updates and being a faster operation than a full image rebuild.
  • Reduces the complexity of patching the image from running a rebuild pipeline to running a single tool on the image.

How?

The copa tool is an extensible engine that:

  1. Parses the needed update packages from the container image’s vulnerability report produced by a scanner like Trivy. New adapters can be written to accommodate more report formats.
  2. Obtains and processes the needed update packages using the appropriate package manager tools such as apt, apk, etc. New adapters can be written to support more package managers.
  3. Applies the resulting update binaries to the container image using buildkit.

This approach is motivated by the core principles of making direct container patching broadly applicable and accessible:

  • Copa supports patching existing container images.
    • Devs don't need to build their images using specific tools or modify them in some way just to support container patching.
  • Copa works with the existing vulnerability scanning and mitigation ecosystems.
    • Image publishers don't need to create new workflows for container patching since Copa supports patching container images using the security update packages already being published today.
    • Consumers do not need to migrate to a new and potentially more limited support ecosystem for custom distros or change their container vulnerability scanning pipelines to include remediation, since Copa can be integrated seamlessly as an extra step to patch containers based on those scanning reports.
  • Copa reduces the technical expertise needed and waiting on dependencies needed to patch an image.
    • For OS package vulnerabilities, no specialized knowledge about a specific image is needed to be patch it as Copa relies on the vulnerability remediation knowledge already embedded in the reports produced by popular container scanning tools today.

For more details, refer to the copa design documentation.

- + \ No newline at end of file diff --git a/website/installation.html b/website/installation.html index d56356fa..016e5354 100644 --- a/website/installation.html +++ b/website/installation.html @@ -7,13 +7,13 @@ - +
Version: v0.4.x

Installation

Homebrew

On macOS and Linux, copa can be installed via Homebrew:

brew install copa

GitHub

You can download the latest and previous versions of copa from the GitHub releases page.

Development Setup

The following instructions are for Ubuntu 22.04 with the dependency versions supported as part of the dev container environment we use for builds and tests. For other distributions and OS, refer to the appropriate installation instructions for each of the components instead.

git clone https://github.com/project-copacetic/copacetic
cd copacetic
make
# OPTIONAL: install copa to a pathed folder
sudo mv dist/linux_amd64/release/copa /usr/local/bin/
- + \ No newline at end of file diff --git a/website/next.html b/website/next.html index 248e6410..1b4cf6d9 100644 --- a/website/next.html +++ b/website/next.html @@ -7,13 +7,13 @@ - +
Version: Next

Project Copacetic: Directly patch container image vulnerabilities

copa is a CLI tool written in Go and based on buildkit that can be used to directly patch container images given the vulnerability scanning results from popular tools like Trivy.

Why?

We needed the ability to patch containers quickly without going upstream for a full rebuild. As the window between vulnerability disclosure and active exploitation continues to narrow, there is a growing operational need to patch critical security vulnerabilities in container images so they can be quickly redeployed into production. The need is especially acute when those vulnerabilities are:

  • inherited from base images several levels deep and waiting on updated releases to percolate through the supply chain is not an option
  • found in 3rd party app images you don't maintain with update cadences that don't meet your security SLAs.

In addition to filling the operational gap not met by left-shift security practices and tools, the ability of copa to patch a container without requiring a rebuild of the container image provides other benefits:

  • Allows users other than the image publishers to also patch container images, such as DevSecOps engineers.
  • Reduces the storage and transmission costs of redistributing patched images by only creating an additional patch layer, instead of rebuilding the entire image which usually results in different layer hashes that break layer caching.
  • Reduces the turnaround time for patching a container image by not having to wait for base image updates and being a faster operation than a full image rebuild.
  • Reduces the complexity of patching the image from running a rebuild pipeline to running a single tool on the image.

How?

The copa tool is an extensible engine that:

  1. Parses the needed update packages from the container image’s vulnerability report produced by a scanner like Trivy. New adapters can be written to accommodate more report formats.
  2. Obtains and processes the needed update packages using the appropriate package manager tools such as apt, apk, etc. New adapters can be written to support more package managers.
  3. Applies the resulting update binaries to the container image using buildkit.

This approach is motivated by the core principles of making direct container patching broadly applicable and accessible:

  • Copa supports patching existing container images.
    • Devs don't need to build their images using specific tools or modify them in some way just to support container patching.
  • Copa works with the existing vulnerability scanning and mitigation ecosystems.
    • Image publishers don't need to create new workflows for container patching since Copa supports patching container images using the security update packages already being published today.
    • Consumers do not need to migrate to a new and potentially more limited support ecosystem for custom distros or change their container vulnerability scanning pipelines to include remediation, since Copa can be integrated seamlessly as an extra step to patch containers based on those scanning reports.
  • Copa reduces the technical expertise needed and waiting on dependencies needed to patch an image.
    • For OS package vulnerabilities, no specialized knowledge about a specific image is needed to be patch it as Copa relies on the vulnerability remediation knowledge already embedded in the reports produced by popular container scanning tools today.

For more details, refer to the copa design documentation.

- + \ No newline at end of file diff --git a/website/next/code-of-conduct.html b/website/next/code-of-conduct.html index 9fa2f3ad..0e2e2eb0 100644 --- a/website/next/code-of-conduct.html +++ b/website/next/code-of-conduct.html @@ -7,7 +7,7 @@ - + @@ -62,7 +62,7 @@ Mozilla's code of conduct enforcement ladder.

For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.

- + \ No newline at end of file diff --git a/website/next/contributing.html b/website/next/contributing.html index 7bd5cb45..06ca546a 100644 --- a/website/next/contributing.html +++ b/website/next/contributing.html @@ -7,7 +7,7 @@ - + @@ -27,7 +27,7 @@ personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.

Contributors sign-off that they adhere to these requirements by adding a Signed-off-by line to commit messages.

This is my commit message

Signed-off-by: Random J Developer <random@developer.example.org>

Git even has a -s command line option to append this automatically to your commit message:

git commit -s -m 'This is my commit message'

Pull requests that do not contain a valid Signed-off-by line cannot be merged.

I didn't sign my commit, now what?

No worries - You can easily amend your commit with a sign-off and force push the change to your submitting branch:

git switch <branch-name>
git commit --amend --no-edit --signoff
git push --force-with-lease <remote-name> <branch-name>

Code of Conduct

This project has adopted the Contributor Covenant Code of Conduct.

- + \ No newline at end of file diff --git a/website/next/design.html b/website/next/design.html index 70ae17c1..da300207 100644 --- a/website/next/design.html +++ b/website/next/design.html @@ -7,13 +7,13 @@ - +
Version: Next

Design

Design Tenets

  • Copa is intended to accelerate container patching by eliminating waiting on base image dependency chains to update. This is a raison d’etre for the Copa project, so if we figured out a different way to patch containers that still relied on waiting for base images to be rebuilt and republished, we would consider spinning that off into a different project instead of making it part of Copa.

  • Copa is intended to work with the existing ecosystem of container images. The project should have a strong preference for solutions that do not require image producers to create or modify their images in special ways to use Copa.

  • Copa is intended to allow parties other than the image authors to address container vulnerabilities. Copa should require a minimum of special knowledge about the lineage and construction of an image from the user to patch it successfully.

  • Copa is intended to do one thing well and be composable with other tools and processes. Copa does not have to be a universal multitool for container patching. For example, it is preferable that it integrates with popular container scanning tools rather than incorporating custom container scanning into the project itself. Similarly, it does not need to become a general container manipulation tool in the vein of crane.

Design Reasoning

The design of copa arises from the application of those tenets to the observed issues in previous efforts directly update container images via rebasing, for example, the experimental crane rebase:

  • Rebasing requires that all actors involved in creation of the image are coordinated so that some layers can be switched out without breaking the image. Attempting to switch out layers in the container overlay structure is brittle because most existing containers are created by writing over shared configuration files and data stores in base images. For example, an apt install during image creation will overwrite the dpkg status file in the base image, which will mask any package updates in a rebased layer. Since many existing container scanners rely on the reported package status to find vulnerable package versions, this can cause new vulnerabilities to not be reported or for patched binaries not to be recognized by the scanners.

    To avoid breaking integration with the existing container ecosystem, copa patches the filesystem bundle as a whole instead of as a collection of layers so that the resulting image state is consistent. This strategy also allows copa to patch vulnerabilties introduced at any layer in the image, including OS packages added in the app layers that is not addressed by a simple rebase. It also supports the core tenet of supporting patching without requiring coordination with all the publishers of the base images that a given image transitively depends on.

  • Rebasing also requires that the user knows a priori what base image (or transitive base image) is in the target image to determine which appropriate rebase image to use. This makes it very difficult for anyone not intimately involved with authoring the image from being able to remediate it, which is one of our tenets.

    While it is possible to embed extra metadata or annotations into the target image to facilitate this base image (or transitive base image) lookup, that would require that the images to be patched be modified or created especially to support updates, which goes against another of our tenets to be able to patch images without requiring them to be customized explicitly for that purpose.

    The design of copa addresses this by reframing the problem of updating containers and understanding the structure or lineage of a container image to the more specific problem of what packages in a given container image need to be updated. This allows copa to tap into the expertise embedded in the much more robust ecosystem for detecting and remediating vulnerabilities at the package level that already exists today. By making copa an additional remediation step that can be run after a container scan in existing workflows, we avoid both of those issues with an additional benefit: it incurs no additional work on the part of base image publishers to support patching of images based on their base images, the existing channels for publishing update packages is sufficient to service those container images as well.

Architecture

The requirements presented encourage an extensible model in order to support broad applicability. Specifically, there are two areas that the tool will need to accommodate multiple implementations to support more use cases:

  • The data schema of various vulnerability scanners producing the input vulnerability report.
  • The state management of various package managers and process for applying patches appropriately through them.

Effectively, copa patch can be considered a command that bridges an extensible Parse action with an extensible Apply action as illustrated in the diagram; the implementation can be thought of as an engine that uses this abstract Go interface to apply security update packages:

type UpdatePackage struct {
Name string
Version string
}

type UpdateManifest struct {
OSType string
OSVersion string
Arch string
Updates []UpdatePackage
}

type ScanReportParser interface {
Parse(reportPath string) (*UpdateManifest, error)
}

type PackageManager interface {
Apply(imagePath string, report *UpdateManifest) error
}

Implementation

copa is a pseudo-frontend to buildkit implemented as a CLI tool. Effectively, instead of taking a container definition to create from scratch, it takes the reference to the target image to patch and a container scan report and builds a series of LLB graphs for buildkit to execute:

  1. Actions to probe the image as a filesystem bundle, for example, retrieving the package manager status in the image.
    • Within each distribution type identified by the scanner report (e.g. Debian) there can be different ways of applying patches to the target image (e.g. distroless), which can be differentiated through these actions.
  2. Actions to fetch and deploy tools that can be injected into the target image to perform the patching.
    • In cases where the package tools are not available in the target image, a standard version of the OS container matching the target image's is used to stage the necessary tooling for patches.
    • In the case of distroless images for example, where there is no valid package status file in the target image, the tooling container is also used to pull down and process the necessary package updates for copy to the target image.
    • Although not pictured, this can also be used to obtain tools (e.g. busybox) to be used in the image probing stage as well.
  3. Actions to deploy the required patch packages to the target image.
    • copa integrates with buildkit at the API level because it uses the diff and merge graph operations directly so that it can stage all the necessary tooling in the target image while producing a resulting image that only contains the original image plus a new layer with all the deployed patches.

Tradeoffs

  • The core architectural choice of relying on packages as the unit of patching creates a couple of constraints:
    • By relying on existing vulnerability scanner behavior that only detects vulnerabilities via presence/absence of vulnerable packages, copa is limited in the kinds of vulnerabilities it can address and false positive/negatives from scanners flow downstream to copa.
    • copa depends on individual package manager adapters to correctly deploy patches to the target images, but there is a long tail of compatibility issues that arise depending on the target image itself (e.g. outdated package manager config/keys, invalid/missing package graph, etc.). Overall, the maintenance cost of the project is expected to be non-trivial to address this.
  • No support for windows containers given the dependency on buildkit.
- + \ No newline at end of file diff --git a/website/next/faq.html b/website/next/faq.html index 70e28b7e..68ccb79d 100644 --- a/website/next/faq.html +++ b/website/next/faq.html @@ -7,13 +7,13 @@ - +
Version: Next

FAQ

What kind of vulnerabilities can Copa patch?

Copa is capable of patching "OS level" vulnerabilities. This includes packages (like openssl) in the image that are managed by a package manager such as apt or yum. Copa is not currently capable of patching vulnerabilities at the "application level" such as Python packages or Go modules.

- + \ No newline at end of file diff --git a/website/next/installation.html b/website/next/installation.html index 51e4c4cd..df1b54d8 100644 --- a/website/next/installation.html +++ b/website/next/installation.html @@ -7,13 +7,13 @@ - +
Version: Next

Installation

Homebrew

On macOS and Linux, copa can be installed via Homebrew:

brew install copa

GitHub

You can download the latest and previous versions of copa from the GitHub releases page.

Development Setup

The following instructions are for Ubuntu 22.04 with the dependency versions supported as part of the dev container environment we use for builds and tests. For other distributions and OS, refer to the appropriate installation instructions for each of the components instead.

git clone https://github.com/project-copacetic/copacetic
cd copacetic
make
# OPTIONAL: install copa to a pathed folder
sudo mv dist/linux_amd64/release/copa /usr/local/bin/
- + \ No newline at end of file diff --git a/website/next/output.html b/website/next/output.html index e3f3fc53..ce0fb8bb 100644 --- a/website/next/output.html +++ b/website/next/output.html @@ -7,13 +7,13 @@ - +
Version: Next

Output

caution

Experimental: This feature might change without preserving backwards compatibility.

Copa optionally outputs a Vulnerability Exploitability eXchange (VEX) file as a result of the patching process to surface the vulnerabilities and packages that were patched.

Currently, Copa supports the OpenVEX format, but it can be extended to support other formats.

OpenVEX

OpenVEX is an implementation of Vulnerability Exploitability eXchange (VEX) format. For more information, see OpenVEX specification.

tip
  • Use COPA_VEX_AUTHOR environment variable to set the author of the VEX document. If it's not set, the author will default to Project Copacetic.

  • A VEX document must contain at least one VEX statement. If there are no fixed vulnerabilities, Copa will not generate a VEX document.

To generate a VEX document using OpenVEX, use --format="openvex" flag, and use --output to specify a file path. For example:

copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --format="openvex" --output "nginx.1.21.6-vex.json"

This will generate a VEX Document that looks like:

{
"@context": "https://openvex.dev/ns",
"@id": "https://openvex.dev/docs/public/vex-6f15c26e0410a4d44e0af4062f4b883fbc19a98e57baf131715d942213e5002a",
"author": "Project Copacetic",
"timestamp": "2023-08-25T21:40:23.891230545Z",
"version": 1,
"tooling": "Project Copacetic",
"statements": [
{
"vulnerability": {
"@id": "CVE-2021-3995"
},
"products": [
{
"@id": "pkg:deb/debian/bsdutils@1:2.36.1-8?arch=amd64"
},
{
"@id": "pkg:deb/debian/libblkid1@2.36.1-8?arch=amd64"
},
{
"@id": "pkg:deb/debian/libmount1@2.36.1-8?arch=amd64"
},
{
"@id": "pkg:deb/debian/libsmartcols1@2.36.1-8?arch=amd64"
},
{
"@id": "pkg:deb/debian/libuuid1@2.36.1-8?arch=amd64"
},
{
"@id": "pkg:deb/debian/mount@2.36.1-8?arch=amd64"
},
{
"@id": "pkg:deb/debian/util-linux@2.36.1-8?arch=amd64"
}
],
"status": "fixed"
},
...
}
- + \ No newline at end of file diff --git a/website/next/quick-start.html b/website/next/quick-start.html index a2e46f44..0ca23c48 100644 --- a/website/next/quick-start.html +++ b/website/next/quick-start.html @@ -7,16 +7,16 @@ - +
Version: Next

Quick Start

This sample illustrates how to patch containers using vulnerability reports with copa.

Prerequisites

Sample Steps

  1. Scan the container image for patchable OS vulnerabilities, outputting the results to a JSON file:

    trivy image --vuln-type os --ignore-unfixed -f json -o nginx.1.21.6.json docker.io/library/nginx:1.21.6

    You can also see the existing patchable vulnerabilities in table form on the shell with:

    trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6

  2. To patch the image, use the Trivy report and specify a buildkit instance to connect to:

    By default copa will attempt to auto-connect to an instance in order:

    1. Default docker buildkit endpoint (requires at least docker v24.0 with containerd snapshotter support enabled)
    2. Currently selected buildx builder (see: docker buildx --help)
    3. buildkit daemon at the default address /run/buildkit/buildkitd.sock

    If an instance doesn't exist or that instance doesn't support all the features copa needs the next will be attempted. -You may need to specify a custom address using the --addr flag. Here are the supported formats:

    • unix:///path/to/buildkit.sock - Connect to buildkit over unix socket.
    • tcp://$BUILDKIT_ADDR:$PORT - Connec to buildkit over TCP. (not recommended for security reasons)
    • docker://<docker connection spec> - Connect to docker, currently only unix sockets are supported, e.g. docker://unix:///var/run/docker.sock (or just docker://).
    • docker-container://my-buildkit-container - Connect to a buildkitd running in a docker container.
    • buildx://my-builder - Connect to a buildx builder (or buildx:// for the currently selected builder). Note: only container-backed buildx instances are currently supported
    • nerdctl-container://my-container-name - Similar to docker-container but uses nerdctl.
    • podman-container://my-container-name - Similar to docker-container but uses podman.
    • ssh://myhost - Connect to a buildkit instance over SSH. Format of the host spec should mimic the SSH command.
    • kubepod://mypod - Connect to buildkit running in a Kubernetes pod. Can also specify kubectl context and pod namespace (kubepod://mypod?context=foo&namespace=notdefault).

    Buildkit Connection Examples

    Example: Connect using defaults:

    copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched

    Example: Connect to buildx

    docker buildx create --name demo
    copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr buildx://demo

    Example: Buildkit in a container

    export BUILDKIT_VERSION=v0.12.0
    docker run \
    --detach \
    --rm \
    --privileged \
    --name buildkitd \
    --entrypoint buildkitd \
    "moby/buildkit:$BUILDKIT_VERSION"

    copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr docker-container://buildkitd

    Example: Buildkit over TCP

    export BUILDKIT_VERSION=v0.12.0
    export BUILDKIT_PORT=8888
    docker run \
    --detach \
    --rm \
    --privileged \
    -p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \
    --name buildkitd \
    --entrypoint buildkitd \
    "moby/buildkit:$BUILDKIT_VERSION" \
    --addr tcp://0.0.0.0:$BUILDKIT_PORT
    copa patch \
    -i docker.io/library/nginx:1.21.6 \
    -r nginx.1.21.6.json \
    -t 1.21.6-patched \
    -a tcp://0.0.0.0:$BUILDKIT_PORT

    In either case, copa is non-destructive and exports a new image with the specified 1.21.6-patched label to the local Docker daemon.

    NOTE: if you're running this sample against an image from a private registry instead, +You may need to specify a custom address using the --addr flag. Here are the supported formats:

    • unix:///path/to/buildkit.sock - Connect to buildkit over unix socket.
    • tcp://$BUILDKIT_ADDR:$PORT - Connect to buildkit over TCP. (not recommended for security reasons)
    • docker://<docker connection spec> - Connect to docker, currently only unix sockets are supported, e.g. docker://unix:///var/run/docker.sock (or just docker://).
    • docker-container://my-buildkit-container - Connect to a buildkitd running in a docker container.
    • buildx://my-builder - Connect to a buildx builder (or buildx:// for the currently selected builder). Note: only container-backed buildx instances are currently supported
    • nerdctl-container://my-container-name - Similar to docker-container but uses nerdctl.
    • podman-container://my-container-name - Similar to docker-container but uses podman.
    • ssh://myhost - Connect to a buildkit instance over SSH. Format of the host spec should mimic the SSH command.
    • kubepod://mypod - Connect to buildkit running in a Kubernetes pod. Can also specify kubectl context and pod namespace (kubepod://mypod?context=foo&namespace=notdefault).

    Buildkit Connection Examples

    Example: Connect using defaults:

    copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched

    Example: Connect to buildx

    docker buildx create --name demo
    copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr buildx://demo

    Example: Buildkit in a container

    export BUILDKIT_VERSION=v0.12.0
    docker run \
    --detach \
    --rm \
    --privileged \
    --name buildkitd \
    --entrypoint buildkitd \
    "moby/buildkit:$BUILDKIT_VERSION"

    copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr docker-container://buildkitd

    Example: Buildkit over TCP

    export BUILDKIT_VERSION=v0.12.0
    export BUILDKIT_PORT=8888
    docker run \
    --detach \
    --rm \
    --privileged \
    -p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \
    --name buildkitd \
    --entrypoint buildkitd \
    "moby/buildkit:$BUILDKIT_VERSION" \
    --addr tcp://0.0.0.0:$BUILDKIT_PORT
    copa patch \
    -i docker.io/library/nginx:1.21.6 \
    -r nginx.1.21.6.json \
    -t 1.21.6-patched \
    -a tcp://0.0.0.0:$BUILDKIT_PORT

    In either case, copa is non-destructive and exports a new image with the specified 1.21.6-patched label to the local Docker daemon.

    NOTE: if you're running this sample against an image from a private registry instead, ensure that the credentials are configured in the default Docker config.json before running copa patch, for example, via sudo docker login -u <user> -p <password> <registry>.

  3. Scan the patched image and verify that the vulnerabilities have been patched:

    trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6-patched

    You can also inspect the structure of the patched image with docker history to see the new patch layer appended to the image:

    $ docker history docker.io/library/nginx:1.21.6-patched
    IMAGE CREATED CREATED BY SIZE COMMENT
    a372df41e06d 1 minute ago mount / from exec sh -c apt install --no-ins… 26.1MB buildkit.exporter.image.v0
    <missing> 3 months ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
    <missing> 3 months ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0
    <missing> 3 months ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
    <missing> 3 months ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
    <missing> 3 months ago COPY 30-tune-worker-processes.sh /docker-ent… 4.61kB buildkit.dockerfile.v0
    <missing> 3 months ago COPY 20-envsubst-on-templates.sh /docker-ent… 1.04kB buildkit.dockerfile.v0
    <missing> 3 months ago COPY 10-listen-on-ipv6-by-default.sh /docker… 1.96kB buildkit.dockerfile.v0
    <missing> 3 months ago COPY docker-entrypoint.sh / # buildkit 1.2kB buildkit.dockerfile.v0
    <missing> 3 months ago RUN /bin/sh -c set -x && addgroup --syst… 61.1MB buildkit.dockerfile.v0
    <missing> 3 months ago ENV PKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0
    <missing> 3 months ago ENV NJS_VERSION=0.7.0 0B buildkit.dockerfile.v0
    <missing> 3 months ago ENV NGINX_VERSION=1.20.2 0B buildkit.dockerfile.v0
    <missing> 3 months ago LABEL maintainer=NGINX Docker Maintainers <d… 0B buildkit.dockerfile.v0
    <missing> 4 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
    <missing> 4 months ago /bin/sh -c #(nop) ADD file:09675d11695f65c55… 80.4MB
  4. Run the container to verify that the image has no regressions:

    $ docker run -it --rm --name nginx-test docker.io/library/nginx:1.21.6-patched
    /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
    /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
    10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
    10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
    /docker-entrypoint.sh: Configuration complete; ready for start up
    2022/05/16 18:00:17 [notice] 1#1: using the "epoll" event method
    2022/05/16 18:00:17 [notice] 1#1: nginx/1.20.2
    2022/05/16 18:00:17 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
    2022/05/16 18:00:17 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2
    2022/05/16 18:00:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
    2022/05/16 18:00:17 [notice] 1#1: start worker processes
    2022/05/16 18:00:17 [notice] 1#1: start worker process 31
    2022/05/16 18:00:17 [notice] 1#1: start worker process 32
    2022/05/16 18:00:17 [notice] 1#1: start worker process 33
    2022/05/16 18:00:17 [notice] 1#1: start worker process 34
    2022/05/16 18:00:17 [notice] 1#1: start worker process 35
    2022/05/16 18:00:17 [notice] 1#1: start worker process 36
    2022/05/16 18:00:17 [notice] 1#1: start worker process 37
    2022/05/16 18:00:17 [notice] 1#1: start worker process 38
    2022/05/16 18:00:17 [notice] 38#38: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 36#36: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 33#33: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 32#32: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 34#34: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 35#35: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 37#37: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 1#1: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 31#31: signal 28 (SIGWINCH) received

    You can stop the container by opening a new shell instance and running: docker stop nginx-test

- + \ No newline at end of file diff --git a/website/next/troubleshooting.html b/website/next/troubleshooting.html index 36912f63..787d94e1 100644 --- a/website/next/troubleshooting.html +++ b/website/next/troubleshooting.html @@ -7,13 +7,13 @@ - +
Version: Next

Troubleshooting

Filtering Vulnerabilities

You might want to filter/ignore some of the vulnerabilities while patching. To do so, you need to first filter those undesired vulnerabilities from your scanner output.

For Trivy, vulnerabilities can be filtered by the following 2 ways:

Rego Policy

An example rego file which demonstrates how to ignore certain Vulnerability IDs or Package Names:

$ cat trivy_ignore.rego

package trivy

import data.lib.trivy

default ignore = false


# Ignore the following Vulnerability IDs
ignore_vulnerability_ids := {
"CVE-2018-14618"
}
# Ignore the following Package Names
ignore_pkgs := {"bash", "vim"}


# For ignoring vulnID
ignore {
input.VulnerabilityID == ignore_vulnerability_ids[_]
}
# For ignoring pkgName
ignore {
input.PkgName == ignore_pkgs[_]
}

After adding the above rego file, run the image scan with the --ignore-policy flag followed by the file name to ignore them while scanning:

trivy image --ignore-policy trivy_ignore.rego ruby:2.4.0

In the above example, the vulnerability "CVE-2018-14618" and the packages "bash" & "vim" are ignored while scanning, and hence patching the image.

Ignore File

Use a .trivyignore file to list all the vulnerabilities you want to ignore.

Example:

$ cat .trivyignore

# Accept the risk
CVE-2018-14618

In the above example, the vulnerability CVE-2018-14618 is ignored while scanning, and hence while patching the image.

For a more detailed explanation on how to ignore certain vulnerabilities with Trivy, please refer to the official documentation here.

- + \ No newline at end of file diff --git a/website/quick-start.html b/website/quick-start.html index 4fca72a4..24ef733d 100644 --- a/website/quick-start.html +++ b/website/quick-start.html @@ -7,7 +7,7 @@ - + @@ -16,7 +16,7 @@ You may need to specify a custom address using the --addr flag. Here are the supported formats:

  • unix:///path/to/buildkit.sock - Connect to buildkit over unix socket.
  • tcp://$BUILDKIT_ADDR:$PORT - Connec to buildkit over TCP. (not recommended for security reasons)
  • docker://<docker connection spec> - Connect to docker, currently only unix sockets are supported, e.g. docker://unix:///var/run/docker.sock (or just docker://).
  • docker-container://my-buildkit-container - Connect to a buildkitd running in a docker container.
  • buildx://my-builder - Connect to a buildx builder (or buildx:// for the currently selected builder). Note: only container-backed buildx instances are currently supported
  • nerdctl-container://my-container-name - Similar to docker-container but uses nerdctl.
  • podman-container://my-container-name - Similar to docker-container but uses podman.
  • ssh://myhost - Connect to a buildkit instance over SSH. Format of the host spec should mimic the SSH command.
  • kubepod://mypod - Connect to buildkit running in a Kubernetes pod. Can also specify kubectl context and pod namespace (kubepod://mypod?context=foo&namespace=notdefault).

Buildkit Connection Examples

Example: Connect using defaults:

copa patch -i mcr.microsoft.com/oss/nginx/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched

Example: Connect to buildx

docker buildx create --name demo
copa patch -i mcr.microsoft.com/oss/nginx/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr buildx://demo

Example: Buildkit in a container

export BUILDKIT_VERSION=v0.12.0
docker run \
--detach \
--rm \
--privileged \
--name buildkitd \
--entrypoint buildkitd \
"moby/buildkit:$BUILDKIT_VERSION"

copa patch -i mcr.microsoft.com/oss/nginx/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched --addr docker-container://buildkitd

Example: Buildkit over TCP

export BUILDKIT_VERSION=v0.12.0
export BUILDKIT_PORT=8888
docker run \
--detach \
--rm \
--privileged \
-p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \
--name buildkitd \
--entrypoint buildkitd \
"moby/buildkit:$BUILDKIT_VERSION" \
--addr tcp://0.0.0.0:$BUILDKIT_PORT
copa patch \
-i mcr.microsoft.com/oss/nginx/nginx:1.21.6 \
-r nginx.1.21.6.json \
-t 1.21.6-patched \
-a tcp://0.0.0.0:$BUILDKIT_PORT

In either case, copa is non-destructive and exports a new image with the specified 1.21.6-patched label to the local Docker daemon.

NOTE: if you're running this sample against an image from a private registry instead, ensure that the credentials are configured in the default Docker config.json before running copa patch, for example, via sudo docker login -u <user> -p <password> <registry>.

  • Scan the patched image and verify that the vulnerabilities have been patched:

    trivy image --vuln-type os --ignore-unfixed mcr.microsoft.com/oss/nginx/nginx:1.21.6-patched

    You can also inspect the structure of the patched image with docker history to see the new patch layer appended to the image:

    $ docker history mcr.microsoft.com/oss/nginx/nginx:1.21.6-patched
    IMAGE CREATED CREATED BY SIZE COMMENT
    a372df41e06d 1 minute ago mount / from exec sh -c apt install --no-ins… 26.1MB buildkit.exporter.image.v0
    <missing> 3 months ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
    <missing> 3 months ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0
    <missing> 3 months ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
    <missing> 3 months ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
    <missing> 3 months ago COPY 30-tune-worker-processes.sh /docker-ent… 4.61kB buildkit.dockerfile.v0
    <missing> 3 months ago COPY 20-envsubst-on-templates.sh /docker-ent… 1.04kB buildkit.dockerfile.v0
    <missing> 3 months ago COPY 10-listen-on-ipv6-by-default.sh /docker… 1.96kB buildkit.dockerfile.v0
    <missing> 3 months ago COPY docker-entrypoint.sh / # buildkit 1.2kB buildkit.dockerfile.v0
    <missing> 3 months ago RUN /bin/sh -c set -x && addgroup --syst… 61.1MB buildkit.dockerfile.v0
    <missing> 3 months ago ENV PKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0
    <missing> 3 months ago ENV NJS_VERSION=0.7.0 0B buildkit.dockerfile.v0
    <missing> 3 months ago ENV NGINX_VERSION=1.20.2 0B buildkit.dockerfile.v0
    <missing> 3 months ago LABEL maintainer=NGINX Docker Maintainers <d… 0B buildkit.dockerfile.v0
    <missing> 4 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
    <missing> 4 months ago /bin/sh -c #(nop) ADD file:09675d11695f65c55… 80.4MB
  • Run the container to verify that the image has no regressions:

    $ docker run -it --rm --name nginx-test mcr.microsoft.com/oss/nginx/nginx:1.21.6-patched
    /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
    /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
    10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
    10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
    /docker-entrypoint.sh: Configuration complete; ready for start up
    2022/05/16 18:00:17 [notice] 1#1: using the "epoll" event method
    2022/05/16 18:00:17 [notice] 1#1: nginx/1.20.2
    2022/05/16 18:00:17 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
    2022/05/16 18:00:17 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2
    2022/05/16 18:00:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
    2022/05/16 18:00:17 [notice] 1#1: start worker processes
    2022/05/16 18:00:17 [notice] 1#1: start worker process 31
    2022/05/16 18:00:17 [notice] 1#1: start worker process 32
    2022/05/16 18:00:17 [notice] 1#1: start worker process 33
    2022/05/16 18:00:17 [notice] 1#1: start worker process 34
    2022/05/16 18:00:17 [notice] 1#1: start worker process 35
    2022/05/16 18:00:17 [notice] 1#1: start worker process 36
    2022/05/16 18:00:17 [notice] 1#1: start worker process 37
    2022/05/16 18:00:17 [notice] 1#1: start worker process 38
    2022/05/16 18:00:17 [notice] 38#38: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 36#36: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 33#33: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 32#32: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 34#34: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 35#35: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 37#37: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 1#1: signal 28 (SIGWINCH) received
    2022/05/16 18:00:17 [notice] 31#31: signal 28 (SIGWINCH) received

    You can stop the container by opening a new shell instance and running: docker stop nginx-test

  • - + \ No newline at end of file diff --git a/website/troubleshooting.html b/website/troubleshooting.html index eea70a50..1a3d988a 100644 --- a/website/troubleshooting.html +++ b/website/troubleshooting.html @@ -7,13 +7,13 @@ - +
    Version: v0.4.x

    Troubleshooting

    Filtering Vulnerabilities

    You might want to filter/ignore some of the vulnerabilities while patching. To do so, you need to first filter those undesired vulnerabilities from your scanner output.

    For Trivy, vulnerabilities can be filtered by the following 2 ways:

    Rego Policy

    An example rego file which demonstrates how to ignore certain Vulnerability IDs or Package Names:

    $ cat trivy_ignore.rego

    package trivy

    import data.lib.trivy

    default ignore = false


    # Ignore the following Vulnerability IDs
    ignore_vulnerability_ids := {
    "CVE-2018-14618"
    }
    # Ignore the following Package Names
    ignore_pkgs := {"bash", "vim"}


    # For ignoring vulnID
    ignore {
    input.VulnerabilityID == ignore_vulnerability_ids[_]
    }
    # For ignoring pkgName
    ignore {
    input.PkgName == ignore_pkgs[_]
    }

    After adding the above rego file, run the image scan with the --ignore-policy flag followed by the file name to ignore them while scanning:

    trivy image --ignore-policy trivy_ignore.rego ruby:2.4.0

    In the above example, the vulnerability "CVE-2018-14618" and the packages "bash" & "vim" are ignored while scanning, and hence patching the image.

    Ignore File

    Use a .trivyignore file to list all the vulnerabilities you want to ignore.

    Example:

    $ cat .trivyignore

    # Accept the risk
    CVE-2018-14618

    In the above example, the vulnerability CVE-2018-14618 is ignored while scanning, and hence while patching the image.

    For a more detailed explanation on how to ignore certain vulnerabilities with Trivy, please refer to the official documentation here.

    - + \ No newline at end of file diff --git a/website/v0.1.x.html b/website/v0.1.x.html index b88f91d0..97bb1666 100644 --- a/website/v0.1.x.html +++ b/website/v0.1.x.html @@ -7,13 +7,13 @@ - +
    Version: v0.1.x

    Project Copacetic: Directly patch container image vulnerabilities

    copa is a CLI tool written in Go and based on buildkit that can be used to directly patch container images given the vulnerability scanning results from popular tools like Trivy.

    Why?

    We needed the ability to patch containers quickly without going upstream for a full rebuild. As the window between vulnerability disclosure and active exploitation continues to narrow, there is a growing operational need to patch critical security vulnerabilities in container images so they can be quickly redeployed into production. The need is especially acute when those vulnerabilities are:

    • inherited from base images several levels deep and waiting on updated releases to percolate through the supply chain is not an option
    • found in 3rd party app images you don't maintain with update cadences that don't meet your security SLAs.

    In addition to filling the operational gap not met by left-shift security practices and tools, the ability of copa to patch a container without requiring a rebuild of the container image provides other benefits:

    • Allows users other than the image publishers to also patch container images, such as DevSecOps engineers.
    • Reduces the storage and transmission costs of redistributing patched images by only creating an additional patch layer, instead of rebuilding the entire image which usually results in different layer hashes that break layer caching.
    • Reduces the turnaround time for patching a container image by not having to wait for base image updates and being a faster operation than a full image rebuild.
    • Reduces the complexity of patching the image from running a rebuild pipeline to running a single tool on the image.

    How?

    The copa tool is an extensible engine that:

    1. Parses the needed update packages from the container image’s vulnerability report produced by a scanner like Trivy. New adapters can be written to accommodate more report formats.
    2. Obtains and processes the needed update packages using the appropriate package manager tools such as apt, apk, etc. New adapters can be written to support more package managers.
    3. Applies the resulting update binaries to the container image using buildkit.

    This approach is motivated by the core principles of making direct container patching broadly applicable and accessible:

    • Copa supports patching existing container images.
      • Devs don't need to build their images using specific tools or modify them in some way just to support container patching.
    • Copa works with the existing vulnerability scanning and mitigation ecosystems.
      • Image publishers don't need to create new workflows for container patching since Copa supports patching container images using the security update packages already being published today.
      • Consumers do not need to migrate to a new and potentially more limited support ecosystem for custom distros or change their container vulnerability scanning pipelines to include remediation, since Copa can be integrated seamlessly as an extra step to patch containers based on those scanning reports.
    • Copa reduces the technical expertise needed and waiting on dependencies needed to patch an image.
      • For OS package vulnerabilities, no specialized knowledge about a specific image is needed to be patch it as Copa relies on the vulnerability remediation knowledge already embedded in the reports produced by popular container scanning tools today.

    For more details, refer to the copa design documentation.

    - + \ No newline at end of file diff --git a/website/v0.1.x/code-of-conduct.html b/website/v0.1.x/code-of-conduct.html index d7c72ffd..1224a577 100644 --- a/website/v0.1.x/code-of-conduct.html +++ b/website/v0.1.x/code-of-conduct.html @@ -7,7 +7,7 @@ - + @@ -62,7 +62,7 @@ Mozilla's code of conduct enforcement ladder.

    For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.

    - + \ No newline at end of file diff --git a/website/v0.1.x/contributing.html b/website/v0.1.x/contributing.html index 3904cea1..8900eccd 100644 --- a/website/v0.1.x/contributing.html +++ b/website/v0.1.x/contributing.html @@ -7,7 +7,7 @@ - + @@ -27,7 +27,7 @@ personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.

    Contributors sign-off that they adhere to these requirements by adding a Signed-off-by line to commit messages.

    This is my commit message

    Signed-off-by: Random J Developer <random@developer.example.org>

    Git even has a -s command line option to append this automatically to your commit message:

    git commit -s -m 'This is my commit message'

    Pull requests that do not contain a valid Signed-off-by line cannot be merged.

    I didn't sign my commit, now what?

    No worries - You can easily amend your commit with a sign-off and force push the change to your submitting branch:

    git switch <branch-name>
    git commit --amend --no-edit --signoff
    git push --force-with-lease <remote-name> <branch-name>

    Code of Conduct

    This project has adopted the Contributor Covenant Code of Conduct.

    - + \ No newline at end of file diff --git a/website/v0.1.x/design.html b/website/v0.1.x/design.html index 1198c9b6..55198e65 100644 --- a/website/v0.1.x/design.html +++ b/website/v0.1.x/design.html @@ -7,13 +7,13 @@ - +
    Version: v0.1.x

    Design

    Design Tenets

    • Copa is intended to accelerate container patching by eliminating waiting on base image dependency chains to update. This is a raison d’etre for the Copa project, so if we figured out a different way to patch containers that still relied on waiting for base images to be rebuilt and republished, we would consider spinning that off into a different project instead of making it part of Copa.

    • Copa is intended to work with the existing ecosystem of container images. The project should have a strong preference for solutions that do not require image producers to create or modify their images in special ways to use Copa.

    • Copa is intended to allow parties other than the image authors to address container vulnerabilities. Copa should require a minimum of special knowledge about the lineage and construction of an image from the user to patch it successfully.

    • Copa is intended to do one thing well and be composable with other tools and processes. Copa does not have to be a universal multitool for container patching. For example, it is preferable that it integrates with popular container scanning tools rather than incorporating custom container scanning into the project itself. Similarly, it does not need to become a general container manipulation tool in the vein of crane.

    Design Reasoning

    The design of copa arises from the application of those tenets to the observed issues in previous efforts directly update container images via rebasing, for example, the experimental crane rebase:

    • Rebasing requires that all actors involved in creation of the image are coordinated so that some layers can be switched out without breaking the image. Attempting to switch out layers in the container overlay structure is brittle because most existing containers are created by writing over shared configuration files and data stores in base images. For example, an apt install during image creation will overwrite the dpkg status file in the base image, which will mask any package updates in a rebased layer. Since many existing container scanners rely on the reported package status to find vulnerable package versions, this can cause new vulnerabilities to not be reported or for patched binaries not to be recognized by the scanners.

      To avoid breaking integration with the existing container ecosystem, copa patches the filesystem bundle as a whole instead of as a collection of layers so that the resulting image state is consistent. This strategy also allows copa to patch vulnerabilties introduced at any layer in the image, including OS packages added in the app layers that is not addressed by a simple rebase. It also supports the core tenet of supporting patching without requiring coordination with all the publishers of the base images that a given image transitively depends on.

    • Rebasing also requires that the user knows a priori what base image (or transitive base image) is in the target image to determine which appropriate rebase image to use. This makes it very difficult for anyone not intimately involved with authoring the image from being able to remediate it, which is one of our tenets.

      While it is possible to embed extra metadata or annotations into the target image to facilitate this base image (or transitive base image) lookup, that would require that the images to be patched be modified or created especially to support updates, which goes against another of our tenets to be able to patch images without requiring them to be customized explicitly for that purpose.

      The design of copa addresses this by reframing the problem of updating containers and understanding the structure or lineage of a container image to the more specific problem of what packages in a given container image need to be updated. This allows copa to tap into the expertise embedded in the much more robust ecosystem for detecting and remediating vulnerabilities at the package level that already exists today. By making copa an additional remediation step that can be run after a container scan in existing workflows, we avoid both of those issues with an additional benefit: it incurs no additional work on the part of base image publishers to support patching of images based on their base images, the existing channels for publishing update packages is sufficient to service those container images as well.

    Architecture

    The requirements presented encourage an extensible model in order to support broad applicability. Specifically, there are two areas that the tool will need to accommodate multiple implementations to support more use cases:

    • The data schema of various vulnerability scanners producing the input vulnerability report.
    • The state management of various package managers and process for applying patches appropriately through them.

    Effectively, copa patch can be considered a command that bridges an extensible Parse action with an extensible Apply action as illustrated in the diagram; the implementation can be thought of as an engine that uses this abstract Go interface to apply security update packages:

    type UpdatePackage struct {
    Name string
    Version string
    }

    type UpdateManifest struct {
    OSType string
    OSVersion string
    Arch string
    Updates []UpdatePackage
    }

    type ScanReportParser interface {
    Parse(reportPath string) (*UpdateManifest, error)
    }

    type PackageManager interface {
    Apply(imagePath string, report *UpdateManifest) error
    }

    Implementation

    copa is a pseudo-frontend to buildkit implemented as a CLI tool. Effectively, instead of taking a container definition to create from scratch, it takes the reference to the target image to patch and a container scan report and builds a series of LLB graphs for buildkit to execute:

    1. Actions to probe the image as a filesystem bundle, for example, retrieving the package manager status in the image.
      • Within each distribution type identified by the scanner report (e.g. Debian) there can be different ways of applying patches to the target image (e.g. distroless), which can be differentiated through these actions.
    2. Actions to fetch and deploy tools that can be injected into the target image to perform the patching.
      • In cases where the package tools are not available in the target image, a standard version of the OS container matching the target image's is used to stage the necessary tooling for patches.
      • In the case of distroless images for example, where there is no valid package status file in the target image, the tooling container is also used to pull down and process the necessary package updates for copy to the target image.
      • Although not pictured, this can also be used to obtain tools (e.g. busybox) to be used in the image probing stage as well.
    3. Actions to deploy the required patch packages to the target image.
      • copa integrates with buildkit at the API level because it uses the diff and merge graph operations directly so that it can stage all the necessary tooling in the target image while producing a resulting image that only contains the original image plus a new layer with all the deployed patches.

    Tradeoffs

    • The core architectural choice of relying on packages as the unit of patching creates a couple of constraints:
      • By relying on existing vulnerability scanner behavior that only detects vulnerabilities via presence/absence of vulnerable packages, copa is limited in the kinds of vulnerabilities it can address and false positive/negatives from scanners flow downstream to copa.
      • copa depends on individual package manager adapters to correctly deploy patches to the target images, but there is a long tail of compatibility issues that arise depending on the target image itself (e.g. outdated package manager config/keys, invalid/missing package graph, etc.). Overall, the maintenance cost of the project is expected to be non-trivial to address this.
    • No support for windows containers given the dependency on buildkit.
    - + \ No newline at end of file diff --git a/website/v0.1.x/faq.html b/website/v0.1.x/faq.html index 7d2c44ca..f496645a 100644 --- a/website/v0.1.x/faq.html +++ b/website/v0.1.x/faq.html @@ -7,13 +7,13 @@ - +
    Version: v0.1.x

    FAQ

    What kind of vulnerabilities can Copa patch?

    Copa is capable of patching "OS level" vulnerabilities. This includes packages (like openssl) in the image that are managed by a package manager such as apt or yum. Copa is not currently capable of patching vulnerabilities at the "application level" such as Python packages or Go modules.

    - + \ No newline at end of file diff --git a/website/v0.1.x/installation.html b/website/v0.1.x/installation.html index 8e8b7da2..fa1238a1 100644 --- a/website/v0.1.x/installation.html +++ b/website/v0.1.x/installation.html @@ -7,13 +7,13 @@ - +
    Version: v0.1.x

    Installation

    Homebrew

    On macOS and Linux, copa can be installed via Homebrew:

    brew install copa

    GitHub

    You can download the latest and previous versions of copa from the GitHub releases page.

    Development Setup

    The following instructions are for Ubuntu 22.04 with the dependency versions supported as part of the dev container environment we use for builds and tests. For other distributions and OS, refer to the appropriate installation instructions for each of the components instead.

    git clone https://github.com/project-copacetic/copacetic
    cd copacetic
    make
    # OPTIONAL: install copa to a pathed folder
    sudo mv dist/linux_amd64/release/copa /usr/local/bin/
    - + \ No newline at end of file diff --git a/website/v0.1.x/quick-start.html b/website/v0.1.x/quick-start.html index 681bfa5a..6e02ba2d 100644 --- a/website/v0.1.x/quick-start.html +++ b/website/v0.1.x/quick-start.html @@ -7,7 +7,7 @@ - + @@ -15,7 +15,7 @@
    Version: v0.1.x

    Quick Start

    This sample illustrates how to patch containers using vulnerability reports with copa.

    Prerequisites

    Sample Steps

    1. Scan the container image for patchable OS vulnerabilities, outputting the results to a JSON file:

      trivy image --vuln-type os --ignore-unfixed -f json -o nginx.1.21.6.json docker.io/library/nginx:1.21.6

      You can also see the existing patchable vulnerabilities in table form on the shell with:

      trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6

    2. Patch the image using the Trivy report. You will need to start buildkitd if it is not already running:

      sudo buildkitd &
      sudo copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched

      Alternatively, you can run buildkitd in a container, which allows copa to be run without root access to the local buildkit socket:

      export BUILDKIT_VERSION=v0.11.4
      export BUILDKIT_PORT=8888
      docker run \
      --detach \
      --rm \
      --privileged \
      -p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \
      --name buildkitd \
      --entrypoint buildkitd \
      "moby/buildkit:$BUILDKIT_VERSION" \
      --addr tcp://0.0.0.0:$BUILDKIT_PORT
      copa patch \
      -i docker.io/library/nginx:1.21.6 \
      -r nginx.1.21.6.json \
      -t 1.21.6-patched \
      -a tcp://0.0.0.0:$BUILDKIT_PORT

      In either case, copa is non-destructive and exports a new image with the specified 1.21.6-patched label to the local Docker daemon.

      NOTE: if you're running this sample against an image from a private registry instead, ensure that the credentials are configured in the default Docker config.json before running copa patch, for example, via sudo docker login -u <user> -p <password> <registry>.

    3. Scan the patched image and verify that the vulnerabilities have been patched:

      trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6-patched

      You can also inspect the structure of the patched image with docker history to see the new patch layer appended to the image:

      $ docker history docker.io/library/nginx:1.21.6-patched
      IMAGE CREATED CREATED BY SIZE COMMENT
      a372df41e06d 1 minute ago mount / from exec sh -c apt install --no-ins… 26.1MB buildkit.exporter.image.v0
      <missing> 3 months ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
      <missing> 3 months ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0
      <missing> 3 months ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
      <missing> 3 months ago COPY 30-tune-worker-processes.sh /docker-ent… 4.61kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY 20-envsubst-on-templates.sh /docker-ent… 1.04kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY 10-listen-on-ipv6-by-default.sh /docker… 1.96kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY docker-entrypoint.sh / # buildkit 1.2kB buildkit.dockerfile.v0
      <missing> 3 months ago RUN /bin/sh -c set -x && addgroup --syst… 61.1MB buildkit.dockerfile.v0
      <missing> 3 months ago ENV PKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENV NJS_VERSION=0.7.0 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENV NGINX_VERSION=1.20.2 0B buildkit.dockerfile.v0
      <missing> 3 months ago LABEL maintainer=NGINX Docker Maintainers <d… 0B buildkit.dockerfile.v0
      <missing> 4 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
      <missing> 4 months ago /bin/sh -c #(nop) ADD file:09675d11695f65c55… 80.4MB
    4. Run the container to verify that the image has no regressions:

      $ docker run -it --rm --name nginx-test docker.io/library/nginx:1.21.6-patched
      /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
      /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
      10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
      10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
      /docker-entrypoint.sh: Configuration complete; ready for start up
      2022/05/16 18:00:17 [notice] 1#1: using the "epoll" event method
      2022/05/16 18:00:17 [notice] 1#1: nginx/1.20.2
      2022/05/16 18:00:17 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
      2022/05/16 18:00:17 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2
      2022/05/16 18:00:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
      2022/05/16 18:00:17 [notice] 1#1: start worker processes
      2022/05/16 18:00:17 [notice] 1#1: start worker process 31
      2022/05/16 18:00:17 [notice] 1#1: start worker process 32
      2022/05/16 18:00:17 [notice] 1#1: start worker process 33
      2022/05/16 18:00:17 [notice] 1#1: start worker process 34
      2022/05/16 18:00:17 [notice] 1#1: start worker process 35
      2022/05/16 18:00:17 [notice] 1#1: start worker process 36
      2022/05/16 18:00:17 [notice] 1#1: start worker process 37
      2022/05/16 18:00:17 [notice] 1#1: start worker process 38
      2022/05/16 18:00:17 [notice] 38#38: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 36#36: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 33#33: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 32#32: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 34#34: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 35#35: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 37#37: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 1#1: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 31#31: signal 28 (SIGWINCH) received

      You can stop the container by opening a new shell instance and running: docker stop nginx-test

    - + \ No newline at end of file diff --git a/website/v0.2.x.html b/website/v0.2.x.html index 3b424031..fdd5f123 100644 --- a/website/v0.2.x.html +++ b/website/v0.2.x.html @@ -7,13 +7,13 @@ - +
    Version: v0.2.x

    Project Copacetic: Directly patch container image vulnerabilities

    copa is a CLI tool written in Go and based on buildkit that can be used to directly patch container images given the vulnerability scanning results from popular tools like Trivy.

    Why?

    We needed the ability to patch containers quickly without going upstream for a full rebuild. As the window between vulnerability disclosure and active exploitation continues to narrow, there is a growing operational need to patch critical security vulnerabilities in container images so they can be quickly redeployed into production. The need is especially acute when those vulnerabilities are:

    • inherited from base images several levels deep and waiting on updated releases to percolate through the supply chain is not an option
    • found in 3rd party app images you don't maintain with update cadences that don't meet your security SLAs.

    In addition to filling the operational gap not met by left-shift security practices and tools, the ability of copa to patch a container without requiring a rebuild of the container image provides other benefits:

    • Allows users other than the image publishers to also patch container images, such as DevSecOps engineers.
    • Reduces the storage and transmission costs of redistributing patched images by only creating an additional patch layer, instead of rebuilding the entire image which usually results in different layer hashes that break layer caching.
    • Reduces the turnaround time for patching a container image by not having to wait for base image updates and being a faster operation than a full image rebuild.
    • Reduces the complexity of patching the image from running a rebuild pipeline to running a single tool on the image.

    How?

    The copa tool is an extensible engine that:

    1. Parses the needed update packages from the container image’s vulnerability report produced by a scanner like Trivy. New adapters can be written to accommodate more report formats.
    2. Obtains and processes the needed update packages using the appropriate package manager tools such as apt, apk, etc. New adapters can be written to support more package managers.
    3. Applies the resulting update binaries to the container image using buildkit.

    This approach is motivated by the core principles of making direct container patching broadly applicable and accessible:

    • Copa supports patching existing container images.
      • Devs don't need to build their images using specific tools or modify them in some way just to support container patching.
    • Copa works with the existing vulnerability scanning and mitigation ecosystems.
      • Image publishers don't need to create new workflows for container patching since Copa supports patching container images using the security update packages already being published today.
      • Consumers do not need to migrate to a new and potentially more limited support ecosystem for custom distros or change their container vulnerability scanning pipelines to include remediation, since Copa can be integrated seamlessly as an extra step to patch containers based on those scanning reports.
    • Copa reduces the technical expertise needed and waiting on dependencies needed to patch an image.
      • For OS package vulnerabilities, no specialized knowledge about a specific image is needed to be patch it as Copa relies on the vulnerability remediation knowledge already embedded in the reports produced by popular container scanning tools today.

    For more details, refer to the copa design documentation.

    - + \ No newline at end of file diff --git a/website/v0.2.x/code-of-conduct.html b/website/v0.2.x/code-of-conduct.html index 9eb91aba..1838ab4d 100644 --- a/website/v0.2.x/code-of-conduct.html +++ b/website/v0.2.x/code-of-conduct.html @@ -7,7 +7,7 @@ - + @@ -62,7 +62,7 @@ Mozilla's code of conduct enforcement ladder.

    For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.

    - + \ No newline at end of file diff --git a/website/v0.2.x/contributing.html b/website/v0.2.x/contributing.html index 463e10a4..e6a937a6 100644 --- a/website/v0.2.x/contributing.html +++ b/website/v0.2.x/contributing.html @@ -7,7 +7,7 @@ - + @@ -27,7 +27,7 @@ personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.

    Contributors sign-off that they adhere to these requirements by adding a Signed-off-by line to commit messages.

    This is my commit message

    Signed-off-by: Random J Developer <random@developer.example.org>

    Git even has a -s command line option to append this automatically to your commit message:

    git commit -s -m 'This is my commit message'

    Pull requests that do not contain a valid Signed-off-by line cannot be merged.

    I didn't sign my commit, now what?

    No worries - You can easily amend your commit with a sign-off and force push the change to your submitting branch:

    git switch <branch-name>
    git commit --amend --no-edit --signoff
    git push --force-with-lease <remote-name> <branch-name>

    Code of Conduct

    This project has adopted the Contributor Covenant Code of Conduct.

    - + \ No newline at end of file diff --git a/website/v0.2.x/design.html b/website/v0.2.x/design.html index dc874573..71d5bdb4 100644 --- a/website/v0.2.x/design.html +++ b/website/v0.2.x/design.html @@ -7,13 +7,13 @@ - +
    Version: v0.2.x

    Design

    Design Tenets

    • Copa is intended to accelerate container patching by eliminating waiting on base image dependency chains to update. This is a raison d’etre for the Copa project, so if we figured out a different way to patch containers that still relied on waiting for base images to be rebuilt and republished, we would consider spinning that off into a different project instead of making it part of Copa.

    • Copa is intended to work with the existing ecosystem of container images. The project should have a strong preference for solutions that do not require image producers to create or modify their images in special ways to use Copa.

    • Copa is intended to allow parties other than the image authors to address container vulnerabilities. Copa should require a minimum of special knowledge about the lineage and construction of an image from the user to patch it successfully.

    • Copa is intended to do one thing well and be composable with other tools and processes. Copa does not have to be a universal multitool for container patching. For example, it is preferable that it integrates with popular container scanning tools rather than incorporating custom container scanning into the project itself. Similarly, it does not need to become a general container manipulation tool in the vein of crane.

    Design Reasoning

    The design of copa arises from the application of those tenets to the observed issues in previous efforts directly update container images via rebasing, for example, the experimental crane rebase:

    • Rebasing requires that all actors involved in creation of the image are coordinated so that some layers can be switched out without breaking the image. Attempting to switch out layers in the container overlay structure is brittle because most existing containers are created by writing over shared configuration files and data stores in base images. For example, an apt install during image creation will overwrite the dpkg status file in the base image, which will mask any package updates in a rebased layer. Since many existing container scanners rely on the reported package status to find vulnerable package versions, this can cause new vulnerabilities to not be reported or for patched binaries not to be recognized by the scanners.

      To avoid breaking integration with the existing container ecosystem, copa patches the filesystem bundle as a whole instead of as a collection of layers so that the resulting image state is consistent. This strategy also allows copa to patch vulnerabilties introduced at any layer in the image, including OS packages added in the app layers that is not addressed by a simple rebase. It also supports the core tenet of supporting patching without requiring coordination with all the publishers of the base images that a given image transitively depends on.

    • Rebasing also requires that the user knows a priori what base image (or transitive base image) is in the target image to determine which appropriate rebase image to use. This makes it very difficult for anyone not intimately involved with authoring the image from being able to remediate it, which is one of our tenets.

      While it is possible to embed extra metadata or annotations into the target image to facilitate this base image (or transitive base image) lookup, that would require that the images to be patched be modified or created especially to support updates, which goes against another of our tenets to be able to patch images without requiring them to be customized explicitly for that purpose.

      The design of copa addresses this by reframing the problem of updating containers and understanding the structure or lineage of a container image to the more specific problem of what packages in a given container image need to be updated. This allows copa to tap into the expertise embedded in the much more robust ecosystem for detecting and remediating vulnerabilities at the package level that already exists today. By making copa an additional remediation step that can be run after a container scan in existing workflows, we avoid both of those issues with an additional benefit: it incurs no additional work on the part of base image publishers to support patching of images based on their base images, the existing channels for publishing update packages is sufficient to service those container images as well.

    Architecture

    The requirements presented encourage an extensible model in order to support broad applicability. Specifically, there are two areas that the tool will need to accommodate multiple implementations to support more use cases:

    • The data schema of various vulnerability scanners producing the input vulnerability report.
    • The state management of various package managers and process for applying patches appropriately through them.

    Effectively, copa patch can be considered a command that bridges an extensible Parse action with an extensible Apply action as illustrated in the diagram; the implementation can be thought of as an engine that uses this abstract Go interface to apply security update packages:

    type UpdatePackage struct {
    Name string
    Version string
    }

    type UpdateManifest struct {
    OSType string
    OSVersion string
    Arch string
    Updates []UpdatePackage
    }

    type ScanReportParser interface {
    Parse(reportPath string) (*UpdateManifest, error)
    }

    type PackageManager interface {
    Apply(imagePath string, report *UpdateManifest) error
    }

    Implementation

    copa is a pseudo-frontend to buildkit implemented as a CLI tool. Effectively, instead of taking a container definition to create from scratch, it takes the reference to the target image to patch and a container scan report and builds a series of LLB graphs for buildkit to execute:

    1. Actions to probe the image as a filesystem bundle, for example, retrieving the package manager status in the image.
      • Within each distribution type identified by the scanner report (e.g. Debian) there can be different ways of applying patches to the target image (e.g. distroless), which can be differentiated through these actions.
    2. Actions to fetch and deploy tools that can be injected into the target image to perform the patching.
      • In cases where the package tools are not available in the target image, a standard version of the OS container matching the target image's is used to stage the necessary tooling for patches.
      • In the case of distroless images for example, where there is no valid package status file in the target image, the tooling container is also used to pull down and process the necessary package updates for copy to the target image.
      • Although not pictured, this can also be used to obtain tools (e.g. busybox) to be used in the image probing stage as well.
    3. Actions to deploy the required patch packages to the target image.
      • copa integrates with buildkit at the API level because it uses the diff and merge graph operations directly so that it can stage all the necessary tooling in the target image while producing a resulting image that only contains the original image plus a new layer with all the deployed patches.

    Tradeoffs

    • The core architectural choice of relying on packages as the unit of patching creates a couple of constraints:
      • By relying on existing vulnerability scanner behavior that only detects vulnerabilities via presence/absence of vulnerable packages, copa is limited in the kinds of vulnerabilities it can address and false positive/negatives from scanners flow downstream to copa.
      • copa depends on individual package manager adapters to correctly deploy patches to the target images, but there is a long tail of compatibility issues that arise depending on the target image itself (e.g. outdated package manager config/keys, invalid/missing package graph, etc.). Overall, the maintenance cost of the project is expected to be non-trivial to address this.
    • No support for windows containers given the dependency on buildkit.
    - + \ No newline at end of file diff --git a/website/v0.2.x/faq.html b/website/v0.2.x/faq.html index 0f62c6cc..c1e66708 100644 --- a/website/v0.2.x/faq.html +++ b/website/v0.2.x/faq.html @@ -7,13 +7,13 @@ - +
    Version: v0.2.x

    FAQ

    What kind of vulnerabilities can Copa patch?

    Copa is capable of patching "OS level" vulnerabilities. This includes packages (like openssl) in the image that are managed by a package manager such as apt or yum. Copa is not currently capable of patching vulnerabilities at the "application level" such as Python packages or Go modules.

    - + \ No newline at end of file diff --git a/website/v0.2.x/installation.html b/website/v0.2.x/installation.html index 0c8f639d..7a273fb3 100644 --- a/website/v0.2.x/installation.html +++ b/website/v0.2.x/installation.html @@ -7,13 +7,13 @@ - +
    Version: v0.2.x

    Installation

    Homebrew

    On macOS and Linux, copa can be installed via Homebrew:

    brew install copa

    GitHub

    You can download the latest and previous versions of copa from the GitHub releases page.

    Development Setup

    The following instructions are for Ubuntu 22.04 with the dependency versions supported as part of the dev container environment we use for builds and tests. For other distributions and OS, refer to the appropriate installation instructions for each of the components instead.

    git clone https://github.com/project-copacetic/copacetic
    cd copacetic
    make
    # OPTIONAL: install copa to a pathed folder
    sudo mv dist/linux_amd64/release/copa /usr/local/bin/
    - + \ No newline at end of file diff --git a/website/v0.2.x/quick-start.html b/website/v0.2.x/quick-start.html index ae040ddb..1d578942 100644 --- a/website/v0.2.x/quick-start.html +++ b/website/v0.2.x/quick-start.html @@ -7,7 +7,7 @@ - + @@ -15,7 +15,7 @@
    Version: v0.2.x

    Quick Start

    This sample illustrates how to patch containers using vulnerability reports with copa.

    Prerequisites

    Sample Steps

    1. Scan the container image for patchable OS vulnerabilities, outputting the results to a JSON file:

      trivy image --vuln-type os --ignore-unfixed -f json -o nginx.1.21.6.json docker.io/library/nginx:1.21.6

      You can also see the existing patchable vulnerabilities in table form on the shell with:

      trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6

    2. Patch the image using the Trivy report. You will need to start buildkitd if it is not already running:

      sudo buildkitd &
      sudo copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched

      Alternatively, you can run buildkitd in a container, which allows copa to be run without root access to the local buildkit socket:

      export BUILDKIT_VERSION=v0.11.4
      export BUILDKIT_PORT=8888
      docker run \
      --detach \
      --rm \
      --privileged \
      -p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \
      --name buildkitd \
      --entrypoint buildkitd \
      "moby/buildkit:$BUILDKIT_VERSION" \
      --addr tcp://0.0.0.0:$BUILDKIT_PORT
      copa patch \
      -i docker.io/library/nginx:1.21.6 \
      -r nginx.1.21.6.json \
      -t 1.21.6-patched \
      -a tcp://0.0.0.0:$BUILDKIT_PORT

      In either case, copa is non-destructive and exports a new image with the specified 1.21.6-patched label to the local Docker daemon.

      NOTE: if you're running this sample against an image from a private registry instead, ensure that the credentials are configured in the default Docker config.json before running copa patch, for example, via sudo docker login -u <user> -p <password> <registry>.

    3. Scan the patched image and verify that the vulnerabilities have been patched:

      trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6-patched

      You can also inspect the structure of the patched image with docker history to see the new patch layer appended to the image:

      $ docker history docker.io/library/nginx:1.21.6-patched
      IMAGE CREATED CREATED BY SIZE COMMENT
      a372df41e06d 1 minute ago mount / from exec sh -c apt install --no-ins… 26.1MB buildkit.exporter.image.v0
      <missing> 3 months ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
      <missing> 3 months ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0
      <missing> 3 months ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
      <missing> 3 months ago COPY 30-tune-worker-processes.sh /docker-ent… 4.61kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY 20-envsubst-on-templates.sh /docker-ent… 1.04kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY 10-listen-on-ipv6-by-default.sh /docker… 1.96kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY docker-entrypoint.sh / # buildkit 1.2kB buildkit.dockerfile.v0
      <missing> 3 months ago RUN /bin/sh -c set -x && addgroup --syst… 61.1MB buildkit.dockerfile.v0
      <missing> 3 months ago ENV PKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENV NJS_VERSION=0.7.0 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENV NGINX_VERSION=1.20.2 0B buildkit.dockerfile.v0
      <missing> 3 months ago LABEL maintainer=NGINX Docker Maintainers <d… 0B buildkit.dockerfile.v0
      <missing> 4 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
      <missing> 4 months ago /bin/sh -c #(nop) ADD file:09675d11695f65c55… 80.4MB
    4. Run the container to verify that the image has no regressions:

      $ docker run -it --rm --name nginx-test docker.io/library/nginx:1.21.6-patched
      /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
      /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
      10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
      10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
      /docker-entrypoint.sh: Configuration complete; ready for start up
      2022/05/16 18:00:17 [notice] 1#1: using the "epoll" event method
      2022/05/16 18:00:17 [notice] 1#1: nginx/1.20.2
      2022/05/16 18:00:17 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
      2022/05/16 18:00:17 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2
      2022/05/16 18:00:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
      2022/05/16 18:00:17 [notice] 1#1: start worker processes
      2022/05/16 18:00:17 [notice] 1#1: start worker process 31
      2022/05/16 18:00:17 [notice] 1#1: start worker process 32
      2022/05/16 18:00:17 [notice] 1#1: start worker process 33
      2022/05/16 18:00:17 [notice] 1#1: start worker process 34
      2022/05/16 18:00:17 [notice] 1#1: start worker process 35
      2022/05/16 18:00:17 [notice] 1#1: start worker process 36
      2022/05/16 18:00:17 [notice] 1#1: start worker process 37
      2022/05/16 18:00:17 [notice] 1#1: start worker process 38
      2022/05/16 18:00:17 [notice] 38#38: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 36#36: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 33#33: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 32#32: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 34#34: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 35#35: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 37#37: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 1#1: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 31#31: signal 28 (SIGWINCH) received

      You can stop the container by opening a new shell instance and running: docker stop nginx-test

    - + \ No newline at end of file diff --git a/website/v0.3.x.html b/website/v0.3.x.html index eb66429d..399c7b5c 100644 --- a/website/v0.3.x.html +++ b/website/v0.3.x.html @@ -7,13 +7,13 @@ - +
    Version: v0.3.x

    Project Copacetic: Directly patch container image vulnerabilities

    copa is a CLI tool written in Go and based on buildkit that can be used to directly patch container images given the vulnerability scanning results from popular tools like Trivy.

    Why?

    We needed the ability to patch containers quickly without going upstream for a full rebuild. As the window between vulnerability disclosure and active exploitation continues to narrow, there is a growing operational need to patch critical security vulnerabilities in container images so they can be quickly redeployed into production. The need is especially acute when those vulnerabilities are:

    • inherited from base images several levels deep and waiting on updated releases to percolate through the supply chain is not an option
    • found in 3rd party app images you don't maintain with update cadences that don't meet your security SLAs.

    In addition to filling the operational gap not met by left-shift security practices and tools, the ability of copa to patch a container without requiring a rebuild of the container image provides other benefits:

    • Allows users other than the image publishers to also patch container images, such as DevSecOps engineers.
    • Reduces the storage and transmission costs of redistributing patched images by only creating an additional patch layer, instead of rebuilding the entire image which usually results in different layer hashes that break layer caching.
    • Reduces the turnaround time for patching a container image by not having to wait for base image updates and being a faster operation than a full image rebuild.
    • Reduces the complexity of patching the image from running a rebuild pipeline to running a single tool on the image.

    How?

    The copa tool is an extensible engine that:

    1. Parses the needed update packages from the container image’s vulnerability report produced by a scanner like Trivy. New adapters can be written to accommodate more report formats.
    2. Obtains and processes the needed update packages using the appropriate package manager tools such as apt, apk, etc. New adapters can be written to support more package managers.
    3. Applies the resulting update binaries to the container image using buildkit.

    This approach is motivated by the core principles of making direct container patching broadly applicable and accessible:

    • Copa supports patching existing container images.
      • Devs don't need to build their images using specific tools or modify them in some way just to support container patching.
    • Copa works with the existing vulnerability scanning and mitigation ecosystems.
      • Image publishers don't need to create new workflows for container patching since Copa supports patching container images using the security update packages already being published today.
      • Consumers do not need to migrate to a new and potentially more limited support ecosystem for custom distros or change their container vulnerability scanning pipelines to include remediation, since Copa can be integrated seamlessly as an extra step to patch containers based on those scanning reports.
    • Copa reduces the technical expertise needed and waiting on dependencies needed to patch an image.
      • For OS package vulnerabilities, no specialized knowledge about a specific image is needed to be patch it as Copa relies on the vulnerability remediation knowledge already embedded in the reports produced by popular container scanning tools today.

    For more details, refer to the copa design documentation.

    - + \ No newline at end of file diff --git a/website/v0.3.x/code-of-conduct.html b/website/v0.3.x/code-of-conduct.html index 6eaac5fd..9624461c 100644 --- a/website/v0.3.x/code-of-conduct.html +++ b/website/v0.3.x/code-of-conduct.html @@ -7,7 +7,7 @@ - + @@ -62,7 +62,7 @@ Mozilla's code of conduct enforcement ladder.

    For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.

    - + \ No newline at end of file diff --git a/website/v0.3.x/contributing.html b/website/v0.3.x/contributing.html index cd5439fe..0b412c47 100644 --- a/website/v0.3.x/contributing.html +++ b/website/v0.3.x/contributing.html @@ -7,7 +7,7 @@ - + @@ -27,7 +27,7 @@ personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.

    Contributors sign-off that they adhere to these requirements by adding a Signed-off-by line to commit messages.

    This is my commit message

    Signed-off-by: Random J Developer <random@developer.example.org>

    Git even has a -s command line option to append this automatically to your commit message:

    git commit -s -m 'This is my commit message'

    Pull requests that do not contain a valid Signed-off-by line cannot be merged.

    I didn't sign my commit, now what?

    No worries - You can easily amend your commit with a sign-off and force push the change to your submitting branch:

    git switch <branch-name>
    git commit --amend --no-edit --signoff
    git push --force-with-lease <remote-name> <branch-name>

    Code of Conduct

    This project has adopted the Contributor Covenant Code of Conduct.

    - + \ No newline at end of file diff --git a/website/v0.3.x/design.html b/website/v0.3.x/design.html index b53cc4b9..f7af803c 100644 --- a/website/v0.3.x/design.html +++ b/website/v0.3.x/design.html @@ -7,13 +7,13 @@ - +
    Version: v0.3.x

    Design

    Design Tenets

    • Copa is intended to accelerate container patching by eliminating waiting on base image dependency chains to update. This is a raison d’etre for the Copa project, so if we figured out a different way to patch containers that still relied on waiting for base images to be rebuilt and republished, we would consider spinning that off into a different project instead of making it part of Copa.

    • Copa is intended to work with the existing ecosystem of container images. The project should have a strong preference for solutions that do not require image producers to create or modify their images in special ways to use Copa.

    • Copa is intended to allow parties other than the image authors to address container vulnerabilities. Copa should require a minimum of special knowledge about the lineage and construction of an image from the user to patch it successfully.

    • Copa is intended to do one thing well and be composable with other tools and processes. Copa does not have to be a universal multitool for container patching. For example, it is preferable that it integrates with popular container scanning tools rather than incorporating custom container scanning into the project itself. Similarly, it does not need to become a general container manipulation tool in the vein of crane.

    Design Reasoning

    The design of copa arises from the application of those tenets to the observed issues in previous efforts directly update container images via rebasing, for example, the experimental crane rebase:

    • Rebasing requires that all actors involved in creation of the image are coordinated so that some layers can be switched out without breaking the image. Attempting to switch out layers in the container overlay structure is brittle because most existing containers are created by writing over shared configuration files and data stores in base images. For example, an apt install during image creation will overwrite the dpkg status file in the base image, which will mask any package updates in a rebased layer. Since many existing container scanners rely on the reported package status to find vulnerable package versions, this can cause new vulnerabilities to not be reported or for patched binaries not to be recognized by the scanners.

      To avoid breaking integration with the existing container ecosystem, copa patches the filesystem bundle as a whole instead of as a collection of layers so that the resulting image state is consistent. This strategy also allows copa to patch vulnerabilties introduced at any layer in the image, including OS packages added in the app layers that is not addressed by a simple rebase. It also supports the core tenet of supporting patching without requiring coordination with all the publishers of the base images that a given image transitively depends on.

    • Rebasing also requires that the user knows a priori what base image (or transitive base image) is in the target image to determine which appropriate rebase image to use. This makes it very difficult for anyone not intimately involved with authoring the image from being able to remediate it, which is one of our tenets.

      While it is possible to embed extra metadata or annotations into the target image to facilitate this base image (or transitive base image) lookup, that would require that the images to be patched be modified or created especially to support updates, which goes against another of our tenets to be able to patch images without requiring them to be customized explicitly for that purpose.

      The design of copa addresses this by reframing the problem of updating containers and understanding the structure or lineage of a container image to the more specific problem of what packages in a given container image need to be updated. This allows copa to tap into the expertise embedded in the much more robust ecosystem for detecting and remediating vulnerabilities at the package level that already exists today. By making copa an additional remediation step that can be run after a container scan in existing workflows, we avoid both of those issues with an additional benefit: it incurs no additional work on the part of base image publishers to support patching of images based on their base images, the existing channels for publishing update packages is sufficient to service those container images as well.

    Architecture

    The requirements presented encourage an extensible model in order to support broad applicability. Specifically, there are two areas that the tool will need to accommodate multiple implementations to support more use cases:

    • The data schema of various vulnerability scanners producing the input vulnerability report.
    • The state management of various package managers and process for applying patches appropriately through them.

    Effectively, copa patch can be considered a command that bridges an extensible Parse action with an extensible Apply action as illustrated in the diagram; the implementation can be thought of as an engine that uses this abstract Go interface to apply security update packages:

    type UpdatePackage struct {
    Name string
    Version string
    }

    type UpdateManifest struct {
    OSType string
    OSVersion string
    Arch string
    Updates []UpdatePackage
    }

    type ScanReportParser interface {
    Parse(reportPath string) (*UpdateManifest, error)
    }

    type PackageManager interface {
    Apply(imagePath string, report *UpdateManifest) error
    }

    Implementation

    copa is a pseudo-frontend to buildkit implemented as a CLI tool. Effectively, instead of taking a container definition to create from scratch, it takes the reference to the target image to patch and a container scan report and builds a series of LLB graphs for buildkit to execute:

    1. Actions to probe the image as a filesystem bundle, for example, retrieving the package manager status in the image.
      • Within each distribution type identified by the scanner report (e.g. Debian) there can be different ways of applying patches to the target image (e.g. distroless), which can be differentiated through these actions.
    2. Actions to fetch and deploy tools that can be injected into the target image to perform the patching.
      • In cases where the package tools are not available in the target image, a standard version of the OS container matching the target image's is used to stage the necessary tooling for patches.
      • In the case of distroless images for example, where there is no valid package status file in the target image, the tooling container is also used to pull down and process the necessary package updates for copy to the target image.
      • Although not pictured, this can also be used to obtain tools (e.g. busybox) to be used in the image probing stage as well.
    3. Actions to deploy the required patch packages to the target image.
      • copa integrates with buildkit at the API level because it uses the diff and merge graph operations directly so that it can stage all the necessary tooling in the target image while producing a resulting image that only contains the original image plus a new layer with all the deployed patches.

    Tradeoffs

    • The core architectural choice of relying on packages as the unit of patching creates a couple of constraints:
      • By relying on existing vulnerability scanner behavior that only detects vulnerabilities via presence/absence of vulnerable packages, copa is limited in the kinds of vulnerabilities it can address and false positive/negatives from scanners flow downstream to copa.
      • copa depends on individual package manager adapters to correctly deploy patches to the target images, but there is a long tail of compatibility issues that arise depending on the target image itself (e.g. outdated package manager config/keys, invalid/missing package graph, etc.). Overall, the maintenance cost of the project is expected to be non-trivial to address this.
    • No support for windows containers given the dependency on buildkit.
    - + \ No newline at end of file diff --git a/website/v0.3.x/faq.html b/website/v0.3.x/faq.html index f1f08026..de871774 100644 --- a/website/v0.3.x/faq.html +++ b/website/v0.3.x/faq.html @@ -7,13 +7,13 @@ - +
    Version: v0.3.x

    FAQ

    What kind of vulnerabilities can Copa patch?

    Copa is capable of patching "OS level" vulnerabilities. This includes packages (like openssl) in the image that are managed by a package manager such as apt or yum. Copa is not currently capable of patching vulnerabilities at the "application level" such as Python packages or Go modules.

    - + \ No newline at end of file diff --git a/website/v0.3.x/installation.html b/website/v0.3.x/installation.html index 020e46ef..aa519a9f 100644 --- a/website/v0.3.x/installation.html +++ b/website/v0.3.x/installation.html @@ -7,13 +7,13 @@ - +
    Version: v0.3.x

    Installation

    Homebrew

    On macOS and Linux, copa can be installed via Homebrew:

    brew install copa

    GitHub

    You can download the latest and previous versions of copa from the GitHub releases page.

    Development Setup

    The following instructions are for Ubuntu 22.04 with the dependency versions supported as part of the dev container environment we use for builds and tests. For other distributions and OS, refer to the appropriate installation instructions for each of the components instead.

    git clone https://github.com/project-copacetic/copacetic
    cd copacetic
    make
    # OPTIONAL: install copa to a pathed folder
    sudo mv dist/linux_amd64/release/copa /usr/local/bin/
    - + \ No newline at end of file diff --git a/website/v0.3.x/quick-start.html b/website/v0.3.x/quick-start.html index f7d45131..46f8b329 100644 --- a/website/v0.3.x/quick-start.html +++ b/website/v0.3.x/quick-start.html @@ -7,7 +7,7 @@ - + @@ -15,7 +15,7 @@
    Version: v0.3.x

    Quick Start

    This sample illustrates how to patch containers using vulnerability reports with copa.

    Prerequisites

    Sample Steps

    1. Scan the container image for patchable OS vulnerabilities, outputting the results to a JSON file:

      trivy image --vuln-type os --ignore-unfixed -f json -o nginx.1.21.6.json docker.io/library/nginx:1.21.6

      You can also see the existing patchable vulnerabilities in table form on the shell with:

      trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6

    2. Patch the image using the Trivy report. You will need to start buildkitd if it is not already running:

      sudo buildkitd &
      sudo copa patch -i docker.io/library/nginx:1.21.6 -r nginx.1.21.6.json -t 1.21.6-patched

      Alternatively, you can run buildkitd in a container, which allows copa to be run without root access to the local buildkit socket:

      export BUILDKIT_VERSION=v0.11.4
      export BUILDKIT_PORT=8888
      docker run \
      --detach \
      --rm \
      --privileged \
      -p 127.0.0.1:$BUILDKIT_PORT:$BUILDKIT_PORT/tcp \
      --name buildkitd \
      --entrypoint buildkitd \
      "moby/buildkit:$BUILDKIT_VERSION" \
      --addr tcp://0.0.0.0:$BUILDKIT_PORT
      copa patch \
      -i docker.io/library/nginx:1.21.6 \
      -r nginx.1.21.6.json \
      -t 1.21.6-patched \
      -a tcp://0.0.0.0:$BUILDKIT_PORT

      In either case, copa is non-destructive and exports a new image with the specified 1.21.6-patched label to the local Docker daemon.

      NOTE: if you're running this sample against an image from a private registry instead, ensure that the credentials are configured in the default Docker config.json before running copa patch, for example, via sudo docker login -u <user> -p <password> <registry>.

    3. Scan the patched image and verify that the vulnerabilities have been patched:

      trivy image --vuln-type os --ignore-unfixed docker.io/library/nginx:1.21.6-patched

      You can also inspect the structure of the patched image with docker history to see the new patch layer appended to the image:

      $ docker history docker.io/library/nginx:1.21.6-patched
      IMAGE CREATED CREATED BY SIZE COMMENT
      a372df41e06d 1 minute ago mount / from exec sh -c apt install --no-ins… 26.1MB buildkit.exporter.image.v0
      <missing> 3 months ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
      <missing> 3 months ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0
      <missing> 3 months ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
      <missing> 3 months ago COPY 30-tune-worker-processes.sh /docker-ent… 4.61kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY 20-envsubst-on-templates.sh /docker-ent… 1.04kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY 10-listen-on-ipv6-by-default.sh /docker… 1.96kB buildkit.dockerfile.v0
      <missing> 3 months ago COPY docker-entrypoint.sh / # buildkit 1.2kB buildkit.dockerfile.v0
      <missing> 3 months ago RUN /bin/sh -c set -x && addgroup --syst… 61.1MB buildkit.dockerfile.v0
      <missing> 3 months ago ENV PKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENV NJS_VERSION=0.7.0 0B buildkit.dockerfile.v0
      <missing> 3 months ago ENV NGINX_VERSION=1.20.2 0B buildkit.dockerfile.v0
      <missing> 3 months ago LABEL maintainer=NGINX Docker Maintainers <d… 0B buildkit.dockerfile.v0
      <missing> 4 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
      <missing> 4 months ago /bin/sh -c #(nop) ADD file:09675d11695f65c55… 80.4MB
    4. Run the container to verify that the image has no regressions:

      $ docker run -it --rm --name nginx-test docker.io/library/nginx:1.21.6-patched
      /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
      /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
      10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
      10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
      /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
      /docker-entrypoint.sh: Configuration complete; ready for start up
      2022/05/16 18:00:17 [notice] 1#1: using the "epoll" event method
      2022/05/16 18:00:17 [notice] 1#1: nginx/1.20.2
      2022/05/16 18:00:17 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
      2022/05/16 18:00:17 [notice] 1#1: OS: Linux 5.10.102.1-microsoft-standard-WSL2
      2022/05/16 18:00:17 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
      2022/05/16 18:00:17 [notice] 1#1: start worker processes
      2022/05/16 18:00:17 [notice] 1#1: start worker process 31
      2022/05/16 18:00:17 [notice] 1#1: start worker process 32
      2022/05/16 18:00:17 [notice] 1#1: start worker process 33
      2022/05/16 18:00:17 [notice] 1#1: start worker process 34
      2022/05/16 18:00:17 [notice] 1#1: start worker process 35
      2022/05/16 18:00:17 [notice] 1#1: start worker process 36
      2022/05/16 18:00:17 [notice] 1#1: start worker process 37
      2022/05/16 18:00:17 [notice] 1#1: start worker process 38
      2022/05/16 18:00:17 [notice] 38#38: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 36#36: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 33#33: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 32#32: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 34#34: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 35#35: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 37#37: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 1#1: signal 28 (SIGWINCH) received
      2022/05/16 18:00:17 [notice] 31#31: signal 28 (SIGWINCH) received

      You can stop the container by opening a new shell instance and running: docker stop nginx-test

    - + \ No newline at end of file