Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
FROM mcr.microsoft.com/devcontainers/base:ubuntu


ARG TARGETARCH
ENV TARGETARCH=${TARGETARCH}

Expand Down
183 changes: 123 additions & 60 deletions .github/scripts/check_ecr_image_scan_results.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#!/usr/bin/env bash
set -e

AWS_MAX_ATTEMPTS=20
export AWS_MAX_ATTEMPTS

if [ -z "${REPOSITORY_NAME}" ]; then
echo "REPOSITORY_NAME not set"
exit 1
Expand All @@ -11,65 +14,125 @@ if [ -z "${IMAGE_TAG}" ]; then
exit 1
fi

function wait_for_scan() {
echo "Giving some time for scan to begin..."
sleep 3
while [[ $(aws ecr describe-image-scan-findings --repository-name "${REPOSITORY_NAME}" --image-id imageTag="${IMAGE_TAG}" | jq -r .imageScanStatus.status) != "COMPLETE" ]];do
echo "SCAN IS NOT YET COMPLETE..."
sleep 3
done
echo "Final sleep to ensure findings are shown correctly"
sleep 60
}

function check_for_high_critical_vuln() {
scan_results=$(aws ecr describe-image-scan-findings --repository-name "${REPOSITORY_NAME}" --image-id imageTag="${IMAGE_TAG}")
high=$(echo "$scan_results" | jq '.imageScanFindings.enhancedFindings[]? | select(.severity == "HIGH" and .status != "SUPPRESSED")')
critical=$(echo "$scan_results" | jq '.imageScanFindings.enhancedFindings[]? | select(.severity == "CRITICAL" and .status != "SUPPRESSED")')
}

function return_scan_results() {
echo "=== BEGIN IMAGE SCAN RESULTS ==="
echo "$scan_results"
echo "=== END IMAGE SCAN RESULTS ==="
}

function return_error() {
echo -e "\n**********************************************************"
echo "**********************************************************"
echo "**********************************************************"
echo "ERROR: There are CRITICAL/HIGH vulnerabilities. Stopping build."
echo "**********************************************************"
echo "**********************************************************"
echo "**********************************************************"
exit 2
}

function analyze_scan_results() {
if [[ -n "$critical" ]]; then
echo "ERROR: There are CRITICAL vulnerabilities. Stopping build."

echo "=== BEGIN CRITICAL IMAGE SCAN RESULTS ==="
echo "$critical"
echo "=== END CRITICAL IMAGE SCAN RESULTS ==="

return_scan_results

return_error
elif [[ -n "$high" ]]; then
echo "ERROR: There are HIGH vulnerabilities. Stopping build."

echo "=== BEGIN HIGH IMAGE SCAN RESULTS ==="
echo "$high"
echo "=== END HIGH IMAGE SCAN RESULTS ==="

return_scan_results
return_error
else
return_scan_results
if [ -z "${AWS_REGION}" ]; then
echo "AWS_REGION not set"
exit 1
fi

if [ -z "${ACCOUNT_ID}" ]; then
echo "AWS_REGION not set"
exit 1
fi

IMAGE_DIGEST=$(aws ecr describe-images \
--repository-name "$REPOSITORY_NAME" \
--image-ids imageTag="$IMAGE_TAG" \
--query 'imageDetails[0].imageDigest' \
--output text)

RESOURCE_ARN="arn:aws:ecr:${AWS_REGION}:${ACCOUNT_ID}:repository/${REPOSITORY_NAME}/${IMAGE_DIGEST}"

echo "Monitoring scan for ${REPOSITORY_NAME}:${IMAGE_TAG}"
echo "Resource ARN: ${RESOURCE_ARN}"
echo

# Wait for ECR scan to reach COMPLETE
STATUS=""
echo "Waiting for ECR scan to complete..."
for i in {1..30}; do
echo "Checking scan status. Attempt ${i}"
STATUS=$(aws ecr describe-image-scan-findings \
--repository-name "$REPOSITORY_NAME" \
--image-id imageDigest="$IMAGE_DIGEST" \
--query 'imageScanStatus.status' \
--output text 2>/dev/null || echo "NONE")

if [[ "$STATUS" == "COMPLETE" ]]; then
echo "ECR scan completed."
break
fi

if [[ "$STATUS" == "FAILED" ]]; then
echo "Scan failed."
exit 1
fi

echo "SCAN IS NOT YET COMPLETE. Waiting 10 seconds before checking again..."
sleep 10
done

if [[ "$STATUS" != "COMPLETE" ]]; then
echo "Timeout waiting for ECR scan to complete."
exit 1
fi

# Wait for Inspector2 findings to appear & stabilize
# this is in place as scan may show as complete but findings have not yet stabilize
echo
echo "Waiting for Inspector2 findings to stabilize..."

PREV_HASH=""
for i in {1..12}; do # ~2 minutes max
FINDINGS=$(aws inspector2 list-findings \
--filter-criteria "{
\"resourceId\": [{\"comparison\": \"EQUALS\", \"value\": \"${RESOURCE_ARN}\"}],
\"findingStatus\": [{\"comparison\": \"EQUALS\", \"value\": \"ACTIVE\"}]
}" \
--output json 2>/dev/null || echo "{}")

CURR_HASH=$(echo "$FINDINGS" | sha256sum)
COUNT=$(echo "$FINDINGS" | jq '.findings | length')

if [[ "$COUNT" -gt 0 && "$CURR_HASH" == "$PREV_HASH" ]]; then
echo "Findings stabilized ($COUNT findings)."
break
fi
}

wait_for_scan
check_for_high_critical_vuln
analyze_scan_results
PREV_HASH="$CURR_HASH"
echo "Attempt: ${i}. Still waiting... (${COUNT} findings so far)"
sleep 10
done

# Extract counts and display findings
echo
echo "Final Inspector2 findings with suppressions removed:"
echo

echo "$FINDINGS" | jq '{
findings: [
.findings[]? | {
severity: .severity,
title: .title,
package: .packageVulnerabilityDetails.vulnerablePackages[0].name,
sourceUrl: .packageVulnerabilityDetails.sourceUrl,
recommendation: (.remediation.recommendation.text // "N/A")
}
]
}'

echo

# Check for critical/high severity
CRITICAL_COUNT=$(echo "$FINDINGS" | jq '[.findings[]? | select(.severity=="CRITICAL")] | length')
HIGH_COUNT=$(echo "$FINDINGS" | jq '[.findings[]? | select(.severity=="HIGH")] | length')

if (( CRITICAL_COUNT > 0 || HIGH_COUNT > 0 )); then
echo "${CRITICAL_COUNT} CRITICAL and ${HIGH_COUNT} HIGH vulnerabilities detected!"
echo
echo "Critical/High vulnerabilities:"
echo "$FINDINGS" | jq -r '
.findings[]? |
select(.severity=="CRITICAL" or .severity=="HIGH") |{
severity: .severity,
title: .title,
package: .packageVulnerabilityDetails.vulnerablePackages[0].name,
sourceUrl: .packageVulnerabilityDetails.sourceUrl,
recommendation: (.remediation.recommendation.text // "N/A")
}'
echo
echo "Failing pipeline due to Critical/High vulnerabilities."
exit 2
else
echo "No Critical or High vulnerabilities found."
exit 0
fi
10 changes: 6 additions & 4 deletions .github/workflows/docker_image_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ jobs:
packages: read
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
ref: ${{ env.BRANCH_NAME }}

- name: Build cdk-utils-build Docker image
id: build-cdk-utils-build-image
env:
VERSION_NUMBER: ${{ inputs.VERSION_NUMBER }}
run: |
docker build -t "cdk-utils-build:${{ inputs.VERSION_NUMBER }}" -f docker/Dockerfile --build-arg VERSION=${{ inputs.VERSION_NUMBER }} .
docker save "cdk-utils-build:${{ inputs.VERSION_NUMBER }}" -o cdk-utils-build.img
docker build -t "cdk-utils-build:${VERSION_NUMBER}" -f docker/Dockerfile --build-arg VERSION="${VERSION_NUMBER}" .
docker save "cdk-utils-build:${VERSION_NUMBER}" -o cdk-utils-build.img

- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
name: Upload docker images
with:
name: docker_artifact
Expand Down
25 changes: 15 additions & 10 deletions .github/workflows/docker_image_upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ on:
secrets:
CDK_PUSH_IMAGE_ROLE:
required: true

jobs:
upload_docker_image:
runs-on: ubuntu-22.04
Expand All @@ -32,22 +32,22 @@ jobs:

steps:
- name: Checkout local github actions
uses: actions/checkout@v5
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
with:
ref: ${{ env.BRANCH_NAME }}
fetch-depth: 0
sparse-checkout: |
.github

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v5
uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8
with:
aws-region: eu-west-2
role-to-assume: ${{ secrets.CDK_PUSH_IMAGE_ROLE }}
role-session-name: upload-cdk-utils-build

- name: docker_artifact download
uses: actions/download-artifact@v5
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0
with:
name: docker_artifact
path: .
Expand All @@ -60,23 +60,28 @@ jobs:
- name: Retrieve AWS Account ID
id: retrieve-account-id
run: echo "ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)" >> "$GITHUB_ENV"

- name: Login to Amazon ECR
id: login-ecr
run: |
aws ecr get-login-password --region eu-west-2 | docker login --username AWS --password-stdin ${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com

- name: Push tagged version cdk-utils-build to Amazon ECR
env:
VERSION_NUMBER: ${{ inputs.VERSION_NUMBER }}
DOCKER_IMAGE_TAG: ${{ inputs.DOCKER_IMAGE_TAG }}
run: |
docker tag "cdk-utils-build:${{ inputs.VERSION_NUMBER }}" "${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:${{ inputs.DOCKER_IMAGE_TAG }}"
docker push "${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:${{ inputs.DOCKER_IMAGE_TAG }}"
docker tag "cdk-utils-build:${VERSION_NUMBER}" "${ACCOUNT_ID}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:${DOCKER_IMAGE_TAG}"
docker push "${ACCOUNT_ID}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:${DOCKER_IMAGE_TAG}"

- name: Push latest cdk-utils-build to Amazon ECR
if: ${{ inputs.TAG_LATEST == true }}
env:
VERSION_NUMBER: ${{ inputs.VERSION_NUMBER }}
run: |
docker tag "cdk-utils-build:${{ inputs.VERSION_NUMBER }}" "${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:latest"
docker push "${{ env.ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:latest"
docker tag "cdk-utils-build:${VERSION_NUMBER}" "${ACCOUNT_ID}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:latest"
docker push "${ACCOUNT_ID}.dkr.ecr.eu-west-2.amazonaws.com/cdk-utils-build-repo:latest"

- name: Check cdk-utils-build scan results
env:
REPOSITORY_NAME: cdk-utils-build-repo
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
issue_number: ${{steps.get_issue_number.outputs.result}}

steps:
- uses: actions/github-script@v8
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd
name: get issue number
id: get_issue_number
with:
Expand Down
47 changes: 27 additions & 20 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,44 +1,51 @@
FROM ubuntu:24.04

ARG TARGETARCH
ENV TARGETARCH=${TARGETARCH}

ARG ASDF_VERSION
COPY .tool-versions.asdf /tmp/.tool-versions.asdf

ARG VERSION

RUN apt-get update \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y upgrade

RUN export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y upgrade \
&& apt-get -y install --no-install-recommends ca-certificates curl git jq make unzip wget \
&& apt-get clean

# install aws stuff
ADD https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip /tmp/awscliv2.zip
RUN unzip /tmp/awscliv2.zip -d /tmp/aws-cli && \
# Download correct AWS CLI for arch
RUN if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" == "aarch64" ]; then \
wget -O /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip"; \
else \
wget -O /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"; \
fi && \
unzip /tmp/awscliv2.zip -d /tmp/aws-cli && \
/tmp/aws-cli/aws/install && \
rm tmp/awscliv2.zip && \
rm -rf /tmp/aws-cli
rm /tmp/awscliv2.zip && rm -rf /tmp/aws-cli

# Install ASDF
RUN ASDF_VERSION=$(awk '!/^#/ && NF {print $1; exit}' /tmp/.tool-versions.asdf) && \
if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" = "aarch64" ]; then \
wget -O /tmp/asdf.tar.gz https://github.com/asdf-vm/asdf/releases/download/v${ASDF_VERSION}/asdf-v${ASDF_VERSION}-linux-arm64.tar.gz; \
else \
wget -O /tmp/asdf.tar.gz https://github.com/asdf-vm/asdf/releases/download/v${ASDF_VERSION}/asdf-v${ASDF_VERSION}-linux-amd64.tar.gz; \
fi && \
tar -xvzf /tmp/asdf.tar.gz && \
mv asdf /usr/bin

RUN useradd -ms /bin/bash cdkuser
RUN chown -R cdkuser /home/cdkuser
WORKDIR /home/cdkuser
USER cdkuser
# Install ASDF
RUN git clone https://github.com/asdf-vm/asdf.git /home/cdkuser/.asdf --branch v0.14.1; \
echo '. /home/cdkuser/.asdf/asdf.sh' >> ~/.bashrc; \
echo '. /home/cdkuser/.asdf/completions/asdf.bash' >> ~/.bashrc; \
echo 'PATH="$PATH:/home/cdkuser/.asdf/bin/"' >> ~/.bashrc;

ENV PATH="$PATH:/home/cdkuser/.asdf/bin/:/home/cdkuser/node_modules/.bin"
ENV PATH="$PATH:/home/cdkuser/.asdf/shims/:/home/cdkuser/node_modules/.bin"

# Install ASDF plugins
RUN asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
# install some common node versions that are used in builds to speed things up
RUN asdf install nodejs 20.19.1; \
asdf install nodejs 23.9.0
# update npm
RUN export ASDF_DIR=/home/cdkuser/.asdf && \
. /home/cdkuser/.asdf/asdf.sh && \
asdf shell nodejs 20.19.1 && \
cd ~/.asdf/installs/nodejs/20.19.1/lib && npm update npm
RUN asdf install nodejs 22.20.0;

# copy files needed for deployment
COPY --chown=cdkuser docker/entrypoint.sh /home/cdkuser/
Expand Down
Loading