Donal Spring
2018-12-04 34fdf3bf8998b5a09558a4186e7d13fcbb0f05ee
commit | author | age
e36a5b 1 # An Enslaved Hope
43f2f2 2
1173e5 3 > In this exercise we'll break free from the chains of point'n'click Jenkins by introducing pipeline as code in the form of `Jenkinsfile`. Following this we will introduce some new Jenkins slaves that will be used in later exercises.
e36a5b 4
921415 5 ![jenkins-fail-meme](../images/exercise4/jenkins-fail-meme.jpeg)
D 6
e36a5b 7 There are a number of ways pipeline as code can be achieved in Jenkins.
1173e5 8  * The Job DSL Plugin - this is a slightly older but very functional DSL mechanism to create reusable pipelines. Create a `groovy` file to run Jenkins Domain Specific Language to create jobs, functions and other items. In Jenkins; you then can execute this file which will build all of the config.xml files needed for each Job.
8894bf 9  * The Scripted Pipeline - The scripted pipeline introduced the Jenkinsfile and the ability for developers to write their Jenkins setup as groovy code. A repo with a Jenkinsfile in its root can be pointed to by Jenkins and it will automatically build out each of the stages described within. The scripted pipeline is ultimately Groovy at its core.
dd12d4 10  * The Declarative Pipeline - This approach looks to simplify and opinionate what you can do and when you can do it in a pipeline. It does this by giving you top level `block` which define sections, directives and steps. The declarative syntax is not run as groovy but you can execute groovy inside script blocks. The advantage of it over scripted is validation of the config and lighter approach with requirement to understand all of the `groovy` syntax
e36a5b 11
43f2f2 12 _____
D 13
14 ## Learning Outcomes
15 As a learner you will be able to
1173e5 16 - Use a Jenkinsfile to create a declarative pipeline to build, bake and deploy the Todolist App
CM 17 - Identify the differences between scripted, declarative and DSL pipelines
b5d705 18 - Create Jenkins slave nodes for use in builds in future exercises
43f2f2 19
D 20 ## Tools and Frameworks
21 > Name of tool - short description and link to docs or website
22
e36a5b 23 1. [Pipeline](https://jenkins.io/doc/book/pipeline/) - Overview of the Jenkinsfile approach
D 24 1. [Pipeline Syntax](https://jenkins.io/doc/book/pipeline/syntax/) - Documentation for the declarative pipeline
25 1. [Groovy](http://groovy-lang.org/) - Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax. It integrates smoothly with any Java program, and immediately delivers to your application powerful features, including scripting capabilities, Domain-Specific Language authoring, runtime and compile-time meta-programming and functional programming.
b664dc 26 1. [Zed Attack Proxy](https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project) - The OWASP Zed Attack Proxy (ZAP) is one of the world’s most popular free security tools and is actively maintained by hundreds of international volunteers*. It can help you automatically find security vulnerabilities in your web applications while you are developing and testing your applications. Its also a great tool for experienced pentesters to use for manual security testing.
D 27 1. [Arachni Crawler](http://www.arachni-scanner.com/) - Arachni is a feature-full, modular, high-performance Ruby framework aimed towards helping penetration testers and administrators evaluate the security of modern web applications. It is free, with its source code public and available for review. It is versatile enough to cover a great deal of use cases, ranging from a simple command line scanner utility, to a global high performance grid of scanners, to a Ruby library allowing for scripted audits, to a multi-user multi-scan web collaboration platform. In addition, its simple REST API makes integration a cinch.
43f2f2 28
D 29 ## Big Picture
664135 30 > From the previous exercise; we gated our pipeline. Now we will add a pipeline-as-code in the form of the Jenkinfile and re-use it on the Backend too.
D 31
32 ![big-picture](../images/big-picture/big-picture-3.jpg)
43f2f2 33
D 34 _____
35
36 ## 10,000 Ft View
b5d705 37 > The goal of this exercise is to move to using the Jenkinsfile in the todolist-api and todolist-fe projects. Additionally we will create new slaves for use in the next exercise.
43f2f2 38
e43fd2 39 2. On Jenkins; create a multibranch pipeline project to scan the GitLab endpoint for each app. Use the Jenkinsfile provided to run the stages. Replace `<YOUR_NAME>` with the appropriate variable.
43f2f2 40
e36a5b 41 2. Create two new Jenkins slaves for the `OWASP ZAP` scanner and the `Arachni` WebCrawler
43f2f2 42
D 43 ## Step by Step Instructions
1173e5 44 > This is a fairly structured guide with references to exact filenames and sections of text to be added.
43f2f2 45
e36a5b 46 ### Part 1 - The Jenkinsfile
b5d705 47 > _In this exercise we'll replace the Pipeline we created in Exercise 2 with a Jenkinsfile approach_
43f2f2 48
e36a5b 49 2. On your terminal navigate to your `todolist-api` project and checkout the pipeline feature branch that's been already created for you.
D 50 ```bash
fad576 51 git checkout feature/jenkinsfile
43f2f2 52 ```
D 53
1173e5 54 2. Open up your `todolist-api` application in your favourite editor and move to the `Jenkinsfile` in the root of the project. The high-level structure of the file is shown collapsed below.
e36a5b 55 ![pipeline-overview](../images/exercise4/pipeline-overview.png)
D 56 Some of the key things to note:
1173e5 57     * `pipeline {}` is how all declarative Jenkins pipelines begin.
db509f 58     * `environment {}` defines environment variables to be used across all build stages
A 59     * `options {}` contains specific Job specs you want to run globally across the jobs e.g. setting the terminal colour
60     * `stage {}` all jobs must have one stage. This is the logical part of the build that will be executed e.g. `bake-image`
e36a5b 61     * `steps {}` each `stage` has one or more steps involved. These could be execute shell or git checkout etc.
1173e5 62     * `agent {}` specifies the node the build should be run on e.g. `jenkins-slave-npm`
e43fd2 63     * `post {}` hook is used to specify the post-build-actions. Jenkins declarative pipeline syntax provides very useful callbacks for `success`, `failure` and `always` which are useful for controlling the job flow
W 64     * `when {}` is used for flow control. It can be used at the stage level and be used to stop pipeline entering that stage. e.g. when branch is master; deploy to `test` environment.
e36a5b 65
b5d705 66 2. The Jenkinsfile is mostly complete to do all the testing etc that was done in previous exercises. Some minor changes will be needed to orchestrate namespaces. Find and replace all instances of `<YOUR_NAME>` in the Jenkinsfile. Update the `<GIT_USERNAME>` to the one you login to the cluster with; this variable is used in the namespace of your git projects when checking out code etc. Ensure the `GITLAB_DOMAIN` matches your git host.
e36a5b 67 ```groovy
D 68     environment {
69         // GLobal Vars
dd12d4 70         PIPELINES_NAMESPACE = "<YOUR_NAME>-ci-cd"
e36a5b 71         APP_NAME = "todolist-api"
D 72
73         JENKINS_TAG = "${JOB_NAME}.${BUILD_NUMBER}".replace("/", "-")
74         JOB_NAME = "${JOB_NAME}".replace("/", "-")
75
76         GIT_SSL_NO_VERIFY = true
77         GIT_CREDENTIALS = credentials('jenkins-git-creds')
530a25 78         GITLAB_DOMAIN = "gitlab.<APPS_URL>"
70ba2a 79         GITLAB_PROJECT = "<GIT_USERNAME>"
e36a5b 80     }
D 81 ```
82
83 2. With these changes in place, push your changes to the `feature/jenkinsfile` branch.
84 ```bash
fad576 85 git add Jenkinsfile
D 86 ```
87 ```bash
88 git commit -m "ADD - namespace and git repo to pipeline"
89 ```
90 ```bash
91 git push
e36a5b 92 ```
D 93
94 2. When the changes have been successfully pushed; Open Jenkins.
95
96 2. Create a `New Item` on Jenkins. Give it the name `todolist-api` and select `Multibranch Pipeline` from the bottom of the list as the job type.
97 ![multibranch-select](../images/exercise4/multibranch-select.png)
98
99 2. On the job's configure page; set the Branch Sources to `git`
100 ![multibranch-select-git](../images/exercise4/multibranch-select-git.png)
101
530a25 102 2. Fill in the Git settings with your `todolist-api` GitLab url and set the credentials as you've done before. `https://gitlab.<APPS_URL>/<YOUR_NAME>/todolist-api.git`
e36a5b 103 ![multibranch-git](../images/exercise4/multibranch-git.png)
D 104
1173e5 105 2. Set the `Scan Multibranch Pipeline Triggers` to be periodic and the interval to 1 minute. This will poll the GitLab instance for new branches or change sets to build.
e36a5b 106 ![multibranch-scan-time](../images/exercise4/multibranch-scan-time.png)
D 107
e43fd2 108 2. Save the Job configuration to run the intial scan. The log will show scans for `master` and `develop` branches, which have no `Jenkinsfile` so are skipped. The resulting view will show the `feature/jenkinsfile` job corresponding the only branch that currently has one. The build should run automatically.
e36a5b 109 ![todolist-api-multi](../images/exercise4/todolist-api-multi.png)
D 110
ed472a 111 2. The pipeline file is setup to only run `bake` & `deploy` stages when on `master` or `develop` branch. This is to provide us with very fast feedback for team members working on feature or bug fix branches. Each time someone commits or creates a new branch a basic build with testing occurs to give very rapid feedback to the team. Let's now update our  `master` and `develop` branches to include the Jenkinsfile and delete the feature branch.
e36a5b 112 ```bash
fad576 113 git checkout develop
D 114 ```
115 ```bash
116 git merge feature/jenkinsfile
ed472a 117 # you may get merge conflicts at this point
fad576 118 ```
D 119 ```bash
120 git add .
121 ```
122 ```bash
123 git commit -m "Jenkinsfile updates"
124 ```
125 ```bash
126 git checkout master
127 ```
128 ```bash
129 git merge develop
130 ```
131 ```bash
132 git push -u origin --all
133 ```
134 ```bash
e36a5b 135 # this is to delete the branch from the remote
fad576 136 git push origin :feature/jenkinsfile
e36a5b 137 ```
D 138
139 2. Back on Jenkins we should see our `todolist-api` pipelines have changed with the `develop` and `master` now appearing. The feature was deleted so this job should have gone away.
140 ![todolist-api-multi-dev-test](../images/exercise4/todolist-api-multi-dev-test.png)
141
142 2. With the builds running for  `develop` and `master` we can explore the Blue Ocean View for Jenkins. On the Job overview page, hit the Open Blue Ocean ![open-blue-ocean](../images/exercise4/open-blue-ocean.png)
143  button on the side to see what modern Jenkins looks like.
144 ![blue-ocean-todolist-api](../images/exercise4/blue-ocean-todolist-api.png)
145
146 2.  We can move on to the `todolist-fe` job. The process is the same as before, checkout the feature branch
147 ```bash
fad576 148 cd todolist-fe
D 149 ```
150 ```bash
151 git checkout feature/jenkinsfile
e36a5b 152 ```
D 153
1173e5 154 2. Open up your `todolist-fe` application in your favourite editor and move to the `Jenkinsfile` in the root of the project. Update all `<YOUR_NAME>` and `<GIT_USERNAME>` as you did before, including in the prepare environment steps. Check the  `GITLAB_DOMAIN` is set too.
ed472a 155 ![jenkinsfile-prep](../images/exercise4/jenkinsfile-prep.png)
e36a5b 156
1173e5 157 2. Commit your changes to your feature branch as you did previously.
e36a5b 158 ```bash
fad576 159 git add Jenkinsfile
D 160 ```
161 ```bash
162 git commit -m "ADD - namespace and git repo to pipeline"
163 ```
164 ```bash
165 git push
e36a5b 166 ```
D 167
168 2. This time update your master and develop branches before creating config in Jenkins
169 ```
fad576 170 git checkout develop
D 171 ```
172 ```bash
173 git merge feature/jenkinsfile
ed472a 174 # you may get merge conflicts at this point
fad576 175 ```
D 176 ```bash
177 git add .
178 ```
179 ```bash
180 git commit -m "Jenkinsfile updates"
181 ```
182 ```bash
183 git checkout master
184 ```
185 ```bash
186 git merge develop
187 ```
188 ```bash
ed472a 189 # this is to delete the branch from the remote
fad576 190 git push origin :feature/jenkinsfile
D 191 ```
192 ```bash
193 git push -u origin --all
e36a5b 194 ```
D 195
196 2. On Jenkins; create a new `Multibranch Pipeline` job called `todolist-fe`.
197
1173e5 198 2. Add the `todolist-fe` git repository and set the credentials for git accordingly.
e36a5b 199
D 200 2. Set the trigger to scan every minute as done previously. Save the configuration and we should see the collection of Jobs as shown below.
201 ![todolist-fe-multi](../images/exercise4/todolist-fe-multi.png)
202
6769e3 203 2. Run the jobs and validate the app is working as expected in the `test` environment!
ed472a 204 ![todolist-test](../images/exercise4/todolist-test.png)
34fb36 205
D 206 ### Part 2 - OCP Pipeline
207 > _This exercise adds a new BuildConfig to our cluster for the todolist-apps to run their pipelines in OpenShift using the OpenShift Jenkins Sync Plugin. We will use the OpenShift Applier to create the content in the cluster_
208
b2ce13 209 2. Open the `todolist-fe` app in your favourite editor. Move to the `.openshift-applier` directory. Explore the `template/ocp-pipeline`. This template creates a BuildConfig for OpenShift with a Jenkinsfile from a given repo. In this case; it will be the `Jenkinsfile` at the root of our application.
34fb36 210
D 211 2. Open the `params/ocp-pipeline` file and update `PIPELINE_SOURCE_REPOSITORY_URL` with the git url of your project (Don't forget to add the `.git` at the end). For example:
212 ```
530a25 213 PIPELINE_SOURCE_REPOSITORY_URL=https://gitlab.<APPS_URL>/<GIT_USERNAME>/todolist-fe.git
34fb36 214 PIPELINE_SOURCE_REPOSITORY_REF=develop
D 215 NAME=todolist-fe
216 ```
217
b2ce13 218 2. Create a new object in `inventory/group_vars/all.yml` to drive the `ocp-pipeline` template with the parameters file you've just created. It can be put under the existing `todolist-fe-build` object.
34fb36 219 ```yaml
D 220   - name: todolist-ocp-pipeline
221     template: "{{ playbook_dir }}/templates/ocp-pipeline.yml"
222     params: "{{ playbook_dir }}/params/ocp-pipeline"
223     namespace: "{{ ci_cd_namespace }}"
224     tags:
225     - pipeline
226 ```
227 ![ocp-pipeline-applier](../images/exercise4/ocp-pipeline-applier.png)
228
1173e5 229 2. Use the OpenShift Applier to create the cluster content
34fb36 230 ```bash
fad576 231 cd .openshift-applier
D 232 ```
233 ```bash
234 ansible-playbook apply.yml -i inventory/ \
34fb36 235      -e "filter_tags=pipeline"
D 236 ```
237
d4f1fa 238 2. With these changes in place, commit your changes to GitLab
D 239 ```bash
fad576 240 git add .
D 241 ```
242 ```bash
243 git commit -m "ADD - ocp pipeline in git repo"
244 ```
245 ```bash
246 git push
d4f1fa 247 ```
D 248
34fb36 249 2. Login to your OpenShift Cluster and go to the `<YOUR_NAME>-ci-cd` namespace. On the side menu; hit Builds > Pipeline to see your newly created pipeline running in OCP Land.
D 250 ![ocp-pipeline-view](../images/exercise4/ocp-pipeline-view.png)
251
252 2. Running the pipeline from here will run it in Jenkins. You can see the job sync between OpenShift and Jenkins if you login to Jenkins. You should see a folder with `<YOUR_NAME>-ci-cd` and your pipeline jobs inside of it.
253 ![ocp-pipeline-jenkins](../images/exercise4/ocp-pipeline-jenkins.png)
254
255 2. With the configuration in place for the `todolist-fe`; repeat the process for the `todolist-api`. Update the `todolist-api/.openshift-applier/inventory/group_vars/all.yml` with a new object to drive the params and template
256 ```yaml
d4f1fa 257   - name: todolist-ocp-pipeline
34fb36 258     template: "{{ playbook_dir }}/templates/ocp-pipeline.yml"
D 259     params: "{{ playbook_dir }}/params/ocp-pipeline"
260     namespace: "{{ ci_cd_namespace }}"
261     tags:
262     - pipeline
263 ```
264
265 2. Update the `todolist-api/.openshift-applier/params/ocp-pipeline`
266 ```
530a25 267 PIPELINE_SOURCE_REPOSITORY_URL=https://gitlab.<APPS_URL>/<GIT_USERNAME>/todolist-api.git
34fb36 268 PIPELINE_SOURCE_REPOSITORY_REF=develop
D 269 NAME=todolist-api
270 ```
271
1173e5 272 2. Use the OpenShift Applier to create the cluster content
34fb36 273 ```bash
fad576 274 cd todolist-api/.openshift-applier
D 275 ```
276 ```bash
277 ansible-playbook apply.yml -i inventory/ \
34fb36 278      -e "filter_tags=pipeline"
D 279 ```
280
281 2. Login to your OpenShift Cluster and go to the `<YOUR_NAME>-ci-cd` namespace. On the side menu; hit Builds > Pipeline to see your newly created pipeline running in OCP Land.
282 ![ocp-pipeline-view2](../images/exercise4/ocp-pipeline-view2.png)
283
d4f1fa 284 2. Commit your changes to GitLab
D 285 ```bash
fad576 286 git add .
D 287 ```
288 ```bash
289 git commit -m "ADD - ocp pipeline in git repo"
290 ```
291 ```bash
292 git push
d4f1fa 293 ```
34fb36 294
D 295 ### Part 3 - Security Scanning Slaves
e36a5b 296 > _This exercise focuses on updating the `enablement-ci-cd` repo with some new jenkins-slave pods for use in future exercise_
43f2f2 297
d4f1fa 298 #### 3a - OWASP ZAP
6769e3 299 > _OWASP ZAP (Zed Attack Proxy) is a free open source security tool used for finding security vulnerabilities in web applications._
A 300
40c0ca 301 3. On your  terminal; move to the `enablement-ci-cd` repo.  We need to checkout a template for OpenShift to build our Jenkins Slave images and some parameters for the `zap` slave.
6769e3 302 ```bash
40c0ca 303 git checkout exercise4/zap-and-arachni params/jenkins-slave-zap templates/jenkins-slave-generic-template.yml
6769e3 304 ```
A 305
5b1604 306 3. This should have created the following files which we will fill out. We will use a `ZAP` image hosted on the `rht-labs/ci-cd` repo so there will be no `Dockerfile` needed:
e32e5c 307     - `params/jenkins-slave-zap`
6769e3 308
da9923 309 3. Create an object in `inventory/host_vars/ci-cd-tooling.yml` called `jenkins-slave-zap` and add the following content:
054490 310 ```yaml
da9923 311     - name: "jenkins-slave-zap"
b664dc 312       namespace: "{{ ci_cd_namespace }}"
D 313       template: "{{ playbook_dir }}/templates/jenkins-slave-generic-template.yml"
da9923 314       params: "{{ playbook_dir }}/params/jenkins-slave-zap"
b664dc 315       tags:
D 316       - zap
6769e3 317 ```
2c15b7 318 ![zap-object](../images/exercise4/zap-object.png)
6769e3 319
A 320 3. Run the ansible playbook filtering with tag `zap` so only the zap build pods are run.
321 ```bash
fad576 322 ansible-playbook apply.yml -e target=tools \
b664dc 323      -i inventory/ \
D 324      -e "filter_tags=zap"
6769e3 325 ```
A 326
530a25 327 3. Head to <CLUSTER_URL> on OpenShift and move to your ci-cd project > builds. You should see `jenkins-slave-zap` has been built.
e32e5c 328 ![zap-build](../images/exercise4/zap-build.png)
6769e3 329
d4f1fa 330 #### 3b - Arachni Scan
6769e3 331 > _Arachni is a feature-full, modular, high-performance Ruby framework aimed towards helping penetration testers and administrators evaluate the security of web applications._
e32e5c 332
1173e5 333 3. On your terminal; checkout the params and Docker file. The Dockerfile for the `Arachni` scanner is included here and we will point the build to it.
e32e5c 334 ```bash
1173e5 335 git checkout exercise4/zap-and-arachni params/jenkins-slave-arachni docker/jenkins-slave-arachni
e32e5c 336 ```
6769e3 337
da9923 338 3. Create an object in `inventory/host_vars/ci-cd-tooling.yml` called `jenkins-slave-arachni` with the following content:
054490 339 ```yaml
da9923 340     - name: "jenkins-slave-arachni"
b664dc 341       namespace: "{{ ci_cd_namespace }}"
D 342       template: "{{ playbook_dir }}/templates/jenkins-slave-generic-template.yml"
da9923 343       params: "{{ playbook_dir }}/params/jenkins-slave-arachni"
b664dc 344       tags:
D 345       - arachni
6769e3 346 ```
A 347
1173e5 348 3. Update the `jenkins-slave-arachni` files `SOURCE_REPOSITORY_URL` to point to your GitLab's hosted version of the `enablement-ci-cd` repo.
e32e5c 349 ```
530a25 350 SOURCE_REPOSITORY_URL=https://gitlab.<APPS_URL>/<GIT_USERNAME>/enablement-ci-cd.git
e32e5c 351 SOURCE_CONTEXT_DIR=docker/jenkins-slave-arachni
D 352 BUILDER_IMAGE_NAME=registry.access.redhat.com/openshift3/jenkins-slave-base-rhel7:latest
353 NAME=jenkins-slave-arachni
354 SOURCE_REPOSITORY_REF=master
355 ```
356
357 3. With these changes in place, push your changes to the `master` branch.
358 ```bash
fad576 359 git add .
D 360 ```
361 ```bash
362 git commit -m "ADD - Arachni scanning image"
363 ```
364 ```bash
365 git push
e32e5c 366 ```
D 367
1173e5 368 3. Run the Ansible playbook filtering with tag `arachni` so only the arachni build pods are run.
6769e3 369 ```bash
fad576 370 ansible-playbook apply.yml -e target=tools \
b664dc 371      -i inventory/ \
D 372      -e "filter_tags=arachni"
6769e3 373 ```
A 374
530a25 375 3. Head to <CLUSTER_URL> on OpenShift and move to your ci-cd project > builds. You should see  `jenkins-slave-arachni`.
33c738 376 ![builds-zap-arachni](../images/exercise4/builds-zap-arachni.png)
43f2f2 377
D 378 _____
379
380 ## Extension Tasks
381 > _Ideas for go-getters. Advanced topic for doers to get on with if they finish early. These will usually not have a solution and are provided for additional scope._
e36a5b 382
D 383 Jenkins S2I
384  - Add the multi-branch configuration to the S2I to have Jenkins come alive with the `todolist-api` and `-fe` configuration cooked into it for future uses.
385
d608d6 386 Jenkins Pipeline Extension
e43fd2 387  - Add an extension to the pipeline that promotes code to the UAT environment once the master job has been successful.
1173e5 388  - Use a WAIT to allow for manual input to approve the promotion
d608d6 389
D 390 Jenkins e2e extension (blue/green)
db509f 391  - Add a step in the pipeline to only deploy to the `test` environment if the e2e tests have run successfully against which ever environment (blue or green) is not deployed.
43f2f2 392
D 393 ## Additional Reading
394 > List of links or other reading that might be of use / reference for the exercise
395
01c4da 396 ## Slide Links
RH 397
398 - [Intro](https://docs.google.com/presentation/d/1B3Fv4g66zZ8ZkqBq9TYmImJhUDvMecXCt4q3DXGWhjc/)
399 - [Wrap-up](https://docs.google.com/presentation/d/1EOk6y798Xh1hsaQlxRuqyr23FIIf7sNY4any_yXIL7A/)
1173e5 400 - [All Material](https://drive.google.com/drive/folders/1oCjpl33Db7aPocmpu3NNF0B9czRvFq3m)