diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..5675917 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,76 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "main" ] + schedule: + - cron: '30 21 * * 3' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/sast.yml b/.github/workflows/sast.yml index 5e57d21..1221246 100644 --- a/.github/workflows/sast.yml +++ b/.github/workflows/sast.yml @@ -5,10 +5,10 @@ on: push: branches: ['main'] workflow_dispatch: - ## Start: Version 3 - #pull_request: - # types: [opened, reopened, synchronize] - ## End: Version 3 + # Start: Version 3 + pull_request: + types: [opened, reopened, synchronize] + # End: Version 3 jobs: scan: @@ -37,25 +37,27 @@ jobs: - ## Start: Version 2 - #- name: Install dependencies - # shell: bash - # run: | - # pip install bandit-sarif-formatter bandit + # Start: Version 2 + - name: Install dependencies + shell: bash + run: | + pip install bandit-sarif-formatter bandit + + - #- name: Bandit - # shell: bash - # run: | - # bandit -f sarif -o results.sarif -r --exit-zero . + - name: Bandit + shell: bash + run: | + bandit -f sarif -o results.sarif -r --exit-zero . - #- name: Upload artifact - # uses: actions/upload-artifact@main - # with: - # name: results.sarif - # path: results.sarif - - #- name: Upload SARIF file - # uses: github/codeql-action/upload-sarif@v2 - # with: - # sarif_file: results.sarif - ## End: Version 2 \ No newline at end of file + - name: Upload artifact + uses: actions/upload-artifact@main + with: + name: results.sarif + path: results.sarif + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: results.sarif + # End: Version 2 diff --git a/.github/workflows/secrets.yml b/.github/workflows/secrets.yml index efa3eb9..7ac1af1 100644 --- a/.github/workflows/secrets.yml +++ b/.github/workflows/secrets.yml @@ -4,19 +4,19 @@ on: push: branches: ['main'] workflow_dispatch: - ## Start: Version 3 - #pull_request: - # types: [opened, reopened, synchronize] - ## End: Version 3 + # Start: Version 3 + pull_request: + types: [opened, reopened, synchronize] + # End: Version 3 jobs: scan: runs-on: ubuntu-latest steps: - ## Start: Version 0 + # Start: Version 0 - name: Checkout repository uses: actions/checkout@v3 - ## End: Version 0 + # End: Version 0 @@ -29,22 +29,22 @@ jobs: - ## Start: Version 2 - #- name: GitLeaks - # continue-on-error: true - # uses: gitleaks/gitleaks-action@v2 - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # GITLEAKS_ENABLE_UPLOAD_ARTIFACT: false - - #- name: Upload artifact - # uses: actions/upload-artifact@main - # with: - # name: results.sarif - # path: results.sarif - - #- name: Upload SARIF file - # uses: github/codeql-action/upload-sarif@v2 - # with: - # sarif_file: results.sarif - ## End: Version 2 + # Start: Version 2 + - name: GitLeaks + continue-on-error: true + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITLEAKS_ENABLE_UPLOAD_ARTIFACT: false + + - name: Upload artifact + uses: actions/upload-artifact@main + with: + name: results.sarif + path: results.sarif + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: results.sarif + # End: Version 2 diff --git a/.github/workflows/trivy_scanning.yml b/.github/workflows/trivy_scanning.yml index ff5250e..c1db197 100644 --- a/.github/workflows/trivy_scanning.yml +++ b/.github/workflows/trivy_scanning.yml @@ -14,7 +14,7 @@ jobs: name: Container Scanning with Trivy runs-on: ubuntu-20.04 steps: - ## Start: Version 0 + # Start: Version 0 - name: Checkout code uses: actions/checkout@v3 @@ -23,7 +23,7 @@ jobs: uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - ## End: Version 0 + # End: Version 0 @@ -38,31 +38,31 @@ jobs: # env: # TRIVY_USERNAME: ${{ github.actor }} # TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} - ## End: Version 1 + # End: Version 1 - ## Start: Version 2 - #- name: Trivy - # uses: aquasecurity/trivy-action@master - # with: - # image-ref: ${{ steps.meta.outputs.tags }} - # format: 'sarif' - # output: 'trivy-results.sarif' - # env: - # TRIVY_USERNAME: ${{ github.actor }} - # TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} - # - #- name: Upload artifact - # uses: actions/upload-artifact@main - # with: - # name: 'trivy-results.sarif' - # path: 'trivy-results.sarif' - # - #- name: Upload Trivy scan results to GitHub Security tab - # uses: github/codeql-action/upload-sarif@v2 - # with: - # sarif_file: 'trivy-results.sarif' - ## End: Version 2 \ No newline at end of file + # Start: Version 2 + - name: Trivy + uses: aquasecurity/trivy-action@master + with: + image-ref: ${{ steps.meta.outputs.tags }} + format: 'sarif' + output: 'trivy-results.sarif' + env: + TRIVY_USERNAME: ${{ github.actor }} + TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload artifact + uses: actions/upload-artifact@main + with: + name: 'trivy-results.sarif' + path: 'trivy-results.sarif' + + - name: Upload Trivy scan results to GitHub Security tab + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: 'trivy-results.sarif' + # End: Version 2 diff --git a/README.md b/README.md index e8949a9..e069281 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,20 @@ # Module 3: DevSecOps Example + +This project demonstrates a basic example of how security can be integrated into development workflows. + +--- + +## Scenario + +You are a **DevOps Engineer**. Until now, the team you are working with has not implemented any security activities in their project. +As your project becomes more mature, the project manager decides it's time to step up and start securing the project. +Now, it's your job to introduce security activities into the project. You start with the following two DevOps phases: + +- **Build** +- **Code** + +--- +# Module 3: DevSecOps Example This project is a basic example on how integrate security can be integrated into development workflows. ## Scenario diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..034e848 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +Tell them where to go, how often they can expect to get an update on a +reported vulnerability, what to expect if the vulnerability is accepted or +declined, etc. diff --git a/abctest.md b/abctest.md new file mode 100644 index 0000000..626e4e2 --- /dev/null +++ b/abctest.md @@ -0,0 +1,3 @@ +# Disaster Recovery Exercise Summary +abc +**Date:** [20 August] diff --git a/poetry.lock b/poetry.lock index e3c6ae6..0642aed 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,16 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + [[package]] name = "certifi" -version = "2022.9.24" +version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, +] [[package]] name = "charset-normalizer" @@ -13,9 +19,13 @@ description = "The Real First Universal Charset Detector. Open, modern and activ category = "main" optional = false python-versions = ">=3.6.0" +files = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +] [package.extras] -unicode_backport = ["unicodedata2"] +unicode-backport = ["unicodedata2"] [[package]] name = "click" @@ -24,6 +34,10 @@ description = "Composable command line interface toolkit" category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -35,6 +49,10 @@ description = "Cross-platform colored terminal text." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, + {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, +] [[package]] name = "Flask" @@ -43,6 +61,10 @@ description = "A simple framework for building complex web applications." category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "Flask-2.2.2-py3-none-any.whl", hash = "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"}, + {file = "Flask-2.2.2.tar.gz", hash = "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b"}, +] [package.dependencies] click = ">=8.0" @@ -61,6 +83,10 @@ description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] [[package]] name = "itsdangerous" @@ -69,6 +95,10 @@ description = "Safely pass data to untrusted environments and back." category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, + {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, +] [[package]] name = "Jinja2" @@ -77,6 +107,10 @@ description = "A very fast and expressive template engine." category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] [package.dependencies] MarkupSafe = ">=2.0" @@ -91,91 +125,7 @@ description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false python-versions = ">=3.7" - -[[package]] -name = "requests" -version = "2.28.1" -description = "Python HTTP for Humans." -category = "main" -optional = false -python-versions = ">=3.7, <4" - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<3" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "urllib3" -version = "1.26.12" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - -[[package]] -name = "Werkzeug" -version = "2.2.2" -description = "The comprehensive WSGI web application library." -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -MarkupSafe = ">=2.1.1" - -[package.extras] -watchdog = ["watchdog"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.10" -content-hash = "ea28afaf58e945483b48456b90815c9510cd842c9d03199c945d3a0d61720108" - -[metadata.files] -certifi = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, -] -charset-normalizer = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -Flask = [ - {file = "Flask-2.2.2-py3-none-any.whl", hash = "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"}, - {file = "Flask-2.2.2.tar.gz", hash = "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b"}, -] -idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, -] -itsdangerous = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, -] -Jinja2 = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, -] -MarkupSafe = [ +files = [ {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, @@ -217,15 +167,65 @@ MarkupSafe = [ {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] -requests = [ + +[[package]] +name = "requests" +version = "2.28.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" +files = [ {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, ] -urllib3 = [ + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "urllib3" +version = "1.26.12" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" +files = [ {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, ] -Werkzeug = [ + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "Werkzeug" +version = "2.2.2" +description = "The comprehensive WSGI web application library." +category = "main" +optional = false +python-versions = ">=3.7" +files = [ {file = "Werkzeug-2.2.2-py3-none-any.whl", hash = "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"}, {file = "Werkzeug-2.2.2.tar.gz", hash = "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f"}, ] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "ea28afaf58e945483b48456b90815c9510cd842c9d03199c945d3a0d61720108"