diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index d9630cf..113c32f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -92,3 +92,34 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + + + # Extract the pure application SBOM from the artifact stage, we want to handle it separately from the container SBOM + # This automaticaly re-uses the previously generated stage from cache, so we get the exact sbom from previous build step + - name: Export Application SBOM from artifact stage + if: ${{ github.event_name != 'pull_request' }} + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: ${{ env.BUILD_CONTEXT }} + file: ${{ env.DOCKERFILE_PATH }} + target: app-sbom-artifact + push: false + outputs: type=local,dest=sbom-output + + # Generate container SBOM. + - name: Run Trivy in GitHub SBOM mode to generate CycloneDX SBOM for container + if: ${{ github.event_name != 'pull_request' }} + uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1 + with: + scan-type: 'image' + format: 'cyclonedx' + output: 'sbom-output/sbom_container.cyclonedx.json' + image-ref: ${{ steps.meta.outputs.tags }} + skip-dirs: '/App' # Skip the /app directory as we handle the content of the application in a seperate SBOM for easier vulnerability management and because trivy misses important fields + + - name: Upload trivy/container AND application SBOMs as a Github artifact + if: ${{ github.event_name != 'pull_request' }} + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: sbom + path: '${{ github.workspace }}/sbom-output/' diff --git a/source/AAS.TwinEngine.DataEngine/Dockerfile b/source/AAS.TwinEngine.DataEngine/Dockerfile index d770afa..63b409d 100644 --- a/source/AAS.TwinEngine.DataEngine/Dockerfile +++ b/source/AAS.TwinEngine.DataEngine/Dockerfile @@ -1,12 +1,23 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:aa05b91be697b83229cb000b90120f0783604ad74ed92a0b45cdf3d1a9c873de AS build +# Install CycloneDX SBOM Generator Package +RUN dotnet tool install --global CycloneDX --version 5.5.0 +ENV PATH="$PATH:/root/.dotnet/tools" +# Build application ARG BUILD_CONFIGURATION=Release WORKDIR /App COPY ["AAS.TwinEngine.DataEngine/", "AAS.TwinEngine.DataEngine/"] RUN dotnet restore "AAS.TwinEngine.DataEngine/AAS.TwinEngine.DataEngine.csproj" RUN dotnet publish "AAS.TwinEngine.DataEngine/AAS.TwinEngine.DataEngine.csproj" -c "$BUILD_CONFIGURATION" -o out +# Generate Application SBOM at sbom/bom.xml (omitting dev/test dependencies as they do not appear in final build) +RUN dotnet-CycloneDX "AAS.TwinEngine.DataEngine/AAS.TwinEngine.DataEngine.csproj" -o "sbom/" --exclude-dev --exclude-test-projects --set-nuget-purl --spec-version 1.6 --disable-package-restore +# Create an "app-sbom-artifact" image which can be use to extract the pure APP SBOM after completing the docker build (we want to keep the SBOM for the application separate from the pure linux image SBOM as this provides more details and simplifies vuln management) +FROM scratch AS app-sbom-artifact +COPY --from=build /App/sbom/bom.xml /sbom_application.cyclonedx.xml + +# Create final image containing application FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine@sha256:a0ce42fe86548363a9602c47fc3bd4cf9c35a2705c68cd98d7ce18ae8735b83c USER app WORKDIR /App COPY --from=build /App/out . -ENTRYPOINT ["dotnet", "AAS.TwinEngine.DataEngine.dll"] \ No newline at end of file +ENTRYPOINT ["dotnet", "AAS.TwinEngine.DataEngine.dll"]