diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml new file mode 100644 index 0000000..f6c2c29 --- /dev/null +++ b/.github/workflows/container.yml @@ -0,0 +1,53 @@ +name: Container Image Builds + +on: + push: + branches: [ main ] + tags: ["v*"] + workflow_dispatch: + +jobs: + images: + name: Build images + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Login to GitHub Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ vars.IMAGE_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Setup container meta information + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ vars.IMAGE_REGISTRY }}/${{ github.repository }} + labels: | + org.opencontainers.image.vendor=Greenbone + org.opencontainers.image.base.name=debian:stable-slim + tags: | + # create container tag for git tags + type=ref,event=tag + # set edge for default branch + type=edge + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and push Container image + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + file: docker/Dockerfile + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/README.md b/README.md index 22aeffa..d27cc39 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ at https://services.nvd.nist.gov/rest/json/cves/2.0. - [Install using pip](#install-using-pip) - [Usage](#usage) - [Settings](#settings) +- [Docker Compose](#docker-compose) - [Development](#development) - [Maintainer](#maintainer) - [License](#license) @@ -63,7 +64,7 @@ Using uvicorn directly allows for more flexibility regarding the [settings](http for serving the API. After starting the web server the CVE API is available at `http://127.0.0.1:8000/cves` -by default. [Interactive API docs](https://github.com/swagger-api/swagger-ui) +(by default). [Interactive API docs](https://github.com/swagger-api/swagger-ui) are served at `http://127.0.0.1:8000/docs`. ## Settings @@ -82,6 +83,33 @@ are served at `http://127.0.0.1:8000/docs`. | API_PORT | Port to listen on | 8000 | | LOG_LEVEL | Log level for server output. Options are `critical`, `error`, `warning`, `info`, `debug` and `trace`. | `info` | +## Docker Compose + +The API is easiest to use via the provided [docker compose](https://docs.docker.com/compose/) +file. [The compose file](./docker/compose.yml) extends the compose file of +[greenbone-scap](https://github.com/greenbone/greenbone-scap/blob/main/docker/compose.yml). +Please take a look at the [README of greenbone-scap](https://github.com/greenbone/greenbone-scap?tab=readme-ov-file#docker-compose) +for the initial setup of the containers. + +For a quick setup the following commands can be used: + +```sh +cd docker +echo "DATABASE_PASSWORD=my-super-safe-password" > .env +docker compose up +``` + +After starting the containers the CVE API is available at `http://127.0.0.1:8000/cves` +(by default). [Interactive API docs](https://github.com/swagger-api/swagger-ui) +are served at `http://127.0.0.1:8000/docs`. + +> [!NOTE] +> On the initial startup all CVE will be downloaded from the [NIST NVD API](https://services.nvd.nist.gov/rest/json/cves/2.0). +> Downloading the data may take several hours and due to unreliable servers at +> NIST may even fail. After a successful full download of the data at NIST, only +> the changed and new CVEs will be downloaded. To trigger a download +> `docker compose up cve` can be used. + ## Development **greenbone-scap-api** uses [poetry] for its own dependency management and build diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..e543ff9 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,50 @@ +FROM debian:stable-slim as builder + +COPY . /source + +WORKDIR /source + +RUN apt-get update && \ + apt-get install --no-install-recommends --no-install-suggests -y \ + python3 \ + python-is-python3 \ + pipx && \ + apt-get remove --purge --auto-remove -y && \ + rm -rf /var/lib/apt/lists/* + +RUN pipx install poetry + +RUN rm -rf dist && /root/.local/bin/poetry build -f wheel + +FROM debian:stable-slim + +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 +ENV PIP_NO_CACHE_DIR off + +WORKDIR /greenbone-scap-api + +RUN apt-get update && \ + apt-get install --no-install-recommends --no-install-suggests -y \ + gosu \ + python3 \ + python-is-python3 \ + python3-pip \ + libpq5 && \ + apt-get remove --purge --auto-remove -y && \ + rm -rf /var/lib/apt/lists/* + +RUN addgroup --gid 1001 --system greenbone && \ + adduser --no-create-home --shell /bin/false --disabled-password --uid 1001 --system --group greenbone + +COPY --from=builder /source/dist/* /greenbone-scap-api/ +COPY docker/entrypoint.sh /usr/local/bin/entrypoint + +RUN python3 -m pip install --break-system-packages /greenbone-scap-api/* + +RUN chown -R greenbone:greenbone /greenbone-scap-api && \ + chmod 755 /usr/local/bin/entrypoint + +ENTRYPOINT [ "/usr/local/bin/entrypoint" ] + +CMD ["greenbone-scap-api"] diff --git a/docker/compose.yml b/docker/compose.yml new file mode 100644 index 0000000..bf6031f --- /dev/null +++ b/docker/compose.yml @@ -0,0 +1,45 @@ +name: greenbone-scap + +services: + db: + image: postgres:15-bookworm + restart: always + environment: + POSTGRES_DB: scap + POSTGRES_USER: scap + POSTGRES_PASSWORD: ${DATABASE_PASSWORD} + volumes: + - postgres:/var/lib/postgresql/data + ports: + - 5432:5432 + + cve: + image: ghcr.io/greenbone/greenbone-scap + depends_on: + - db + environment: + DATABASE_HOST: db + DATABASE_NAME: scap + DATABASE_USER: scap + DATABASE_PASSWORD: ${DATABASE_PASSWORD} + NVD_API_KEY: ${NVD_API_KEY} + volumes: + - data:/mnt/data + command: ["greenbone-cve-download", "--since-from-file", "/mnt/data/last-cve-download", "--store-runtime", "/mnt/data/last-cve-download"] + + cve-api: + image: ghcr.io/greenbone/greenbone-scap-api + depends_on: + - db + environment: + DATABASE_HOST: db + DATABASE_NAME: scap + DATABASE_USER: scap + DATABASE_PASSWORD: ${DATABASE_PASSWORD} + API_HOST: 0.0.0.0 + ports: + - 8000:8000 + +volumes: + postgres: + data: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..5e0ec02 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +exec gosu greenbone "$@"