Ravi Srinivasan
2019-01-30 44d7bcd56160adfdaced32ccfa80728b5a79f1c1
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
44d7bc 5 <!-- ![jenkins-fail-meme](../images/exercise4/jenkins-fail-meme.jpeg) -->
921415 6
e36a5b 7 There are a number of ways pipeline as code can be achieved in Jenkins.
44d7bc 8
1173e5 9  * 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.
44d7bc 10
8894bf 11  * 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.
44d7bc 12
dd12d4 13  * 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 14
43f2f2 15 _____
D 16
17 ## Learning Outcomes
18 As a learner you will be able to
1173e5 19 - Use a Jenkinsfile to create a declarative pipeline to build, bake and deploy the Todolist App
CM 20 - Identify the differences between scripted, declarative and DSL pipelines
b5d705 21 - Create Jenkins slave nodes for use in builds in future exercises
43f2f2 22
D 23 ## Tools and Frameworks
44d7bc 24 <!-- > Name of tool - short description and link to docs or website -->
43f2f2 25
44d7bc 26 1. [Jenkins Pipeline](https://jenkins.io/doc/book/pipeline/) - Overview of the Jenkinsfile approach
e36a5b 27 1. [Pipeline Syntax](https://jenkins.io/doc/book/pipeline/syntax/) - Documentation for the declarative pipeline
D 28 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 29 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 30 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 31
D 32 ## Big Picture
664135 33 > 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 34
14a966 35 ![big-picture](../images/big-picture/big-picture-4.jpg)
43f2f2 36
D 37 _____
38
44d7bc 39 <!-- ## 10,000 Ft View
b5d705 40 > 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 41
e43fd2 42 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 43
44d7bc 44 2. Create two new Jenkins slaves for the `OWASP ZAP` scanner and the `Arachni` WebCrawler -->
43f2f2 45
D 46 ## Step by Step Instructions
44d7bc 47 <!-- > This is a fairly structured guide with references to exact filenames and sections of text to be added. -->
43f2f2 48
e36a5b 49 ### Part 1 - The Jenkinsfile
44d7bc 50 > _In this exercise we'll replace the Pipeline we created in the previous with a Jenkinsfile approach_
43f2f2 51
e36a5b 52 2. On your terminal navigate to your `todolist-api` project and checkout the pipeline feature branch that's been already created for you.
D 53 ```bash
fad576 54 git checkout feature/jenkinsfile
43f2f2 55 ```
D 56
1173e5 57 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 58 ![pipeline-overview](../images/exercise4/pipeline-overview.png)
D 59 Some of the key things to note:
1173e5 60     * `pipeline {}` is how all declarative Jenkins pipelines begin.
db509f 61     * `environment {}` defines environment variables to be used across all build stages
A 62     * `options {}` contains specific Job specs you want to run globally across the jobs e.g. setting the terminal colour
63     * `stage {}` all jobs must have one stage. This is the logical part of the build that will be executed e.g. `bake-image`
e36a5b 64     * `steps {}` each `stage` has one or more steps involved. These could be execute shell or git checkout etc.
1173e5 65     * `agent {}` specifies the node the build should be run on e.g. `jenkins-slave-npm`
e43fd2 66     * `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 67     * `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 68
b5d705 69 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 70 ```groovy
D 71     environment {
72         // GLobal Vars
dd12d4 73         PIPELINES_NAMESPACE = "<YOUR_NAME>-ci-cd"
e36a5b 74         APP_NAME = "todolist-api"
D 75
76         JENKINS_TAG = "${JOB_NAME}.${BUILD_NUMBER}".replace("/", "-")
77         JOB_NAME = "${JOB_NAME}".replace("/", "-")
78
79         GIT_SSL_NO_VERIFY = true
80         GIT_CREDENTIALS = credentials('jenkins-git-creds')
530a25 81         GITLAB_DOMAIN = "gitlab.<APPS_URL>"
70ba2a 82         GITLAB_PROJECT = "<GIT_USERNAME>"
e36a5b 83     }
D 84 ```
85
86 2. With these changes in place, push your changes to the `feature/jenkinsfile` branch.
87 ```bash
fad576 88 git add Jenkinsfile
D 89 ```
90 ```bash
91 git commit -m "ADD - namespace and git repo to pipeline"
92 ```
93 ```bash
94 git push
e36a5b 95 ```
D 96
97 2. When the changes have been successfully pushed; Open Jenkins.
98
99 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.
100 ![multibranch-select](../images/exercise4/multibranch-select.png)
101
102 2. On the job's configure page; set the Branch Sources to `git`
103 ![multibranch-select-git](../images/exercise4/multibranch-select-git.png)
104
530a25 105 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 106 ![multibranch-git](../images/exercise4/multibranch-git.png)
D 107
1173e5 108 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 109 ![multibranch-scan-time](../images/exercise4/multibranch-scan-time.png)
D 110
e43fd2 111 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 112 ![todolist-api-multi](../images/exercise4/todolist-api-multi.png)
D 113
ed472a 114 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 115 ```bash
fad576 116 git checkout develop
D 117 ```
118 ```bash
119 git merge feature/jenkinsfile
ed472a 120 # you may get merge conflicts at this point
fad576 121 ```
D 122 ```bash
123 git add .
124 ```
125 ```bash
126 git commit -m "Jenkinsfile updates"
127 ```
128 ```bash
129 git checkout master
130 ```
131 ```bash
132 git merge develop
133 ```
134 ```bash
135 git push -u origin --all
136 ```
137 ```bash
e36a5b 138 # this is to delete the branch from the remote
fad576 139 git push origin :feature/jenkinsfile
e36a5b 140 ```
D 141
142 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.
143 ![todolist-api-multi-dev-test](../images/exercise4/todolist-api-multi-dev-test.png)
144
145 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)
146  button on the side to see what modern Jenkins looks like.
147 ![blue-ocean-todolist-api](../images/exercise4/blue-ocean-todolist-api.png)
148
149 2.  We can move on to the `todolist-fe` job. The process is the same as before, checkout the feature branch
150 ```bash
fad576 151 cd todolist-fe
D 152 ```
153 ```bash
154 git checkout feature/jenkinsfile
e36a5b 155 ```
D 156
1173e5 157 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 158 ![jenkinsfile-prep](../images/exercise4/jenkinsfile-prep.png)
e36a5b 159
1173e5 160 2. Commit your changes to your feature branch as you did previously.
e36a5b 161 ```bash
fad576 162 git add Jenkinsfile
D 163 ```
164 ```bash
165 git commit -m "ADD - namespace and git repo to pipeline"
166 ```
167 ```bash
168 git push
e36a5b 169 ```
D 170
171 2. This time update your master and develop branches before creating config in Jenkins
172 ```
fad576 173 git checkout develop
D 174 ```
175 ```bash
176 git merge feature/jenkinsfile
ed472a 177 # you may get merge conflicts at this point
fad576 178 ```
D 179 ```bash
180 git add .
181 ```
182 ```bash
183 git commit -m "Jenkinsfile updates"
184 ```
185 ```bash
186 git checkout master
187 ```
188 ```bash
189 git merge develop
190 ```
191 ```bash
ed472a 192 # this is to delete the branch from the remote
fad576 193 git push origin :feature/jenkinsfile
D 194 ```
195 ```bash
196 git push -u origin --all
e36a5b 197 ```
D 198
199 2. On Jenkins; create a new `Multibranch Pipeline` job called `todolist-fe`.
200
1173e5 201 2. Add the `todolist-fe` git repository and set the credentials for git accordingly.
e36a5b 202
D 203 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.
204 ![todolist-fe-multi](../images/exercise4/todolist-fe-multi.png)
205
6769e3 206 2. Run the jobs and validate the app is working as expected in the `test` environment!
ed472a 207 ![todolist-test](../images/exercise4/todolist-test.png)
34fb36 208
D 209 ### Part 2 - OCP Pipeline
210 > _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_
211
b2ce13 212 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 213
D 214 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:
215 ```
530a25 216 PIPELINE_SOURCE_REPOSITORY_URL=https://gitlab.<APPS_URL>/<GIT_USERNAME>/todolist-fe.git
34fb36 217 PIPELINE_SOURCE_REPOSITORY_REF=develop
D 218 NAME=todolist-fe
219 ```
220
b2ce13 221 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 222 ```yaml
D 223   - name: todolist-ocp-pipeline
224     template: "{{ playbook_dir }}/templates/ocp-pipeline.yml"
225     params: "{{ playbook_dir }}/params/ocp-pipeline"
226     namespace: "{{ ci_cd_namespace }}"
227     tags:
228     - pipeline
229 ```
230 ![ocp-pipeline-applier](../images/exercise4/ocp-pipeline-applier.png)
231
1173e5 232 2. Use the OpenShift Applier to create the cluster content
34fb36 233 ```bash
fad576 234 cd .openshift-applier
D 235 ```
236 ```bash
237 ansible-playbook apply.yml -i inventory/ \
34fb36 238      -e "filter_tags=pipeline"
D 239 ```
240
d4f1fa 241 2. With these changes in place, commit your changes to GitLab
D 242 ```bash
fad576 243 git add .
D 244 ```
245 ```bash
246 git commit -m "ADD - ocp pipeline in git repo"
247 ```
248 ```bash
249 git push
d4f1fa 250 ```
D 251
34fb36 252 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 253 ![ocp-pipeline-view](../images/exercise4/ocp-pipeline-view.png)
254
255 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.
256 ![ocp-pipeline-jenkins](../images/exercise4/ocp-pipeline-jenkins.png)
257
258 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
259 ```yaml
d4f1fa 260   - name: todolist-ocp-pipeline
34fb36 261     template: "{{ playbook_dir }}/templates/ocp-pipeline.yml"
D 262     params: "{{ playbook_dir }}/params/ocp-pipeline"
263     namespace: "{{ ci_cd_namespace }}"
264     tags:
265     - pipeline
266 ```
267
268 2. Update the `todolist-api/.openshift-applier/params/ocp-pipeline`
269 ```
530a25 270 PIPELINE_SOURCE_REPOSITORY_URL=https://gitlab.<APPS_URL>/<GIT_USERNAME>/todolist-api.git
34fb36 271 PIPELINE_SOURCE_REPOSITORY_REF=develop
D 272 NAME=todolist-api
273 ```
274
1173e5 275 2. Use the OpenShift Applier to create the cluster content
34fb36 276 ```bash
fad576 277 cd todolist-api/.openshift-applier
D 278 ```
279 ```bash
280 ansible-playbook apply.yml -i inventory/ \
34fb36 281      -e "filter_tags=pipeline"
D 282 ```
283
284 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.
285 ![ocp-pipeline-view2](../images/exercise4/ocp-pipeline-view2.png)
286
d4f1fa 287 2. Commit your changes to GitLab
D 288 ```bash
fad576 289 git add .
D 290 ```
291 ```bash
292 git commit -m "ADD - ocp pipeline in git repo"
293 ```
294 ```bash
295 git push
d4f1fa 296 ```
34fb36 297
D 298 ### Part 3 - Security Scanning Slaves
44d7bc 299 > _This part of the exercise focuses on updating the `enablement-ci-cd` repo with some new jenkins-slave pods for use in future exercise_
43f2f2 300
44d7bc 301 <!-- #### 3a - OWASP ZAP
6769e3 302 > _OWASP ZAP (Zed Attack Proxy) is a free open source security tool used for finding security vulnerabilities in web applications._
A 303
40c0ca 304 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 305 ```bash
40c0ca 306 git checkout exercise4/zap-and-arachni params/jenkins-slave-zap templates/jenkins-slave-generic-template.yml
6769e3 307 ```
A 308
5b1604 309 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 310     - `params/jenkins-slave-zap`
6769e3 311
da9923 312 3. Create an object in `inventory/host_vars/ci-cd-tooling.yml` called `jenkins-slave-zap` and add the following content:
054490 313 ```yaml
da9923 314     - name: "jenkins-slave-zap"
b664dc 315       namespace: "{{ ci_cd_namespace }}"
D 316       template: "{{ playbook_dir }}/templates/jenkins-slave-generic-template.yml"
da9923 317       params: "{{ playbook_dir }}/params/jenkins-slave-zap"
b664dc 318       tags:
D 319       - zap
6769e3 320 ```
2c15b7 321 ![zap-object](../images/exercise4/zap-object.png)
6769e3 322
A 323 3. Run the ansible playbook filtering with tag `zap` so only the zap build pods are run.
324 ```bash
fad576 325 ansible-playbook apply.yml -e target=tools \
b664dc 326      -i inventory/ \
D 327      -e "filter_tags=zap"
6769e3 328 ```
A 329
530a25 330 3. Head to <CLUSTER_URL> on OpenShift and move to your ci-cd project > builds. You should see `jenkins-slave-zap` has been built.
44d7bc 331 ![zap-build](../images/exercise4/zap-build.png) -->
6769e3 332
d4f1fa 333 #### 3b - Arachni Scan
6769e3 334 > _Arachni is a feature-full, modular, high-performance Ruby framework aimed towards helping penetration testers and administrators evaluate the security of web applications._
e32e5c 335
1173e5 336 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 337 ```bash
1173e5 338 git checkout exercise4/zap-and-arachni params/jenkins-slave-arachni docker/jenkins-slave-arachni
e32e5c 339 ```
6769e3 340
da9923 341 3. Create an object in `inventory/host_vars/ci-cd-tooling.yml` called `jenkins-slave-arachni` with the following content:
054490 342 ```yaml
da9923 343     - name: "jenkins-slave-arachni"
b664dc 344       namespace: "{{ ci_cd_namespace }}"
D 345       template: "{{ playbook_dir }}/templates/jenkins-slave-generic-template.yml"
da9923 346       params: "{{ playbook_dir }}/params/jenkins-slave-arachni"
b664dc 347       tags:
D 348       - arachni
6769e3 349 ```
A 350
1173e5 351 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 352 ```
530a25 353 SOURCE_REPOSITORY_URL=https://gitlab.<APPS_URL>/<GIT_USERNAME>/enablement-ci-cd.git
e32e5c 354 SOURCE_CONTEXT_DIR=docker/jenkins-slave-arachni
D 355 BUILDER_IMAGE_NAME=registry.access.redhat.com/openshift3/jenkins-slave-base-rhel7:latest
356 NAME=jenkins-slave-arachni
357 SOURCE_REPOSITORY_REF=master
358 ```
359
360 3. With these changes in place, push your changes to the `master` branch.
361 ```bash
fad576 362 git add .
D 363 ```
364 ```bash
365 git commit -m "ADD - Arachni scanning image"
366 ```
367 ```bash
368 git push
e32e5c 369 ```
D 370
1173e5 371 3. Run the Ansible playbook filtering with tag `arachni` so only the arachni build pods are run.
6769e3 372 ```bash
fad576 373 ansible-playbook apply.yml -e target=tools \
b664dc 374      -i inventory/ \
D 375      -e "filter_tags=arachni"
6769e3 376 ```
A 377
530a25 378 3. Head to <CLUSTER_URL> on OpenShift and move to your ci-cd project > builds. You should see  `jenkins-slave-arachni`.
33c738 379 ![builds-zap-arachni](../images/exercise4/builds-zap-arachni.png)
43f2f2 380
D 381 _____
382
44d7bc 383 <!-- ## Extension Tasks
43f2f2 384 > _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 385
D 386 Jenkins S2I
387  - 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.
388
d608d6 389 Jenkins Pipeline Extension
e43fd2 390  - Add an extension to the pipeline that promotes code to the UAT environment once the master job has been successful.
1173e5 391  - Use a WAIT to allow for manual input to approve the promotion
d608d6 392
D 393 Jenkins e2e extension (blue/green)
db509f 394  - 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 395
D 396 ## Additional Reading
397 > List of links or other reading that might be of use / reference for the exercise
398
01c4da 399 ## Slide Links
RH 400
401 - [Intro](https://docs.google.com/presentation/d/1B3Fv4g66zZ8ZkqBq9TYmImJhUDvMecXCt4q3DXGWhjc/)
402 - [Wrap-up](https://docs.google.com/presentation/d/1EOk6y798Xh1hsaQlxRuqyr23FIIf7sNY4any_yXIL7A/)
44d7bc 403 - [All Material](https://drive.google.com/drive/folders/1oCjpl33Db7aPocmpu3NNF0B9czRvFq3m) -->