Tuesday, 31 August 2021

Munging Dockerfiles using Bash and Jenkins

Whilst trying to mitigate an issue with a Docker image, in order to remediate a pair of CVE: -

CVE-2021-3711

CVE-2021-3712

I needed to ensure that the latest version of openssl was being used.

Now this image is based, in part, on Alpine Linux, and already included: -

FROM alpine:3.14.1 AS run

...

RUN apk --no-cache add openssl

which *should* mean that I'd be getting the required version of openssl as advised by the two CVEs, namely: -

OpenSSL 1.1.1l

and yet I was still seeing the issues when scanning the resulting image using IBM Container Registry's Vulnerability Advisor tool.

I even added: -

RUN apk info --all openssl

to the Dockerfile, which returned: -

openssl-1.1.1l-r0 description:
WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/main: No such file or directory
WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/community: No such file or directory
Toolkit for Transport Layer Security (TLS)
openssl-1.1.1l-r0 webpage:
https://www.openssl.org/
openssl-1.1.1l-r0 installed size:
660 KiB
openssl-1.1.1l-r0 depends on:
so:libc.musl-x86_64.so.1
so:libcrypto.so.1.1
so:libssl.so.1.1
openssl-1.1.1l-r0 provides:
cmd:openssl
openssl-1.1.1l-r0 is required by:
openssl-1.1.1l-r0 contains:
usr/bin/openssl
openssl-1.1.1l-r0 triggers:
openssl-1.1.1l-r0 has auto-install rule:
openssl-1.1.1l-r0 affects auto-installation of:
openssl-1.1.1l-r0 replaces:
libressl
openssl-1.1.1l-r0 license:
OpenSSL

After much tinkering, I came to the realisation that there's more to life than just apk add, namely there's a need to (a) update the Alpine repository sources and (b) upgrade Alpine itself ...

In the Ubuntu world, this would achieved by apt get update && apt-get upgrade -y

In the Alpine world, this is achieved by apk update && apk upgrade

Therefore, I amended my Dockerfile from: -

RUN apk --no-cache add openssl

to: -

RUN apk update && apk upgrade && apk --no-cache add openssl

which did the trick

However, because I'm building the image using Jenkins, via a Bash script wrapped up in a Groovy script ( the Jenkinsfile ), I needed to do some escape magic.

I started with this: -

sed -i'' "s/RUN apk \-\-no-cache add openssl/RUN apk update \&\& apk upgrade \&\& apk \-\-no-cache add openssl/g" Dockerfile

but the Jenkins job failed with: -

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 22: unexpected char: '\' @ line 22, column 41.
             sed -i'' "s/RUN apk \-\-no-cac


Now I was going a little bit OTT with the escape characters, as I didn't really need to escape out the hyphens ( - ) but the same problem occurred with this: -

sed -i'' "s/RUN apk --no-cache add openssl/RUN apk update \&\& apk upgrade \&\& apk --no-cache add openssl/g" Dockerfile

because I'd forgotten that escaping in Bash in Groovy has its own set of peculiar rules ...

TL;DR; I needed to double escape ...

sed -i'' "s/RUN apk --no-cache add openssl/RUN apk update \\&\\& apk upgrade \\&\\& apk --no-cache add openssl/g" Dockerfile

With this in place, all is good - the build runs smoothly AND the resulting image is clean and green ...


No comments:

TIL - read-only variables in Linux

 A co-worker was seeing an exception: -  line 8: TMOUT: readonly variable when trying to SCP a file from a remote Linux box. I did some digg...