diff --git a/.github/workflows/container-build-neutron.yaml b/.github/workflows/container-build-neutron.yaml index b60b9c2..3d2a845 100644 --- a/.github/workflows/container-build-neutron.yaml +++ b/.github/workflows/container-build-neutron.yaml @@ -19,19 +19,14 @@ on: - cron: '0 0 * * 0' # Run Weekly at midnight UTC workflow_dispatch: inputs: - openstack-constraints: - description: 'Version of OpenStack Constraints to use' + ovs-version: + description: 'Version of OVS to use' required: true default: "master" type: choice options: - master - - stable/2024.1 - - stable/2025.1 - project-version: - description: 'Version of OpenStack Neutroon to build, defaults to openstack-constraints if unspecified' - required: false - type: string + - v3.5.1 env: REGISTRY: ghcr.io diff --git a/.github/workflows/container-build-ovs.yaml b/.github/workflows/container-build-ovs.yaml new file mode 100644 index 0000000..d903d1a --- /dev/null +++ b/.github/workflows/container-build-ovs.yaml @@ -0,0 +1,152 @@ +--- +name: Create and publish a ovs image + +permissions: + actions: read + contents: read + id-token: write + packages: write + pull-requests: write + security-events: write + +on: + pull_request: + paths: + - .github/workflows/container-build-ovs.yaml + - ContainerFiles/ovs + schedule: + - cron: '0 0 * * 0' # Run Weekly at midnight UTC + workflow_dispatch: + inputs: + ovs-version: + description: 'Version of ovs to use' + required: true + default: "main" + type: choice + options: + - "main" + - "v3.5.1" + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }}/ovs + # NOTE(cloudnull): This is used to parse the workflow_dispatch inputs, sadly the inputs are not available in the + # workflow_dispatch event, so they're being stored in the environment variables. This is a + # workaround until there's a better way to handle this. + ovs_release: > + ["v3.5.1"] +jobs: + init: + runs-on: ubuntu-latest + outputs: + ovs-version: ${{ steps.generate-matrix.outputs.ovs_release }} + steps: + - name: generate-matrix + id: generate-matrix + run: | + if [ "${{ github.event_name == 'workflow_dispatch' }}" = "true" ]; then + ovs_release="$(echo '${{ github.event.inputs.ovs-version }}' | jq -R '[select(length>0)]' | jq -c '.')" + fi + echo "ovs_release=${ovs_release:-${{ env.ovs_release }}}" >> $GITHUB_OUTPUT + build-and-push-image: + needs: + - init + strategy: + matrix: + ovs-version: ${{ fromJSON(needs.init.outputs.ovs-version) }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Dynamically set MY_DATE environment variable + run: echo "MY_DATE=$(date +%s)" >> $GITHUB_ENV + - name: Dynamically set environment variables + run: | + VERSION=$(echo -n "${{ matrix.ovs-version }}" | awk -F'/' '{($2=="" ? x=$1 : x=$2); print x}') + echo "OS_VERSION_PARSE=${VERSION}" >> $GITHUB_ENV + NAME=$(echo -n "${{ env.IMAGE_NAME }}" | awk -F'/' '{print $NF}') + echo "CATEGORY_NAME=${VERSION}-${NAME}" >> $GITHUB_ENV + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ContainerFiles/ovs + push: false + load: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: | + ${{ env.IMAGE_NAME }}:local + labels: ${{ steps.meta.outputs.labels }} + build-args: | + OVS_VERSION=${{ matrix.ovs-version }} + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@0.28.0 + if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} + with: + image-ref: '${{ env.IMAGE_NAME }}:local' + format: 'sarif' + output: 'trivy-results.sarif' + ignore-unfixed: true + severity: 'CRITICAL,HIGH' + - name: Upload Trivy scan results to GitHub Security tab + continue-on-error: true + if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: 'trivy-results.sarif' + category: "${{ env.CATEGORY_NAME }}" + - name: Run Trivy scanner + uses: aquasecurity/trivy-action@0.28.0 + if: ${{ github.event_name == 'pull_request' }} + with: + image-ref: '${{ env.IMAGE_NAME }}:local' + output: trivy.txt + ignore-unfixed: true + severity: 'CRITICAL,HIGH' + - name: Create trivy output file in markdown format + if: ${{ github.event_name == 'pull_request' }} + run: | + if [[ -s trivy.txt ]]; then + echo "### Security Output" > trivy-output.txt + echo '```terraform' >> trivy-output.txt + cat trivy.txt >> trivy-output.txt + echo '```' >> trivy-output.txt + fi + - name: Publish Trivy Output to Summary + if: ${{ github.event_name == 'pull_request' }} + run: | + if [[ -s trivy-output.txt ]]; then + { + cat trivy-output.txt + } >> $GITHUB_STEP_SUMMARY + fi + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: ContainerFiles/ovs + push: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} + cache-from: type=gha + cache-to: type=gha,mode=max + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.MY_DATE }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + OVS_VERSION=${{ matrix.ovs-version }} diff --git a/ContainerFiles/neutron b/ContainerFiles/neutron index 1d0219c..4b769b1 100644 --- a/ContainerFiles/neutron +++ b/ContainerFiles/neutron @@ -2,13 +2,14 @@ # This Dockerfile uses multi-stage build to customize DEV and PROD images: # https://docs.docker.com/develop/develop-images/multistage-build/ -ARG VENV_TAG=3.12-latest -FROM ghcr.io/rackerlabs/genestack-images/openstack-venv:${VENV_TAG} AS dependency_build +ARG VENV_TAG=v3.5.1-latest +FROM ghcr.io/rackerlabs/genestack-images/ovs:${VENV_TAG} AS dependency_build ARG OS_VERSION=master ARG OS_CONSTRAINTS=master RUN export DEBIAN_FRONTEND=noninteractive \ && apt-get update && apt-get upgrade -y \ && apt-get install --no-install-recommends -y \ + dh-autoreconf \ bash \ brotli \ build-essential \ @@ -36,7 +37,9 @@ RUN /var/lib/openstack/bin/pip install --constraint https://opendev.org/openstac git+https://opendev.org/openstack/neutron-dynamic-routing@${OS_VERSION}#egg=neutron-dynamic-routing \ git+https://opendev.org/openstack/neutron-fwaas@${OS_VERSION}#egg=neutron-fwaas \ git+https://opendev.org/openstack/neutron-vpnaas@${OS_VERSION}#egg=neutron-vpnaas \ - PyMySQL + PyMySQL \ + graphviz \ + netaddr COPY scripts/neutron-cve-patching.sh /opt/ RUN bash /opt/neutron-cve-patching.sh @@ -55,6 +58,9 @@ LABEL vendor="Rackspace OpenStack Team" LABEL org.opencontainers.image.name="neutron" LABEL org.opencontainers.image.description="OpenStack Service (neutron) built for the enterprise." COPY --from=dependency_build /var/lib/openstack /var/lib/openstack +COPY --from=dependency_build /usr/local /usr/local +COPY --from=dependency_build /etc/openvswitch /etc/openvswitch +COPY --from=dependency_build /var/lib/openvswitch /var/lib/openvswitch RUN export DEBIAN_FRONTEND=noninteractive \ && apt-get update && apt-get upgrade -y \ && apt-get install --no-install-recommends -y conntrack \ @@ -64,9 +70,16 @@ RUN export DEBIAN_FRONTEND=noninteractive \ iptables \ iputils-arping \ keepalived \ + libatomic1 \ + libbpf1 \ + libcap-ng0 \ + libnuma1 \ + libssl3 \ + libunbound8 \ + libunwind8 \ + libxdp1 \ net-tools \ - openvswitch-common \ - openvswitch-switch \ + openssl \ radvd \ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ && apt-get clean -y \ diff --git a/ContainerFiles/ovs b/ContainerFiles/ovs new file mode 100644 index 0000000..5582f72 --- /dev/null +++ b/ContainerFiles/ovs @@ -0,0 +1,51 @@ +# syntax = docker/dockerfile:1 +# This Dockerfile uses multi-stage build to customize DEV and PROD images: +# https://docs.docker.com/develop/develop-images/multistage-build/ + +ARG VENV_TAG=3.12-latest +FROM ghcr.io/rackerlabs/genestack-images/openstack-venv:${VENV_TAG} AS dependency_build +ARG OVS_VERSION=main +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get update && apt-get upgrade -y \ + && apt-get install --no-install-recommends -y \ + dh-autoreconf \ + bash \ + brotli \ + build-essential \ + curl \ + docutils-common \ + gettext \ + git \ + libffi-dev \ + libjs-sphinxdoc \ + libjs-underscore \ + libldap2-dev \ + libpq-dev \ + libsasl2-dev \ + libssl-dev \ + libsystemd-dev \ + libxml2-dev \ + libxslt1-dev \ + libxslt1.1 \ + pkg-config \ + ssl-cert \ + xmlsec1 \ + libcap-ng-dev \ + libbpf-dev \ + libxdp-dev \ + libnuma-dev +RUN git clone --branch ${OVS_VERSION} https://github.com/openvswitch/ovs /opt/ovs +WORKDIR /opt/ovs +RUN ./boot.sh +RUN ./configure --sysconfdir=/etc --localstatedir=/var +RUN PROC="$([ nproc > 4 ] && echo 4 || nproc)" make -j $PROC && make install + +FROM python:3.12-slim-bookworm +LABEL maintainer="Rackspace" +LABEL vendor="Rackspace OpenStack Team" +LABEL org.opencontainers.image.name="ovs" +LABEL org.opencontainers.image.description="OVS built for the enterprise." +COPY --from=dependency_build /usr/local /usr/local +COPY --from=dependency_build /etc/openvswitch /etc/openvswitch +COPY --from=dependency_build /var/lib/openvswitch /var/lib/openvswitch +ENV PATH="/usr/local/bin:/usr/local/sbin:$PATH" diff --git a/README.md b/README.md index e54ce7e..cb17283 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ This repository contains GitHub Actions workflows and Containerfiles for buildin - **Shibd** - Shibboleth Service Provider daemon - **OpenStack Venv** - Base image for OpenStack services with Python 3.12 - **Apache** - Apache HTTP server with mod_wsgi +- **OVS** - OVS - built within the OpenStack Venv container ## Container Images @@ -285,6 +286,31 @@ docker build \ -t apache:local . ``` +### OVS + +OpenVSwitch Service Provider container: + +**Features:** + +- Minimal footprint for security + +#### Running OVS + +```bash +docker run -d \ + --name ovs \ + ghcr.io/rackspace/genestack-images/ovs:latest +``` + +#### Building OVS + +```bash +docker build \ + -f ContainerFiles/ovs \ + --build-arg OVS_VERSION=master \ + -t ovs:local . +``` + ## Automation Workflows Automated workflows are defined in `.github/workflows/` to build, test, and publish images to GitHub Container Registry (GHCR).