├── .gitattributes ├── .gitignore ├── LICENSE ├── Readme.md ├── Vagrantfile ├── assets └── devsecops.png ├── defectdojo └── docker-compose.yml ├── jenkins ├── Dockerfile ├── docker-compose.yml ├── jenkins-casc.yaml └── plugins.txt ├── nexus └── docker-compose.yml ├── nginx └── devsecops.conf ├── provision.sh ├── provision.yml ├── sonarqube └── docker-compose.yml └── zap └── docker-compose.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | .idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Alexey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 |

🐍 Python DevSecOps pipeline

2 | 3 |

4 | 5 | 6 | 7 | 8 | 9 | 10 |

11 | 12 |

Виртуальная инфраструктура для быстрой интеграции DevSecOps в процессы разработки веб-приложений на Python3.

13 | 14 | ## 🚀 Let's go! 15 | 16 |

17 | 18 |

19 | 20 | 1. Добавьте следующее в ваш `hosts` файл: 21 | 22 | ```text 23 | 127.0.0.1 jenkins.devops.local 24 | 127.0.0.1 defectdojo.devops.local 25 | 127.0.0.1 sonarqube.devops.local 26 | 127.0.0.1 nexus.devops.local 27 | 127.0.0.1 zap.devops.local 28 | 127.0.0.1 api.zap.devops.local 29 | 127.0.0.1 sandbox.devops.local 30 | ``` 31 | 32 | > [!TIP] 33 | > Где находится файл hosts? 34 | > 35 | > В Windows: `C:\Windows\System32\hosts` 36 | > 37 | > В Linux: `/etc/hosts` 38 | 39 | 2. Запустите виртуалку: 40 | 41 | > [!WARNING] 42 | > Должны быть установлены `Vagrant` и `VirtualBox`. 43 | 44 | > [!TIP] 45 | > Базовый box `ubuntu/focal64` можно скачать [отсюда](https://portal.cloud.hashicorp.com/vagrant/discover/ubuntu/focal64). 46 | 47 | ```shell 48 | vagrant up 49 | ``` 50 | 51 | ## 🔒 Первичный доступ к сервисам 52 | 53 | ### Jenkins 54 | 55 | - Админ: `admin:admin` 56 | 57 | - Разработчик: `developer:developer` 58 | 59 | - Наблюдатель: `viewer:viewer` 60 | 61 | ### SonarQube 62 | 63 | Логин: `admin` 64 | 65 | Пароль: `admin` 66 | 67 | ### DefectDojo 68 | 69 | Логин: `admin` 70 | 71 | Пароль получаем командой: 72 | 73 | ```shell 74 | vagrant ssh -c "cd /vagrant/defectdojo && sudo docker compose logs initializer | grep 'Admin password:'" 75 | ``` 76 | 77 | ### Nexus 78 | 79 | Логин: `admin` 80 | 81 | Пароль получаем командой: 82 | 83 | ```shell 84 | vagrant ssh -c "cd /vagrant/nexus && sudo docker compose exec nexus cat /nexus-data/admin.password 85 | ``` 86 | 87 | ## 🚩 Уязвимые приложения 88 | 89 | TODO: дописать 90 | 91 | ## 📈 Тестирование эффективности 92 | 93 | TODO: сравнительная таблица для заложенных и найденных уязвимостей в приложениях 94 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | 6 | config.vm.define "devsecops" do |devsecops| 7 | devsecops.vm.box = "ubuntu/focal64" 8 | devsecops.vm.hostname = "devsecops-vm" 9 | devsecops.vm.network "private_network", ip: "192.168.56.10" 10 | devsecops.vm.network "forwarded_port", guest: 80, host: 80 11 | 12 | config.vm.provider "virtualbox" do |vb| 13 | vb.memory = "6144" 14 | vb.cpus = "5" 15 | end 16 | 17 | config.vm.provision "shell", inline: <<-SHELL 18 | apt-get update 19 | apt-get install -y ansible 20 | ansible-galaxy collection install community.docker --force 21 | SHELL 22 | 23 | config.vm.provision "ansible_local" do |ansible| 24 | ansible.playbook = "/vagrant/provision.yml" 25 | ansible.compatibility_mode = "2.0" 26 | ansible.install = false 27 | end 28 | 29 | end 30 | 31 | config.vm.define "sandbox" do |sandbox| 32 | sandbox.vm.box = "ubuntu/focal64" 33 | sandbox.vm.hostname = "sandbox" 34 | sandbox.vm.network "private_network", ip: "192.168.56.20" 35 | #sandbox.vm.network "forwarded_port", guest: 9000, host: 9000 36 | 37 | sandbox.vm.synced_folder ".", "/vagrant", disabled: true 38 | 39 | sandbox.vm.provider "virtualbox" do |vb| 40 | vb.memory = "2048" 41 | vb.cpus = "2" 42 | end 43 | 44 | sandbox.vm.provision "shell", inline: <<-SHELL 45 | apt-get update 46 | apt-get install -y docker.io 47 | docker volume create portainer_data 48 | docker run -d -p 9000:9000 --name portainer \ 49 | -v /var/run/docker.sock:/var/run/docker.sock \ 50 | -v portainer_data:/data \ 51 | portainer/portainer-ce 52 | SHELL 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /assets/devsecops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/light-hat/python-devsecops/a8dca4550dd20f604e63293283ce30b0950ea113/assets/devsecops.png -------------------------------------------------------------------------------- /defectdojo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | defect-router: 4 | image: "defectdojo/defectdojo-nginx:${NGINX_VERSION:-latest}" 5 | depends_on: 6 | - uwsgi 7 | environment: 8 | NGINX_METRICS_ENABLED: "${NGINX_METRICS_ENABLED:-false}" 9 | volumes: 10 | - defectdojo_media:/usr/share/nginx/html/media 11 | ports: 12 | - "127.0.0.1:8081:8080" 13 | restart: always 14 | networks: 15 | - dojo_internal 16 | - devsecops_network 17 | 18 | uwsgi: 19 | image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" 20 | depends_on: 21 | - postgres 22 | entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST:-postgres}:${DD_DATABASE_PORT:-5432}', '-t', '30', '--', '/entrypoint-uwsgi.sh'] 23 | environment: 24 | DD_DEBUG: 'False' 25 | DD_DJANGO_METRICS_ENABLED: "${DD_DJANGO_METRICS_ENABLED:-False}" 26 | DD_ALLOWED_HOSTS: "${DD_ALLOWED_HOSTS:-*}" 27 | DD_DATABASE_URL: ${DD_DATABASE_URL:-postgresql://defectdojo:defectdojo@postgres:5432/defectdojo} 28 | DD_CELERY_BROKER_URL: ${DD_CELERY_BROKER_URL:-redis://redis:6379/0} 29 | DD_SECRET_KEY: "${DD_SECRET_KEY:-hhZCp@D28z!n@NED*yB!ROMt+WzsY*iq}" 30 | DD_CREDENTIAL_AES_256_KEY: "${DD_CREDENTIAL_AES_256_KEY:-&91a*agLqesc*0DJ+2*bAbsUZfR*4nLw}" 31 | DD_DATABASE_READINESS_TIMEOUT: "${DD_DATABASE_READINESS_TIMEOUT:-30}" 32 | volumes: 33 | - "defectdojo_media:${DD_MEDIA_ROOT:-/app/media}" 34 | restart: always 35 | networks: 36 | - dojo_internal 37 | 38 | celerybeat: 39 | image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" 40 | depends_on: 41 | - postgres 42 | - redis 43 | entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST:-postgres}:${DD_DATABASE_PORT:-5432}', '-t', '30', '--', '/entrypoint-celery-beat.sh'] 44 | environment: 45 | DD_DATABASE_URL: ${DD_DATABASE_URL:-postgresql://defectdojo:defectdojo@postgres:5432/defectdojo} 46 | DD_CELERY_BROKER_URL: ${DD_CELERY_BROKER_URL:-redis://redis:6379/0} 47 | DD_SECRET_KEY: "${DD_SECRET_KEY:-hhZCp@D28z!n@NED*yB!ROMt+WzsY*iq}" 48 | DD_CREDENTIAL_AES_256_KEY: "${DD_CREDENTIAL_AES_256_KEY:-&91a*agLqesc*0DJ+2*bAbsUZfR*4nLw}" 49 | DD_DATABASE_READINESS_TIMEOUT: "${DD_DATABASE_READINESS_TIMEOUT:-30}" 50 | restart: always 51 | networks: 52 | - dojo_internal 53 | 54 | celeryworker: 55 | image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" 56 | depends_on: 57 | - postgres 58 | - redis 59 | entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST:-postgres}:${DD_DATABASE_PORT:-5432}', '-t', '30', '--', '/entrypoint-celery-worker.sh'] 60 | environment: 61 | DD_DATABASE_URL: ${DD_DATABASE_URL:-postgresql://defectdojo:defectdojo@postgres:5432/defectdojo} 62 | DD_CELERY_BROKER_URL: ${DD_CELERY_BROKER_URL:-redis://redis:6379/0} 63 | DD_SECRET_KEY: "${DD_SECRET_KEY:-hhZCp@D28z!n@NED*yB!ROMt+WzsY*iq}" 64 | DD_CREDENTIAL_AES_256_KEY: "${DD_CREDENTIAL_AES_256_KEY:-&91a*agLqesc*0DJ+2*bAbsUZfR*4nLw}" 65 | DD_DATABASE_READINESS_TIMEOUT: "${DD_DATABASE_READINESS_TIMEOUT:-30}" 66 | volumes: 67 | - "defectdojo_media:${DD_MEDIA_ROOT:-/app/media}" 68 | restart: always 69 | networks: 70 | - dojo_internal 71 | 72 | initializer: 73 | image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" 74 | depends_on: 75 | - postgres 76 | entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST:-postgres}:${DD_DATABASE_PORT:-5432}', '--', '/entrypoint-initializer.sh'] 77 | environment: 78 | DD_DATABASE_URL: ${DD_DATABASE_URL:-postgresql://defectdojo:defectdojo@postgres:5432/defectdojo} 79 | DD_ADMIN_USER: "${DD_ADMIN_USER:-admin}" 80 | DD_ADMIN_MAIL: "${DD_ADMIN_USER:-admin@defectdojo.local}" 81 | DD_ADMIN_FIRST_NAME: "${DD_ADMIN_FIRST_NAME:-Admin}" 82 | DD_ADMIN_LAST_NAME: "${DD_ADMIN_LAST_NAME:-User}" 83 | DD_INITIALIZE: "${DD_INITIALIZE:-true}" 84 | DD_SECRET_KEY: "${DD_SECRET_KEY:-hhZCp@D28z!n@NED*yB!ROMt+WzsY*iq}" 85 | DD_CREDENTIAL_AES_256_KEY: "${DD_CREDENTIAL_AES_256_KEY:-&91a*agLqesc*0DJ+2*bAbsUZfR*4nLw}" 86 | DD_DATABASE_READINESS_TIMEOUT: "${DD_DATABASE_READINESS_TIMEOUT:-30}" 87 | networks: 88 | - dojo_internal 89 | 90 | postgres: 91 | image: postgres:17.1-alpine@sha256:0d9624535618a135c5453258fd629f4963390338b11aaffb92292c12df3a6c17 92 | environment: 93 | POSTGRES_DB: ${DD_DATABASE_NAME:-defectdojo} 94 | POSTGRES_USER: ${DD_DATABASE_USER:-defectdojo} 95 | POSTGRES_PASSWORD: ${DD_DATABASE_PASSWORD:-defectdojo} 96 | volumes: 97 | - defectdojo_postgres:/var/lib/postgresql/data 98 | restart: always 99 | networks: 100 | - dojo_internal 101 | 102 | redis: 103 | image: redis:7.2.5-alpine@sha256:6aaf3f5e6bc8a592fbfe2cccf19eb36d27c39d12dab4f4b01556b7449e7b1f44 104 | volumes: 105 | - defectdojo_redis:/data 106 | restart: always 107 | networks: 108 | - dojo_internal 109 | 110 | volumes: 111 | defectdojo_postgres: {} 112 | defectdojo_media: {} 113 | defectdojo_redis: {} 114 | 115 | networks: 116 | devsecops_network: 117 | external: true 118 | dojo_internal: 119 | -------------------------------------------------------------------------------- /jenkins/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins/jenkins:lts-jdk17 2 | 3 | USER root 4 | 5 | RUN apt-get update && \ 6 | apt-get install -y docker.io && \ 7 | rm -rf /var/lib/apt/lists/* 8 | 9 | USER jenkins 10 | 11 | COPY plugins.txt /usr/share/jenkins/ref/plugins.txt 12 | 13 | RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt 14 | 15 | ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false" 16 | 17 | COPY jenkins-casc.yaml /var/jenkins_home/casc_configs/jenkins.yaml 18 | 19 | ENV CASC_JENKINS_CONFIG="/var/jenkins_home/casc_configs/jenkins.yaml" 20 | -------------------------------------------------------------------------------- /jenkins/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | jenkins: 3 | build: . 4 | restart: always 5 | user: root 6 | ports: 7 | - "127.0.0.1:8080:8080" 8 | - "127.0.0.1:50000:50000" 9 | volumes: 10 | - jenkins_home:/var/jenkins_home 11 | - /var/run/docker.sock:/var/run/docker.sock 12 | networks: 13 | - devsecops_network 14 | 15 | volumes: 16 | jenkins_home: 17 | 18 | networks: 19 | devsecops_network: 20 | external: true 21 | -------------------------------------------------------------------------------- /jenkins/jenkins-casc.yaml: -------------------------------------------------------------------------------- 1 | jenkins: 2 | systemMessage: "Jenkins сконфигурирован автоматически при помощи JCasC." 3 | 4 | # Security Realm for user authentication 5 | securityRealm: 6 | local: 7 | allowsSignup: false 8 | users: 9 | - id: "admin" 10 | password: "admin" 11 | 12 | - id: "developer" 13 | password: "developer" 14 | 15 | - id: "viewer" 16 | password: "viewer" 17 | 18 | # Authorization Strategy 19 | authorizationStrategy: 20 | projectMatrix: 21 | entries: 22 | - user: 23 | name: admin 24 | permissions: 25 | - Overall/Administer 26 | - user: 27 | name: developer 28 | permissions: 29 | - Overall/Read 30 | - Job/Build 31 | - user: 32 | name: viewer 33 | permissions: 34 | - Overall/Read 35 | 36 | # Tool Configuration 37 | tool: 38 | git: 39 | installations: 40 | - name: "Default" 41 | home: "/usr/bin/git" 42 | maven: 43 | installations: 44 | - name: maven3 45 | properties: 46 | - installSource: 47 | installers: 48 | - maven: 49 | id: "3.8.4" 50 | 51 | # Sample Job Configuration 52 | jobs: 53 | - script: > 54 | pipelineJob('Template DevSecOps pipeline') { 55 | parameters { 56 | stringParam('REPO_URL', 'https://github.com/Contrast-Security-OSS/vulnpy', 'URL репозитория для клонирования') 57 | stringParam('BRANCH_NAME', 'master', 'Ветка для клонирования') 58 | } 59 | definition { 60 | cps { 61 | script(''' 62 | pipeline { 63 | agent any 64 | stages { 65 | stage('Checkout') { 66 | steps { 67 | checkout([$class: 'GitSCM', 68 | branches: [[name: "*/${params.BRANCH_NAME}"]], //${params.BRANCH_NAME} 69 | userRemoteConfigs: [[url: "${params.REPO_URL}"]] //${params.REPO_URL} 70 | ]) 71 | } 72 | } 73 | stage('SAST (Bandit)') { 74 | agent { 75 | docker { 76 | image 'python:3.10' 77 | } 78 | } 79 | steps { 80 | echo 'Preparing environment...' 81 | sh 'pip install bandit' 82 | sh 'python3 -m bandit -r .' 83 | } 84 | } 85 | stage('SonarQube Analysis') { 86 | steps { 87 | script { 88 | def scannerHome = tool 'SonarScanner'; 89 | def projectKey=test; 90 | } 91 | withSonarQubeEnv('SonarQube') { 92 | sh "'${scannerHome}/bin/sonar-scanner' -Dsonar.projectKey=${projectKey} -Dsonar.sources=." 93 | } 94 | } 95 | } 96 | stage('SCA (Dependency-Check)') { 97 | steps { 98 | script { 99 | dependencyCheck analysisMode: 'INCREMENTAL', 100 | project: 'MyProject', 101 | zipExtensions: '', 102 | failBuildOnCVSS: '7.0', 103 | active: true 104 | } 105 | } 106 | } 107 | stage('Deploy') { 108 | steps { 109 | echo 'Deploying...' 110 | } 111 | } 112 | } 113 | } 114 | ''') 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /jenkins/plugins.txt: -------------------------------------------------------------------------------- 1 | git 2 | workflow-aggregator 3 | configuration-as-code 4 | matrix-auth 5 | job-dsl 6 | docker-plugin 7 | docker-workflow 8 | credentials-binding 9 | pipeline-stage-view 10 | dependency-check-jenkins-plugin 11 | sonar 12 | defectdojo 13 | -------------------------------------------------------------------------------- /nexus/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | nexus: 3 | image: sonatype/nexus3 4 | restart: always 5 | volumes: 6 | - "nexus-data:/sonatype-work" 7 | ports: 8 | - "8083:8081" 9 | - "8085:8085" 10 | networks: 11 | - devsecops_network 12 | 13 | volumes: 14 | nexus-data: {} 15 | 16 | networks: 17 | devsecops_network: 18 | external: true 19 | -------------------------------------------------------------------------------- /nginx/devsecops.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name jenkins.devops.local; 4 | 5 | location / { 6 | proxy_pass http://127.0.0.1:8080; 7 | proxy_set_header Host $host; 8 | proxy_set_header X-Real-IP $remote_addr; 9 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 10 | } 11 | } 12 | 13 | server { 14 | listen 80; 15 | server_name defectdojo.devops.local; 16 | 17 | location / { 18 | proxy_pass http://127.0.0.1:8081; 19 | proxy_set_header Host $host; 20 | proxy_set_header X-Real-IP $remote_addr; 21 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 22 | } 23 | } 24 | 25 | server { 26 | listen 80; 27 | server_name sonarqube.devops.local; 28 | 29 | location / { 30 | proxy_pass http://127.0.0.1:9000; 31 | proxy_set_header Host $host; 32 | proxy_set_header X-Real-IP $remote_addr; 33 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 34 | } 35 | } 36 | 37 | server { 38 | listen 80; 39 | server_name nexus.devops.local; 40 | 41 | location / { 42 | proxy_pass http://127.0.0.1:8083; 43 | proxy_set_header Host $host; 44 | proxy_set_header X-Real-IP $remote_addr; 45 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 46 | } 47 | } 48 | 49 | server { 50 | listen 80; 51 | server_name zap.devops.local; 52 | 53 | location / { 54 | proxy_pass http://127.0.0.1:8084/zap; 55 | proxy_set_header Host $host; 56 | proxy_set_header X-Real-IP $remote_addr; 57 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 58 | } 59 | } 60 | 61 | server { 62 | listen 80; 63 | server_name api.zap.devops.local; 64 | 65 | location / { 66 | proxy_pass http://127.0.0.1:8094; 67 | proxy_set_header Host $host; 68 | proxy_set_header X-Real-IP $remote_addr; 69 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 70 | } 71 | } 72 | 73 | server { 74 | listen 80; 75 | server_name sandbox.devops.local; 76 | 77 | location / { 78 | proxy_pass http://192.168.56.20:9000; 79 | proxy_set_header Host $host; 80 | proxy_set_header X-Real-IP $remote_addr; 81 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /provision.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo apt update 4 | 5 | apt-get install -y \ 6 | ca-certificates \ 7 | curl \ 8 | gnupg \ 9 | lsb-release 10 | 11 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 12 | echo \ 13 | "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ 14 | $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null 15 | 16 | sudo apt-get update 17 | 18 | sudo apt-get install -y docker-ce docker-ce-cli containerd.io 19 | 20 | sudo curl -L "https://github.com/docker/compose/releases/download/$(curl -sL https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d'"' -f4)/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 21 | sudo chmod +x /usr/local/bin/docker-compose 22 | 23 | NETWORK_NAME="devsecops_network" 24 | 25 | if docker network inspect "$NETWORK_NAME" > /dev/null 2>&1; then 26 | echo "Network '$NETWORK_NAME' already exists." 27 | else 28 | echo "The network '$NETWORK_NAME' does not exist. I am creating a network..." 29 | docker network create "$NETWORK_NAME" 30 | if [ $? -eq 0 ]; then 31 | echo "The network '$NETWORK_NAME' was created successfully." 32 | else 33 | echo "Error creating network '$NETWORK_NAME'." 34 | exit 1 35 | fi 36 | fi 37 | 38 | docker pull python:3.10 39 | docker pull zaproxy/zap-stable:latest 40 | 41 | cd /vagrant/jenkins && docker compose up -d --build 42 | 43 | sysctl -w vm.max_map_count=262144 44 | cd /vagrant/sonarqube && docker compose up -d --build 45 | 46 | cd /vagrant/defectdojo && docker compose up -d --build 47 | 48 | cd /vagrant/nexus && docker compose up -d --build 49 | 50 | cd /vagrant/zap && docker compose up -d --build 51 | 52 | sudo apt-get install -y nginx 53 | 54 | cp -rf /vagrant/nginx/devsecops.conf /etc/nginx/sites-available/devsecops.conf 55 | 56 | ln -fs /etc/nginx/sites-available/devsecops.conf /etc/nginx/sites-enabled/devsecops.conf 57 | 58 | rm -f /etc/nginx/sites-enabled/default 59 | 60 | systemctl restart nginx 61 | -------------------------------------------------------------------------------- /provision.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Provision DevSecOps VM 3 | hosts: all 4 | become: true 5 | vars: 6 | ansible_connection: local 7 | tasks: 8 | - name: Run apt update 9 | apt: 10 | name: aptitude 11 | state: latest 12 | update_cache: true 13 | 14 | - name: Install required system packages 15 | apt: 16 | pkg: 17 | - apt-transport-https 18 | - ca-certificates 19 | - curl 20 | - software-properties-common 21 | - python3-pip 22 | - virtualenv 23 | - python3-setuptools 24 | state: latest 25 | update_cache: true 26 | 27 | - name: Add Docker GPG apt Key 28 | apt_key: 29 | url: https://download.docker.com/linux/ubuntu/gpg 30 | state: present 31 | 32 | - name: Add Docker Repository 33 | apt_repository: 34 | repo: deb https://download.docker.com/linux/ubuntu focal stable 35 | state: present 36 | 37 | - name: Install Docker 38 | apt: 39 | name: docker-ce 40 | state: latest 41 | update_cache: true 42 | 43 | - name: Install Docker Module for Python 44 | pip: 45 | name: docker 46 | 47 | - name: Install Docker Compose 48 | shell: | 49 | curl -L "https://github.com/docker/compose/releases/download/$(curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r .tag_name)/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 50 | chmod +x /usr/local/bin/docker-compose 51 | args: 52 | creates: /usr/local/bin/docker-compose 53 | 54 | - name: Verify Docker Compose installation 55 | command: docker compose version 56 | register: result 57 | failed_when: "'Docker Compose version' not in result.stdout" 58 | 59 | - name: Display Docker Compose version 60 | debug: 61 | msg: "{{ result.stdout }}" 62 | 63 | - name: Create external Docker network 64 | shell: 65 | cmd: docker network create --driver bridge devsecops_network || true 66 | 67 | - name: Deploy Jenkins 68 | shell: 69 | cmd: docker compose up -d --build 70 | chdir: /vagrant/jenkins 71 | 72 | - name: Set sysctl vm.max_map_count 73 | sysctl: 74 | name: vm.max_map_count 75 | value: 262144 76 | sysctl_set: yes 77 | state: present 78 | 79 | - name: Deploy SonarQube 80 | shell: 81 | cmd: docker compose up -d --build 82 | chdir: /vagrant/sonarqube 83 | 84 | - name: Deploy DefectDojo 85 | shell: 86 | cmd: docker compose up -d --build 87 | chdir: /vagrant/defectdojo 88 | 89 | - name: Deploy Nexus 90 | shell: 91 | cmd: docker compose up -d --build 92 | chdir: /vagrant/nexus 93 | 94 | - name: Deploy OWASP ZAP 95 | shell: 96 | cmd: docker compose up -d --build 97 | chdir: /vagrant/zap 98 | 99 | - name: Install Nginx 100 | apt: 101 | name: nginx 102 | state: present 103 | 104 | - name: Deploy Nginx configuration 105 | ansible.builtin.copy: 106 | src: /vagrant/nginx/devsecops.conf 107 | dest: /etc/nginx/sites-available/devsecops.conf 108 | 109 | - name: Enable Nginx configuration 110 | ansible.builtin.file: 111 | src: /etc/nginx/sites-available/devsecops.conf 112 | dest: /etc/nginx/sites-enabled/devsecops.conf 113 | state: link 114 | force: true 115 | 116 | - name: Remove default Nginx configuration 117 | ansible.builtin.file: 118 | path: /etc/nginx/sites-enabled/default 119 | state: absent 120 | 121 | - name: Restart Nginx 122 | ansible.builtin.service: 123 | name: nginx 124 | state: restarted 125 | -------------------------------------------------------------------------------- /sonarqube/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | sonarqube: 3 | image: sonarqube:community 4 | hostname: sonarqube 5 | container_name: sonarqube 6 | read_only: true 7 | depends_on: 8 | db: 9 | condition: service_healthy 10 | environment: 11 | SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar 12 | SONAR_JDBC_USERNAME: sonar 13 | SONAR_JDBC_PASSWORD: sonar 14 | volumes: 15 | - sonarqube_data:/opt/sonarqube/data 16 | - sonarqube_extensions:/opt/sonarqube/extensions 17 | - sonarqube_logs:/opt/sonarqube/logs 18 | - sonarqube_temp:/opt/sonarqube/temp 19 | ports: 20 | - "127.0.0.1:9000:9000" 21 | networks: 22 | - devsecops_network 23 | - sonar_internal 24 | 25 | db: 26 | image: postgres:15 27 | healthcheck: 28 | test: ["CMD-SHELL", "pg_isready"] 29 | interval: 10s 30 | timeout: 5s 31 | retries: 5 32 | hostname: postgresql 33 | container_name: postgresql 34 | environment: 35 | POSTGRES_USER: sonar 36 | POSTGRES_PASSWORD: sonar 37 | POSTGRES_DB: sonar 38 | volumes: 39 | - postgresql:/var/lib/postgresql 40 | - postgresql_data:/var/lib/postgresql/data 41 | networks: 42 | - sonar_internal 43 | 44 | volumes: 45 | sonarqube_data: 46 | sonarqube_temp: 47 | sonarqube_extensions: 48 | sonarqube_logs: 49 | postgresql: 50 | postgresql_data: 51 | 52 | networks: 53 | devsecops_network: 54 | external: true 55 | sonar_internal: 56 | -------------------------------------------------------------------------------- /zap/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | zap: 3 | image: zaproxy/zap-stable 4 | container_name: owasp_zap 5 | ports: 6 | - "8084:8080" 7 | - "8094:8090" 8 | environment: 9 | - JAVA_OPTS=-Xmx512m 10 | - ZAP_API_KEY=your-zap-api-key 11 | - ZAP_ENABLE_API=true 12 | - ZAP_DISABLE_KEY=false 13 | volumes: 14 | - ./zap_data:/zap/wrk 15 | command: > 16 | zap.sh 17 | -daemon 18 | -host 0.0.0.0 19 | -port 8090 20 | -config api.addrs.addr.name=.* 21 | -config api.addrs.addr.regex=true 22 | networks: 23 | - devsecops_network 24 | 25 | networks: 26 | devsecops_network: 27 | external: true 28 | --------------------------------------------------------------------------------