├── Jenkinsfile ├── LICENSE ├── README.md ├── config.xml ├── docker-compose.yml ├── jenkins ├── Dockerfile ├── ansible.cfg ├── plugins.txt └── setupJenkins.groovy ├── jenkins_home ├── ansible_hosts ├── authDAST.py ├── configureTestEnv.yml ├── configureWAF.yml ├── createAwsEc2.yml ├── hostaudit.yml ├── killec2.yml └── strategy.ini └── setup-ubuntu.sh /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /* 2 | This pipeline will carry out the following on the project: 3 | 4 | 1. Git secret checker 5 | 2. Software Composition Analysis 6 | 3. Static Application Security Testing 7 | 4. Container security audit 8 | 5. Dynamic Application Security Testing 9 | 6. Host system security audit 10 | 7. Host application protection 11 | 12 | */ 13 | 14 | testenv = "null" 15 | 16 | pipeline { 17 | /* Which agent are we running this pipeline on? We can configure different OS */ 18 | agent any 19 | 20 | stages { 21 | stage('Checkout project'){ 22 | steps { 23 | echo 'downloading git directory..' 24 | git 'https://github.com/pawnu/secDevLabs.git' 25 | } 26 | } 27 | stage('git secret check'){ 28 | steps{ 29 | script{ 30 | echo 'running trufflehog to check project history for secrets' 31 | sh 'trufflehog --regex --entropy=False --max_depth=3 https://github.com/pawnu/secDevLabs' 32 | } 33 | } 34 | } 35 | stage('SCA'){ 36 | steps{ 37 | echo 'running python safety check on requirements.txt file' 38 | sh 'safety check -r $WORKSPACE/owasp-top10-2017-apps/a7/gossip-world/app/requirements.txt' 39 | /* 40 | echo 'running liccheck on dependencies' 41 | sh """ 42 | virtualenv --no-site-packages . 43 | source bin/activate 44 | pip install -r $WORKSPACE/owasp-top10-2017-apps/a7/gossip-world/app/requirements.txt 45 | liccheck -s ~/my_strategy.ini -r $WORKSPACE/owasp-top10-2017-apps/a7/gossip-world/app/requirements.txt 46 | deactivate 47 | """ 48 | */ 49 | } 50 | } 51 | stage('SAST') { 52 | steps { 53 | echo 'Testing source code for security bugs and vulnerabilities' 54 | sh 'bandit -r $WORKSPACE/owasp-top10-2017-apps/a7/gossip-world/app/ -ll || true' 55 | } 56 | } 57 | stage('Container audit') { 58 | steps { 59 | echo 'Audit the dockerfile used to spin up the web application' 60 | script{ 61 | def exists = fileExists '/var/jenkins_home/lynis/lynis' 62 | if(exists){ 63 | echo 'lynis already exists' 64 | }else{ 65 | sh """ 66 | wget https://downloads.cisofy.com/lynis/lynis-2.7.5.tar.gz 67 | tar xfvz lynis-2.7.5.tar.gz -C ~/ 68 | rm lynis-2.7.5.tar.gz 69 | """ 70 | } 71 | } 72 | dir("/var/jenkins_home/lynis"){ 73 | sh """ 74 | mkdir $WORKSPACE/$BUILD_TAG/ 75 | ./lynis audit dockerfile $WORKSPACE/owasp-top10-2017-apps/a7/gossip-world/deployments/Dockerfile | ansi2html > $WORKSPACE/$BUILD_TAG/docker-report.html 76 | mv /tmp/lynis.log $WORKSPACE/$BUILD_TAG/docker_lynis.log 77 | mv /tmp/lynis-report.dat $WORKSPACE/$BUILD_TAG/docker_lynis-report.dat 78 | """ 79 | } 80 | } 81 | } 82 | stage('Setup test env') { 83 | steps { 84 | sh """ 85 | #refresh inventory 86 | echo "[local]" > ~/ansible_hosts 87 | echo "localhost ansible_connection=local" >> ~/ansible_hosts 88 | echo "[tstlaunched]" >> ~/ansible_hosts 89 | 90 | tar cvfz /var/jenkins_home/pythonapp.tar.gz -C $WORKSPACE/owasp-top10-2017-apps/a7/ . 91 | 92 | ssh-keygen -t rsa -N "" -f ~/.ssh/psp_ansible_key || true 93 | ansible-playbook -i ~/ansible_hosts ~/createAwsEc2.yml 94 | """ 95 | script{ 96 | testenv = sh(script: "sed -n '/tstlaunched/{n;p;}' /var/jenkins_home/ansible_hosts", returnStdout: true).trim() 97 | } 98 | echo "${testenv}" 99 | sh 'ansible-playbook -i ~/ansible_hosts ~/configureTestEnv.yml' 100 | } 101 | } 102 | stage('DAST') { 103 | steps { 104 | script{ 105 | //Test the web application from its frontend 106 | /* 107 | def exists = fileExists '/var/jenkins_home/nikto-master/program/nikto.pl' 108 | if(exists){ 109 | echo 'nikto already exists' 110 | }else{ 111 | sh """ 112 | wget https://github.com/sullo/nikto/archive/master.zip 113 | unzip master.zip -d ~/ || true 114 | rm master.zip 115 | """ 116 | } 117 | */ 118 | def seleniumIp = env.SeleniumPrivateIp 119 | if("${testenv}" != "null"){ 120 | sh "python ~/authDAST.py $seleniumIp ${testenv} $WORKSPACE/$BUILD_TAG/DAST_results.html" 121 | //sh "perl /var/jenkins_home/nikto-master/program/nikto.pl -h http://${testenv}:10007/login" 122 | } 123 | } 124 | } 125 | } 126 | stage('System security audit') { 127 | steps { 128 | echo 'Run lynis audit on host and fetch result' 129 | sh 'ansible-playbook -i ~/ansible_hosts ~/hostaudit.yml --extra-vars "logfolder=$WORKSPACE/$BUILD_TAG/"' 130 | } 131 | } 132 | stage('Deploy WAF') { 133 | steps { 134 | echo 'Deploy modsecurity as reverse proxy' 135 | sh 'ansible-playbook -i ~/ansible_hosts ~/configureWAF.yml' 136 | } 137 | } 138 | } 139 | post { 140 | always { 141 | echo 'We could bring down the ec2 here' 142 | /* 143 | echo 'Tear down activity' 144 | script{ 145 | if("${testenv}" != "null"){ 146 | echo "killing host ${testenv}" 147 | sh 'ansible-playbook -i ~/ansible_hosts ~/killec2.yml' 148 | } 149 | } 150 | */ 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Pawan Uppadey 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 | # DevSecOps pipeline for Python project 2 | 3 | A Jenkins end-to-end DevSecOps pipeline for Python web application, hosted on AWS Ubuntu 18.04 4 | 5 | ![pipeline](https://user-images.githubusercontent.com/11514346/71473164-e57a5500-27cd-11ea-97cb-3c25f0266407.JPG) 6 | 7 | psparchitecture 8 | 9 | *Disclaimer: This project is for demonstration purpose with surface level checks only, do not use it as-is for production* 10 | 11 | > **Checkout project** - check out python application project repository with XSS vulnerability 12 | 13 | > **git secret check** - check there is no password/token/keys/secrets accidently commited to project github 14 | 15 | > **SCA** - check external dependencies/libraries used by the project have no known vulnerabilities 16 | 17 | > **SAST** - static analysis of the application source code for exploits, bugs, vulnerabilites 18 | 19 | > **Container audit** - audit the container that is used to deploy the python application 20 | 21 | > **DAST** - deploy the application, register, login, attack & analyse it from the frontend as authenticated user 22 | 23 | > **System security audit** - analyse at the security posture of the system hosting the application 24 | 25 | > **WAF** - deploy application with WAF which will filter malicious requests according to OWASP core ruleset 26 | 27 | 28 | ## Installation steps 29 | 30 | 1. Clone this repository to your Ubuntu Server (t2-medium recommended) 31 | ``` 32 | git clone https://github.com/pawnu/PythonSecurityPipeline.git 33 | ``` 34 | 35 | 2. Edit the code to make it work on your AWS 36 | - Change to your AWS subnet [vpc_subnet_id](jenkins_home/createAwsEc2.yml#L30) 37 | - Change to your AWS [security_group](jenkins_home/createAwsEc2.yml#L10) (allow inbound ssh(22), WAF(80), *Optional* web-app(10007) from your IP ONLY) 38 | - Create an IAM role which gives full-ec2-access and assign it to your ubuntu server 39 | 40 | 3. Run the setup script to create CICD server with Jenkins+pipeline ready to go 41 | ``` 42 | cd PythonSecurityPipeline 43 | sudo sh setup-ubuntu.sh 44 | ``` 45 | 46 | 4. Make sure your firewall allows incoming traffic to port 8080. Then, go to your jenkins server URL 47 | ``` 48 | http://your-jenkins-server:8080/ 49 | ``` 50 | 5. Use the temporary credentials provided on the logs to login. Change your password! 51 | 6. Go to the python pipeline project dashboard, click on "Build Now" button to start it off. 52 | 53 | ## Setting up a Jenkins Pipeline project manually 54 | 55 | **A sample pipeline is already provided through automation** 56 | 57 | 1. Click on New Item, input name for your project and select Pipeline as the option and click OK. 58 | 2. Scroll down to Pipeline section - Definition, select "Pipeline script from SCM" from drop down menu. 59 | 3. Select Git under SCM, and input Repository URL. 60 | 4. (Optional) Create and Add your credentials for the Git repo if your repo is private, and click Save. 61 | 5. You will be brought to the Dashboard of your Pipeline project, click on "Build Now" button to start off the pipeline. 62 | 63 | 64 | **To do list:** 65 | - [x] Select appropriate security tools and sample python project 66 | - [x] Set up Jenkins server using docker (Dockerfile) and pipeline as code (Jenkinsfile) to run the checks 67 | - [x] Use ansible to create AWS ec2 test instance, configure the environment, and interact with it 68 | - [x] Hook up the web-app with ~~nginx~~+modsecurity providing WAF, ~~DDoS protection~~, reverse proxy capabilities 69 | - [x] Bootstrap with Jenkins API/configfile to setup and automatically create the pipeline job 70 | - [x] Carry out authenticated DAST scan on the python web app 71 | 72 | ## Demo 73 | 74 | ![finalgif4](https://user-images.githubusercontent.com/11514346/72058904-db298200-32c8-11ea-9a15-46c179c4a0fb.gif) 75 | 76 | ### Report 77 | 78 | ![workspace](https://user-images.githubusercontent.com/11514346/71560987-46bd5500-2a68-11ea-8f1f-63c7cf65f631.JPG) 79 | 80 | ## Authors 81 | 82 | * **Pawan Uppadey** - [pawnu](https://github.com/pawnu) 83 | 84 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | false 14 | 15 | 16 | 17 | 2 18 | 19 | 20 | https://github.com/pawnu/PythonSecurityPipeline.git 21 | 22 | 23 | 24 | 25 | */master 26 | 27 | 28 | false 29 | 30 | 31 | 32 | Jenkinsfile 33 | true 34 | 35 | 36 | false 37 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | jenkins-master: 4 | build: 5 | context: ./jenkins 6 | restart: always 7 | ports: 8 | - "50000:50000" 9 | - "8080:8080" 10 | volumes: 11 | - ./jenkins_home:/var/jenkins_home 12 | container_name: jenkins-master 13 | environment: 14 | - "Jenkins_PW=${Jenkins_PW}" 15 | - "JAVA_OPTS=${JAVA_OPTS}" 16 | - "JenkinsPublicHostname=${JenkinsPublicHostname}" 17 | - "SeleniumPrivateIp=${SeleniumPrivateIp}" 18 | selenium-chrome: 19 | image: selenium/standalone-chrome 20 | restart: always 21 | container_name: selenium-chrome 22 | ports: 23 | - "4444:4444" 24 | volumes: 25 | - "/dev/shm:/dev/shm" 26 | -------------------------------------------------------------------------------- /jenkins/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkins/jenkins:lts 2 | MAINTAINER pawan uppadey 3 | 4 | #Install Jenkins plugin to make this pipeline work 5 | COPY plugins.txt /usr/share/jenkins/ref/plugins.txt 6 | RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt 7 | 8 | #Copy script to auto create user to jenkins init folder 9 | COPY setupJenkins.groovy /usr/share/jenkins/ref/init.groovy.d/ 10 | 11 | #setup the docker container for scanners 12 | USER root 13 | RUN apt-get update && apt-get install -y \ 14 | python-pip \ 15 | curl \ 16 | maven \ 17 | git \ 18 | perl \ 19 | wget \ 20 | kbtin \ 21 | libnet-ssleay-perl \ 22 | software-properties-common 23 | 24 | #add public key for the multiverse repo which has nikto 25 | RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32 26 | RUN add-apt-repository 'deb http://archive.ubuntu.com/ubuntu bionic multiverse' 27 | RUN add-apt-repository 'deb http://archive.ubuntu.com/ubuntu bionic-security multiverse' 28 | RUN add-apt-repository 'deb http://archive.ubuntu.com/ubuntu bionic-updates multiverse' 29 | 30 | RUN apt-get update -y 31 | RUN apt-get install -y nikto 32 | 33 | #Install virtualenv to isolate each project dependencies 34 | RUN pip install virtualenv 35 | #Install python SCA tool/dependency checker, license check 36 | RUN pip install safety 37 | RUN pip install liccheck 38 | #Install the git history checker for secrets 39 | RUN pip install trufflehog 40 | #Install python SAST tool 41 | RUN pip install bandit 42 | 43 | # Used for authenticated DAST scan 44 | RUN pip install selenium 45 | 46 | #install the orchestration tool, boto for ec2 module, some lib upgrade under requests 47 | RUN pip install ansible 48 | RUN pip install boto 49 | RUN pip install boto3 50 | 51 | # configure ansible to use right keys and not check host auth for this ephemeral/temp aws host 52 | # Not authenticating existing/long-term hosts requiring relogins may lead to mitm.. be careful 53 | COPY ansible.cfg /etc/ansible/ansible.cfg 54 | 55 | # drop back to the regular jenkins user - good practice 56 | USER jenkins 57 | -------------------------------------------------------------------------------- /jenkins/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking = False 3 | private_key_file = ~/.ssh/psp_ansible_key 4 | -------------------------------------------------------------------------------- /jenkins/plugins.txt: -------------------------------------------------------------------------------- 1 | pipeline-input-step:2.11 2 | git-server:1.9 3 | junit:1.28 4 | workflow-multibranch:2.21 5 | apache-httpcomponents-client-4-api:4.5.10-2.0 6 | lockable-resources:2.7 7 | matrix-auth:2.5 8 | pipeline-milestone-step:1.3.1 9 | workflow-job:2.36 10 | ldap:1.21 11 | token-macro:2.10 12 | structs:1.20 13 | script-security:1.68 14 | workflow-support:3.3 15 | ssh-credentials:1.18 16 | pipeline-model-declarative-agent:1.1.1 17 | ws-cleanup:0.38 18 | git-client:3.0.0 19 | resource-disposer:0.14 20 | display-url-api:2.3.2 21 | gradle:1.35 22 | ant:1.10 23 | email-ext:2.68 24 | ace-editor:1.1 25 | docker-commons:1.16 26 | cloudbees-folder:6.10.1 27 | authentication-tokens:1.3 28 | pipeline-model-definition:1.5.0 29 | antisamy-markup-formatter:1.6 30 | workflow-scm-step:2.9 31 | bouncycastle-api:2.17 32 | trilead-api:1.0.5 33 | ssh-slaves:1.31.0 34 | timestamper:1.10 35 | workflow-step-api:2.21 36 | jdk-tool:1.4 37 | durable-task:1.33 38 | mailer:1.29 39 | workflow-api:2.38 40 | workflow-aggregator:2.6 41 | pipeline-github-lib:1.0 42 | pipeline-model-extensions:1.5.0 43 | pipeline-model-api:1.5.0 44 | workflow-durable-task-step:2.35 45 | github-branch-source:2.5.8 46 | branch-api:2.5.5 47 | jackson2-api:2.10.1 48 | build-timeout:1.19 49 | pam-auth:1.6 50 | jsch:0.1.55.1 51 | workflow-cps-global-lib:2.15 52 | jquery-detached:1.2.1 53 | git:4.0.0 54 | pipeline-stage-step:2.3 55 | subversion:2.13.0 56 | github:1.29.5 57 | pipeline-stage-tags-metadata:1.5.0 58 | command-launcher:1.4 59 | scm-api:2.6.3 60 | matrix-project:1.14 61 | pipeline-graph-analysis:1.10 62 | mapdb-api:1.0.9.0 63 | momentjs:1.1.1 64 | workflow-cps:2.78 65 | pipeline-stage-view:2.12 66 | plain-credentials:1.5 67 | credentials-binding:1.20 68 | credentials:2.3.0 69 | pipeline-build-step:2.10 70 | handlebars:1.1.1 71 | docker-workflow:1.21 72 | workflow-basic-steps:2.18 73 | github-api:1.95 74 | pipeline-rest-api:2.12 75 | -------------------------------------------------------------------------------- /jenkins/setupJenkins.groovy: -------------------------------------------------------------------------------- 1 | import jenkins.model.* 2 | import hudson.security.* 3 | import jenkins.security.s2m.AdminWhitelistRule 4 | import jenkins.model.Jenkins 5 | import hudson.security.csrf.DefaultCrumbIssuer 6 | 7 | //don't let slave instance kill the master 8 | Jenkins.instance.getInjector().getInstance(AdminWhitelistRule.class) 9 | .setMasterKillSwitch(false) 10 | 11 | def env = System.getenv() 12 | 13 | /* 14 | Jenkins needs URL in order for reference links to point to other pages, resources, pipeline build etc 15 | */ 16 | jlc = JenkinsLocationConfiguration.get() 17 | jlc.setUrl("http://"+env.JenkinsPublicHostname +":8080/") 18 | jlc.save() 19 | 20 | //Set CSRF token for Jenkins server 21 | def instance = Jenkins.instance 22 | instance.setCrumbIssuer(new DefaultCrumbIssuer(true)) 23 | instance.save() 24 | 25 | /* 26 | Create admin user to login 27 | */ 28 | def jenkins = Jenkins.getInstance() 29 | if(!(jenkins.getSecurityRealm() instanceof HudsonPrivateSecurityRealm)) 30 | jenkins.setSecurityRealm(new HudsonPrivateSecurityRealm(false)) 31 | 32 | if(!(jenkins.getAuthorizationStrategy() instanceof GlobalMatrixAuthorizationStrategy)) 33 | jenkins.setAuthorizationStrategy(new GlobalMatrixAuthorizationStrategy()) 34 | 35 | def user = jenkins.getSecurityRealm().createAccount("myjenkins", env.Jenkins_PW) 36 | user.save() 37 | jenkins.getAuthorizationStrategy().add(Jenkins.ADMINISTER, "myjenkins") 38 | 39 | jenkins.save() 40 | -------------------------------------------------------------------------------- /jenkins_home/ansible_hosts: -------------------------------------------------------------------------------- 1 | [local] 2 | localhost ansible_connection=local 3 | 4 | [tstlaunched] 5 | -------------------------------------------------------------------------------- /jenkins_home/authDAST.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.common.keys import Keys 3 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 4 | import json 5 | import subprocess 6 | import sys 7 | import random 8 | import string 9 | 10 | def randomString(stringLength): 11 | letters = string.ascii_letters 12 | return ''.join(random.choice(letters) for i in range(stringLength)) 13 | 14 | def bash_command(cmd): 15 | subprocess.Popen(cmd, shell=True, executable='/bin/bash') 16 | 17 | myusername = randomString(8) 18 | mypassword = randomString(12) 19 | 20 | if len(sys.argv) < 4: 21 | print '1. Provide the ip address for selenium remote server!' 22 | print '2. Provide the ip address for target DAST scan!' 23 | print '3. Provide the output location of html report!' 24 | sys.exit(1) 25 | 26 | driver = webdriver.Remote("http://"+sys.argv[1]+":4444/wd/hub", DesiredCapabilities.CHROME) 27 | 28 | driver.get("http://"+sys.argv[2]+":10007/login") 29 | 30 | registerbutton = driver.find_element_by_xpath("/html/body/div/div/div/form/center[3]/a") 31 | registerbutton.click() 32 | print("we're at: " + driver.current_url) 33 | 34 | print("creating a user..") 35 | username = driver.find_element_by_name("username") 36 | password1 = driver.find_element_by_name("password1") 37 | password2 = driver.find_element_by_name("password2") 38 | 39 | username.clear() 40 | username.send_keys(myusername) 41 | password1.clear() 42 | password1.send_keys(mypassword) 43 | password2.clear() 44 | password2.send_keys(mypassword) 45 | password2.send_keys(Keys.RETURN) 46 | login = driver.find_element_by_xpath('/html/body/div/div/div/center[2]/h4') 47 | assert "Login" in login.text 48 | 49 | print("created user") 50 | 51 | driver.get("http://"+sys.argv[2]+":10007/login") 52 | print("we're at: " + driver.current_url) 53 | username = driver.find_element_by_name("username") 54 | password = driver.find_element_by_name("password") 55 | username.clear() 56 | username.send_keys(myusername) 57 | password.clear() 58 | password.send_keys(mypassword) 59 | password.send_keys(Keys.RETURN) 60 | header = driver.find_element_by_xpath("/html/body/div/div/div[1]/h1") 61 | assert "Last gossips" in header.text 62 | print("logged in successfully.. getting cookie") 63 | 64 | nikto_string = "STATIC-COOKIE=" 65 | cookies_list = driver.get_cookies() 66 | for cookie in cookies_list: 67 | nikto_string+= '\"' + cookie['name'] + '\"=' 68 | nikto_string+= '\"'+ cookie['value'] + '\"' 69 | bash_command("cp /etc/nikto/config.txt ~/nikto-config.txt") 70 | bash_command("echo '" + nikto_string +"' >> ~/nikto-config.txt") 71 | print("added cookie to nikto config file to carry out authenticated scan..") 72 | bash_command("nikto -ask no -config ~/nikto-config.txt -Format html -h http://"+sys.argv[2]+":10007/gossip -output "+ sys.argv[3]) 73 | -------------------------------------------------------------------------------- /jenkins_home/configureTestEnv.yml: -------------------------------------------------------------------------------- 1 | # Configure launched instance for test 2 | - name: Configure instance(s) 3 | hosts: tstlaunched 4 | become: True 5 | remote_user: ubuntu 6 | gather_facts: True 7 | tasks: 8 | - name: update package manager 9 | apt: update_cache=yes 10 | - name: Install docker 11 | apt: name=docker.io state=present 12 | - name: Install docker-compose 13 | apt: name=docker-compose update_cache=yes state=present 14 | - name: Install kbtin for lynis to produce html report 15 | apt: name=kbtin state=present 16 | - name: Install make to build the pythonapp 17 | apt: name=make state=present 18 | - name: Copy the zip file of project 19 | copy: 20 | src: pythonapp.tar.gz 21 | dest: /home/ubuntu/pythonapp.tar.gz 22 | - name: Unzip it 23 | unarchive: 24 | src: /home/ubuntu/pythonapp.tar.gz 25 | dest: /home/ubuntu/ 26 | copy: no 27 | - name: Run the application with docker 28 | shell: make install 29 | args: 30 | chdir: gossip-world/ 31 | -------------------------------------------------------------------------------- /jenkins_home/configureWAF.yml: -------------------------------------------------------------------------------- 1 | # Configure launched instance for WAF 2 | - name: Configure instance(s) 3 | hosts: tstlaunched 4 | become: True 5 | remote_user: ubuntu 6 | gather_facts: True 7 | tasks: 8 | - name: Run the WAF on docker 9 | docker_container: 10 | name: modsecurity_waf 11 | image: owasp/modsecurity-crs 12 | state: started 13 | restart_policy: always 14 | ports: 15 | - "80:80" 16 | env: 17 | PARANOIA: "2" 18 | PROXY: "1" 19 | PROXYLOCATION: "http://{{ ansible_default_ipv4.address }}:10007/" 20 | -------------------------------------------------------------------------------- /jenkins_home/createAwsEc2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Create ec2 instance and add it to ansible inventory 3 | - name: Create a sandbox instance 4 | hosts: localhost 5 | connection: local 6 | gather_facts: False 7 | vars: 8 | keyname: psp_ansible_key 9 | instance_type: t2.micro 10 | security_group: launch-wizard-1 11 | image: ami-0be057a22c63962cb 12 | region: eu-west-2 13 | tagname: Name=TestServer 14 | 15 | tasks: 16 | - name: Upload public key to AWS 17 | ec2_key: 18 | name: "{{ keyname }}" 19 | key_material: "{{ lookup('file', '~/.ssh/{{ keyname }}.pub') }}" 20 | region: "{{ region }}" 21 | 22 | - name: Launch instance 23 | ec2: 24 | key_name: "{{ keyname }}" 25 | group: "{{ security_group }}" 26 | instance_type: "{{ instance_type }}" 27 | image: "{{ image }}" 28 | wait: true 29 | region: "{{ region }}" 30 | vpc_subnet_id: subnet-02a17e56e6827124a 31 | assign_public_ip: yes 32 | instance_tags: "{{tagname}}" 33 | register: ec2 34 | 35 | - name: Add new instance to hosts group for test 36 | local_action: lineinfile 37 | dest="~/ansible_hosts" 38 | regexp={{ item.private_ip }} 39 | insertafter="[tstlaunched]" 40 | line="{{ item.private_ip }}" 41 | state=present 42 | with_items: "{{ ec2.instances }}" 43 | 44 | - name: Wait for SSH to come up 45 | local_action: wait_for 46 | host={{ item.private_ip }} 47 | port=22 48 | state=started 49 | with_items: "{{ ec2.instances }}" 50 | -------------------------------------------------------------------------------- /jenkins_home/hostaudit.yml: -------------------------------------------------------------------------------- 1 | # Run lynis audit on system and fetch logs 2 | - name: Run host audit in instance(s) 3 | hosts: tstlaunched 4 | remote_user: ubuntu 5 | gather_facts: False 6 | tasks: 7 | - name: Get the lynis installer 8 | get_url: 9 | url: https://downloads.cisofy.com/lynis/lynis-2.7.5.tar.gz 10 | dest: /tmp/ 11 | - name: Unzip it 12 | unarchive: 13 | src: /tmp/lynis-2.7.5.tar.gz 14 | dest: /home/ubuntu/ 15 | copy: no 16 | - name: Run system audit 17 | shell: ./lynis audit system --quick --auditor "The Auditor" | ansi2html > host_audit_report.html 18 | args: 19 | chdir: lynis/ 20 | - name: Fetch log file from host 21 | fetch: 22 | src: /tmp/lynis.log 23 | dest: "{{ logfolder }}" 24 | flat: yes 25 | - name: Fetch report file from host 26 | fetch: 27 | src: /tmp/lynis-report.dat 28 | dest: "{{ logfolder }}" 29 | flat: yes 30 | - name: Fetch fancy html report 31 | fetch: 32 | src: /home/ubuntu/lynis/host_audit_report.html 33 | dest: "{{ logfolder }}" 34 | flat: yes 35 | - name: Remove html report on host 36 | file: 37 | path: /home/ubuntu/lynis/host_audit_report.html 38 | state: absent 39 | - name: Remove log file on host 40 | file: 41 | path: /tmp/lynis.log 42 | state: absent 43 | - name: Remove report on host 44 | file: 45 | path: /tmp/lynis-report.dat 46 | state: absent 47 | -------------------------------------------------------------------------------- /jenkins_home/killec2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Gather remote host info 3 | hosts: tstlaunched 4 | remote_user: ubuntu 5 | vars: 6 | region: "eu-west-2" 7 | tasks: 8 | - name: get remote instance metadata 9 | ec2_metadata_facts: 10 | - name: destroy the instance with instance id 11 | ec2: 12 | state: 'absent' 13 | region: "{{ region }}" 14 | instance_ids: "{{ ansible_ec2_instance_id }}" 15 | delegate_to: localhost 16 | -------------------------------------------------------------------------------- /jenkins_home/strategy.ini: -------------------------------------------------------------------------------- 1 | # Authorized and unauthorized licenses in LOWER CASE 2 | [Licenses] 3 | authorized_licenses: 4 | bsd 5 | new bsd 6 | bsd license 7 | new bsd license 8 | simplified bsd 9 | apache 10 | apache 2.0 11 | apache software license 12 | gnu lgpl 13 | lgpl with exceptions or zpl 14 | isc license 15 | isc license (iscl) 16 | mit 17 | mit license 18 | python software foundation license 19 | zpl 2.1 20 | 21 | unauthorized_licenses: 22 | gpl v3 23 | 24 | [Authorized Packages] 25 | # Python software license (see http://zesty.ca/python/uuid.README.txt) 26 | uuid: 1.30 27 | -------------------------------------------------------------------------------- /setup-ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt-get update 4 | apt install docker.io -y 5 | apt-get install -y docker-compose 6 | apt install default-jre -y 7 | 8 | #have to relogin as ubuntu user 9 | usermod -aG docker ubuntu 10 | 11 | # restart new session with docker group 12 | #newgrp docker 13 | 14 | #let docker run when server is restarted 15 | systemctl enable docker 16 | 17 | #create random password for jenkins user which will be created automatically 18 | export Jenkins_PW=$(openssl rand -base64 16) 19 | export JAVA_OPTS="-Djenkins.install.runSetupWizard=false" 20 | 21 | #we're providing the server its public hostname for its relative links 22 | export JenkinsPublicHostname=$(curl -s http://169.254.169.254/latest/meta-data/public-hostname) 23 | export SeleniumPrivateIp=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4) 24 | #build the jenkins container 25 | docker-compose up -d --build 26 | 27 | #let the jenkins docker complete bootstrapping with our groovy script provided 28 | sleep 45 29 | 30 | #create new environment without inheriting anything from this shell for this wget to work.. 31 | env -i /bin/bash -c 'wget http://127.0.0.1:8080/jnlpJars/jenkins-cli.jar' 32 | 33 | sleep 5 34 | #create the pipeline in jenkins 35 | java -jar ./jenkins-cli.jar -s http://localhost:8080 -auth myjenkins:$Jenkins_PW create-job pythonpipeline < config.xml 36 | 37 | echo "------- Your temporary Jenkins login ---------" 38 | echo "myjenkins" 39 | echo $Jenkins_PW 40 | --------------------------------------------------------------------------------