What is Alpine Linux?
Alpine Linux is an extremely lightweight Linux distribution popular for use in CI/CD pipelines owing to the very small image size. The reason it is so tiny is that it has nothing installed on it at all beyond basic kernel and core linux packages like echo, printf and sed. Even bash needs to be installed to run shell scripts etc and even standard packages like those that handle certificates for corporate use (ca-certificates) need to be installed to work through proxies etc. The latest current version at time of writing is v3.18 but some earlier versions are kept up to date until their support period runs out.
Situation
My client was running a very old Alpine 3.12 linux build pipeline image used in their CI/CD pipeline. The image dated way back to 2020 and as with all older Linux distributions suffers from a lack of continued support for late package versions such as Python etc. This limits the ability to install supported software and their dependencies. As a build pipeline image, it only had a single job to do which was to deploy Infrastructure as Code (IaC) and was working perfectly fine. There were several vulnerabilities due to outdated packages being reported on and there was keen interest in upgrading to a later version of Alpine but also no express driver to do so until recently during a planned feature update with CDK (forcing an upgrade).
Task
The task given to me was to upgrade to AWS CLI v2 to support new features and services being released and allow collapsing of legacy workarounds. In addition, there was a planned upgrade to CDK v1 to CDK v2. After some initial investigation, it was determined there was a need to upgrade the build image to a later version of Alpine to support both streams of work. This was required to support Python 3.10+ as part of the latest build for AWS CLI v2 requirements and Nodejs 16+ for CDK v2. I needed to find a way to build the image with a simple way to maintain the AWS CLI v2 and CDK v2 versions.
Action
Build a working build pipeline image based on Alpine v3.17.3 to bootstrap new AWS accounts using a combination of CDK v2 and AWS CLI v2. This involved learning the nuances of the changes made in Alpine Linux v3.17 and mitigating those challenges to work inside a highly regulated corporate environment. Access had to work through corporate proxies and the image would be used as a complete bootstrapped image with pre-installed packages and gems to reduce the time needed to run release pipelines. This article speaks to installing AWS CLI v2 only.
Changes to Alpine Linux
One of the major changes made to Alpine Linux from v3.17 and beyond is that TLS 1.3 is enforced and legacy TLS renegotiation is disabled. In prior versions (starting in v3.15), TLS 1.3 was enabled also however legacy renegotiation hadn’t yet been disabled. This means that sources using say TLS 1.2 or earlier will no longer work under Alpine v3.17+.
When working within corporate proxy environments, it is necessary for your proxies to support TLS 1.3 but if they don’t, you will get “legacy renegotiation is disabled” errors when trying to access packages and repositories using TLS 1.3 such as Ruby Gems and Nodejs packages via NPM. This will require you to enable legacy renegotiation between your Docker container and your proxies:
printf ‘openssl_conf = openssl_init\n\ |
To install and update any certificates issued by the corporate Certificate Authority (CA) to allow for trusting connections between proxies and the client, you need to install the “ca-certificate” package. I had to copy in the certificates from another base image that already had been bootstrapped so the CA certs were installed prior. To support access to apk repositories using TLS 1.3 until your proxies support it, it may be necessary to either use HTTP repositories or enable legacy renegotiation globally. In my case as I wanted to have the capability to easily roll back and not reconfigure the global “/etc/ssl/openssl.cnf”, I went with using HTTP apk repositories instead:
RUN sed -ie “s/https/http/g” /etc/apk/repositories && \ |
Result
Installing AWS CLI v2
One of the updates made to AWS CLI in version 2 is that it is no longer possible to install it via Python Pip like you could in version 1. In AWS CLI v2, there are several ways of installing it however not all of these work in Alpine. The AWS CLI v2 is compiled with the glibc library, however Alpine Linux uses the musl libc library. This renders official AWS instructions useless for working with Alpine. There are many articles that mention the gcompat compatibility package, however this wasn’t enough for me to compile the AWS CLI v2 packages. Below is the solution that worked for me and it involved a lot more packages to successfully compile:
apk add —update —no-cache python3 py3-pip python3-dev binutils make cmake gcc g++ libc-dev libffi-dev openssl-dev groff && \ |
While there are many examples of ways to install and compile the packages, here is what worked for me on Alpine 3.17.3:
export AWS_CLI_VERSION=2.11.14 |
TL;DR
The complete Dockerfile can be found below:
FROM ${BASE_IMAGE} AS certs |
Removing Changes
Once end-to-end TLS 1.3 is supported and you no longer need to enable legacy renegotiation, simply remove the following lines:
printf ‘openssl_conf = openssl_init\n\ |
Then, set apk repositories back to HTTPS before removing it entirely:
sed -ie “s/http/https/g” /etc/apk/repositories && \ |
An Easier Way To Install AWS CLI v2
Not all customer environments enable the use of the apk edge repositories for compliance and/or governance reasons (as in my own case). If your organisation or customer does, then your life got a whole lot simpler as you can simply install the “aws-cli” package from the apk edge repository (https://pkgs.alpinelinux.org/package/edge/community/x86_64/aws-cli):
apk add python3 py3-awscrt py3-certifi py3-colorama py3-cryptography py3-dateutil py3-distro py3-docutils py3-jmespath py3-prompt_toolkit py3-ruamel.yaml py3-urlib3 aws-cli –repository=https://dl-cdn.alpinelinux.org/alpine/edge/community |