From 9c52732164aa9eb518fcfdc3a5e68e65cfb7c169 Mon Sep 17 00:00:00 2001 From: tawoe Date: Mon, 17 Apr 2023 14:16:09 +0200 Subject: [PATCH] create container pipeline for OC --- .github/Dockerfile_OC | 15 ++++++ .github/Dockerfile_nginx_OC | 24 ++++++++++ .github/apimanager.conf | 27 +++++++++++ .github/gunicorn.conf.py | 10 ++++ .github/local_settings_container.py | 28 +++++++++++ .github/workflows/build_container_image.yml | 49 +++++++++++++++++++ .github/workflows/run_trivy.yml | 52 +++++++++++++++++++++ 7 files changed, 205 insertions(+) create mode 100644 .github/Dockerfile_OC create mode 100644 .github/Dockerfile_nginx_OC create mode 100644 .github/apimanager.conf create mode 100644 .github/gunicorn.conf.py create mode 100644 .github/local_settings_container.py create mode 100644 .github/workflows/build_container_image.yml create mode 100644 .github/workflows/run_trivy.yml diff --git a/.github/Dockerfile_OC b/.github/Dockerfile_OC new file mode 100644 index 0000000..dffd717 --- /dev/null +++ b/.github/Dockerfile_OC @@ -0,0 +1,15 @@ +FROM registry.access.redhat.com/ubi9/python-39 +USER root +RUN dnf update -y +RUN dnf install python3-psycopg2 -y +ADD . /app +COPY ./.github/local_settings_container.py /app/apimanager/apimanager/local_settings.py +COPY ./.github/gunicorn.conf.py /app/gunicorn.conf.py +RUN pip install -r /app/requirements.txt +WORKDIR /app +RUN ./apimanager/manage.py migrate +RUN chgrp -R 0 /app && chmod -R g+rwX /app +USER 501 +WORKDIR /app/apimanager +EXPOSE 8000 +CMD ["gunicorn", "--bind", ":8000", "--config", "../gunicorn.conf.py", "apimanager.wsgi"] \ No newline at end of file diff --git a/.github/Dockerfile_nginx_OC b/.github/Dockerfile_nginx_OC new file mode 100644 index 0000000..32f64d0 --- /dev/null +++ b/.github/Dockerfile_nginx_OC @@ -0,0 +1,24 @@ +FROM registry.access.redhat.com/ubi9/python-39 AS builder +USER 0 +RUN dnf update -y +RUN dnf install python3-psycopg2 -y +ADD . /app +RUN cp /app/.github/local_settings_container.py /app/apimanager/apimanager/local_settings.py +RUN pip install -r /app/requirements.txt +RUN chown 501 / +RUN chown -R 501 /app +RUN chgrp -R 0 /app && chmod -R g+rwX /app +USER 1001 +WORKDIR /app +RUN python ./apimanager/manage.py collectstatic --noinput + +FROM registry.access.redhat.com/ubi9/nginx-120 +USER 0 +RUN dnf update -y +ADD .github/apimanager.conf "${NGINX_DEFAULT_CONF_PATH}" +COPY --from=builder /app/apimanager/static /opt/app-root/src +RUN chgrp -R 0 /opt/app-root/src/ && chmod -R g+rwX /opt/app-root/src/ +USER 1001 +CMD nginx -g "daemon off;" + + diff --git a/.github/apimanager.conf b/.github/apimanager.conf new file mode 100644 index 0000000..aade1e8 --- /dev/null +++ b/.github/apimanager.conf @@ -0,0 +1,27 @@ +#http { +# server { +# listen 8080 default_server; +# listen [::]:8080 default_server; + + server_name apimanager; + + location / { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # enable this if and only if you use HTTPS + # proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_redirect off; + proxy_pass http://127.0.0.1:8000; + } + + location /en/static { + alias /opt/app-root/src; + } + location /es/static { + alias /opt/app-root/src; + } + location /static { + alias /opt/app-root/src; + } +# } +#} diff --git a/.github/gunicorn.conf.py b/.github/gunicorn.conf.py new file mode 100644 index 0000000..b577d07 --- /dev/null +++ b/.github/gunicorn.conf.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import multiprocessing +import os + + +bind = '127.0.0.1:8000' +accesslog = '-' +errorlog = '-' +loglevel = os.getenv('DEBUG_LEVEL', 'info') +workers = multiprocessing.cpu_count() * 2 + 1 diff --git a/.github/local_settings_container.py b/.github/local_settings_container.py new file mode 100644 index 0000000..6f8e30a --- /dev/null +++ b/.github/local_settings_container.py @@ -0,0 +1,28 @@ +import os + +if os.getenv('OAUTH_CONSUMER_KEY'): + OAUTH_CONSUMER_KEY = os.getenv('OAUTH_CONSUMER_KEY') +else: + OAUTH_CONSUMER_KEY = "initial_migration_dummy_value" +if os.getenv('OAUTH_CONSUMER_SECRET'): + OAUTH_CONSUMER_SECRET = os.getenv('OAUTH_CONSUMER_SECRET') +else: + OAUTH_CONSUMER_SECRET = "initial_migration_dummy_value" +if os.getenv('SECRET_KEY'): + SECRET_KEY = os.getenv('SECRET_KEY') +else: + SECRET_KEY = "initial_migration_dummy_value" +if os.getenv('API_HOST'): + API_HOST = os.getenv('API_HOST') +if os.getenv('API_PORTAL'): + API_PORTAL = os.getenv('API_PORTAL') +if os.getenv('ALLOWED_HOSTS'): + ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS').split(',') +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} +STATIC_ROOT = os.path.join(BASE_DIR, 'static') diff --git a/.github/workflows/build_container_image.yml b/.github/workflows/build_container_image.yml new file mode 100644 index 0000000..a1f9153 --- /dev/null +++ b/.github/workflows/build_container_image.yml @@ -0,0 +1,49 @@ +name: build and publish container + +on: [push] +env: + DOCKER_HUB_ORGANIZATION: tawoe + DOCKER_HUB_REPOSITORY_NGINX: apimanager-nginx + DOCKER_HUB_REPOSITORY: api-manager + + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Extract branch name + shell: bash + run: echo "branch=$(echo ${GITHUB_REF#refs/heads/})" >>$GITHUB_OUTPUT + id: extract_branch + + - uses: actions/checkout@v2 + - name: Build the Docker image + run: | + echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" --password-stdin docker.io + docker build . --file .github/Dockerfile_nginx_OC --tag docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY_NGINX }}:$GITHUB_SHA --tag docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY_NGINX }}:${{ steps.extract_branch.outputs.branch }}-OC + docker push docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY_NGINX }} --all-tags + echo docker apimanager-nginx done + docker build . --file .github/Dockerfile_OC --tag docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:$GITHUB_SHA --tag docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:${{ steps.extract_branch.outputs.branch }}-OC + docker push docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }} --all-tags + echo docker api-manager done + - uses: sigstore/cosign-installer@main + - name: Write signing key to disk (only needed for `cosign sign --key`) + run: echo "${{ secrets.COSIGN_PRIVATE_KEY }}" > cosign.key + - name: Sign container image with annotations from our environment + env: + COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} + run: | + cosign sign -y --key cosign.key \ + -a "repo=${{ github.repository }}" \ + -a "workflow=${{ github.workflow }}" \ + -a "ref=${{ github.sha }}" \ + docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:${{ steps.extract_branch.outputs.branch }}-OC + cosign sign -y --key cosign.key \ + -a "repo=${{ github.repository }}" \ + -a "workflow=${{ github.workflow }}" \ + -a "ref=${{ github.sha }}-nginx" \ + docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY_NGINX }}:${{ steps.extract_branch.outputs.branch }}-OC + + + diff --git a/.github/workflows/run_trivy.yml b/.github/workflows/run_trivy.yml new file mode 100644 index 0000000..83e3df3 --- /dev/null +++ b/.github/workflows/run_trivy.yml @@ -0,0 +1,52 @@ +name: scan container image + +on: + workflow_run: + workflows: [build and publish container] + types: + - completed +env: + ## Sets environment variable + DOCKER_HUB_ORGANIZATION: tawoe + DOCKER_HUB_REPOSITORY: api-manager + + +jobs: + build: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + + steps: + - uses: actions/checkout@v3 + - id: trivy-db + name: Check trivy db sha + env: + GH_TOKEN: ${{ github.token }} + run: | + endpoint='/orgs/aquasecurity/packages/container/trivy-db/versions' + headers='Accept: application/vnd.github+json' + jqFilter='.[] | select(.metadata.container.tags[] | contains("latest")) | .name | sub("sha256:";"")' + sha=$(gh api -H "${headers}" "${endpoint}" | jq --raw-output "${jqFilter}") + echo "Trivy DB sha256:${sha}" + echo "::set-output name=sha::${sha}" + - uses: actions/cache@v3 + with: + path: .trivy + key: ${{ runner.os }}-trivy-db-${{ steps.trivy-db.outputs.sha }} + - name: Run Trivy vulnerability scanner + uses: aquasecurity/trivy-action@master + with: + image-ref: 'docker.io/${{ env.DOCKER_HUB_ORGANIZATION }}/${{ env.DOCKER_HUB_REPOSITORY }}:${{ github.sha }}' + format: 'template' + template: '@/contrib/sarif.tpl' + output: 'trivy-results.sarif' + security-checks: 'vuln' + severity: 'CRITICAL,HIGH' + timeout: '30m' + cache-dir: .trivy + - name: Fix .trivy permissions + run: sudo chown -R $(stat . -c %u:%g) .trivy + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: 'trivy-results.sarif' \ No newline at end of file