Building a DevSecOps Pipeline for Flask application

In this article, we will build a DevSecOps CI pipeline for a flask application.

We will use a very simple flask application in this article and we will host the application using Gunicorn.

Below is the code for the flask application:

https://github.com/lalith2211/DevSecOps-flask

app.py:

# app.py
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/')
def home():
    return jsonify({"message": "Welcome to the Flask DevSecOps App!"})

@app.route('/health')
def health():
    return jsonify({"status": "healthy"}), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

requirements.txt:

Flask
gunicorn

gunicorn_config.py:

import os

workers = int(os.environ.get('GUNICORN_PROCESSES', '2'))
threads = int(os.environ.get('GUNICORN_THREADS', '4'))
bind = os.environ.get('GUNICORN_BIND', '0.0.0.0:8080')
forwarded_allow_ips = '*'
secure_scheme_headers = { 'X-Forwarded-Proto': 'https' }

dockerfile:

FROM python:3.10:slim
WORKDIR /app
COPY app.py requirements.txt gunicorn_config.py /app/
RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["gunicorn","-b","0.0.0.0:5000","app:app"]

Build docker using the below command test it:

docker build -t sailalithv/flask-devsecops-app .
docker run -b 5000:5000 sailalithv/flask-devsecops-app

Great! Now that we are done with our application and dockerfile. Let’s push the dockerfile to docker hub:

docker login

docker push sailalithv/flask-devsecops-app

Now, lets get started with the github actions workflow:

name: DevSecOps Pipeline for Flask Application (Gunicorn) 

on:
  push:
    branches:
     - main

jobs:
  build:
    runs-on: Ubuntu-latest
    steps:
    - name: Setup Python            
      uses: actions/setup-python@v5.4.0
      with:
        python-version: '3.10'

    - name: Checkout
      uses: actions/checkout@v4.2.2

    - name: install requirements
      run: |
        pip install -r requirements.txt
        pip install flake8 bandit safety

    - name: code linting
      run: flake8 app.py

    # Bandit scans Python code for common security issues like insecure use of eval().
    - name: Bandit Scan
      run: bandit -r .

    # using Safety - for checking the vulnerabilites in the packages
    - name: safety package auditing
      run: safety check --file=requirements.txt 

    - name: Gitleaks
      uses: gitleaks/gitleaks-action@v2.3.4

    - name: Docker Login
      uses: docker/login-action@v3.3.0
      with:
        username: sailalithdevops
        password: ${{ secrets.DOCKER_PASSWORD }}

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3

    - name: Docker Build and push
      uses: docker/build-push-action@v6
      with:
        push: true
        tags: sailalithdevops/flask-devsecops-app:${{ github.run_id }}
        provenance: true
        sbom: true

This code only consists of pushing the build image to docker registry.

some sample outputs if something goes wrong in the CI steps:

Bandit error:

[main]    INFO    profile include tests: None
[main]    INFO    profile exclude tests: None
[main]    INFO    cli include tests: None
[main]    INFO    cli exclude tests: None
[main]    INFO    running on Python 3.10.16
Run started:2025-03-06 13:35:23.472408

Test results:
>> Issue: [B104:hardcoded_bind_all_interfaces] Possible binding to all interfaces.
   Severity: Medium   Confidence: Medium
   CWE: CWE-605 (https://cwe.mitre.org/data/definitions/605.html)
   More Info: https://bandit.readthedocs.io/en/1.8.3/plugins/b104_hardcoded_bind_all_interfaces.html
   Location: ./app.py:17:17
16    if __name__ == '__main__':
17        app.run(host='0.0.0.0', port=5000)

--------------------------------------------------

Code scanned:
    Total lines of code: 16
    Total lines skipped (#nosec): 0
    Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0

Run metrics:
    Total issues (by severity):
        Undefined: 0
        Low: 0
        Medium: 1
        High: 0
    Total issues (by confidence):
        Undefined: 0
        Low: 0
        Medium: 1
        High: 0
Files skipped (0):
Error: Process completed with exit code 1.

0
Subscribe to my newsletter

Read articles from Sai Lalith Voopalanchi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sai Lalith Voopalanchi
Sai Lalith Voopalanchi