├── .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 |
--------------------------------------------------------------------------------