├── LICENSE ├── README.md ├── bootstrap ├── deploy_demo.yaml ├── deploy_signing.yaml └── roles │ ├── ocp4-config-gitops │ ├── tasks │ │ ├── argocd.yaml │ │ └── main.yaml │ └── templates │ │ ├── argocd-app-dev.yaml.j2 │ │ ├── argocd-app-stage.yaml.j2 │ │ └── argocd-petclinic-project.yaml.j2 │ ├── ocp4-install-acs │ ├── defaults │ │ └── main.yaml │ ├── tasks │ │ ├── central.yaml │ │ ├── main.yaml │ │ └── sensor.yaml │ └── templates │ │ ├── acs-password.yml.j2 │ │ ├── central.yml.j2 │ │ ├── securedcluster.yaml.j2 │ │ └── subs.yml.j2 │ ├── ocp4-install-cicd │ ├── tasks │ │ ├── cicd.yaml │ │ └── main.yaml │ └── templates │ │ ├── cicd-gogs-configmap.yaml.j2 │ │ ├── cicd-gogs.yaml.j2 │ │ ├── cicd-nexus.yaml.j2 │ │ ├── cicd-rb.yaml.j2 │ │ ├── cicd-reports-repo.yaml.j2 │ │ └── cicd-sonarqube.yaml.j2 │ ├── ocp4-install-gitops │ ├── defaults │ │ └── main.yaml │ ├── tasks │ │ ├── gitops.yaml │ │ ├── main.yaml │ │ └── pre.yaml │ └── templates │ │ ├── gitops-argocd.yaml.j2 │ │ ├── gitops-env-cm.yaml.j2 │ │ ├── gitops-env-secret.yaml.j2 │ │ ├── gitops-rb.yml.j2 │ │ ├── namespaces.yaml.j2 │ │ ├── subs-gitops.yml.j2 │ │ └── subs-pipelines.yml.j2 │ ├── ocp4-install-noobaa │ ├── defaults │ │ └── main.yaml │ ├── tasks │ │ ├── main.yaml │ │ └── noobaa-create.yaml │ └── templates │ │ ├── noobaa-backingstore.yaml.j2 │ │ ├── noobaa-object.yaml.j2 │ │ ├── ocs-subscription.yaml.j2 │ │ ├── odf-namespace.yaml.j2 │ │ ├── odf-subscription.yaml.j2 │ │ └── operatorgroup-storage.yaml.j2 │ ├── ocp4-install-pipelines │ ├── defaults │ │ └── main.yaml │ ├── tasks │ │ ├── main.yaml │ │ └── pipelines.yaml │ └── templates │ │ ├── cicd-gogs-init-taskrun.yaml.j2 │ │ ├── pipeline-build-dev.yaml.j2 │ │ ├── pipeline-build-pvc.yaml.j2 │ │ ├── pipeline-build-stage.yaml.j2 │ │ ├── task-argo-sync-and-wait.yaml.j2 │ │ ├── task-dependency-report.yaml.j2 │ │ ├── task-gatling.yaml.j2 │ │ ├── task-git-update-deployment.yaml.j2 │ │ ├── task-image-scan-task.yaml.j2 │ │ ├── task-mvn-cm.yaml.j2 │ │ ├── task-mvn.yaml.j2 │ │ ├── task-rox-deployment-check.yaml.j2 │ │ ├── task-rox-image-check.yaml.j2 │ │ ├── task-s2i-java-11.yaml.j2 │ │ ├── task-zap-proxy.yaml.j2 │ │ ├── trigger-eventlistener-route.yaml.j2 │ │ ├── trigger-eventlistener.yaml.j2 │ │ ├── trigger-gogs-triggerbinding.yaml.j2 │ │ └── triggertemplate.yaml.j2 │ ├── ocp4-install-quay │ ├── defaults │ │ └── main.yaml │ ├── tasks │ │ ├── configure-quay.yaml │ │ ├── install-quay.yaml │ │ └── main.yaml │ └── templates │ │ ├── quay-config-secret.yaml.j2 │ │ ├── quay-namespace.yaml.j2 │ │ ├── quay-subscription.yaml.j2 │ │ └── quayregistry.yaml.j2 │ ├── ocp4-install-signing │ ├── defaults │ │ └── main.yaml │ ├── files │ │ └── policies │ │ │ └── signed-image-policy.json │ ├── tasks │ │ ├── add-cosign-secret-acs.yaml │ │ ├── build-cosign-infra.yaml │ │ ├── main.yaml │ │ ├── patch-pipeline.yaml │ │ └── tektonchain.yaml │ └── templates │ │ ├── cosign-anyuid-scc.yaml.j2 │ │ ├── cosign-build.yaml.j2 │ │ ├── cosign-deployment.yaml.j2 │ │ ├── cosign-is.yaml.j2 │ │ ├── cosign-role.yaml.j2 │ │ ├── cosign-rolebinding-cicd.yaml.j2 │ │ ├── cosign-rolebinding.yaml.j2 │ │ ├── cosign-serviceaccount.yaml.j2 │ │ ├── cosign-task.yaml.j2 │ │ ├── cosign-ubi-is.yaml.j2 │ │ ├── pipeline-build-dev.yaml.j2 │ │ ├── pipeline-build-stage.yaml.j2 │ │ └── tektonchain-cr.yaml.j2 │ └── ocp4-post-acs │ ├── defaults │ └── main.yaml │ ├── files │ └── policies │ │ ├── cvss_7.json │ │ ├── process_uid_0.json │ │ └── read_write_root_fs.json │ ├── tasks │ ├── main.yaml │ ├── policies.yaml │ └── post_ci.yaml │ └── templates │ ├── acs-console-link.yml.j2 │ ├── ocp_registry_acs.yml.j2 │ └── policy.json.j2 ├── demo.sh ├── docs ├── Steps.md ├── disable_policy_enforcement.md ├── pics │ ├── acs-trusted-signature-violation.png │ ├── demo_overview.png │ ├── pipeline-with-sign-task.png │ ├── pipeline1.png │ ├── pipeline2.png │ ├── pipeline3.png │ ├── pipeline4.png │ ├── pipeline5.png │ ├── pipeline6.png │ ├── quay-with-signatures.png │ ├── result0.png │ ├── result1.png │ ├── result10.png │ ├── result11.png │ ├── result12.png │ ├── result13.png │ ├── result14.png │ ├── result15.png │ ├── result16.png │ ├── result17.png │ ├── result18.png │ ├── result18_1.png │ ├── result19.png │ ├── result19_1.png │ ├── result1_1.png │ ├── result2.png │ ├── result20.png │ ├── result20_1.png │ ├── result20_2.png │ ├── result20_3.png │ ├── result20_4.png │ ├── result3.png │ ├── result4.png │ ├── result5.png │ ├── result6.png │ ├── result7.png │ ├── result8.png │ ├── result9.png │ ├── result99.png │ ├── result9_1.png │ └── taskrun.png ├── promote.md ├── slack_integration.md ├── todo.md ├── triggers.md └── tshoot.md ├── extend.sh ├── fix-image └── s2ijava-mgr.yaml ├── install.sh ├── run ├── pipeline-build-dev-run.yaml ├── pipeline-build-stage-run.yaml └── verify │ └── verify-pipeline.sh └── status.sh /bootstrap/deploy_demo.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: 'Install the ACS Demo' 3 | hosts: localhost 4 | connection: local 5 | tasks: 6 | 7 | - name: 'Install Gitops' 8 | include_role: 9 | name: "ocp4-install-gitops" 10 | 11 | - name: 'Install CICD Infra' 12 | include_role: 13 | name: "ocp4-install-cicd" 14 | 15 | - name: 'Install Pipelines' 16 | include_role: 17 | name: "ocp4-install-pipelines" 18 | 19 | - name: 'Config GitOps' 20 | include_role: 21 | name: "ocp4-config-gitops" 22 | 23 | - name: 'Install the ACS Central' 24 | include_role: 25 | name: "ocp4-install-acs" 26 | 27 | # Include the policies, and some content to show in the demo 28 | - name: 'Install the ACS Post Content' 29 | include_role: 30 | name: "ocp4-post-acs" 31 | -------------------------------------------------------------------------------- /bootstrap/deploy_signing.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: 'Extend Original Demo for Image and TaskRun Signing' 3 | hosts: localhost 4 | connection: local 5 | tasks: 6 | - name: 'Install NooBaa' 7 | include_role: 8 | name: "ocp4-install-noobaa" 9 | 10 | - name: 'Install and configure Quay' 11 | include_role: 12 | name: "ocp4-install-quay" 13 | 14 | - name: 'Install and Enable the infra for Signing and Tekton Chaining' 15 | include_role: 16 | name: "ocp4-install-signing" 17 | 18 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-config-gitops/tasks/argocd.yaml: -------------------------------------------------------------------------------- 1 | # Check Gogs 2 | - name: Get gogs route 3 | kubernetes.core.k8s_info: 4 | kind: Route 5 | api_version: route.openshift.io/v1 6 | namespace: cicd 7 | name: gogs 8 | register: r_gogs_route 9 | retries: 10 10 | delay: 20 11 | until: 12 | - r_gogs_route.resources[0].spec.host is defined 13 | 14 | - name: Create OpenShift Objects for ArgoCD projects 15 | k8s: 16 | state: present 17 | definition: "{{ lookup('template', item ) | from_yaml }}" 18 | loop: 19 | - ./templates/argocd-petclinic-project.yaml.j2 20 | - ./templates/argocd-app-dev.yaml.j2 21 | - ./templates/argocd-app-stage.yaml.j2 22 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-config-gitops/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | 2 | - import_tasks: argocd.yaml 3 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-config-gitops/templates/argocd-app-dev.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: dev-spring-petclinic 5 | namespace: openshift-gitops 6 | spec: 7 | destination: 8 | namespace: devsecops-dev 9 | server: https://kubernetes.default.svc 10 | project: spring-petclinic 11 | source: 12 | path: environments/dev 13 | repoURL: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic-config 14 | targetRevision: HEAD 15 | syncPolicy: 16 | automated: 17 | prune: false 18 | selfHeal: false 19 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-config-gitops/templates/argocd-app-stage.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: stage-spring-petclinic 5 | namespace: openshift-gitops 6 | spec: 7 | destination: 8 | namespace: devsecops-qa 9 | server: https://kubernetes.default.svc 10 | project: spring-petclinic 11 | source: 12 | path: environments/stage 13 | repoURL: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic-config 14 | targetRevision: HEAD 15 | syncPolicy: 16 | automated: 17 | prune: false 18 | selfHeal: false 19 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-config-gitops/templates/argocd-petclinic-project.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: AppProject 3 | metadata: 4 | name: spring-petclinic 5 | namespace: openshift-gitops 6 | spec: 7 | sourceRepos: 8 | - '*' 9 | destinations: 10 | - namespace: '*' 11 | server: '*' 12 | clusterResourceWhitelist: 13 | - group: '*' 14 | kind: '*' 15 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-acs/tasks/central.yaml: -------------------------------------------------------------------------------- 1 | - name: Get cluster version 2 | k8s_info: 3 | api_version: config.openshift.io/v1 4 | kind: ClusterVersion 5 | name: version 6 | register: r_cluster_version 7 | 8 | - name: Set ocp4_cluster_version fact 9 | set_fact: 10 | ocp4_cluster_version: "{{ r_cluster_version.resources[0].status.history[0].version }}" 11 | 12 | - name: Print OpenShift version 13 | debug: 14 | msg: "{{ ocp4_cluster_version }}" 15 | 16 | - name: Create ACS namespace 17 | kubernetes.core.k8s: 18 | name: stackrox 19 | api_version: v1 20 | kind: Namespace 21 | state: present 22 | 23 | - name: Create ACS Central password 24 | kubernetes.core.k8s: 25 | state: present 26 | definition: "{{ lookup('template', 'acs-password.yml.j2') }}" 27 | 28 | - name: Install ACS Operator 29 | kubernetes.core.k8s: 30 | state: present 31 | definition: "{{ lookup('template', 'subs.yml.j2') }}" 32 | 33 | - name: Adapt to the openshift_cluster_version LESS than 4.9 34 | when: ocp4_cluster_version is version_compare('4.9', '<') 35 | block: 36 | 37 | - name: Wait for ACS CRD to exist 38 | kubernetes.core.k8s_info: 39 | api_version: "apiextensions.k8s.io/v1beta1" 40 | kind: CustomResourceDefinition 41 | name: "{{ item }}" 42 | loop: "{{ acs_expected_crds }}" 43 | register: crds 44 | until: crds.resources|length > 0 45 | retries: 30 46 | delay: 10 47 | 48 | - name: Adapt to the openshift_cluster_version MORE than 4.9 49 | when: ocp4_cluster_version is version_compare('4.9', '>=') 50 | block: 51 | 52 | - name: Wait for ACS CRD to exist 53 | kubernetes.core.k8s_info: 54 | api_version: "apiextensions.k8s.io/v1" 55 | kind: CustomResourceDefinition 56 | name: "{{ item }}" 57 | loop: "{{ acs_expected_crds }}" 58 | register: crds 59 | until: crds.resources|length > 0 60 | retries: 30 61 | delay: 10 62 | 63 | - name: Wait for ACS Operator to be up and running 64 | pause: 65 | minutes: 1 66 | 67 | - name: Create ACS Central 68 | kubernetes.core.k8s: 69 | state: present 70 | definition: "{{ lookup('template', 'central.yml.j2') }}" 71 | 72 | - name: Get central route 73 | kubernetes.core.k8s_info: 74 | kind: Route 75 | api_version: route.openshift.io/v1 76 | namespace: stackrox 77 | name: central 78 | register: r_stackrox_central_route 79 | retries: 10 80 | delay: 20 81 | until: 82 | - r_stackrox_central_route.resources[0].spec.host is defined 83 | 84 | - name: Store central route as a fact 85 | set_fact: 86 | f_stackrox_central_addr: "{{ r_stackrox_central_route.resources[0].spec.host }}" 87 | 88 | - name: Wait for Central availability 89 | uri: 90 | url: "https://{{ f_stackrox_central_addr }}/v1/ping" 91 | method: GET 92 | user: admin 93 | password: "{{ stackrox_central_admin_password }}" 94 | force_basic_auth: true 95 | validate_certs: false 96 | register: result 97 | until: result.status == 200 98 | retries: 15 99 | delay: 20 100 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-acs/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | 2 | - import_tasks: central.yaml 3 | - import_tasks: sensor.yaml 4 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-acs/tasks/sensor.yaml: -------------------------------------------------------------------------------- 1 | - name: Get cluster init bundle 2 | uri: 3 | url: "https://{{ f_stackrox_central_addr }}/v1/cluster-init/init-bundles" 4 | body: "{ \"name\": \"prod-{{ lookup('password', '/dev/null chars=ascii_lowercase,digits length=8') }}\"}" 5 | method: POST 6 | user: admin 7 | password: "{{ stackrox_central_admin_password }}" 8 | body_format: json 9 | force_basic_auth: true 10 | validate_certs: false 11 | register: r_stackrox_cluster_init_response 12 | 13 | - name: Store cluster init bundle as a fact 14 | set_fact: 15 | f_stackrox_bundle: "{{ r_stackrox_cluster_init_response.json.kubectlBundle | b64decode }}" 16 | 17 | - name: Create init-bundle secrets 18 | kubernetes.core.k8s: 19 | namespace: stackrox 20 | state: present 21 | definition: "{{ f_stackrox_bundle }}" 22 | 23 | - name: Install Sensor on OpenShift Container Platform 24 | kubernetes.core.k8s: 25 | state: present 26 | definition: "{{ lookup('template', 'securedcluster.yaml.j2') }}" 27 | 28 | - name: Wait for ready sensor 29 | kubernetes.core.k8s_info: 30 | name: sensor 31 | kind: Deployment 32 | api_version: apps/v1 33 | namespace: stackrox 34 | register: r_stackrox_sensor_deployment 35 | until: 36 | - r_stackrox_sensor_deployment.resources[0].status.readyReplicas is defined 37 | - r_stackrox_sensor_deployment.resources[0].status.readyReplicas | int >= 1 38 | delay: 20 39 | retries: 15 40 | 41 | - name: Determine number of collectors 42 | kubernetes.core.k8s_info: 43 | name: collector 44 | kind: DaemonSet 45 | api_version: apps/v1 46 | namespace: stackrox 47 | register: r_stackrox_collector_daemonset 48 | until: r_stackrox_collector_daemonset.resources[0].status.desiredNumberScheduled is defined 49 | 50 | - name: Wait for collectors 51 | kubernetes.core.k8s_info: 52 | name: collector 53 | kind: DaemonSet 54 | api_version: apps/v1 55 | namespace: stackrox 56 | register: r_stackrox_collector_daemonset 57 | until: 58 | - r_stackrox_collector_daemonset.resources[0].status.numberReady is defined 59 | # yamllint disable-line rule:line-length 60 | - r_stackrox_collector_daemonset.resources[0].status.numberReady | int == r_stackrox_collector_daemonset.resources[0].status.desiredNumberScheduled | int 61 | delay: 20 62 | retries: 15 63 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-acs/templates/acs-password.yml.j2: -------------------------------------------------------------------------------- 1 | kind: Secret 2 | apiVersion: v1 3 | metadata: 4 | name: acs-password 5 | namespace: stackrox 6 | data: 7 | password: c3RhY2tyb3g= 8 | type: Opaque 9 | 10 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-acs/templates/central.yml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: platform.stackrox.io/v1alpha1 2 | kind: Central 3 | metadata: 4 | namespace: stackrox 5 | name: stackrox-central-services 6 | spec: 7 | central: 8 | adminPasswordSecret: 9 | name: acs-password 10 | exposure: 11 | loadBalancer: 12 | enabled: false 13 | port: 443 14 | nodePort: 15 | enabled: false 16 | route: 17 | enabled: true 18 | persistence: 19 | persistentVolumeClaim: 20 | claimName: stackrox-db 21 | egress: 22 | connectivityPolicy: Online 23 | scanner: 24 | analyzer: 25 | scaling: 26 | autoScaling: Enabled 27 | maxReplicas: 5 28 | minReplicas: 2 29 | replicas: 3 30 | scannerComponent: Enabled 31 | 32 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-acs/templates/securedcluster.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: platform.stackrox.io/v1alpha1 2 | kind: SecuredCluster 3 | metadata: 4 | namespace: stackrox 5 | name: stackrox-secured-cluster-services 6 | spec: 7 | clusterName: development 8 | admissionControl: 9 | listenOnCreates: false 10 | listenOnEvents: true 11 | listenOnUpdates: false 12 | perNode: 13 | collector: 14 | collection: EBPF 15 | imageFlavor: Regular 16 | taintToleration: TolerateTaints 17 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-acs/templates/subs.yml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1alpha1 2 | kind: Subscription 3 | metadata: 4 | name: rhacs-operator 5 | namespace: openshift-operators 6 | spec: 7 | channel: latest 8 | installPlanApproval: Automatic 9 | name: rhacs-operator 10 | source: redhat-operators 11 | sourceNamespace: openshift-marketplace 12 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/tasks/cicd.yaml: -------------------------------------------------------------------------------- 1 | - name: Add RoleBinding to the devsecops projects 2 | kubernetes.core.k8s: 3 | state: present 4 | definition: "{{ lookup('template', 'cicd-rb.yaml.j2') }}" 5 | 6 | - name: Install Gogs 7 | kubernetes.core.k8s: 8 | state: present 9 | definition: "{{ lookup('template', 'cicd-gogs.yaml.j2') }}" 10 | 11 | - name: Install nexus 12 | kubernetes.core.k8s: 13 | state: present 14 | definition: "{{ lookup('template', 'cicd-nexus.yaml.j2') }}" 15 | 16 | - name: Install sonarqube 17 | kubernetes.core.k8s: 18 | state: present 19 | definition: "{{ lookup('template', 'cicd-sonarqube.yaml.j2') }}" 20 | 21 | - name: Install reports repo 22 | kubernetes.core.k8s: 23 | state: present 24 | definition: "{{ lookup('template', 'cicd-reports-repo.yaml.j2') }}" 25 | 26 | # Check Gogs 27 | - name: Get gogs route 28 | kubernetes.core.k8s_info: 29 | kind: Route 30 | api_version: route.openshift.io/v1 31 | namespace: cicd 32 | name: gogs 33 | register: r_gogs_route 34 | retries: 10 35 | delay: 20 36 | until: 37 | - r_gogs_route.resources[0].spec.host is defined 38 | 39 | - name: Debug gogs route 40 | debug: 41 | msg: "{{ r_gogs_route.resources[0].spec.host }}" 42 | 43 | - name: Patch with specific route domain 44 | kubernetes.core.k8s: 45 | state: present 46 | definition: "{{ lookup('template', 'cicd-gogs-configmap.yaml.j2') }}" 47 | 48 | - name: Wait for gogs and gogs-postgresql to be running 49 | uri: 50 | url: http://{{ r_gogs_route.resources[0].spec.host }} 51 | status_code: 200 52 | register: result 53 | until: result.status == 200 54 | retries: 10 55 | delay: 30 56 | 57 | # Check Nexus Route 58 | - name: Get nexus route 59 | kubernetes.core.k8s_info: 60 | kind: Route 61 | api_version: route.openshift.io/v1 62 | namespace: cicd 63 | name: nexus 64 | register: r_nexus_route 65 | retries: 10 66 | delay: 20 67 | until: 68 | - r_nexus_route.resources[0].spec.host is defined 69 | 70 | - name: Debug nexus route 71 | debug: 72 | msg: "{{ r_nexus_route.resources[0].spec.host }}" 73 | 74 | - name: Wait for nexus to be running 75 | uri: 76 | url: http://{{ r_nexus_route.resources[0].spec.host }} 77 | status_code: 200 78 | register: result 79 | until: result.status == 200 80 | retries: 10 81 | delay: 30 82 | 83 | # Check Sonarqube Route 84 | - name: Get sonarqube route 85 | kubernetes.core.k8s_info: 86 | kind: Route 87 | api_version: route.openshift.io/v1 88 | namespace: cicd 89 | name: sonarqube 90 | register: r_sonarqube_route 91 | retries: 10 92 | delay: 20 93 | until: 94 | - r_sonarqube_route.resources[0].spec.host is defined 95 | 96 | - name: Debug sonarqube route 97 | debug: 98 | msg: "{{ r_sonarqube_route.resources[0].spec.host }}" 99 | 100 | - name: Wait for sonarqube to be running 101 | uri: 102 | url: https://{{ r_sonarqube_route.resources[0].spec.host }} 103 | status_code: 200 104 | validate_certs: no 105 | register: result 106 | until: result.status == 200 107 | retries: 10 108 | delay: 30 109 | 110 | # Check Reports Repo Route 111 | - name: Get reports route 112 | kubernetes.core.k8s_info: 113 | kind: Route 114 | api_version: route.openshift.io/v1 115 | namespace: cicd 116 | name: reports-repo 117 | register: r_reports_route 118 | retries: 10 119 | delay: 20 120 | until: 121 | - r_reports_route.resources[0].spec.host is defined 122 | 123 | - name: Debug reports route 124 | debug: 125 | msg: "{{ r_reports_route.resources[0].spec.host }}" 126 | 127 | - name: Wait for reports to be running 128 | uri: 129 | url: http://{{ r_reports_route.resources[0].spec.host }} 130 | status_code: 200 131 | register: result 132 | until: result.status == 200 133 | retries: 10 134 | delay: 30 135 | 136 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | 2 | - import_tasks: cicd.yaml 3 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/templates/cicd-gogs-configmap.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: ConfigMap 2 | apiVersion: v1 3 | metadata: 4 | name: gogs-config 5 | namespace: cicd 6 | labels: 7 | app: gogs 8 | data: 9 | app.ini: | 10 | RUN_MODE = prod 11 | RUN_USER = gogs 12 | 13 | [database] 14 | DB_TYPE = postgres 15 | HOST = gogs-postgresql:5432 16 | NAME = gogs 17 | USER = gogs 18 | PASSWD = gogs 19 | 20 | [repository] 21 | ROOT = /opt/gogs/data/repositories 22 | 23 | [server] 24 | ROOT_URL=http://{{ r_gogs_route.resources[0].spec.host }} 25 | SSH_DOMAIN={{ r_gogs_route.resources[0].spec.host }} 26 | 27 | [security] 28 | INSTALL_LOCK = true 29 | 30 | [service] 31 | ENABLE_CAPTCHA = false 32 | 33 | [webhook] 34 | SKIP_TLS_VERIFY = true 35 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/templates/cicd-gogs.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: gogs-postgresql 6 | namespace: cicd 7 | annotations: 8 | image.openshift.io/triggers: >- 9 | [{"from":{"kind":"ImageStreamTag","name":"rhel8/postgresql-13:latest", "namespace":"openshift"},"fieldPath":"spec.template.spec.containers[?(@.name==\"postgresql\")].image"}] 10 | labels: 11 | app: gogs 12 | app.kubernetes.io/component: database 13 | app.kubernetes.io/instance: gogs 14 | app.kubernetes.io/name: gogs-postgresql 15 | app.kubernetes.io/part-of: gogs 16 | spec: 17 | replicas: 1 18 | selector: 19 | matchLabels: 20 | app: gogs 21 | name: gogs-postgresql 22 | template: 23 | metadata: 24 | labels: 25 | app: gogs 26 | name: gogs-postgresql 27 | spec: 28 | containers: 29 | - name: postgresql 30 | imagePullPolicy: Always 31 | image: registry.redhat.io/rhel8/postgresql-13:latest 32 | env: 33 | - name: POSTGRESQL_USER 34 | value: gogs 35 | - name: POSTGRESQL_PASSWORD 36 | value: gogs 37 | - name: POSTGRESQL_DATABASE 38 | value: gogs 39 | - name: POSTGRESQL_MAX_CONNECTIONS 40 | value: "100" 41 | - name: POSTGRESQL_SHARED_BUFFERS 42 | value: 12MB 43 | - name: POSTGRESQL_ADMIN_PASSWORD 44 | value: gogs 45 | ports: 46 | - containerPort: 5432 47 | livenessProbe: 48 | initialDelaySeconds: 30 49 | tcpSocket: 50 | port: 5432 51 | timeoutSeconds: 1 52 | failureThreshold: 10 53 | periodSeconds: 20 54 | readinessProbe: 55 | exec: 56 | command: 57 | - /bin/sh 58 | - -i 59 | - -c 60 | - psql -h 127.0.0.1 -U ${POSTGRESQL_USER} -q -d ${POSTGRESQL_DATABASE} -c 'SELECT 1' 61 | resources: 62 | limits: 63 | memory: 512Mi 64 | volumeMounts: 65 | - mountPath: /var/lib/pgsql/data 66 | name: gogs-postgres-data 67 | volumes: 68 | - name: gogs-postgres-data 69 | persistentVolumeClaim: 70 | claimName: gogs-postgres-data 71 | --- 72 | kind: Service 73 | apiVersion: v1 74 | metadata: 75 | name: gogs-postgresql 76 | namespace: cicd 77 | labels: 78 | app: gogs 79 | spec: 80 | ports: 81 | - name: postgresql 82 | port: 5432 83 | targetPort: 5432 84 | selector: 85 | name: gogs-postgresql 86 | app: gogs 87 | --- 88 | apiVersion: apps/v1 89 | kind: Deployment 90 | metadata: 91 | name: gogs 92 | namespace: cicd 93 | labels: 94 | app: gogs 95 | app.kubernetes.io/component: gogs 96 | app.kubernetes.io/instance: gogs 97 | app.kubernetes.io/name: gogs 98 | app.kubernetes.io/part-of: gogs 99 | spec: 100 | replicas: 1 101 | selector: 102 | matchLabels: 103 | app: gogs 104 | name: gogs 105 | template: 106 | metadata: 107 | labels: 108 | app: gogs 109 | name: gogs 110 | spec: 111 | containers: 112 | - name: gogs 113 | imagePullPolicy: Always 114 | image: quay.io/rcarrata/gogs:stable 115 | ports: 116 | - containerPort: 3000 117 | protocol: TCP 118 | volumeMounts: 119 | - name: gogs-data 120 | mountPath: /opt/gogs/data 121 | - name: gogs-config 122 | mountPath: /etc/gogs/conf 123 | readinessProbe: 124 | httpGet: 125 | path: / 126 | port: 3000 127 | scheme: HTTP 128 | initialDelaySeconds: 40 129 | timeoutSeconds: 1 130 | periodSeconds: 20 131 | successThreshold: 1 132 | failureThreshold: 10 133 | livenessProbe: 134 | httpGet: 135 | path: / 136 | port: 3000 137 | scheme: HTTP 138 | initialDelaySeconds: 40 139 | timeoutSeconds: 1 140 | periodSeconds: 10 141 | successThreshold: 1 142 | failureThreshold: 10 143 | volumes: 144 | - name: gogs-data 145 | persistentVolumeClaim: 146 | claimName: gogs-data 147 | - name: gogs-config 148 | configMap: 149 | name: gogs-config 150 | items: 151 | - key: app.ini 152 | path: app.ini 153 | --- 154 | kind: Service 155 | apiVersion: v1 156 | metadata: 157 | labels: 158 | app: gogs 159 | name: gogs 160 | namespace: cicd 161 | spec: 162 | ports: 163 | - name: 3000-tcp 164 | port: 3000 165 | protocol: TCP 166 | targetPort: 3000 167 | selector: 168 | app: gogs 169 | name: gogs 170 | type: ClusterIP 171 | --- 172 | kind: Route 173 | apiVersion: route.openshift.io/v1 174 | id: gogs-http 175 | metadata: 176 | labels: 177 | app: gogs 178 | name: gogs 179 | namespace: cicd 180 | spec: 181 | to: 182 | name: gogs 183 | --- 184 | kind: PersistentVolumeClaim 185 | apiVersion: v1 186 | metadata: 187 | name: gogs-data 188 | namespace: cicd 189 | labels: 190 | app: gogs 191 | spec: 192 | accessModes: 193 | - ReadWriteOnce 194 | resources: 195 | requests: 196 | storage: 1Gi 197 | --- 198 | kind: PersistentVolumeClaim 199 | apiVersion: v1 200 | metadata: 201 | name: gogs-postgres-data 202 | namespace: cicd 203 | labels: 204 | app: gogs 205 | spec: 206 | accessModes: 207 | - ReadWriteOnce 208 | resources: 209 | requests: 210 | storage: 1Gi 211 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/templates/cicd-nexus.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app: nexus 7 | app.kubernetes.io/instance: nexus 8 | app.kubernetes.io/name: nexus 9 | app.kubernetes.io/part-of: nexus 10 | name: nexus 11 | namespace: cicd 12 | spec: 13 | replicas: 1 14 | selector: 15 | matchLabels: 16 | app: nexus 17 | template: 18 | metadata: 19 | labels: 20 | app: nexus 21 | spec: 22 | containers: 23 | - name: nexus 24 | image: quay.io/rcarrata/nexus3:3.16.2 25 | env: 26 | - name: CONTEXT_PATH 27 | value: / 28 | imagePullPolicy: IfNotPresent 29 | ports: 30 | - containerPort: 8081 31 | protocol: TCP 32 | livenessProbe: 33 | exec: 34 | command: 35 | - echo 36 | - ok 37 | failureThreshold: 3 38 | initialDelaySeconds: 30 39 | periodSeconds: 10 40 | successThreshold: 1 41 | timeoutSeconds: 1 42 | readinessProbe: 43 | failureThreshold: 3 44 | httpGet: 45 | path: / 46 | port: 8081 47 | scheme: HTTP 48 | initialDelaySeconds: 30 49 | periodSeconds: 10 50 | successThreshold: 1 51 | timeoutSeconds: 1 52 | resources: 53 | limits: 54 | memory: 4Gi 55 | cpu: 2 56 | requests: 57 | memory: 512Mi 58 | cpu: 200m 59 | terminationMessagePath: /dev/termination-log 60 | volumeMounts: 61 | - mountPath: /nexus-data 62 | name: nexus-data 63 | volumes: 64 | - name: nexus-data 65 | persistentVolumeClaim: 66 | claimName: nexus-pv 67 | --- 68 | apiVersion: v1 69 | kind: Service 70 | metadata: 71 | labels: 72 | app: nexus 73 | name: nexus 74 | namespace: cicd 75 | spec: 76 | ports: 77 | - name: 8081-tcp 78 | port: 8081 79 | protocol: TCP 80 | targetPort: 8081 81 | selector: 82 | app: nexus 83 | sessionAffinity: None 84 | type: ClusterIP 85 | --- 86 | apiVersion: route.openshift.io/v1 87 | kind: Route 88 | metadata: 89 | labels: 90 | app: nexus 91 | name: nexus 92 | namespace: cicd 93 | spec: 94 | port: 95 | targetPort: 8081-tcp 96 | to: 97 | kind: Service 98 | name: nexus 99 | weight: 100 100 | --- 101 | apiVersion: v1 102 | kind: PersistentVolumeClaim 103 | metadata: 104 | labels: 105 | app: nexus 106 | name: nexus-pv 107 | namespace: cicd 108 | spec: 109 | accessModes: 110 | - ReadWriteOnce 111 | resources: 112 | requests: 113 | storage: 25Gi 114 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/templates/cicd-rb.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: RoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: edit 5 | namespace: devsecops-dev 6 | subjects: 7 | - kind: ServiceAccount 8 | name: pipeline 9 | namespace: cicd 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: ClusterRole 13 | name: edit 14 | --- 15 | kind: RoleBinding 16 | apiVersion: rbac.authorization.k8s.io/v1 17 | metadata: 18 | name: edit 19 | namespace: devsecops-dev 20 | subjects: 21 | - kind: ServiceAccount 22 | name: pipeline 23 | namespace: cicd 24 | roleRef: 25 | apiGroup: rbac.authorization.k8s.io 26 | kind: ClusterRole 27 | name: edit 28 | --- 29 | kind: RoleBinding 30 | apiVersion: rbac.authorization.k8s.io/v1 31 | metadata: 32 | name: system:image-puller-dev 33 | namespace: cicd 34 | subjects: 35 | - kind: ServiceAccount 36 | name: default 37 | namespace: devsecops-dev 38 | roleRef: 39 | apiGroup: rbac.authorization.k8s.io 40 | kind: ClusterRole 41 | name: system:image-puller 42 | --- 43 | kind: RoleBinding 44 | apiVersion: rbac.authorization.k8s.io/v1 45 | metadata: 46 | name: system:image-puller-qa 47 | namespace: cicd 48 | subjects: 49 | - kind: ServiceAccount 50 | name: default 51 | namespace: devsecops-qa 52 | roleRef: 53 | apiGroup: rbac.authorization.k8s.io 54 | kind: ClusterRole 55 | name: system:image-puller 56 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/templates/cicd-reports-repo.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app: reports-repo 7 | app.kubernetes.io/instance: reports-repo 8 | app.kubernetes.io/name: reports-repo 9 | app.kubernetes.io/part-of: reports-repo 10 | name: reports-repo 11 | namespace: cicd 12 | spec: 13 | replicas: 1 14 | selector: 15 | matchLabels: 16 | app: reports-repo 17 | deployment: reports-repo 18 | template: 19 | metadata: 20 | labels: 21 | app: reports-repo 22 | deployment: reports-repo 23 | spec: 24 | containers: 25 | - name: uploader 26 | image: quay.io/chmouel/go-simple-uploader:latest 27 | imagePullPolicy: IfNotPresent 28 | env: 29 | - name: UPLOADER_PORT 30 | value: "9000" 31 | - name: UPLOADER_DIRECTORY 32 | value: "/fileuploads" 33 | volumeMounts: 34 | - mountPath: /fileuploads 35 | name: staticfiles 36 | - image: quay.io/siamaksade/nginx:latest 37 | name: nginx 38 | ports: 39 | - containerPort: 8080 40 | protocol: TCP 41 | volumeMounts: 42 | - mountPath: /etc/nginx/conf.d/ 43 | name: nginx-conf 44 | - mountPath: /fileuploads 45 | name: staticfiles 46 | volumes: 47 | - name: nexus-data 48 | persistentVolumeClaim: 49 | claimName: nexus-pv 50 | volumes: 51 | - configMap: 52 | defaultMode: 420 53 | name: reports-repo-nginx-conf 54 | name: nginx-conf 55 | - name: staticfiles 56 | persistentVolumeClaim: 57 | claimName: reports-repo-pv 58 | --- 59 | apiVersion: v1 60 | kind: ConfigMap 61 | metadata: 62 | name: reports-repo-nginx-conf 63 | namespace: cicd 64 | data: 65 | htpasswd: | 66 | reports:$apr1$MHzwWLP6$P/dRWWfgBe4J8wfId78v71 67 | nginx.conf: "types {\n text/plain yaml yml;\n}\n\nserver {\n listen 8080 68 | default_server;\n gzip on;\n\n\tlocation /upload {\n\t\tsatisfy any;\n\t\tauth_basic 69 | \"Welcome to the Jungle!\"; #For Basic Auth\n \tauth_basic_user_file conf.d/htpasswd; 70 | \ #For Basic Auth\n\t\tdeny all;\n\n\t\tproxy_set_header Host $host;\n\t\tproxy_set_header 71 | \ X-Real-IP $remote_addr;\n\t\tproxy_set_header X-Forwarded-Proto https;\n\t\tproxy_set_header 72 | \ X-Forwarded-For $remote_addr;\n\t\tproxy_set_header X-Forwarded-Host $remote_addr;\n\n\t\tproxy_pass 73 | http://localhost:9000;\n\t}\n\n\tlocation /private {\n\t\troot /fileuploads;\n\n\t\tsatisfy 74 | any;\n\t\tauth_basic \"Welcome to the Jungle!\"; #For Basic Auth\n \tauth_basic_user_file 75 | conf.d/htpasswd; #For Basic Auth\n\t\tdeny all;\n\n\t autoindex 76 | on;\n\t autoindex_exact_size off;\n\t autoindex_localtime on;\n\t}\n\n\tlocation 77 | / {\n\t\troot /fileuploads;\n\t autoindex on;\n\t autoindex_exact_size off;\n\t 78 | \ autoindex_localtime on;\n\t}\n}\n" 79 | --- 80 | apiVersion: v1 81 | kind: Service 82 | metadata: 83 | labels: 84 | app: reports-repo 85 | name: reports-repo 86 | namespace: cicd 87 | spec: 88 | ports: 89 | - name: 8080-tcp 90 | port: 8080 91 | protocol: TCP 92 | targetPort: 8080 93 | selector: 94 | app: reports-repo 95 | deployment: reports-repo 96 | --- 97 | apiVersion: route.openshift.io/v1 98 | kind: Route 99 | metadata: 100 | labels: 101 | app: reports-repo 102 | name: reports-repo 103 | namespace: cicd 104 | spec: 105 | port: 106 | targetPort: 8080-tcp 107 | to: 108 | kind: Service 109 | name: reports-repo 110 | weight: 100 111 | --- 112 | apiVersion: v1 113 | kind: PersistentVolumeClaim 114 | metadata: 115 | labels: 116 | app: reports-repo 117 | name: reports-repo-pv 118 | namespace: cicd 119 | spec: 120 | accessModes: 121 | - ReadWriteOnce 122 | resources: 123 | requests: 124 | storage: 5Gi 125 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-cicd/templates/cicd-sonarqube.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: sonarqube 6 | namespace: cicd 7 | labels: 8 | app: sonarqube 9 | app.kubernetes.io/component: sonarqube 10 | app.kubernetes.io/instance: sonarqube 11 | app.kubernetes.io/name: sonarqube 12 | app.kubernetes.io/part-of: sonarqube 13 | spec: 14 | replicas: 1 15 | selector: 16 | matchLabels: 17 | app: sonarqube 18 | name: sonarqube 19 | template: 20 | metadata: 21 | labels: 22 | app: sonarqube 23 | name: sonarqube 24 | spec: 25 | containers: 26 | - name: sonarqube 27 | imagePullPolicy: Always 28 | image: quay.io/rcarrata/sonarqube:8.3-community 29 | ports: 30 | - containerPort: 9000 31 | protocol: TCP 32 | volumeMounts: 33 | - mountPath: /opt/sq/temp 34 | name: sonarqube-temp 35 | - mountPath: /opt/sq/conf 36 | name: sonarqube-conf 37 | - mountPath: /opt/sq/data 38 | name: sonarqube-data 39 | - mountPath: /opt/sq/extensions 40 | name: sonarqube-extensions 41 | - mountPath: /opt/sq/logs 42 | name: sonarqube-logs 43 | livenessProbe: 44 | failureThreshold: 10 45 | httpGet: 46 | path: / 47 | port: 9000 48 | scheme: HTTP 49 | initialDelaySeconds: 45 50 | periodSeconds: 10 51 | successThreshold: 1 52 | timeoutSeconds: 1 53 | readinessProbe: 54 | failureThreshold: 10 55 | httpGet: 56 | path: / 57 | port: 9000 58 | scheme: HTTP 59 | initialDelaySeconds: 10 60 | periodSeconds: 10 61 | successThreshold: 1 62 | timeoutSeconds: 1 63 | resources: 64 | limits: 65 | cpu: "1" 66 | memory: 4Gi 67 | requests: 68 | cpu: 200m 69 | memory: 512Mi 70 | volumes: 71 | - name: sonarqube-temp 72 | emptyDir: {} 73 | - name: sonarqube-conf 74 | emptyDir: {} 75 | - name: sonarqube-data 76 | emptyDir: {} 77 | - name: sonarqube-extensions 78 | emptyDir: {} 79 | - name: sonarqube-logs 80 | emptyDir: {} 81 | --- 82 | apiVersion: route.openshift.io/v1 83 | kind: Route 84 | metadata: 85 | labels: 86 | app: sonarqube 87 | name: sonarqube 88 | namespace: cicd 89 | spec: 90 | port: 91 | targetPort: 9000-tcp 92 | tls: 93 | termination: edge 94 | to: 95 | kind: Service 96 | name: sonarqube 97 | weight: 100 98 | wildcardPolicy: None 99 | --- 100 | apiVersion: v1 101 | kind: Service 102 | metadata: 103 | labels: 104 | app: sonarqube 105 | name: sonarqube 106 | namespace: cicd 107 | spec: 108 | ports: 109 | - name: 9000-tcp 110 | port: 9000 111 | protocol: TCP 112 | targetPort: 9000 113 | selector: 114 | app: sonarqube 115 | name: sonarqube 116 | type: ClusterIP 117 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | pipelines_expected_crds: 2 | - pipelineruns.tekton.dev 3 | - pipelines.tekton.dev 4 | - tektonpipelines.operator.tekton.dev 5 | 6 | gitops_expected_crds: 7 | - applications.argoproj.io 8 | - applicationsets.argoproj.io 9 | - appprojects.argoproj.io 10 | - argocds.argoproj.io 11 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/tasks/gitops.yaml: -------------------------------------------------------------------------------- 1 | - name: Get cluster version 2 | k8s_info: 3 | api_version: config.openshift.io/v1 4 | kind: ClusterVersion 5 | name: version 6 | register: r_cluster_version 7 | 8 | - name: Set ocp4_cluster_version fact 9 | set_fact: 10 | ocp4_cluster_version: "{{ r_cluster_version.resources[0].status.history[0].version }}" 11 | 12 | - name: Print OpenShift version 13 | debug: 14 | msg: "{{ ocp4_cluster_version }}" 15 | 16 | - name: Install GitOps Operator 17 | kubernetes.core.k8s: 18 | state: present 19 | definition: "{{ lookup('template', 'subs-gitops.yml.j2') }}" 20 | 21 | - name: Adapt to the openshift_cluster_version LESS than 4.9 22 | when: ocp4_cluster_version is version_compare('4.9', '<') 23 | block: 24 | 25 | - name: Wait for GitOps CRD to exist 26 | kubernetes.core.k8s_info: 27 | api_version: "apiextensions.k8s.io/v1beta1" 28 | kind: CustomResourceDefinition 29 | name: "{{ item }}" 30 | loop: "{{ gitops_expected_crds }}" 31 | register: crds 32 | until: crds.resources|length > 0 33 | retries: 30 34 | delay: 10 35 | 36 | - name: Adapt to the openshift_cluster_version MORE than 4.9 37 | when: ocp4_cluster_version is version_compare('4.9', '>=') 38 | block: 39 | 40 | - name: Wait for GitOps CRD to exist 41 | kubernetes.core.k8s_info: 42 | api_version: "apiextensions.k8s.io/v1" 43 | kind: CustomResourceDefinition 44 | name: "{{ item }}" 45 | loop: "{{ gitops_expected_crds }}" 46 | register: crds 47 | until: crds.resources|length > 0 48 | retries: 30 49 | delay: 10 50 | 51 | - name: Install OCP Pipelines Operator 52 | kubernetes.core.k8s: 53 | state: present 54 | definition: "{{ lookup('template', 'subs-pipelines.yml.j2') }}" 55 | 56 | - name: Adapt to the openshift_cluster_version LESS than 4.9 57 | when: ocp4_cluster_version is version_compare('4.9', '<') 58 | block: 59 | 60 | - name: Wait for Pipelines CRD to exist 61 | kubernetes.core.k8s_info: 62 | api_version: "apiextensions.k8s.io/v1beta1" 63 | kind: CustomResourceDefinition 64 | name: "{{ item }}" 65 | loop: "{{ pipelines_expected_crds }}" 66 | register: crds 67 | until: crds.resources|length > 0 68 | retries: 30 69 | delay: 10 70 | 71 | - name: Adapt to the openshift_cluster_version MORE than 4.9 72 | when: ocp4_cluster_version is version_compare('4.9', '>=') 73 | block: 74 | 75 | - name: Wait for Pipelines CRD to exist 76 | kubernetes.core.k8s_info: 77 | api_version: "apiextensions.k8s.io/v1" 78 | kind: CustomResourceDefinition 79 | name: "{{ item }}" 80 | loop: "{{ pipelines_expected_crds }}" 81 | register: crds 82 | until: crds.resources|length > 0 83 | retries: 30 84 | delay: 10 85 | 86 | - name: Add ClusterRoleBinding to the openshift-gitops-controller 87 | kubernetes.core.k8s: 88 | state: present 89 | definition: "{{ lookup('template', 'gitops-rb.yml.j2') }}" 90 | 91 | - name: Install ArgoCD 92 | k8s: 93 | state: present 94 | definition: "{{ lookup('template', 'gitops-argocd.yaml.j2') | from_yaml }}" 95 | 96 | - name: Patch the CM of Openshift GitOps to add role admin by default 97 | command: oc patch cm/argocd-rbac-cm -n openshift-gitops --type=merge -p '{"data":{"policy.default":"role:admin"}}' 98 | 99 | - name: Add SSO Keycloak in Openshift GitOps by default 100 | shell: | 101 | oc -n openshift-gitops patch argocd openshift-gitops --type='json' -p='[{"op": "add", "path": "/spec/sso", "value": {"provider": "keycloak"} }]' 102 | 103 | - name: Get ArgoCD route 104 | kubernetes.core.k8s_info: 105 | kind: Route 106 | api_version: route.openshift.io/v1 107 | name: openshift-gitops-server 108 | namespace: openshift-gitops 109 | register: r_argo_route 110 | retries: 10 111 | delay: 20 112 | until: 113 | - r_argo_route.resources[0].spec.host is defined 114 | 115 | - name: Get argocd password 116 | kubernetes.core.k8s_info: 117 | kind: Secret 118 | api_version: /v1 119 | name: openshift-gitops-cluster 120 | namespace: openshift-gitops 121 | register: r_argopass 122 | 123 | #- name: debug 124 | # debug: 125 | # msg: "{{ r_argopass.resources[0].data['admin.password'] }}" 126 | 127 | - name: Add CM for ArgoCD env 128 | kubernetes.core.k8s: 129 | state: present 130 | definition: "{{ lookup('template', 'gitops-env-cm.yaml.j2') }}" 131 | 132 | - name: Add Secrets for ArgoCD env 133 | kubernetes.core.k8s: 134 | state: present 135 | definition: "{{ lookup('template', 'gitops-env-secret.yaml.j2') }}" 136 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | 2 | - import_tasks: pre.yaml 3 | - import_tasks: gitops.yaml 4 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/tasks/pre.yaml: -------------------------------------------------------------------------------- 1 | ## Prerequisites for install CICD Infra 2 | 3 | - name: Create Namespaces 4 | kubernetes.core.k8s: 5 | state: present 6 | definition: "{{ lookup('template', 'namespaces.yaml.j2') }}" 7 | 8 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/templates/gitops-argocd.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: ArgoCD 3 | metadata: 4 | name: openshift-gitops 5 | namespace: openshift-gitops 6 | spec: 7 | server: 8 | autoscale: 9 | enabled: false 10 | grpc: 11 | ingress: 12 | enabled: false 13 | ingress: 14 | enabled: false 15 | insecure: true 16 | route: 17 | enabled: true 18 | tls: 19 | insecureEdgeTerminationPolicy: Redirect 20 | termination: edge 21 | service: 22 | type: '' 23 | grafana: 24 | enabled: false 25 | ingress: 26 | enabled: false 27 | route: 28 | enabled: false 29 | prometheus: 30 | enabled: false 31 | ingress: 32 | enabled: false 33 | route: 34 | enabled: false 35 | initialSSHKnownHosts: {} 36 | sso: 37 | provider: keycloak 38 | applicationSet: 39 | resources: 40 | limits: 41 | cpu: '2' 42 | memory: 1Gi 43 | requests: 44 | cpu: 250m 45 | memory: 512Mi 46 | rbac: 47 | policy: 'g, system:cluster-admins, role:admin' 48 | scopes: '[groups]' 49 | repo: {} 50 | resourceExclusions: | 51 | - apiGroups: 52 | - tekton.dev 53 | clusters: 54 | - '*' 55 | kinds: 56 | - TaskRun 57 | - PipelineRun 58 | dex: 59 | openShiftOAuth: true 60 | ha: 61 | enabled: false 62 | resources: 63 | limits: 64 | cpu: 500m 65 | memory: 256Mi 66 | requests: 67 | cpu: 250m 68 | memory: 128Mi 69 | tls: 70 | ca: {} 71 | redis: {} 72 | controller: 73 | processors: {} 74 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/templates/gitops-env-cm.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: argocd-env-configmap 5 | namespace: cicd 6 | data: 7 | ARGOCD_SERVER: openshift-gitops-server.openshift-gitops:443 8 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/templates/gitops-env-secret.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: argocd-env-secret 5 | namespace: cicd 6 | type: Opaque 7 | data: 8 | ARGOCD_USERNAME: YWRtaW4K 9 | ARGOCD_PASSWORD: {{ r_argopass.resources[0].data['admin.password'] }} 10 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/templates/gitops-rb.yml.j2: -------------------------------------------------------------------------------- 1 | kind: ClusterRoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: openshift-gitops-controller-admin 5 | subjects: 6 | - kind: ServiceAccount 7 | name: openshift-gitops-application-controller 8 | namespace: openshift-gitops 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: ClusterRole 12 | name: admin 13 | --- 14 | kind: RoleBinding 15 | apiVersion: rbac.authorization.k8s.io/v1 16 | metadata: 17 | name: openshift-gitops-controller-admin 18 | namespace: devsecops-dev 19 | roleRef: 20 | apiGroup: rbac.authorization.k8s.io 21 | kind: ClusterRole 22 | name: admin 23 | subjects: 24 | - kind: ServiceAccount 25 | name: openshift-gitops-argocd-application-controller 26 | namespace: openshift-gitops 27 | --- 28 | kind: RoleBinding 29 | apiVersion: rbac.authorization.k8s.io/v1 30 | metadata: 31 | name: openshift-gitops-controller-admin 32 | namespace: devsecops-qa 33 | roleRef: 34 | apiGroup: rbac.authorization.k8s.io 35 | kind: ClusterRole 36 | name: admin 37 | subjects: 38 | - kind: ServiceAccount 39 | name: openshift-gitops-argocd-application-controller 40 | namespace: openshift-gitops 41 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/templates/namespaces.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: cicd 5 | --- 6 | apiVersion: v1 7 | kind: Namespace 8 | metadata: 9 | name: devsecops-dev 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: devsecops-qa 15 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/templates/subs-gitops.yml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1alpha1 2 | kind: Subscription 3 | metadata: 4 | name: openshift-gitops-operator 5 | namespace: openshift-operators 6 | spec: 7 | channel: latest 8 | installPlanApproval: Automatic 9 | name: openshift-gitops-operator 10 | source: redhat-operators 11 | sourceNamespace: openshift-marketplace 12 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-gitops/templates/subs-pipelines.yml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1alpha1 2 | kind: Subscription 3 | metadata: 4 | name: openshift-pipelines-operator-rh 5 | namespace: openshift-operators 6 | spec: 7 | channel: latest 8 | installPlanApproval: Automatic 9 | name: openshift-pipelines-operator-rh 10 | source: redhat-operators 11 | sourceNamespace: openshift-marketplace 12 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | noobaa_storage_class: "" 2 | noobaa_size: "50Gi" 3 | backing_store_name: "noobaa-pv-backing-store" 4 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | 2 | - import_tasks: noobaa-create.yaml -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/tasks/noobaa-create.yaml: -------------------------------------------------------------------------------- 1 | - name: Get cluster version 2 | k8s_info: 3 | api_version: config.openshift.io/v1 4 | kind: ClusterVersion 5 | name: version 6 | register: r_cluster_version 7 | 8 | - name: Set ocp4_cluster_version fact 9 | set_fact: 10 | ocp4_cluster_version: "{{ r_cluster_version.resources[0].status.history[0].version }}" 11 | 12 | - name: Obtain Channel from Version 13 | set_fact: 14 | ocp4_channel: "{{ ocp4_cluster_version.split('.') }}" 15 | 16 | - name: Set Openshift Channel 17 | set_fact: 18 | ocp4_channel: "stable-{{ ocp4_channel[0] + '.' + ocp4_channel[1] }}" 19 | 20 | - name: Print OpenShift version 21 | debug: 22 | msg: "{{ ocp4_channel }}" 23 | 24 | - name: Adapt to the openshift_cluster_version LESS than 4.9 25 | when: ocp4_cluster_version is version_compare('4.9', '<') 26 | block: 27 | - name: Create OpenShift Objects to install Noobaa 28 | k8s: 29 | state: present 30 | definition: "{{ lookup('template', item ) | from_yaml }}" 31 | loop: 32 | - ./templates/odf-namespace.yaml.j2 33 | - ./templates/operatorgroup-storage.yaml.j2 34 | - ./templates/ocs-subscription.yaml.j2 35 | 36 | - name: Wait for NooBaa CRD to exist 37 | kubernetes.core.k8s_info: 38 | api_version: "apiextensions.k8s.io/v1beta1" 39 | kind: CustomResourceDefinition 40 | name: "noobaas.noobaa.io" 41 | register: crds 42 | until: crds.resources|length > 0 43 | retries: 30 44 | delay: 10 45 | 46 | - name: Adapt to the openshift_cluster_version MORE than 4.9 47 | when: ocp4_cluster_version is version_compare('4.9', '>=') 48 | block: 49 | - name: Create OpenShift Objects to install Noobaa 50 | k8s: 51 | state: present 52 | definition: "{{ lookup('template', item ) | from_yaml }}" 53 | loop: 54 | - ./templates/odf-namespace.yaml.j2 55 | - ./templates/operatorgroup-storage.yaml.j2 56 | - ./templates/odf-subscription.yaml.j2 57 | 58 | - name: Wait for NooBaa CRD to exist 59 | kubernetes.core.k8s_info: 60 | api_version: "apiextensions.k8s.io/v1" 61 | kind: CustomResourceDefinition 62 | name: "noobaas.noobaa.io" 63 | register: crds 64 | until: crds.resources|length > 0 65 | retries: 30 66 | delay: 10 67 | 68 | - name: Create Noobaa Object 69 | k8s: 70 | state: present 71 | definition: "{{ lookup('template', item ) | from_yaml }}" 72 | loop: 73 | - ./templates/noobaa-object.yaml.j2 74 | 75 | - name: Wait Until NooBaa Object is Ready 76 | shell: | 77 | oc get noobaas.noobaa.io/noobaa -n openshift-storage -o jsonpath='{.status.phase}' 78 | register: noobaa_status 79 | retries: 10 80 | delay: 20 81 | until: 82 | - noobaa_status.stdout == "Ready" 83 | 84 | - name: Get Default Openshift Storage Class 85 | shell: | 86 | oc get sc -o=jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}' 87 | register: default_openshift_storage_class 88 | when: noobaa_storage_class == "" 89 | 90 | - name: Get any other Storage Class 91 | shell: | 92 | oc get sc -o name | head -n 1 | cut -d "/" -f2 93 | register: other_openshift_storage_class 94 | when: (default_openshift_storage_class.stdout |default("") == "" ) and (noobaa_storage_class == "") 95 | 96 | - name: Use default storage class if it was set 97 | ansible.builtin.set_fact: 98 | noobaa_storage_class: "{{ default_openshift_storage_class.stdout }}" 99 | when: (default_openshift_storage_class.stdout |default("") != "" ) and (noobaa_storage_class == "") 100 | 101 | - name: Try other possible storage class if no defined/default storage class 102 | ansible.builtin.set_fact: 103 | noobaa_storage_class: "{{ other_openshift_storage_class.stdout }}" 104 | when: (default_openshift_storage_class.stdout |default("") == "" ) and (noobaa_storage_class == "") and (other_openshift_storage_class|default("") != "") 105 | 106 | - name: Create NooBaa Backing Store 107 | k8s: 108 | state: present 109 | definition: "{{ lookup('template', item ) | from_yaml }}" 110 | loop: 111 | - ./templates/noobaa-backingstore.yaml.j2 112 | 113 | - name: Wait Until NooBaa Object is Ready 114 | shell: | 115 | oc get BackingStore/"{{ backing_store_name }}" -n openshift-storage -o jsonpath='{.status.phase}' 116 | register: backing_store 117 | retries: 10 118 | delay: 20 119 | until: 120 | - backing_store.stdout == "Ready" 121 | 122 | - name: Patch Bucket Class with Backing Store 123 | shell: | 124 | oc patch bucketclass noobaa-default-bucket-class --patch '{"spec":{"placementPolicy":{"tiers":[{"backingStores":["{{backing_store_name}}"]}]}}}' --type merge -n openshift-storage 125 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/templates/noobaa-backingstore.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: noobaa.io/v1alpha1 2 | kind: BackingStore 3 | metadata: 4 | finalizers: 5 | - noobaa.io/finalizer 6 | labels: 7 | app: noobaa 8 | name: noobaa-pv-backing-store 9 | namespace: openshift-storage 10 | spec: 11 | pvPool: 12 | numVolumes: 1 13 | resources: 14 | requests: 15 | storage: {{ noobaa_size }} 16 | storageClass: {{ noobaa_storage_class }} 17 | type: pv-pool -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/templates/noobaa-object.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: noobaa.io/v1alpha1 2 | kind: NooBaa 3 | metadata: 4 | name: noobaa 5 | namespace: openshift-storage 6 | spec: 7 | dbResources: 8 | requests: 9 | cpu: '0.1' 10 | memory: 1Gi 11 | dbType: postgres 12 | coreResources: 13 | requests: 14 | cpu: '0.1' 15 | memory: 1Gi -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/templates/ocs-subscription.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1alpha1 2 | kind: Subscription 3 | metadata: 4 | name: ocs-operator 5 | namespace: openshift-storage 6 | spec: 7 | channel: {{ ocp4_channel }} 8 | installPlanApproval: Automatic 9 | name: ocs-operator 10 | source: redhat-operators 11 | sourceNamespace: openshift-marketplace -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/templates/odf-namespace.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: Namespace 2 | apiVersion: v1 3 | metadata: 4 | name: openshift-storage 5 | labels: 6 | kubernetes.io/metadata.name: openshift-storage 7 | spec: {} 8 | 9 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/templates/odf-subscription.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1alpha1 2 | kind: Subscription 3 | metadata: 4 | labels: 5 | operators.coreos.com/odf-operator.openshift-storage: '' 6 | name: odf-operator 7 | namespace: openshift-storage 8 | spec: 9 | channel: {{ ocp4_channel }} 10 | installPlanApproval: Automatic 11 | name: odf-operator 12 | source: redhat-operators 13 | sourceNamespace: openshift-marketplace 14 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-noobaa/templates/operatorgroup-storage.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1 2 | kind: OperatorGroup 3 | metadata: 4 | name: openshift-storage-test 5 | namespace: openshift-storage 6 | spec: 7 | targetNamespaces: 8 | - openshift-storage -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | pipelines_expected_crds: 2 | - pipelineresources.tekton.dev 3 | - pipelineruns.tekton.dev 4 | - pipelines.tekton.dev 5 | - tektonpipelines.operator.tekton.dev 6 | 7 | gitops_expected_crds: 8 | - applications.argoproj.io 9 | - applicationsets.argoproj.io 10 | - appprojects.argoproj.io 11 | - argocds.argoproj.io 12 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | 2 | - import_tasks: pipelines.yaml 3 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/tasks/pipelines.yaml: -------------------------------------------------------------------------------- 1 | - name: Create OpenShift Objects for Openshift Pipeline Tasks 2 | k8s: 3 | state: present 4 | definition: "{{ lookup('template', item ) | from_yaml }}" 5 | loop: 6 | - ./templates/task-argo-sync-and-wait.yaml.j2 7 | - ./templates/task-dependency-report.yaml.j2 8 | - ./templates/task-gatling.yaml.j2 9 | - ./templates/task-git-update-deployment.yaml.j2 10 | - ./templates/task-image-scan-task.yaml.j2 11 | - ./templates/task-mvn-cm.yaml.j2 12 | - ./templates/task-mvn.yaml.j2 13 | - ./templates/task-rox-deployment-check.yaml.j2 14 | - ./templates/task-rox-image-check.yaml.j2 15 | - ./templates/task-s2i-java-11.yaml.j2 16 | - ./templates/task-zap-proxy.yaml.j2 17 | 18 | - name: Create OpenShift Objects for Openshift Pipeline Triggers 19 | k8s: 20 | state: present 21 | definition: "{{ lookup('template', item ) | from_yaml }}" 22 | loop: 23 | - ./templates/trigger-eventlistener.yaml.j2 24 | - ./templates/trigger-eventlistener-route.yaml.j2 25 | - ./templates/trigger-gogs-triggerbinding.yaml.j2 26 | - ./templates/triggertemplate.yaml.j2 27 | 28 | # Check Gogs 29 | - name: Get gogs route 30 | kubernetes.core.k8s_info: 31 | kind: Route 32 | api_version: route.openshift.io/v1 33 | namespace: cicd 34 | name: gogs 35 | register: r_gogs_route 36 | retries: 10 37 | delay: 20 38 | until: 39 | - r_gogs_route.resources[0].spec.host is defined 40 | 41 | - name: Debug gogs route 42 | debug: 43 | msg: "{{ r_gogs_route.resources[0].spec.host }}" 44 | 45 | - name: Create OpenShift Objects for Openshift Pipelines Templates 46 | k8s: 47 | state: present 48 | definition: "{{ lookup('template', item ) | from_yaml }}" 49 | loop: 50 | - ./templates/pipeline-build-dev.yaml.j2 51 | - ./templates/pipeline-build-stage.yaml.j2 52 | - ./templates/pipeline-build-pvc.yaml.j2 53 | 54 | # K8s doesn't support the generateName in taskRun 55 | - name: Add gogs init taskrun for add pipelines 56 | shell: oc create -n cicd -f "{{ item }}" 57 | loop: 58 | - "{{ role_path }}/templates/cicd-gogs-init-taskrun.yaml.j2" 59 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/cicd-gogs-init-taskrun.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: TaskRun 3 | metadata: 4 | generateName: init-gogs- 5 | namespace: cicd 6 | spec: 7 | taskSpec: 8 | params: 9 | - name: GOGS_USER 10 | type: string 11 | description: Gogs admin username 12 | default: gogs 13 | - name: GOGS_PASSWORD 14 | type: string 15 | description: Gogs admin password 16 | default: gogs 17 | stepTemplate: 18 | env: 19 | - name: NAMESPACE 20 | valueFrom: 21 | fieldRef: 22 | fieldPath: metadata.namespace 23 | steps: 24 | - name: init-gogs 25 | image: quay.io/siamaksade/python-oc 26 | script: | 27 | #!/usr/bin/env python3 28 | 29 | import os 30 | import requests 31 | 32 | gogs_user = "$(params.GOGS_USER)" 33 | gogs_pwd = "$(params.GOGS_PASSWORD)" 34 | webhookURL = "http://" + os.popen('oc get route el-webhook -o template --template="{{.spec.host}}"').read() 35 | gogsURL = "http://" + os.popen('oc get svc gogs -o template --template="{{.spec.clusterIP}}"').read() + ":3000" 36 | 37 | # create admin user 38 | data_user = { 39 | 'user_name': gogs_user, 40 | 'password': gogs_pwd, 41 | 'retype': gogs_pwd, 42 | 'email': 'admin@gogs.com' 43 | } 44 | 45 | resp = requests.post(url = gogsURL + "/user/sign_up", data = data_user) 46 | 47 | if resp.status_code != 200: 48 | print("Error creating Gogs admin (status code: {})".format(resp.status_code)) 49 | print(resp.content) 50 | else: 51 | print("Created admin user {}:{}".format(gogs_user, gogs_pwd)) 52 | 53 | # create git repo spring-petclinic 54 | data_repo = '{"clone_addr": "https://github.com/rcarrata/spring-petclinic", "uid": 1, "repo_name": "spring-petclinic"}' 55 | headers = {'Content-Type': 'application/json'} 56 | resp = requests.post(url = gogsURL + "/api/v1/repos/migrate", headers = headers, auth = (gogs_user, gogs_pwd), data = data_repo) 57 | 58 | if resp.status_code != 200 and resp.status_code != 201: 59 | print("Error creating git repo (status code: {})".format(resp.status_code)) 60 | print(resp.content) 61 | else: 62 | print("Created git repo spring-petclinic") 63 | 64 | # configure webhook on spring-petclinic 65 | data_webhook = '{"type": "gogs", "config": { "url": "' + webhookURL + '", "content_type": "json"}, "events": ["push"], "active": true}' 66 | headers = {'Content-Type': 'application/json'} 67 | resp = requests.post(url = gogsURL + "/api/v1/repos/" + gogs_user + "/spring-petclinic/hooks", 68 | headers = headers, 69 | auth = (gogs_user, gogs_pwd), 70 | data = data_webhook) 71 | 72 | if resp.status_code != 200 and resp.status_code != 201: 73 | print("Error configuring the webhook (status code: {})".format(resp.status_code)) 74 | print(resp.content) 75 | else: 76 | print("Configured webhook: " + webhookURL) 77 | 78 | # create git repo spring-petclinic-config 79 | data_repo = '{"clone_addr": "https://github.com/rcarrata/spring-petclinic-config.git", "uid": 1, "repo_name": "spring-petclinic-config"}' 80 | headers = {'Content-Type': 'application/json'} 81 | resp = requests.post(url = gogsURL + "/api/v1/repos/migrate", headers = headers, auth = (gogs_user, gogs_pwd), data = data_repo) 82 | 83 | if resp.status_code != 200 and resp.status_code != 201: 84 | print("Error creating git repo (status code: {})".format(resp.status_code)) 85 | print(resp.content) 86 | else: 87 | print("Created git repo spring-petclinic-config") 88 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/pipeline-build-dev.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Pipeline 3 | metadata: 4 | name: petclinic-build-dev 5 | namespace: cicd 6 | spec: 7 | params: 8 | - name: APP_SOURCE_GIT 9 | type: string 10 | description: The application git repository 11 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic 12 | - name: APP_SOURCE_REVISION 13 | type: string 14 | description: The application git revision 15 | default: master 16 | - name: APP_MANIFESTS_GIT 17 | type: string 18 | description: The application manifests git repository 19 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic-config 20 | - name: APP_IMAGE_TAG 21 | type: string 22 | default: latest 23 | description: The application image tag to build 24 | - name: DEV_NAMESPACE 25 | type: string 26 | default: devsecops-dev 27 | description: The namespace for Stage environments 28 | - name: APP_TESTS_GIT 29 | type: string 30 | description: The application test cases git repository 31 | default: https://github.com/rcarrata/spring-petclinic-gatling 32 | workspaces: 33 | - name: workspace 34 | - name: maven-settings 35 | tasks: 36 | - name: source-clone 37 | taskRef: 38 | name: git-clone 39 | kind: ClusterTask 40 | workspaces: 41 | - name: output 42 | workspace: workspace 43 | params: 44 | - name: url 45 | value: $(params.APP_SOURCE_GIT) 46 | - name: revision 47 | value: $(params.APP_SOURCE_REVISION) 48 | - name: depth 49 | value: "0" 50 | - name: subdirectory 51 | value: spring-petclinic 52 | - name: deleteExisting 53 | value: "true" 54 | - name: unit-tests 55 | taskRef: 56 | name: maven 57 | runAfter: 58 | - source-clone 59 | workspaces: 60 | - name: source 61 | workspace: workspace 62 | - name: maven-settings 63 | workspace: maven-settings 64 | params: 65 | - name: GOALS 66 | value: ["package", "-f", "spring-petclinic"] 67 | - name: code-analysis 68 | taskRef: 69 | name: maven 70 | runAfter: 71 | - source-clone 72 | workspaces: 73 | - name: source 74 | workspace: workspace 75 | - name: maven-settings 76 | workspace: maven-settings 77 | params: 78 | - name: GOALS 79 | value: 80 | - install 81 | - sonar:sonar 82 | - -f 83 | - spring-petclinic 84 | - -Dsonar.host.url=http://sonarqube:9000 85 | - -Dsonar.userHome=/tmp/sonar 86 | - -DskipTests=true 87 | - name: dependency-report 88 | taskRef: 89 | name: dependency-report 90 | runAfter: 91 | - source-clone 92 | workspaces: 93 | - name: source 94 | workspace: workspace 95 | - name: maven-settings 96 | workspace: maven-settings 97 | params: 98 | - name: SOURCE_DIR 99 | value: spring-petclinic 100 | - name: release-app 101 | taskRef: 102 | name: maven 103 | runAfter: 104 | - code-analysis 105 | - unit-tests 106 | - dependency-report 107 | workspaces: 108 | - name: source 109 | workspace: workspace 110 | - name: maven-settings 111 | workspace: maven-settings 112 | params: 113 | - name: GOALS 114 | value: 115 | - deploy 116 | - -f 117 | - spring-petclinic 118 | - -DskipTests=true 119 | - -DaltDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-releases/ 120 | - -DaltSnapshotDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-snapshots/ 121 | - name: build-image 122 | taskRef: 123 | name: s2i-java-11 124 | runAfter: 125 | - release-app 126 | params: 127 | - name: TLSVERIFY 128 | value: "false" 129 | - name: MAVEN_MIRROR_URL 130 | value: http://nexus:8081/repository/maven-public/ 131 | - name: PATH_CONTEXT 132 | value: spring-petclinic/target 133 | - name: IMAGE_NAME 134 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 135 | - name: IMAGE_TAG 136 | value: $(params.APP_IMAGE_TAG) 137 | workspaces: 138 | - name: source 139 | workspace: workspace 140 | - name: image-scan 141 | runAfter: 142 | - build-image 143 | taskRef: 144 | name: rox-image-scan 145 | kind: ClusterTask 146 | params: 147 | - name: image 148 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 149 | - name: rox_api_token 150 | value: roxsecrets 151 | - name: rox_central_endpoint 152 | value: roxsecrets 153 | - name: output_format 154 | value: table 155 | - name: image_digest 156 | value: $(tasks.build-image.results.IMAGE_DIGEST) 157 | - name: image-check 158 | runAfter: 159 | - build-image 160 | taskRef: 161 | name: rox-image-check 162 | kind: ClusterTask 163 | params: 164 | - name: image 165 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 166 | - name: rox_api_token 167 | value: roxsecrets 168 | - name: rox_central_endpoint 169 | value: roxsecrets 170 | - name: image_digest 171 | value: $(tasks.build-image.results.IMAGE_DIGEST) 172 | - name: deploy-check 173 | runAfter: 174 | - build-image 175 | taskRef: 176 | name: rox-deployment-check 177 | kind: ClusterTask 178 | params: 179 | - name: GIT_REPOSITORY 180 | value: "$(params.APP_MANIFESTS_GIT)" 181 | - name: rox_api_token 182 | value: roxsecrets 183 | - name: rox_central_endpoint 184 | value: roxsecrets 185 | - name: file 186 | value: deployment.yaml 187 | - name: deployment_files_path 188 | value: app 189 | workspaces: 190 | - name: workspace 191 | workspace: workspace 192 | - name: update-deployment 193 | runAfter: 194 | - image-scan 195 | - image-check 196 | - deploy-check 197 | taskRef: 198 | name: git-update-deployment 199 | params: 200 | - name: GIT_REPOSITORY 201 | value: "$(params.APP_MANIFESTS_GIT)" 202 | - name: GIT_USERNAME 203 | value: gogs 204 | - name: GIT_PASSWORD 205 | value: gogs 206 | - name: CURRENT_IMAGE 207 | value: quay.io/siamaksade/spring-petclinic:latest 208 | - name: NEW_IMAGE 209 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 210 | - name: NEW_DIGEST 211 | value: "$(tasks.build-image.results.IMAGE_DIGEST)" 212 | - name: KUSTOMIZATION_PATH 213 | value: environments/dev 214 | workspaces: 215 | - name: workspace 216 | workspace: workspace 217 | - name: wait-application 218 | taskRef: 219 | name: argocd-task-sync-and-wait 220 | runAfter: 221 | - update-deployment 222 | params: 223 | - name: application-name 224 | value: dev-spring-petclinic 225 | - name: perf-tests-clone 226 | taskRef: 227 | name: git-clone 228 | kind: ClusterTask 229 | workspaces: 230 | - name: output 231 | workspace: workspace 232 | runAfter: 233 | - wait-application 234 | params: 235 | - name: url 236 | value: $(params.APP_TESTS_GIT) 237 | - name: subdirectory 238 | value: spring-petclinic-gatling 239 | - name: deleteExisting 240 | value: "true" 241 | - name: pentesting-test 242 | taskRef: 243 | name: zap-proxy 244 | runAfter: 245 | - perf-tests-clone 246 | params: 247 | - name: APP_URL 248 | value: "http://spring-petclinic.$(params.DEV_NAMESPACE).svc.cluster.local:8080" 249 | workspaces: 250 | - name: workspace 251 | workspace: workspace 252 | - name: performance-test 253 | taskRef: 254 | name: gatling 255 | runAfter: 256 | - perf-tests-clone 257 | params: 258 | - name: APP_URL 259 | value: "http://spring-petclinic.$(params.DEV_NAMESPACE).svc.cluster.local:8080" 260 | workspaces: 261 | - name: simulations 262 | workspace: workspace 263 | subPath: spring-petclinic-gatling 264 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/pipeline-build-pvc.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: petclinic-build-workspace 5 | namespace: cicd 6 | spec: 7 | resources: 8 | requests: 9 | storage: 5Gi 10 | volumeMode: Filesystem 11 | accessModes: 12 | - ReadWriteOnce 13 | persistentVolumeReclaimPolicy: Retain 14 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/pipeline-build-stage.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Pipeline 3 | metadata: 4 | name: petclinic-build-stage 5 | namespace: cicd 6 | spec: 7 | params: 8 | - name: APP_SOURCE_GIT 9 | type: string 10 | description: The application git repository 11 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic 12 | - name: APP_SOURCE_REVISION 13 | type: string 14 | description: The application git revision 15 | default: master 16 | - name: APP_MANIFESTS_GIT 17 | type: string 18 | description: The application manifests git repository 19 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic-config 20 | - name: APP_IMAGE_TAG 21 | type: string 22 | default: latest 23 | description: The application image tag to build 24 | - name: STAGE_NAMESPACE 25 | type: string 26 | default: devsecops-qa 27 | description: The namespace for Stage environments 28 | - name: APP_TESTS_GIT 29 | type: string 30 | description: The application test cases git repository 31 | default: https://github.com/rcarrata/spring-petclinic-gatling 32 | workspaces: 33 | - name: workspace 34 | - name: maven-settings 35 | tasks: 36 | - name: source-clone 37 | taskRef: 38 | name: git-clone 39 | kind: ClusterTask 40 | workspaces: 41 | - name: output 42 | workspace: workspace 43 | params: 44 | - name: url 45 | value: $(params.APP_SOURCE_GIT) 46 | - name: revision 47 | value: $(params.APP_SOURCE_REVISION) 48 | - name: depth 49 | value: "0" 50 | - name: subdirectory 51 | value: spring-petclinic 52 | - name: deleteExisting 53 | value: "true" 54 | - name: unit-tests 55 | taskRef: 56 | name: maven 57 | runAfter: 58 | - source-clone 59 | workspaces: 60 | - name: source 61 | workspace: workspace 62 | - name: maven-settings 63 | workspace: maven-settings 64 | params: 65 | - name: GOALS 66 | value: ["package", "-f", "spring-petclinic"] 67 | - name: code-analysis 68 | taskRef: 69 | name: maven 70 | runAfter: 71 | - source-clone 72 | workspaces: 73 | - name: source 74 | workspace: workspace 75 | - name: maven-settings 76 | workspace: maven-settings 77 | params: 78 | - name: GOALS 79 | value: 80 | - install 81 | - sonar:sonar 82 | - -f 83 | - spring-petclinic 84 | - -Dsonar.host.url=http://sonarqube:9000 85 | - -Dsonar.userHome=/tmp/sonar 86 | - -DskipTests=true 87 | - name: dependency-report 88 | taskRef: 89 | name: dependency-report 90 | runAfter: 91 | - source-clone 92 | workspaces: 93 | - name: source 94 | workspace: workspace 95 | - name: maven-settings 96 | workspace: maven-settings 97 | params: 98 | - name: SOURCE_DIR 99 | value: spring-petclinic 100 | - name: release-app 101 | taskRef: 102 | name: maven 103 | runAfter: 104 | - code-analysis 105 | - unit-tests 106 | - dependency-report 107 | workspaces: 108 | - name: source 109 | workspace: workspace 110 | - name: maven-settings 111 | workspace: maven-settings 112 | params: 113 | - name: GOALS 114 | value: 115 | - deploy 116 | - -f 117 | - spring-petclinic 118 | - -DskipTests=true 119 | - -DaltDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-releases/ 120 | - -DaltSnapshotDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-snapshots/ 121 | - name: build-image 122 | taskRef: 123 | name: s2i-java-11 124 | runAfter: 125 | - release-app 126 | params: 127 | - name: TLSVERIFY 128 | value: "false" 129 | - name: MAVEN_MIRROR_URL 130 | value: http://nexus:8081/repository/maven-public/ 131 | - name: PATH_CONTEXT 132 | value: spring-petclinic/target 133 | - name: IMAGE_NAME 134 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 135 | - name: IMAGE_TAG 136 | value: $(params.APP_IMAGE_TAG) 137 | workspaces: 138 | - name: source 139 | workspace: workspace 140 | - name: image-scan 141 | runAfter: 142 | - build-image 143 | taskRef: 144 | name: rox-image-scan 145 | kind: ClusterTask 146 | params: 147 | - name: image 148 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 149 | - name: rox_api_token 150 | value: roxsecrets 151 | - name: rox_central_endpoint 152 | value: roxsecrets 153 | - name: output_format 154 | value: table 155 | - name: image_digest 156 | value: $(tasks.build-image.results.IMAGE_DIGEST) 157 | - name: image-check 158 | runAfter: 159 | - build-image 160 | taskRef: 161 | name: rox-image-check 162 | kind: ClusterTask 163 | params: 164 | - name: image 165 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 166 | - name: rox_api_token 167 | value: roxsecrets 168 | - name: rox_central_endpoint 169 | value: roxsecrets 170 | - name: image_digest 171 | value: $(tasks.build-image.results.IMAGE_DIGEST) 172 | - name: deploy-check 173 | runAfter: 174 | - build-image 175 | taskRef: 176 | name: rox-deployment-check 177 | kind: ClusterTask 178 | params: 179 | - name: GIT_REPOSITORY 180 | value: "$(params.APP_MANIFESTS_GIT)" 181 | - name: rox_api_token 182 | value: roxsecrets 183 | - name: rox_central_endpoint 184 | value: roxsecrets 185 | - name: file 186 | value: deployment.yaml 187 | - name: deployment_files_path 188 | value: app 189 | workspaces: 190 | - name: workspace 191 | workspace: workspace 192 | - name: update-deployment 193 | runAfter: 194 | - image-scan 195 | - image-check 196 | - deploy-check 197 | taskRef: 198 | name: git-update-deployment 199 | params: 200 | - name: GIT_REPOSITORY 201 | value: "$(params.APP_MANIFESTS_GIT)" 202 | - name: GIT_USERNAME 203 | value: gogs 204 | - name: GIT_PASSWORD 205 | value: gogs 206 | - name: CURRENT_IMAGE 207 | value: quay.io/siamaksade/spring-petclinic:latest 208 | - name: NEW_IMAGE 209 | value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/spring-petclinic 210 | - name: NEW_DIGEST 211 | value: "$(tasks.build-image.results.IMAGE_DIGEST)" 212 | - name: KUSTOMIZATION_PATH 213 | value: environments/stage 214 | workspaces: 215 | - name: workspace 216 | workspace: workspace 217 | - name: wait-application 218 | taskRef: 219 | name: argocd-task-sync-and-wait 220 | runAfter: 221 | - update-deployment 222 | params: 223 | - name: application-name 224 | value: stage-spring-petclinic 225 | - name: perf-tests-clone 226 | taskRef: 227 | name: git-clone 228 | kind: ClusterTask 229 | workspaces: 230 | - name: output 231 | workspace: workspace 232 | runAfter: 233 | - wait-application 234 | params: 235 | - name: url 236 | value: $(params.APP_TESTS_GIT) 237 | - name: subdirectory 238 | value: spring-petclinic-gatling 239 | - name: deleteExisting 240 | value: "true" 241 | - name: pentesting-test 242 | taskRef: 243 | name: zap-proxy 244 | runAfter: 245 | - perf-tests-clone 246 | params: 247 | - name: APP_URL 248 | value: "http://spring-petclinic.$(params.STAGE_NAMESPACE).svc.cluster.local:8080" 249 | workspaces: 250 | - name: workspace 251 | workspace: workspace 252 | - name: performance-test 253 | taskRef: 254 | name: gatling 255 | runAfter: 256 | - perf-tests-clone 257 | params: 258 | - name: APP_URL 259 | value: "http://spring-petclinic.$(params.STAGE_NAMESPACE).svc.cluster.local:8080" 260 | workspaces: 261 | - name: simulations 262 | workspace: workspace 263 | subPath: spring-petclinic-gatling 264 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-argo-sync-and-wait.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: argocd-task-sync-and-wait 5 | namespace: cicd 6 | labels: 7 | app.kubernetes.io/version: "0.1" 8 | annotations: 9 | tekton.dev/pipelines.minVersion: "0.12.1" 10 | tekton.dev/tags: deploy 11 | tekton.dev/displayName: "argocd" 12 | spec: 13 | description: >- 14 | This task syncs (deploys) an Argo CD application and waits for it to be healthy. 15 | 16 | To do so, it requires the address of the Argo CD server and some form of 17 | authentication either a username/password or an authentication token. 18 | 19 | params: 20 | - name: application-name 21 | description: name of the application to sync 22 | - name: revision 23 | description: the revision to sync to 24 | default: HEAD 25 | - name: flags 26 | default: -- 27 | - name: argocd-version 28 | default: v2.2.5 29 | stepTemplate: 30 | envFrom: 31 | - configMapRef: 32 | name: argocd-env-configmap # used for server address 33 | - secretRef: 34 | name: argocd-env-secret # used for authentication (username/password or auth token) 35 | steps: 36 | - name: login-sync-wait 37 | image: quay.io/rcarrata/argocd:$(params.argocd-version) 38 | script: | 39 | if [ -z $ARGOCD_AUTH_TOKEN ]; then 40 | yes | argocd login $ARGOCD_SERVER --username=$ARGOCD_USERNAME --password=$ARGOCD_PASSWORD ; 41 | fi 42 | 43 | argocd app sync $(params.application-name) --revision $(params.revision) $(params.flags) && sleep 3 44 | 45 | argocd app wait $(params.application-name) --health $(params.flags) 46 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-dependency-report.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: dependency-report 5 | namespace: cicd 6 | annotations: 7 | tekton.dev/pipelines.minVersion: 0.12.1 8 | spec: 9 | params: 10 | - name: SOURCE_DIR 11 | description: The directory within the workspace where application source is located 12 | default: "." 13 | - name: REPORTS_REPO_HOST 14 | description: The reports repository host based on https://github.com/chmouel/openshift-django-uploader 15 | default: http://reports-repo:8080 16 | - name: REPORTS_REPO_USERNAME 17 | description: The reports repository username 18 | default: reports 19 | - name: REPORTS_REPO_PASSWORD 20 | description: The reports repository password 21 | default: reports 22 | - default: '' 23 | description: The Maven repository mirror url 24 | name: MAVEN_MIRROR_URL 25 | type: string 26 | - default: '' 27 | description: The username for the proxy server 28 | name: PROXY_USER 29 | type: string 30 | - default: '' 31 | description: The password for the proxy server 32 | name: PROXY_PASSWORD 33 | type: string 34 | - default: '' 35 | description: Port number for the proxy server 36 | name: PROXY_PORT 37 | type: string 38 | - default: '' 39 | description: Proxy server Host 40 | name: PROXY_HOST 41 | type: string 42 | - default: '' 43 | description: Non proxy server host 44 | name: PROXY_NON_PROXY_HOSTS 45 | type: string 46 | - default: http 47 | description: Protocol for the proxy ie http or https 48 | name: PROXY_PROTOCOL 49 | type: string 50 | workspaces: 51 | - description: The workspace consisting of maven project. 52 | name: source 53 | - description: The workspace consisting of the custom maven settings provided by the user. 54 | name: maven-settings 55 | steps: 56 | - image: 'registry.access.redhat.com/ubi8/ubi-minimal:latest' 57 | name: mvn-settings 58 | resources: {} 59 | script: > 60 | #!/usr/bin/env bash 61 | 62 | 63 | [[ -f $(workspaces.maven-settings.path)/settings.xml ]] && \ 64 | 65 | echo 'using existing $(workspaces.maven-settings.path)/settings.xml' && 66 | exit 0 67 | 68 | 69 | cat > $(workspaces.maven-settings.path)/settings.xml < 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | EOF 83 | 84 | 85 | xml="" 86 | 87 | if [ -n "$(params.PROXY_HOST)" -a -n "$(params.PROXY_PORT)" ]; then 88 | xml="\ 89 | genproxy\ 90 | true\ 91 | $(params.PROXY_PROTOCOL)\ 92 | $(params.PROXY_HOST)\ 93 | $(params.PROXY_PORT)" 94 | if [ -n "$(params.PROXY_USER)" -a -n "$(params.PROXY_PASSWORD)" ]; then 95 | xml="$xml\ 96 | $(params.PROXY_USER)\ 97 | $(params.PROXY_PASSWORD)" 98 | fi 99 | if [ -n "$(params.PROXY_NON_PROXY_HOSTS)" ]; then 100 | xml="$xml\ 101 | $(params.PROXY_NON_PROXY_HOSTS)" 102 | fi 103 | xml="$xml\ 104 | " 105 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 106 | fi 107 | 108 | 109 | if [ -n "$(params.MAVEN_MIRROR_URL)" ]; then 110 | xml=" \ 111 | mirror.default\ 112 | $(params.MAVEN_MIRROR_URL)\ 113 | central\ 114 | " 115 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 116 | fi 117 | - args: 118 | - -Dmaven.repo.local=$(workspaces.source.path)/.m2 119 | - -f 120 | - $(params.SOURCE_DIR) 121 | - -s 122 | - $(workspaces.maven-settings.path)/settings.xml 123 | - site 124 | - -DskipTests=true 125 | command: 126 | - /usr/bin/mvn 127 | image: gcr.io/cloud-builders/mvn 128 | name: mvn-goals 129 | resources: {} 130 | workingDir: $(workspaces.source.path) 131 | - name: archive-site 132 | workingDir: $(workspaces.source.path) 133 | image: registry.access.redhat.com/ubi8/ubi:latest 134 | env: 135 | - name: PIPELINERUN_NAME 136 | valueFrom: 137 | fieldRef: 138 | fieldPath: metadata.labels['tekton.dev/pipelineRun'] 139 | script: | 140 | #!/usr/bin/env bash 141 | 142 | for f in $(find $(params.SOURCE_DIR)/target/site -type f); do 143 | curl -u $(params.REPORTS_REPO_USERNAME):$(params.REPORTS_REPO_PASSWORD) -F path=$PIPELINERUN_NAME/${f} -X POST -F file=@${f} $(params.REPORTS_REPO_HOST)/upload; echo "" 144 | done 145 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-gatling.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: gatling 5 | namespace: cicd 6 | spec: 7 | params: 8 | - name: DURATION 9 | description: The duration of running simulations 10 | type: string 11 | default: "30" 12 | - name: CONCURRENT_USERS 13 | description: The number of concurrent users 14 | type: string 15 | default: "10" 16 | - name: APP_URL 17 | description: The application under test url 18 | type: string 19 | - name: REPORTS_REPO_HOST 20 | description: The reports repository host based on https://github.com/chmouel/openshift-django-uploader 21 | default: http://reports-repo:8080 22 | - name: REPORTS_REPO_USERNAME 23 | description: The reports repository username 24 | default: reports 25 | - name: REPORTS_REPO_PASSWORD 26 | description: The reports repository password 27 | default: reports 28 | workspaces: 29 | - description: The workspace consisting of maven project. 30 | name: simulations 31 | steps: 32 | - name: run-tests 33 | image: quay.io/siamaksade/gatling:latest 34 | env: 35 | - name: PIPELINERUN_NAME 36 | valueFrom: 37 | fieldRef: 38 | fieldPath: metadata.labels['tekton.dev/pipelineRun'] 39 | script: | 40 | #!/usr/bin/env bash 41 | 42 | set -x 43 | 44 | cd /opt/gatling/ 45 | ls -lhrt 46 | 47 | # set simulation params 48 | export JAVA_OPTS="-DtestDuration=$(params.CONCURRENT_USERS) -DuserCount=$(params.DURATION) -Dserver=$(params.APP_URL)" 49 | 50 | # run simulation 51 | /opt/gatling/bin/gatling.sh -rd "Spring PetClinic Performance Test" -sf $(workspaces.simulations.path) 52 | 53 | # upload results 54 | REPORT=$(ls -td /opt/gatling/results/* | head -1) 55 | for f in $(find $REPORT/ -type f); do 56 | curl -u $(params.REPORTS_REPO_USERNAME):$(params.REPORTS_REPO_PASSWORD) -F path=$PIPELINERUN_NAME${f#/opt/gatling/results} -X POST -F file=@${f} $(params.REPORTS_REPO_HOST)/upload; echo "" 57 | done 58 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-git-update-deployment.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | annotations: 5 | tekton.dev/pipelines.minVersion: 0.12.1 6 | tekton.dev/tags: git 7 | name: git-update-deployment 8 | namespace: cicd 9 | labels: 10 | app.kubernetes.io/version: '0.1' 11 | operator.tekton.dev/provider-type: community 12 | spec: 13 | description: This Task can be used to update image digest in a Git repo using kustomize 14 | params: 15 | - name: GIT_REPOSITORY 16 | type: string 17 | - name: GIT_USERNAME 18 | type: string 19 | - name: GIT_PASSWORD 20 | type: string 21 | - name: CURRENT_IMAGE 22 | type: string 23 | - name: NEW_IMAGE 24 | type: string 25 | - name: NEW_DIGEST 26 | type: string 27 | - name: KUSTOMIZATION_PATH 28 | type: string 29 | workspaces: 30 | - description: The workspace consisting of maven project. 31 | name: workspace 32 | 33 | results: 34 | - name: commit 35 | description: The commit SHA 36 | 37 | steps: 38 | - name: git-clone 39 | image: quay.io/rcarrata/git:v2.26.2 40 | workingDir: $(workspaces.workspace.path) 41 | script: | 42 | rm -rf git-update-digest-workdir 43 | git clone $(params.GIT_REPOSITORY) git-update-digest-workdir 44 | 45 | - name: update-digest 46 | image: k8s.gcr.io/kustomize/kustomize:v3.8.7 47 | workingDir: $(workspaces.workspace.path) 48 | script: | 49 | cd git-update-digest-workdir/$(params.KUSTOMIZATION_PATH) 50 | /app/kustomize edit set image $(params.CURRENT_IMAGE)=$(params.NEW_IMAGE)@$(params.NEW_DIGEST) 51 | 52 | echo "##########################" 53 | echo "### kustomization.yaml ###" 54 | echo "##########################" 55 | cat kustomization.yaml 56 | 57 | - name: git-commit 58 | image: quay.io/rcarrata/git:v2.26.2 59 | workingDir: $(workspaces.workspace.path) 60 | script: | 61 | cd git-update-digest-workdir 62 | git config user.email "tekton-pipelines-ci@redhat.com" 63 | git config user.name "tekton-pipelines-ci" 64 | 65 | git status 66 | git add $(params.KUSTOMIZATION_PATH)/kustomization.yaml 67 | # git commit -m "[$(context.pipelineRun.name)] Image digest updated" 68 | git commit -m "[ci] Image digest updated" 69 | 70 | git remote add auth-origin $(echo $(params.GIT_REPOSITORY) | sed -E "s#http://(.*)#http://$(params.GIT_USERNAME):$(params.GIT_PASSWORD)@\1#g") 71 | git push auth-origin master 72 | 73 | RESULT_SHA="$(git rev-parse HEAD | tr -d '\n')" 74 | EXIT_CODE="$?" 75 | if [ "$EXIT_CODE" != 0 ] 76 | then 77 | exit $EXIT_CODE 78 | fi 79 | # Make sure we don't add a trailing newline to the result! 80 | echo -n "$RESULT_SHA" > $(results.commit.path) 81 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-image-scan-task.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: ClusterTask 3 | metadata: 4 | name: rox-image-scan 5 | spec: 6 | params: 7 | - name: rox_central_endpoint 8 | type: string 9 | description: Secret containing the address:port tuple for StackRox Central (example - rox.stackrox.io:443) 10 | - name: rox_api_token 11 | type: string 12 | description: Secret containing the StackRox API token with CI permissions 13 | - name: image 14 | type: string 15 | description: Full name of image to scan (example -- gcr.io/rox/sample:5.0-rc1) 16 | - name: output_format 17 | type: string 18 | description: Output format (json | csv | table) 19 | default: json 20 | - name: image_digest 21 | description: Digest in sha256 hash format of the image to scan 22 | type: string 23 | steps: 24 | - name: rox-image-scan 25 | image: registry.access.redhat.com/ubi8/ubi-minimal:latest 26 | env: 27 | - name: ROX_API_TOKEN 28 | valueFrom: 29 | secretKeyRef: 30 | name: $(params.rox_api_token) 31 | key: rox_api_token 32 | - name: ROX_CENTRAL_ENDPOINT 33 | valueFrom: 34 | secretKeyRef: 35 | name: $(params.rox_central_endpoint) 36 | key: rox_central_endpoint 37 | script: | 38 | #!/usr/bin/env bash 39 | set +x 40 | export NO_COLOR="True" 41 | curl -k -L -H "Authorization: Bearer $ROX_API_TOKEN" https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output ./roxctl > /dev/null; echo "Getting roxctl" 42 | chmod +x ./roxctl > /dev/null 43 | echo "## Scanning image $(params.image)@$(params.image_digest)" 44 | ./roxctl image scan --insecure-skip-tls-verify -e $ROX_CENTRAL_ENDPOINT --image $(params.image)@$(params.image_digest) --output $(params.output_format) 45 | echo "## Go to https://$ROX_CENTRAL_ENDPOINT/main/vulnerability-management/image/$(params.image_digest) to check more info" 46 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-mvn-cm.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: maven-settings 5 | namespace: cicd 6 | data: 7 | settings.xml: | 8 | 9 | 10 | 11 | 12 | nexus 13 | admin 14 | admin123 15 | 16 | 17 | 18 | 19 | nexus 20 | nexus 21 | http://nexus:8081/repository/maven-public/ 22 | * 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-mvn.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | annotations: 5 | tekton.dev/pipelines.minVersion: 0.12.1 6 | tekton.dev/tags: build-tool 7 | name: maven 8 | namespace: cicd 9 | labels: 10 | app.kubernetes.io/version: '0.1' 11 | operator.tekton.dev/provider-type: community 12 | spec: 13 | description: This Task can be used to run a Maven build. 14 | params: 15 | - default: gcr.io/cloud-builders/mvn:3.5.0-jdk-8 16 | description: Maven base image 17 | name: MAVEN_IMAGE 18 | type: string 19 | - default: 20 | - package 21 | description: maven goals to run 22 | name: GOALS 23 | type: array 24 | - default: '' 25 | description: The Maven repository mirror url 26 | name: MAVEN_MIRROR_URL 27 | type: string 28 | - default: '' 29 | description: The username for the proxy server 30 | name: PROXY_USER 31 | type: string 32 | - default: '' 33 | description: The password for the proxy server 34 | name: PROXY_PASSWORD 35 | type: string 36 | - default: '' 37 | description: Port number for the proxy server 38 | name: PROXY_PORT 39 | type: string 40 | - default: '' 41 | description: Proxy server Host 42 | name: PROXY_HOST 43 | type: string 44 | - default: '' 45 | description: Non proxy server host 46 | name: PROXY_NON_PROXY_HOSTS 47 | type: string 48 | - default: http 49 | description: Protocol for the proxy ie http or https 50 | name: PROXY_PROTOCOL 51 | type: string 52 | workspaces: 53 | - description: The workspace consisting of maven project. 54 | name: source 55 | - description: The workspace consisting of the custom maven settings provided by the user. 56 | name: maven-settings 57 | steps: 58 | - image: 'registry.access.redhat.com/ubi8/ubi-minimal:latest' 59 | name: mvn-settings 60 | resources: {} 61 | script: > 62 | #!/usr/bin/env bash 63 | 64 | 65 | [[ -f $(workspaces.maven-settings.path)/settings.xml ]] && \ 66 | 67 | echo 'using existing $(workspaces.maven-settings.path)/settings.xml' && 68 | exit 0 69 | 70 | 71 | cat > $(workspaces.maven-settings.path)/settings.xml < 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | EOF 85 | 86 | 87 | xml="" 88 | 89 | if [ -n "$(params.PROXY_HOST)" -a -n "$(params.PROXY_PORT)" ]; then 90 | xml="\ 91 | genproxy\ 92 | true\ 93 | $(params.PROXY_PROTOCOL)\ 94 | $(params.PROXY_HOST)\ 95 | $(params.PROXY_PORT)" 96 | if [ -n "$(params.PROXY_USER)" -a -n "$(params.PROXY_PASSWORD)" ]; then 97 | xml="$xml\ 98 | $(params.PROXY_USER)\ 99 | $(params.PROXY_PASSWORD)" 100 | fi 101 | if [ -n "$(params.PROXY_NON_PROXY_HOSTS)" ]; then 102 | xml="$xml\ 103 | $(params.PROXY_NON_PROXY_HOSTS)" 104 | fi 105 | xml="$xml\ 106 | " 107 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 108 | fi 109 | 110 | 111 | if [ -n "$(params.MAVEN_MIRROR_URL)" ]; then 112 | xml=" \ 113 | mirror.default\ 114 | $(params.MAVEN_MIRROR_URL)\ 115 | central\ 116 | " 117 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 118 | fi 119 | - args: 120 | - -Dmaven.repo.local=$(workspaces.source.path)/.m2 121 | - '-s' 122 | - $(workspaces.maven-settings.path)/settings.xml 123 | - $(params.GOALS) 124 | command: 125 | - /usr/bin/mvn 126 | image: $(params.MAVEN_IMAGE) 127 | name: mvn-goals 128 | workingDir: $(workspaces.source.path) 129 | resources: 130 | requests: 131 | memory: 512Mi 132 | cpu: 200m 133 | limits: 134 | memory: 4Gi 135 | cpu: 1 136 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-rox-deployment-check.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: ClusterTask 3 | metadata: 4 | name: rox-deployment-check 5 | spec: 6 | params: 7 | - name: GIT_REPOSITORY 8 | type: string 9 | - name: rox_central_endpoint 10 | type: string 11 | description: Secret containing the address:port tuple for StackRox Central (example - rox.stackrox.io:443) 12 | - name: rox_api_token 13 | type: string 14 | description: Secret containing the StackRox API token with CI permissions 15 | - name: file 16 | type: string 17 | description: YAML file in the deployfiles workspace 18 | - name: deployment_files_path 19 | type: string 20 | description: Path/Folder for the k8s deployment files to check 21 | results: 22 | - name: check_output 23 | description: Output of `roxctl deployment check` 24 | workspaces: 25 | - description: The workspace consisting of maven project. 26 | name: workspace 27 | steps: 28 | 29 | - name: git-clone 30 | image: quay.io/rcarrata/git:v2.26.2 31 | workingDir: $(workspaces.workspace.path) 32 | script: | 33 | rm -rf git-update-digest-workdir 34 | git clone $(params.GIT_REPOSITORY) git-update-digest-workdir 35 | cd git-update-digest-workdir/$(params.deployment_files_path) 36 | 37 | - name: rox-deployment-check 38 | image: registry.access.redhat.com/ubi8/ubi-minimal:latest 39 | workingDir: $(workspaces.workspace.path) 40 | env: 41 | - name: ROX_API_TOKEN 42 | valueFrom: 43 | secretKeyRef: 44 | name: $(params.rox_api_token) 45 | key: rox_api_token 46 | - name: ROX_CENTRAL_ENDPOINT 47 | valueFrom: 48 | secretKeyRef: 49 | name: $(params.rox_central_endpoint) 50 | key: rox_central_endpoint 51 | script: | 52 | #!/usr/bin/env bash 53 | set +x 54 | cd git-update-digest-workdir/$(params.deployment_files_path) 55 | cat $(params.file) 56 | curl -k -L -H "Authorization: Bearer $ROX_API_TOKEN" https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output ./roxctl > /dev/null; echo "Getting roxctl" 57 | chmod +x ./roxctl > /dev/null 58 | ./roxctl deployment check --insecure-skip-tls-verify -e $ROX_CENTRAL_ENDPOINT -f $(params.file) 59 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-rox-image-check.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: ClusterTask 3 | metadata: 4 | name: rox-image-check 5 | spec: 6 | params: 7 | - description: >- 8 | Secret containing the address:port tuple for StackRox Central (example - 9 | rox.stackrox.io:443) 10 | name: rox_central_endpoint 11 | type: string 12 | - description: Secret containing the StackRox API token with CI permissions 13 | name: rox_api_token 14 | type: string 15 | - description: 'Full name of image to scan (example -- gcr.io/rox/sample:5.0-rc1)' 16 | name: image 17 | type: string 18 | - name: image_digest 19 | description: Digest in sha256 hash format of the image to check 20 | type: string 21 | results: 22 | - description: Output of `roxctl image check` 23 | name: check_output 24 | steps: 25 | - env: 26 | - name: ROX_API_TOKEN 27 | valueFrom: 28 | secretKeyRef: 29 | key: rox_api_token 30 | name: $(params.rox_api_token) 31 | - name: ROX_CENTRAL_ENDPOINT 32 | valueFrom: 33 | secretKeyRef: 34 | key: rox_central_endpoint 35 | name: $(params.rox_central_endpoint) 36 | image: registry.access.redhat.com/ubi8/ubi-minimal:latest 37 | name: rox-image-check 38 | resources: {} 39 | script: >- 40 | #!/usr/bin/env bash 41 | 42 | set +x 43 | 44 | curl -k -L -H "Authorization: Bearer $ROX_API_TOKEN" 45 | https://$ROX_CENTRAL_ENDPOINT/api/cli/download/roxctl-linux --output 46 | ./roxctl > /dev/null; echo "Getting roxctl" 47 | 48 | chmod +x ./roxctl > /dev/null 49 | 50 | ./roxctl image check --insecure-skip-tls-verify -e $ROX_CENTRAL_ENDPOINT 51 | --image $(params.image)@$(params.image_digest) 52 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-s2i-java-11.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | annotations: 5 | tekton.dev/displayName: s2i java 11 6 | tekton.dev/pipelines.minVersion: 0.11.3 7 | tekton.dev/tags: 's2i, java, workspace' 8 | name: s2i-java-11 9 | namespace: cicd 10 | spec: 11 | description: >- 12 | s2i-java-11 task clones a Git repository and builds and pushes a container 13 | image using S2I and a Java 11 builder image. 14 | params: 15 | - default: . 16 | description: The location of the path to run s2i from 17 | name: PATH_CONTEXT 18 | type: string 19 | - default: 'true' 20 | description: >- 21 | Verify the TLS on the registry endpoint (for push/pull to a non-TLS 22 | registry) 23 | name: TLSVERIFY 24 | type: string 25 | - default: '' 26 | description: Additional Maven arguments 27 | name: MAVEN_ARGS_APPEND 28 | type: string 29 | - default: 'false' 30 | description: Remove the Maven repository after the artifact is built 31 | name: MAVEN_CLEAR_REPO 32 | type: string 33 | - default: '' 34 | description: The base URL of a mirror used for retrieving artifacts 35 | name: MAVEN_MIRROR_URL 36 | type: string 37 | - description: Location of the repo where image has to be pushed 38 | name: IMAGE_NAME 39 | type: string 40 | - default: latest 41 | description: The tag of the image to be pushed 42 | name: IMAGE_TAG 43 | type: string 44 | results: 45 | - description: Digest of the image just built. 46 | name: IMAGE_DIGEST 47 | type: string 48 | steps: 49 | - args: 50 | - |- 51 | echo "MAVEN_CLEAR_REPO=$(params.MAVEN_CLEAR_REPO)" > env-file 52 | 53 | [[ '$(params.MAVEN_ARGS_APPEND)' != "" ]] && 54 | echo "MAVEN_ARGS_APPEND=$(params.MAVEN_ARGS_APPEND)" >> env-file 55 | 56 | [[ '$(params.MAVEN_MIRROR_URL)' != "" ]] && 57 | echo "MAVEN_MIRROR_URL=$(params.MAVEN_MIRROR_URL)" >> env-file 58 | 59 | echo "Generated Env file" 60 | echo "------------------------------" 61 | cat env-file 62 | echo "------------------------------" 63 | command: 64 | - /bin/sh 65 | - '-c' 66 | image: >- 67 | registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8@sha256:562dbdac04ae9260e21d457585b3251fd8cc5310966f8fc544fb77dc544c92f8 68 | name: gen-env-file 69 | resources: {} 70 | volumeMounts: 71 | - mountPath: /env-params 72 | name: envparams 73 | workingDir: /env-params 74 | - command: 75 | - s2i 76 | - build 77 | - $(params.PATH_CONTEXT) 78 | - 'image-registry.openshift-image-registry.svc:5000/openshift/java:11' 79 | - '--image-scripts-url' 80 | - 'image:///usr/local/s2i' 81 | - '--as-dockerfile' 82 | - /gen-source/Dockerfile.gen 83 | - '--environment-file' 84 | - /env-params/env-file 85 | image: >- 86 | registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8@sha256:562dbdac04ae9260e21d457585b3251fd8cc5310966f8fc544fb77dc544c92f8 87 | name: generate 88 | resources: {} 89 | volumeMounts: 90 | - mountPath: /gen-source 91 | name: gen-source 92 | - mountPath: /env-params 93 | name: envparams 94 | workingDir: $(workspaces.source.path) 95 | - command: 96 | - buildah 97 | - bud 98 | - '--storage-driver=vfs' 99 | - '--tls-verify=$(params.TLSVERIFY)' 100 | - '--layers' 101 | - '-f' 102 | - /gen-source/Dockerfile.gen 103 | - '-t' 104 | - '$(params.IMAGE_NAME):$(params.IMAGE_TAG)' 105 | - '-t' 106 | - '$(params.IMAGE_NAME):latest' 107 | - . 108 | image: >- 109 | registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 110 | name: build 111 | resources: {} 112 | securityContext: 113 | capabilities: 114 | add: 115 | - SETFCAP 116 | volumeMounts: 117 | - mountPath: /var/lib/containers 118 | name: varlibcontainers 119 | - mountPath: /gen-source 120 | name: gen-source 121 | workingDir: /gen-source 122 | - command: 123 | - buildah 124 | - push 125 | - '--storage-driver=vfs' 126 | - '--tls-verify=$(params.TLSVERIFY)' 127 | - '--digestfile' 128 | - $(workspaces.source.path)/image-digest 129 | - '$(params.IMAGE_NAME):$(params.IMAGE_TAG)' 130 | - 'docker://$(params.IMAGE_NAME):$(params.IMAGE_TAG)' 131 | image: >- 132 | registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 133 | name: push-tag 134 | resources: {} 135 | securityContext: 136 | capabilities: 137 | add: 138 | - SETFCAP 139 | volumeMounts: 140 | - mountPath: /var/lib/containers 141 | name: varlibcontainers 142 | - command: 143 | - buildah 144 | - push 145 | - '--storage-driver=vfs' 146 | - '--tls-verify=$(params.TLSVERIFY)' 147 | - '--digestfile' 148 | - $(workspaces.source.path)/image-digest 149 | - '$(params.IMAGE_NAME):$(params.IMAGE_TAG)' 150 | - 'docker://$(params.IMAGE_NAME):latest' 151 | image: >- 152 | registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 153 | name: push-latest 154 | resources: {} 155 | securityContext: 156 | capabilities: 157 | add: 158 | - SETFCAP 159 | volumeMounts: 160 | - mountPath: /var/lib/containers 161 | name: varlibcontainers 162 | - image: >- 163 | registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 164 | name: digest-to-results 165 | resources: {} 166 | script: >- 167 | cat $(workspaces.source.path)/image-digest | tee 168 | /tekton/results/IMAGE_DIGEST 169 | volumes: 170 | - emptyDir: {} 171 | name: varlibcontainers 172 | - emptyDir: {} 173 | name: gen-source 174 | - emptyDir: {} 175 | name: envparams 176 | workspaces: 177 | - mountPath: /workspace/source 178 | name: source 179 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/task-zap-proxy.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | annotations: 5 | tekton.dev/pipelines.minVersion: 0.12.1 6 | tekton.dev/tags: git 7 | name: zap-proxy 8 | namespace: cicd 9 | labels: 10 | app.kubernetes.io/version: '0.1' 11 | operator.tekton.dev/provider-type: community 12 | spec: 13 | description: This Task can be used to update image digest in a Git repo using kustomize 14 | params: 15 | - name: REPORTS_REPO_USERNAME 16 | description: The reports repository username 17 | default: reports 18 | - name: REPORTS_REPO_PASSWORD 19 | description: The reports repository password 20 | default: reports 21 | - name: APP_URL 22 | description: The application under test url 23 | - name: REPORTS_REPO_HOST 24 | description: The reports repository host based on https://github.com/chmouel/openshift-django-uploader 25 | default: http://reports-repo:8080 26 | workspaces: 27 | - description: The workspace for the zap proxy task 28 | name: workspace 29 | 30 | steps: 31 | - name: zap-proxy 32 | image: quay.io/rcarrata/zap2docker-stable:latest 33 | env: 34 | - name: PIPELINERUN_NAME 35 | valueFrom: 36 | fieldRef: 37 | fieldPath: metadata.labels['tekton.dev/pipelineRun'] 38 | workingDir: $(workspaces.workspace.path) 39 | script: | 40 | #!/usr/bin/env bash 41 | 42 | set -x 43 | 44 | echo "Make the wrk directory available to save the reports" 45 | cd /zap 46 | mkdir /zap/wrk 47 | 48 | echo "Starting the pentesting..." 49 | /zap/zap-baseline.py -t $(params.APP_URL) -r $PIPELINERUN_NAME.html 50 | 51 | ls -lhrt /zap/wrk 52 | 53 | echo "Uploading the report into the report server" 54 | curl -u $(params.REPORTS_REPO_USERNAME):$(params.REPORTS_REPO_PASSWORD) -F path=$PIPELINERUN_NAME/$PIPELINERUN_NAME.html -F file=@/zap/wrk/$PIPELINERUN_NAME.html -X POST $(params.REPORTS_REPO_HOST)/upload; echo "" 55 | 56 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/trigger-eventlistener-route.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: route.openshift.io/v1 2 | kind: Route 3 | metadata: 4 | name: el-webhook 5 | namespace: cicd 6 | labels: 7 | app.kubernetes.io/managed-by: EventListener 8 | app.kubernetes.io/part-of: Triggers 9 | eventlistener: webhook 10 | spec: 11 | port: 12 | targetPort: http-listener 13 | to: 14 | kind: "Service" 15 | name: el-webhook 16 | weight: 100 17 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/trigger-eventlistener.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: triggers.tekton.dev/v1alpha1 2 | kind: EventListener 3 | metadata: 4 | name: webhook 5 | namespace: cicd 6 | spec: 7 | serviceAccountName: pipeline 8 | triggers: 9 | - name: petclinic-webhook 10 | interceptors: 11 | - cel: 12 | overlays: 13 | - key: short_sha 14 | expression: "body.after.truncate(7)" 15 | - key: branch_name 16 | expression: "body.ref.split('/')[2]" 17 | bindings: 18 | - ref: gogs-triggerbinding 19 | template: 20 | ref: petclinic-trigger-template 21 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/trigger-gogs-triggerbinding.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: triggers.tekton.dev/v1alpha1 3 | kind: TriggerBinding 4 | metadata: 5 | name: gogs-triggerbinding 6 | namespace: cicd 7 | spec: 8 | params: 9 | - name: gitrevision 10 | value: $(body.after) 11 | - name: gitshortsha 12 | value: $(body.short_sha) 13 | - name: gitbranchname 14 | value: $(body.branch_name) 15 | - name: gitrepositoryurl 16 | value: $(body.repository.clone_url) 17 | - name: contenttype 18 | value: $(header.Content-Type) 19 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-pipelines/templates/triggertemplate.yaml.j2: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: triggers.tekton.dev/v1alpha1 3 | kind: TriggerTemplate 4 | metadata: 5 | name: petclinic-trigger-template 6 | namespace: cicd 7 | spec: 8 | params: 9 | - name: gitrevision 10 | description: The git revision 11 | default: master 12 | - name: gitshortsha 13 | description: The short commit sha 14 | default: master 15 | - name: gitbranchname 16 | description: The branch name 17 | default: master 18 | - name: gitrepositoryurl 19 | description: The git repository url 20 | - name: message 21 | description: The message to print 22 | default: This is the default message 23 | - name: contenttype 24 | description: The Content-Type of the event 25 | resourcetemplates: 26 | - apiVersion: tekton.dev/v1beta1 27 | kind: PipelineRun 28 | metadata: 29 | generateName: petclinic-build-dev 30 | # name: petclinic-dev-$(tt.params.gitbranchname)-$(tt.params.gitshortsha) 31 | labels: 32 | tekton.dev/pipeline: petclinic-build-dev 33 | spec: 34 | pipelineRef: 35 | name: petclinic-build-dev 36 | params: 37 | - name: APP_SOURCE_GIT 38 | value: $(tt.params.gitrepositoryurl) 39 | - name: APP_SOURCE_REVISION 40 | value: $(tt.params.gitrevision) 41 | - name: APP_IMAGE_TAG 42 | value: $(tt.params.gitbranchname)-$(tt.params.gitshortsha) 43 | workspaces: 44 | - name: maven-settings 45 | configMap: 46 | name: maven-settings 47 | - name: workspace 48 | persistentVolumeClaim: 49 | claimName: petclinic-build-workspace 50 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-quay/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | quay_project_name: quay-demo 2 | quay_admin_username: quayadmin 3 | quay_admin_email: quayadmin@redhat.com 4 | quay_admin_password: quaypass123 5 | quay_registry_name: demo-registry 6 | quay_org_name: cicd-demo 7 | quay_secret_name: quay-robot-secret 8 | quay_repositories: 9 | - spring-petclinic-dev 10 | - spring-petclinic-stage 11 | quay_robot_account: demo_robot 12 | pipeline_namespace: cicd 13 | csrf_pattern: ".*window.__token\ =\ '(.*)';.*" 14 | #Can obtain status codes from Swagger of quay route/api/v1/discovery 15 | quay_user_found_success_status_code: 200 16 | quay_org_not_found_error_code: 404 17 | quay_org_found_success_status_code: 200 18 | quay_org_created_success_status_code: 201 19 | quay_repo_not_found_error_code: 404 20 | quay_repo_found_success_status_code: 200 21 | quay_repo_created_success_status_code: 201 22 | quay_robot_not_found_error_code: 400 23 | quay_robot_found_success_status_code: 200 24 | quay_robot_created_success_status_code: 201 25 | quay_perm_success_status_code: 200 26 | secret_required_namespaces: 27 | - cicd 28 | - devsecops-dev 29 | - devsecops-qa -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-quay/tasks/install-quay.yaml: -------------------------------------------------------------------------------- 1 | - name: Create OpenShift Objects to install Quay 2 | k8s: 3 | state: present 4 | definition: "{{ lookup('template', item ) | from_yaml }}" 5 | loop: 6 | - ./templates/quay-subscription.yaml.j2 7 | - ./templates/quay-namespace.yaml.j2 8 | 9 | #Only necessary if Quay not managing storage 10 | # - name: Get NooBaa Secret 11 | # shell: | 12 | # oc get noobaa/noobaa -n openshift-storage -o json | jq -r '.status.accounts.admin.secretRef.name' 13 | # register: noobaa_secret 14 | 15 | # - name: Set NooBaa Secret Value 16 | # ansible.builtin.set_fact: 17 | # NOOBAA_SECRET: "{{ noobaa_secret.stdout }}" 18 | 19 | # - name: Get NooBaa Mgmt Address 20 | # shell: | 21 | # oc get noobaa noobaa -n openshift-storage -o json | jq -r '.status.services.serviceMgmt.nodePorts[0]' 22 | # register: noobaa_mgmt 23 | 24 | # - name: Set NooBaa Mgmt Address 25 | # ansible.builtin.set_fact: 26 | # NOOBAA_MGMT: "{{ noobaa_mgmt.stdout }}" 27 | 28 | # - name: Get NooBaa S3 Address 29 | # shell: | 30 | # oc get noobaa noobaa -n openshift-storage -o json | jq -r '.status.services.serviceS3.nodePorts[0]' 31 | # register: noobaa_s3 32 | 33 | # - name: Set NooBaa S3 Address 34 | # ansible.builtin.set_fact: 35 | # NOOBAA_S3: "{{ noobaa_s3.stdout }}" 36 | 37 | # - name: Get NooBaa Access Key 38 | # shell: | 39 | # oc get secret "{{ NOOBAA_SECRET }}" -n openshift-storage -o json | jq -r '.data.AWS_ACCESS_KEY_ID|@base64d' 40 | # register: noobaa_access_key 41 | 42 | # - name: Set NooBaa Access Key 43 | # ansible.builtin.set_fact: 44 | # NOOBAA_ACCESS_KEY: "{{ noobaa_access_key.stdout }}" 45 | 46 | # - name: Get NooBaa Secret Key 47 | # shell: | 48 | # oc get secret $NOOBAA_SECRET -n openshift-storage -o json | jq -r '.data.AWS_SECRET_ACCESS_KEY|@base64d' 49 | # register: noobaa_secret_key 50 | 51 | # - name: Set NooBaa Secret Key 52 | # ansible.builtin.set_fact: 53 | # NOOBAA_SECRET_KEY: "{{ noobaa_secret_key.stdout }}" 54 | 55 | - name: Wait for QuayRegistry CRD to exist 56 | kubernetes.core.k8s_info: 57 | api_version: "apiextensions.k8s.io/v1" 58 | kind: CustomResourceDefinition 59 | name: "quayregistries.quay.redhat.com" 60 | register: crds 61 | until: crds.resources|length > 0 62 | retries: 30 63 | delay: 10 64 | 65 | - name: Create Quay Registry Object 66 | k8s: 67 | state: present 68 | definition: "{{ lookup('template', item ) | from_yaml }}" 69 | loop: 70 | - ./templates/quay-config-secret.yaml.j2 71 | - ./templates/quayregistry.yaml.j2 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-quay/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - import_tasks: install-quay.yaml 2 | 3 | - include_tasks: configure-quay.yaml 4 | loop: "{{ quay_repositories }}" 5 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-quay/templates/quay-config-secret.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | stringData: 3 | config.yaml: | 4 | FEATURE_GENERAL_OCI_SUPPORT: true 5 | FEATURE_USER_INITIALIZE: true 6 | BROWSER_API_CALLS_XHR_ONLY: false 7 | SUPER_USERS: 8 | - {{ quay_admin_username }} 9 | FEATURE_USER_CREATION: false 10 | kind: Secret 11 | metadata: 12 | name: quay-config-bundle 13 | namespace: {{ quay_project_name }} 14 | type: Opaque 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-quay/templates/quay-namespace.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: Namespace 2 | apiVersion: v1 3 | metadata: 4 | name: {{ quay_project_name }} 5 | labels: 6 | kubernetes.io/metadata.name: {{ quay_project_name }} 7 | spec: {} 8 | 9 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-quay/templates/quay-subscription.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operators.coreos.com/v1alpha1 2 | kind: Subscription 3 | metadata: 4 | name: quay-operator 5 | namespace: openshift-operators 6 | spec: 7 | channel: stable-3.7 8 | installPlanApproval: Automatic 9 | name: quay-operator 10 | source: redhat-operators 11 | sourceNamespace: openshift-marketplace 12 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-quay/templates/quayregistry.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: quay.redhat.com/v1 2 | kind: QuayRegistry 3 | metadata: 4 | name: {{ quay_registry_name }} 5 | namespace: {{ quay_project_name }} 6 | spec: 7 | configBundleSecret: quay-config-bundle 8 | components: 9 | - managed: true 10 | kind: clair 11 | - managed: true 12 | kind: postgres 13 | - managed: true 14 | kind: objectstorage 15 | - managed: true 16 | kind: redis 17 | - managed: true 18 | kind: horizontalpodautoscaler 19 | - managed: true 20 | kind: route 21 | - managed: true 22 | kind: mirror 23 | - managed: true 24 | kind: monitoring 25 | - managed: true 26 | kind: tls 27 | - managed: true 28 | kind: quay 29 | - managed: true 30 | kind: clairpostgres 31 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/defaults/main.yaml: -------------------------------------------------------------------------------- 1 | tekton_chain_keys: 2 | "artifacts.oci.storage": "" 3 | "artifacts.taskrun.format": "tekton" 4 | "artifacts.taskrun.storage": "tekton" 5 | "artifacts.oci.signer": "x509" 6 | "artifacts.oci.format": "simplesigning" 7 | #tekton_operator_namespace: openshift-pipelines 8 | pipeline_namespace: cicd 9 | dev_namespace: devsecops-dev 10 | qa_namespace: devsecops-qa 11 | tekton_operator_namespace: tekton-chains 12 | tekton_chain_version: 'v0.10.0' 13 | tekton_install_type: manifest 14 | cosign_image: "image-registry.openshift-image-registry.svc:5000/{{ pipeline_namespace }}/cosign-pod:latest" 15 | #cosign_image: "gcr.io/projectsigstore/cosign:v1.9.0" 16 | secret_generate_name: signing-secrets 17 | stackrox_central_admin_password: stackrox 18 | quay_secret_name: quay-robot-secret 19 | quay_registry_name: demo-registry 20 | quay_org_name: cicd-demo 21 | quay_project_name: quay-demo 22 | quay_repositories: 23 | - spring-petclinic-dev 24 | - spring-petclinic-stage 25 | secret_required_namespaces: 26 | - cicd 27 | - devsecops-dev 28 | - devsecops-qa -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/files/policies/signed-image-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "policies": [ 3 | { 4 | "id": "c8fde2c3-980c-40e3-bc9d-6245b13ab81e", 5 | "name": "Trusted_Signature_Image_Policy", 6 | "description": "Alert on Images that have not been signed", 7 | "rationale": "rationale", 8 | "remediation": "All images should be signed by our cosign-demo signature", 9 | "disabled": false, 10 | "categories": [ 11 | "Security Best Practices" 12 | ], 13 | "lifecycleStages": [ 14 | "BUILD", 15 | "DEPLOY" 16 | ], 17 | "severity": "HIGH_SEVERITY", 18 | "enforcementActions": [], 19 | "notifiers": [], 20 | "SORTName": "", 21 | "SORTLifecycleStage": "", 22 | "SORTEnforcement": false, 23 | "policyVersion": "1.1", 24 | "policySections": [ 25 | { 26 | "sectionName": "Policy Section 1", 27 | "policyGroups": [ 28 | { 29 | "fieldName": "Image Signature Verified By", 30 | "booleanOperator": "OR", 31 | "negate": false, 32 | "values": [ 33 | { 34 | "value": "io.stackrox.signatureintegration.f9352803-d5c9-45d6-abe0-e1361a24559a" 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | ], 41 | "mitreAttackVectors": [], 42 | "criteriaLocked": false, 43 | "mitreVectorsLocked": false, 44 | "isDefault": false 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/tasks/add-cosign-secret-acs.yaml: -------------------------------------------------------------------------------- 1 | - name: Get ACS details from ACS secret 2 | kubernetes.core.k8s_info: 3 | api_version: v1 4 | kind: Secret 5 | name: roxsecrets 6 | namespace: "{{ pipeline_namespace }}" 7 | register: acs_secret 8 | 9 | - name: Get ACS Server URL from Secret 10 | ansible.builtin.set_fact: 11 | acs_url: "{{ acs_secret.resources.0.data.rox_central_endpoint | b64decode }}" 12 | 13 | - name: Get ACS Token Secret 14 | ansible.builtin.set_fact: 15 | acs_token: "{{ acs_secret.resources.0.data.rox_api_token | b64decode }}" 16 | 17 | - name: Get Cosign Secret Details 18 | kubernetes.core.k8s_info: 19 | api_version: v1 20 | kind: Secret 21 | name: "{{ secret_generate_name }}" 22 | namespace: "{{ pipeline_namespace }}" 23 | register: cosign_secret 24 | 25 | - name: Get Cosign Key from secret 26 | ansible.builtin.set_fact: 27 | cosign_key: "{{ cosign_secret.resources.0.data['cosign.key'] | b64decode | trim }}" 28 | 29 | - name: Get Cosign Password from secret 30 | ansible.builtin.set_fact: 31 | cosign_password: "{{ cosign_secret.resources.0.data['cosign.password'] | b64decode | trim }}" 32 | 33 | - name: Get Cosign Public Key from secret 34 | ansible.builtin.set_fact: 35 | cosign_pub: "{{ cosign_secret.resources.0.data['cosign.pub'] | b64decode | trim | replace('\n', '\\n')}}" 36 | 37 | - name: Get list of ACS Signatures 38 | uri: 39 | url: "https://{{ acs_url}}/v1/signatureintegrations" 40 | headers: 41 | Content-Type: application/json 42 | method: GET 43 | user: admin 44 | password: "{{ stackrox_central_admin_password }}" 45 | body_format: json 46 | force_basic_auth: true 47 | validate_certs: no 48 | register: cosign_signature_list 49 | 50 | - name: Filter List of Integration Names 51 | ansible.builtin.set_fact: 52 | integration_names: "{{ cosign_signature_list.json.integrations | map(attribute='name') }}" 53 | integration_ids: "{{ cosign_signature_list.json.integrations | map(attribute='id') }}" 54 | when: cosign_signature_list.json.integrations | length>0 55 | 56 | - name: Print List of Integrations 57 | ansible.builtin.debug: 58 | msg: "{{ integration_names }}" 59 | when: cosign_signature_list.json.integrations | length>0 60 | 61 | - name: Set signature ID 62 | ansible.builtin.set_fact: 63 | signature_id: "{% if item.0 == 'cosign-demo' %}{{item.1}}{% else %}''{% endif %}" 64 | when: cosign_signature_list.json.integrations | length>0 65 | loop: "{{ integration_names|zip(integration_ids)|list }}" 66 | 67 | - name: Print signature ID 68 | ansible.builtin.debug: 69 | msg: "{{ signature_id }}" 70 | when: cosign_signature_list.json.integrations | length>0 71 | 72 | - name: Add Cosign Signature to ACS 73 | uri: 74 | url: "https://{{ acs_url }}/v1/signatureintegrations" 75 | headers: 76 | Content-Type: application/json 77 | body: '{"id":"","name":"cosign-demo","cosign":{"publicKeys":[{"name":"cosign-demo","publicKeyPemEnc":"{{ cosign_pub }}"}]}}' 78 | method: POST 79 | user: admin 80 | password: "{{ stackrox_central_admin_password }}" 81 | body_format: json 82 | force_basic_auth: true 83 | validate_certs: no 84 | register: cosign_signature_response 85 | when: "'cosign-demo' not in integration_names|default('')" 86 | 87 | - name: Set signature ID 88 | ansible.builtin.set_fact: 89 | signature_id: "{{ cosign_signature_response.json.id }}" 90 | when: cosign_signature_response.json|default("") != "" 91 | 92 | - name: Print signature ID 93 | ansible.builtin.debug: 94 | msg: "{{ signature_id }}" 95 | when: cosign_signature_response.json|default("") != "" 96 | 97 | - name: Try Replace Hidden Characters in Signature ID 98 | ansible.builtin.set_fact: 99 | signature_id: "{{ signature_id | regex_replace('io\\.\\*+\\.([\\w\\.-]*)$','io.stackrox.\\1') }}" 100 | ignore_errors: true 101 | 102 | - name: Print signature ID 103 | ansible.builtin.debug: 104 | msg: "{{ signature_id }}" 105 | 106 | - name: Replace SignatureId in our policy file' 107 | ansible.builtin.replace: 108 | path: "{{ role_path }}/files/policies/signed-image-policy.json" 109 | regexp: 'io\.[\*\w]*\.[\w\.-]*' 110 | replace: "{{ signature_id }}" 111 | 112 | - name: Apply/update policies 113 | uri: 114 | url: "https://{{ acs_url }}/v1/policies/import" 115 | body: "{{ lookup('file', item ) }}" 116 | method: POST 117 | user: admin 118 | password: "{{ stackrox_central_admin_password }}" 119 | body_format: json 120 | force_basic_auth: true 121 | validate_certs: no 122 | with_fileglob: 123 | - "files/policies/*.json" 124 | 125 | - name: Check if Quay Secret Exists 126 | k8s_info: 127 | kind: Secret 128 | name: "{{ quay_secret_name }}" 129 | namespace: "{{ pipeline_namespace }}" 130 | register: secret_check_status 131 | 132 | - name: extract quay hostname 133 | shell: | 134 | oc get route {{ quay_registry_name }}-quay -o jsonpath='{.spec.host}' -n {{ quay_project_name }} 135 | register: quay_hostname_result 136 | delay: 5 137 | retries: 10 138 | until: 139 | - quay_hostname_result.stdout != "" 140 | 141 | - name: Set Quay hostname 142 | ansible.builtin.set_fact: 143 | quay_route: "{{ quay_hostname_result.stdout }}" 144 | 145 | 146 | # - name: Add our Quay Registry as an Insecure Registry 147 | # uri: 148 | # url: "https://{{ acs_url }}/v1/imageintegrations" 149 | # headers: 150 | # Content-Type: application/json 151 | # body: '{"id":"","name":"quay-demo-registry","categories":["REGISTRY","SCANNER"],"quay":{"endpoint":"{{ quay_route}}","oauthToken":"wewewewee","insecure":true},"autogenerated":false,"clusterId":"","clusters":[],"skipTestIntegration":true,"type":"quay"}' 152 | # method: POST 153 | # user: admin 154 | # password: "{{ stackrox_central_admin_password }}" 155 | # body_format: json 156 | # force_basic_auth: true 157 | # validate_certs: no 158 | # register: cosign_signature_response 159 | # when: "'cosign-demo' not in integration_names|default('')" -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/tasks/build-cosign-infra.yaml: -------------------------------------------------------------------------------- 1 | - name: Create OpenShift Objects to build a pod to run Cosign Binary 2 | k8s: 3 | state: present 4 | definition: "{{ lookup('template', item ) | from_yaml }}" 5 | loop: 6 | - ./templates/cosign-ubi-is.yaml.j2 7 | - ./templates/cosign-is.yaml.j2 8 | - ./templates/cosign-build.yaml.j2 9 | 10 | - name: Wait Until cosign build is complete 11 | shell: | 12 | oc get build -l build=cosign-pod -n "{{ pipeline_namespace }}" --sort-by=.metadata.creationTimestamp | tail -n 1 | awk '{print $4}' 13 | register: build_status 14 | retries: 10 15 | delay: 20 16 | until: 17 | - build_status.stdout == "Complete" 18 | 19 | # - name: Make Sure Any Previously Generated Secrets are Absent 20 | # kubernetes.core.k8s: 21 | # state: absent 22 | # api_version: v1 23 | # kind: Secret 24 | # namespace: "{{ pipeline_namespace }}" 25 | # name: "{{ secret_generate_name }}" 26 | # wait: yes 27 | 28 | - name: Generate Random Cosign Password 29 | set_fact: 30 | cosign_password: "{{ lookup('password', '/dev/null chars=ascii_lowercase,digits length=6') }}" 31 | 32 | - name: Create OpenShift Objects for Cosign Usage 33 | k8s: 34 | state: present 35 | definition: "{{ lookup('template', item ) | from_yaml }}" 36 | loop: 37 | # - ./templates/cosign-serviceaccount.yaml.j2 38 | - ./templates/cosign-role.yaml.j2 39 | - ./templates/cosign-rolebinding.yaml.j2 40 | - ./templates/cosign-rolebinding-cicd.yaml.j2 41 | - ./templates/cosign-deployment.yaml.j2 42 | 43 | - name: Wait till Cosign Deployment is Ready 44 | k8s_info: 45 | kind: Deployment 46 | name: cosign-pod 47 | namespace: "{{ pipeline_namespace }}" 48 | register: output_info 49 | until: output_info.resources | json_query('[*].status.conditions[?reason==`NewReplicaSetAvailable`][].status') | select ('match','True') | list | length == 1 50 | delay: 5 51 | retries: 5 52 | 53 | - name: Get Cosign Pod Name 54 | shell: | 55 | oc get pods -n "{{ pipeline_namespace }}" -l app=cosign-pod --sort-by=.metadata.creationTimestamp | tail -n 1| awk '{print $1}' 56 | register: pod_name 57 | 58 | - name: Check if Cosign Signing Secret Already Exists 59 | k8s_info: 60 | kind: Secret 61 | name: "{{ secret_generate_name }}" 62 | namespace: "{{ pipeline_namespace }}" 63 | register: secret_check_status 64 | 65 | - name: Create Cosign Secret 66 | shell: | 67 | oc exec pod/"{{ pod_name.stdout }}" -n "{{ pipeline_namespace }}" -- /bin/bash -c 'cosign generate-key-pair k8s://"{{ pipeline_namespace }}"/"{{ secret_generate_name }}"' 68 | when: 69 | secret_check_status.resources | length<1 70 | 71 | - name: Confirm Cosign Secret is Created 72 | kubernetes.core.k8s: 73 | state: present 74 | api_version: v1 75 | kind: Secret 76 | namespace: "{{ pipeline_namespace }}" 77 | name: "{{ secret_generate_name }}" 78 | wait: yes -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | - import_tasks: build-cosign-infra.yaml 2 | - import_tasks: add-cosign-secret-acs.yaml 3 | - import_tasks: tektonchain.yaml 4 | - import_tasks: patch-pipeline.yaml 5 | 6 | 7 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/tasks/patch-pipeline.yaml: -------------------------------------------------------------------------------- 1 | - name: Check if Quay Secret Exists 2 | k8s_info: 3 | kind: Secret 4 | name: "{{ quay_secret_name }}" 5 | namespace: "{{ pipeline_namespace }}" 6 | register: secret_check_status 7 | 8 | - name: extract quay hostname 9 | shell: | 10 | oc get route {{ quay_registry_name }}-quay -o jsonpath='{.spec.host}' -n {{ quay_project_name }} 11 | register: quay_hostname_result 12 | delay: 5 13 | retries: 10 14 | until: 15 | - quay_hostname_result.stdout != "" 16 | 17 | - name: Set Quay hostname 18 | ansible.builtin.set_fact: 19 | quay_route: "{{ quay_hostname_result.stdout }}" 20 | 21 | - name: Link Quay Secret to Pipeline ServiceAccount for Pipeline Namespace 22 | shell: | 23 | oc secrets link pipeline "{{ quay_secret_name }}" --for=pull,mount -n {{ pipeline_namespace }} 24 | 25 | - name: Link Quay Secret to default accounts for namespaces that should pull from quay 26 | shell: | 27 | oc secrets link default "{{ quay_secret_name }}" --for=pull,mount -n {{ item }} 28 | loop: "{{ secret_required_namespaces }}" 29 | 30 | - name: Create Quay Signing Task 31 | k8s: 32 | state: present 33 | definition: "{{ lookup('template', item ) | from_yaml }}" 34 | loop: 35 | - ./templates/cosign-task.yaml.j2 36 | 37 | # Check Gogs 38 | - name: Get gogs route 39 | kubernetes.core.k8s_info: 40 | kind: Route 41 | api_version: route.openshift.io/v1 42 | namespace: cicd 43 | name: gogs 44 | register: r_gogs_route 45 | retries: 10 46 | delay: 20 47 | until: 48 | - r_gogs_route.resources[0].spec.host is defined 49 | 50 | - name: Debug gogs route 51 | debug: 52 | msg: "{{ r_gogs_route.resources[0].spec.host }}" 53 | 54 | - name: Create OpenShift Objects for Openshift Pipelines Templates 55 | k8s: 56 | state: present 57 | definition: "{{ lookup('template', item ) | from_yaml }}" 58 | loop: 59 | - ./templates/pipeline-build-dev.yaml.j2 60 | - ./templates/pipeline-build-stage.yaml.j2 61 | # - ./templates/pipeline-build-pvc.yaml.j2 62 | 63 | - name: Patch Openshift Image Config - Message 64 | ansible.builtin.debug: 65 | msg: "As we did not generate a cert, we need to add our quay registry as an insecure registry in Openshift" 66 | 67 | - name: Patch Openshift Image Config 68 | ansible.builtin.shell: | 69 | oc patch image.config.openshift.io cluster --type=merge -p '{"spec":{"registrySources":{"insecureRegistries":["{{ quay_route }}"]}}}' 70 | register: insecure_patch 71 | 72 | - name: Pause for 4 minutes to wait for MCP to recieve changes 73 | ansible.builtin.pause: 74 | minutes: 4 75 | when: "'no change' not in insecure_patch.stdout" 76 | 77 | # - name: Waiting Until Openshift Cluster is Ready from Patch 78 | # ansible.builtin.shell: | 79 | # oc get mcp -o json | jq '.items[] | select (.status.machineCount==.status.updatedMachineCount)' 80 | # register: mcp_result 81 | # delay: 10 82 | # retries: 15 83 | # until: 84 | # - mcp_result.stdout != "" 85 | # when: "'no change' not in insecure_patch.stdout" -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/tasks/tektonchain.yaml: -------------------------------------------------------------------------------- 1 | - name: Delete Operator Namespace if it Exists 2 | kubernetes.core.k8s: 3 | state: absent 4 | api_version: project.openshift.io/v1 5 | kind: Project 6 | name: "{{ tekton_operator_namespace }}" 7 | wait: yes 8 | 9 | #Tekton Manifest Based Installation -https://github.com/tektoncd/chains#installation 10 | - name: Install Tekton Chains via Manifest 11 | shell: | 12 | oc apply -f https://storage.googleapis.com/tekton-releases/chains/previous/"{{ tekton_chain_version }}"/release.yaml 13 | when: tekton_install_type == "manifest" 14 | 15 | #Tekton CR Based Installation - https://docs.openshift.com/container-platform/4.10/cicd/pipelines/using-tekton-chains-for-openshift-pipelines-supply-chain-security.html 16 | - name: Install Tekton Chains via Pipeline CR 17 | k8s: 18 | state: present 19 | definition: "{{ lookup('template', item ) | from_yaml }}" 20 | loop: 21 | - ./templates/tektonchain-cr.yaml.j2 22 | when: tekton_install_type != "manifest" 23 | 24 | - name: Apply TektonChain Controller SCC 25 | shell: | 26 | oc project {{ tekton_operator_namespace }} && oc adm policy add-scc-to-user nonroot -z tekton-chains-controller 27 | 28 | # Wait Until TektonChain Controller Pod Is Ready 29 | - name: Get TektonChain Pod 30 | kubernetes.core.k8s_info: 31 | kind: Pod 32 | api_version: v1 33 | namespace: "{{ tekton_operator_namespace }}" 34 | label_selectors: 35 | - app = tekton-chains-controller 36 | wait: yes 37 | retries: 3 38 | delay: 20 39 | 40 | # - name: Check if Cosign Signing Secret Already Exists in Operator Namespace 41 | # k8s_info: 42 | # kind: Secret 43 | # name: "{{ secret_generate_name }}" 44 | # namespace: "{{ tekton_operator_namespace }}" 45 | # register: secret_check_status_operator 46 | 47 | - name: Delete Cosign Secret if exists 48 | kubernetes.core.k8s: 49 | state: absent 50 | api_version: v1 51 | kind: Secret 52 | namespace: "{{ tekton_operator_namespace }}" 53 | name: "{{ secret_generate_name }}" 54 | wait: yes 55 | 56 | - name: Check if Cosign Signing Secret Already Exists in Pipeline Namespace 57 | k8s_info: 58 | kind: Secret 59 | name: "{{ secret_generate_name }}" 60 | namespace: "{{ pipeline_namespace }}" 61 | register: secret_check_status_pipeline 62 | 63 | - name: Print Secret from Pipeline Namespace if it Exists 64 | ansible.builtin.debug: 65 | msg: "{{ secret_check_status_pipeline.resources }}" 66 | 67 | - name: Copy Secret from Pipeline Namespace if it Exists 68 | ansible.builtin.shell: | 69 | oc get secret {{ secret_generate_name }} -n {{ pipeline_namespace }} -o json | jq 'del(.metadata.namespace,.metadata.resourceVersion,.metadata.uid,.metadata.selfLink,.metadata.managedFields,.metadata.annotations."kubectl.kubernetes.io/last-applied-configuration") | .metadata.creationTimestamp=null | .metadata.name="{{ secret_generate_name }}"'| oc apply -n {{ tekton_operator_namespace }} -f - 70 | when: 71 | - secret_check_status_pipeline.resources | default([]) | length>0 72 | 73 | - name: Create Cosign Secret 74 | shell: | 75 | oc exec pod/"{{ pod_name.stdout }}" -n "{{ pipeline_namespace }}" -- /bin/bash -c 'cosign generate-key-pair k8s://"{{ pipeline_namespace }}"/"{{ secret_generate_name }}"' 76 | when: 77 | - secret_check_status_pipeline.resources | default([]) | length<1 78 | 79 | - name: Confirm Cosign Secret is Created 80 | kubernetes.core.k8s: 81 | state: present 82 | api_version: v1 83 | kind: Secret 84 | namespace: "{{ pipeline_namespace }}" 85 | name: "{{ secret_generate_name }}" 86 | wait: yes 87 | 88 | - name: Patch the CM of Openshift Piplines to enable Tekton Chains 89 | command: oc patch configmap chains-config -n {{ tekton_operator_namespace }} -p='{"data":{'\"{{ item.key }}\"':'\"{{ item.value }}\"'}}' 90 | loop: "{{ tekton_chain_keys | dict2items }}" 91 | 92 | - name: Recreate Tekton Chain Controller 93 | shell: | 94 | oc delete po -l app=tekton-chains-controller -n "{{ tekton_operator_namespace }}" -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-anyuid-scc.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: ClusterRoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: cosign-sa-anyuid-scc 5 | subjects: 6 | - kind: ServiceAccount 7 | name: cosign-sa 8 | namespace: {{ tekton_operator_namespace }} 9 | roleRef: 10 | apiGroup: rbac.authorization.k8s.io 11 | kind: ClusterRole 12 | name: 'system:openshift:scc:anyuid' 13 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-build.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: BuildConfig 2 | apiVersion: build.openshift.io/v1 3 | metadata: 4 | name: cosign-pod 5 | namespace: {{ pipeline_namespace }} 6 | labels: 7 | build: cosign-pod 8 | spec: 9 | nodeSelector: null 10 | output: 11 | to: 12 | kind: ImageStreamTag 13 | name: 'cosign-pod:latest' 14 | resources: {} 15 | successfulBuildsHistoryLimit: 5 16 | failedBuildsHistoryLimit: 5 17 | strategy: 18 | type: Docker 19 | dockerStrategy: 20 | from: 21 | kind: ImageStreamTag 22 | name: 'ubi:8.0' 23 | postCommit: {} 24 | source: 25 | type: Dockerfile 26 | dockerfile: >- 27 | FROM registry.redhat.io/ubi8/ubi:8.0 28 | 29 | 30 | RUN yum install go git wget tar rsync -y && wget 31 | https://github.com/sigstore/cosign/releases/download/v1.9.0/cosign-1.9.0.x86_64.rpm 32 | \ 33 | && yum localinstall -y cosign-1.9.0.x86_64.rpm \ 34 | && wget https://mirror.openshift.com/pub/openshift-v4/x86_64/clients/ocp/stable/openshift-client-linux.tar.gz \ 35 | && tar -xvf openshift-client-linux.tar.gz && mv oc /usr/local/bin \ 36 | && rm -rf openshift-client-linux.tar.gz \ 37 | && rm -rf cosign-1.9.0.x86_64.rpm \ 38 | && mkdir /.docker \ 39 | && mkdir -p /tekton/home \ 40 | && mkdir /workdir 41 | 42 | USER 0 43 | 44 | RUN chgrp -R 0 /usr/bin && \ 45 | chmod -R g=u /usr/bin && \ 46 | chgrp -R 0 /.docker && \ 47 | chmod -R g=u /.docker && \ 48 | chgrp -R 0 /tekton/home && \ 49 | chmod -R g=u /tekton/home && \ 50 | chgrp -R 0 /workdir && \ 51 | chmod -R g=u /workdir 52 | 53 | WORKDIR /workdir 54 | 55 | USER 1001 56 | 57 | ENTRYPOINT cosign 58 | triggers: 59 | - type: ConfigChange 60 | - type: ImageChange 61 | imageChange: {} 62 | runPolicy: Serial 63 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-deployment.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: cosign-pod 5 | namespace: {{ pipeline_namespace }} 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: cosign-pod 10 | replicas: 1 11 | template: 12 | metadata: 13 | labels: 14 | app: cosign-pod 15 | spec: 16 | containers: 17 | - name: cosign-pod 18 | image: {{cosign_image}} 19 | env: 20 | - name: COSIGN_PASSWORD 21 | value: {{ cosign_password }} 22 | command: 23 | - '/bin/bash' 24 | args: 25 | - -c 26 | - sleep infinity 27 | serviceAccountName: pipeline 28 | serviceAccount: pipeline 29 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-is.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: ImageStream 2 | apiVersion: image.openshift.io/v1 3 | metadata: 4 | name: cosign-pod 5 | namespace: {{ pipeline_namespace }} 6 | labels: 7 | build: cosign-pod 8 | spec: 9 | lookupPolicy: 10 | local: false 11 | status: 12 | dockerImageRepository: >- 13 | image-registry.openshift-image-registry.svc:5000/{{ pipeline_namespace }}/cosign-pod 14 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-role.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: Role 3 | metadata: 4 | name: cosign-role 5 | namespace: {{ pipeline_namespace }} 6 | rules: 7 | - verbs: 8 | - '*' 9 | apiGroups: 10 | - '' 11 | resources: 12 | - secrets -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-rolebinding-cicd.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: RoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: cosign-sa-edit 5 | namespace: {{ pipeline_namespace }} 6 | subjects: 7 | - kind: ServiceAccount 8 | name: pipeline 9 | namespace: {{ pipeline_namespace }} 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: ClusterRole 13 | name: edit 14 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-rolebinding.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: RoleBinding 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | name: cosign-rolebinding 5 | namespace: {{ pipeline_namespace }} 6 | subjects: 7 | - kind: ServiceAccount 8 | name: cosign-sa 9 | namespace: {{ pipeline_namespace }} 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: Role 13 | name: cosign-role 14 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-serviceaccount.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: cosign-sa 5 | namespace: {{ tekton_operator_namespace }} 6 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-task.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: cosign-task 5 | namespace: {{ pipeline_namespace }} 6 | labels: 7 | app.kubernetes.io/version: "0.6" 8 | annotations: 9 | tekton.dev/pipelines.minVersion: "0.17.0" 10 | tekton.dev/categories: security 11 | tekton.dev/tags: security 12 | tekton.dev/displayName: "Sign and Verify Images" 13 | tekton.dev/platforms: "linux/amd64" 14 | spec: 15 | description: >- 16 | This Task can be used to sign an image in a registry 17 | params: 18 | - name: IMAGE 19 | description: Name (reference) of the cosign image 20 | - name: SIGNATURE_IMAGE 21 | description: Image to be signed 22 | - name: ARGS 23 | type: array 24 | description: args to pass to cosign command to 25 | default: [] 26 | steps: 27 | - name: cosign-actions 28 | image: $(params.IMAGE) 29 | script: | 30 | #!/usr/bin/env bash 31 | cmd="cosign $* $(params.SIGNATURE_IMAGE)" 32 | echo "Starting Image Signing Task" 33 | echo "This is the command we will run $cmd" 34 | $cmd 35 | args: 36 | - "$(params.ARGS)" 37 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/cosign-ubi-is.yaml.j2: -------------------------------------------------------------------------------- 1 | kind: ImageStream 2 | apiVersion: image.openshift.io/v1 3 | metadata: 4 | name: ubi 5 | namespace: {{ pipeline_namespace }} 6 | labels: 7 | build: cosign-pod 8 | spec: 9 | lookupPolicy: 10 | local: false 11 | tags: 12 | - name: '8.0' 13 | annotations: 14 | openshift.io/imported-from: 'registry.redhat.io/ubi8/ubi:8.0' 15 | from: 16 | kind: DockerImage 17 | name: 'registry.redhat.io/ubi8/ubi:8.0' 18 | generation: 2 19 | importPolicy: {} 20 | referencePolicy: 21 | type: Source -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/pipeline-build-dev.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Pipeline 3 | metadata: 4 | name: petclinic-build-dev 5 | namespace: cicd 6 | spec: 7 | params: 8 | - name: APP_SOURCE_GIT 9 | type: string 10 | description: The application git repository 11 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic 12 | - name: APP_SOURCE_REVISION 13 | type: string 14 | description: The application git revision 15 | default: master 16 | - name: APP_MANIFESTS_GIT 17 | type: string 18 | description: The application manifests git repository 19 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic-config 20 | - name: APP_IMAGE_TAG 21 | type: string 22 | default: latest 23 | description: The application image tag to build 24 | - name: DEV_NAMESPACE 25 | type: string 26 | default: devsecops-dev 27 | description: The namespace for Stage environments 28 | - name: APP_TESTS_GIT 29 | type: string 30 | description: The application test cases git repository 31 | default: https://github.com/rcarrata/spring-petclinic-gatling 32 | workspaces: 33 | - name: workspace 34 | - name: maven-settings 35 | tasks: 36 | - name: source-clone 37 | taskRef: 38 | name: git-clone 39 | kind: ClusterTask 40 | workspaces: 41 | - name: output 42 | workspace: workspace 43 | params: 44 | - name: url 45 | value: $(params.APP_SOURCE_GIT) 46 | - name: revision 47 | value: $(params.APP_SOURCE_REVISION) 48 | - name: depth 49 | value: "0" 50 | - name: subdirectory 51 | value: spring-petclinic 52 | - name: deleteExisting 53 | value: "true" 54 | - name: unit-tests 55 | taskRef: 56 | name: maven 57 | runAfter: 58 | - source-clone 59 | workspaces: 60 | - name: source 61 | workspace: workspace 62 | - name: maven-settings 63 | workspace: maven-settings 64 | params: 65 | - name: GOALS 66 | value: ["package", "-f", "spring-petclinic"] 67 | - name: code-analysis 68 | taskRef: 69 | name: maven 70 | runAfter: 71 | - source-clone 72 | workspaces: 73 | - name: source 74 | workspace: workspace 75 | - name: maven-settings 76 | workspace: maven-settings 77 | params: 78 | - name: GOALS 79 | value: 80 | - install 81 | - sonar:sonar 82 | - -f 83 | - spring-petclinic 84 | - -Dsonar.host.url=http://sonarqube:9000 85 | - -Dsonar.userHome=/tmp/sonar 86 | - -DskipTests=true 87 | - name: dependency-report 88 | taskRef: 89 | name: dependency-report 90 | runAfter: 91 | - source-clone 92 | workspaces: 93 | - name: source 94 | workspace: workspace 95 | - name: maven-settings 96 | workspace: maven-settings 97 | params: 98 | - name: SOURCE_DIR 99 | value: spring-petclinic 100 | - name: release-app 101 | taskRef: 102 | name: maven 103 | runAfter: 104 | - code-analysis 105 | - unit-tests 106 | - dependency-report 107 | workspaces: 108 | - name: source 109 | workspace: workspace 110 | - name: maven-settings 111 | workspace: maven-settings 112 | params: 113 | - name: GOALS 114 | value: 115 | - deploy 116 | - -f 117 | - spring-petclinic 118 | - -DskipTests=true 119 | - -DaltDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-releases/ 120 | - -DaltSnapshotDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-snapshots/ 121 | - name: build-image 122 | taskRef: 123 | name: s2i-java-11 124 | runAfter: 125 | - release-app 126 | params: 127 | - name: TLSVERIFY 128 | value: "false" 129 | - name: MAVEN_MIRROR_URL 130 | value: http://nexus:8081/repository/maven-public/ 131 | - name: PATH_CONTEXT 132 | value: spring-petclinic/target 133 | - name: IMAGE_NAME 134 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-dev 135 | - name: IMAGE_TAG 136 | value: $(params.APP_IMAGE_TAG) 137 | workspaces: 138 | - name: source 139 | workspace: workspace 140 | - name: image-sign 141 | taskRef: 142 | name: cosign-task 143 | runAfter: 144 | - build-image 145 | params: 146 | - name: IMAGE 147 | value: "image-registry.openshift-image-registry.svc:5000/{{pipeline_namespace}}/cosign-pod" 148 | - name: SIGNATURE_IMAGE 149 | value: "{{ quay_route}}/{{ quay_org_name }}/spring-petclinic-dev" 150 | - name: ARGS 151 | value: 152 | - "sign" 153 | - "--allow-insecure-registry" 154 | - "--key k8s://{{ pipeline_namespace }}/{{ secret_generate_name }}" 155 | - name: image-scan 156 | runAfter: 157 | - build-image 158 | taskRef: 159 | name: rox-image-scan 160 | kind: ClusterTask 161 | params: 162 | - name: image 163 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-dev 164 | - name: rox_api_token 165 | value: roxsecrets 166 | - name: rox_central_endpoint 167 | value: roxsecrets 168 | - name: output_format 169 | value: table 170 | - name: image_digest 171 | value: $(tasks.build-image.results.IMAGE_DIGEST) 172 | - name: image-check 173 | runAfter: 174 | - build-image 175 | taskRef: 176 | name: rox-image-check 177 | kind: ClusterTask 178 | params: 179 | - name: image 180 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-dev 181 | - name: rox_api_token 182 | value: roxsecrets 183 | - name: rox_central_endpoint 184 | value: roxsecrets 185 | - name: image_digest 186 | value: $(tasks.build-image.results.IMAGE_DIGEST) 187 | - name: deploy-check 188 | runAfter: 189 | - build-image 190 | taskRef: 191 | name: rox-deployment-check 192 | kind: ClusterTask 193 | params: 194 | - name: GIT_REPOSITORY 195 | value: "$(params.APP_MANIFESTS_GIT)" 196 | - name: rox_api_token 197 | value: roxsecrets 198 | - name: rox_central_endpoint 199 | value: roxsecrets 200 | - name: file 201 | value: deployment.yaml 202 | - name: deployment_files_path 203 | value: app 204 | workspaces: 205 | - name: workspace 206 | workspace: workspace 207 | - name: update-deployment 208 | runAfter: 209 | - image-sign 210 | - image-scan 211 | - image-check 212 | - deploy-check 213 | taskRef: 214 | name: git-update-deployment 215 | params: 216 | - name: GIT_REPOSITORY 217 | value: "$(params.APP_MANIFESTS_GIT)" 218 | - name: GIT_USERNAME 219 | value: gogs 220 | - name: GIT_PASSWORD 221 | value: gogs 222 | - name: CURRENT_IMAGE 223 | value: quay.io/siamaksade/spring-petclinic:latest 224 | - name: NEW_IMAGE 225 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-dev 226 | - name: NEW_DIGEST 227 | value: "$(tasks.build-image.results.IMAGE_DIGEST)" 228 | - name: KUSTOMIZATION_PATH 229 | value: environments/dev 230 | workspaces: 231 | - name: workspace 232 | workspace: workspace 233 | - name: wait-application 234 | taskRef: 235 | name: argocd-task-sync-and-wait 236 | runAfter: 237 | - update-deployment 238 | params: 239 | - name: application-name 240 | value: dev-spring-petclinic 241 | - name: perf-tests-clone 242 | taskRef: 243 | name: git-clone 244 | kind: ClusterTask 245 | workspaces: 246 | - name: output 247 | workspace: workspace 248 | runAfter: 249 | - wait-application 250 | params: 251 | - name: url 252 | value: $(params.APP_TESTS_GIT) 253 | - name: subdirectory 254 | value: spring-petclinic-gatling 255 | - name: deleteExisting 256 | value: "true" 257 | - name: pentesting-test 258 | taskRef: 259 | name: zap-proxy 260 | runAfter: 261 | - perf-tests-clone 262 | params: 263 | - name: APP_URL 264 | value: "http://spring-petclinic.$(params.DEV_NAMESPACE).svc.cluster.local:8080" 265 | workspaces: 266 | - name: workspace 267 | workspace: workspace 268 | - name: performance-test 269 | taskRef: 270 | name: gatling 271 | runAfter: 272 | - perf-tests-clone 273 | params: 274 | - name: APP_URL 275 | value: "http://spring-petclinic.$(params.DEV_NAMESPACE).svc.cluster.local:8080" 276 | workspaces: 277 | - name: simulations 278 | workspace: workspace 279 | subPath: spring-petclinic-gatling 280 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/pipeline-build-stage.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Pipeline 3 | metadata: 4 | name: petclinic-build-stage 5 | namespace: cicd 6 | spec: 7 | params: 8 | - name: APP_SOURCE_GIT 9 | type: string 10 | description: The application git repository 11 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic 12 | - name: APP_SOURCE_REVISION 13 | type: string 14 | description: The application git revision 15 | default: master 16 | - name: APP_MANIFESTS_GIT 17 | type: string 18 | description: The application manifests git repository 19 | default: http://{{ r_gogs_route.resources[0].spec.host }}/gogs/spring-petclinic-config 20 | - name: APP_IMAGE_TAG 21 | type: string 22 | default: latest 23 | description: The application image tag to build 24 | - name: STAGE_NAMESPACE 25 | type: string 26 | default: devsecops-qa 27 | description: The namespace for Stage environments 28 | - name: APP_TESTS_GIT 29 | type: string 30 | description: The application test cases git repository 31 | default: https://github.com/rcarrata/spring-petclinic-gatling 32 | workspaces: 33 | - name: workspace 34 | - name: maven-settings 35 | tasks: 36 | - name: source-clone 37 | taskRef: 38 | name: git-clone 39 | kind: ClusterTask 40 | workspaces: 41 | - name: output 42 | workspace: workspace 43 | params: 44 | - name: url 45 | value: $(params.APP_SOURCE_GIT) 46 | - name: revision 47 | value: $(params.APP_SOURCE_REVISION) 48 | - name: depth 49 | value: "0" 50 | - name: subdirectory 51 | value: spring-petclinic 52 | - name: deleteExisting 53 | value: "true" 54 | - name: unit-tests 55 | taskRef: 56 | name: maven 57 | runAfter: 58 | - source-clone 59 | workspaces: 60 | - name: source 61 | workspace: workspace 62 | - name: maven-settings 63 | workspace: maven-settings 64 | params: 65 | - name: GOALS 66 | value: ["package", "-f", "spring-petclinic"] 67 | - name: code-analysis 68 | taskRef: 69 | name: maven 70 | runAfter: 71 | - source-clone 72 | workspaces: 73 | - name: source 74 | workspace: workspace 75 | - name: maven-settings 76 | workspace: maven-settings 77 | params: 78 | - name: GOALS 79 | value: 80 | - install 81 | - sonar:sonar 82 | - -f 83 | - spring-petclinic 84 | - -Dsonar.host.url=http://sonarqube:9000 85 | - -Dsonar.userHome=/tmp/sonar 86 | - -DskipTests=true 87 | - name: dependency-report 88 | taskRef: 89 | name: dependency-report 90 | runAfter: 91 | - source-clone 92 | workspaces: 93 | - name: source 94 | workspace: workspace 95 | - name: maven-settings 96 | workspace: maven-settings 97 | params: 98 | - name: SOURCE_DIR 99 | value: spring-petclinic 100 | - name: release-app 101 | taskRef: 102 | name: maven 103 | runAfter: 104 | - code-analysis 105 | - unit-tests 106 | - dependency-report 107 | workspaces: 108 | - name: source 109 | workspace: workspace 110 | - name: maven-settings 111 | workspace: maven-settings 112 | params: 113 | - name: GOALS 114 | value: 115 | - deploy 116 | - -f 117 | - spring-petclinic 118 | - -DskipTests=true 119 | - -DaltDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-releases/ 120 | - -DaltSnapshotDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-snapshots/ 121 | - name: build-image 122 | taskRef: 123 | name: s2i-java-11 124 | runAfter: 125 | - release-app 126 | params: 127 | - name: TLSVERIFY 128 | value: "false" 129 | - name: MAVEN_MIRROR_URL 130 | value: http://nexus:8081/repository/maven-public/ 131 | - name: PATH_CONTEXT 132 | value: spring-petclinic/target 133 | - name: IMAGE_NAME 134 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-stage 135 | - name: IMAGE_TAG 136 | value: $(params.APP_IMAGE_TAG) 137 | workspaces: 138 | - name: source 139 | workspace: workspace 140 | - name: image-sign 141 | taskRef: 142 | name: cosign-task 143 | runAfter: 144 | - build-image 145 | params: 146 | - name: IMAGE 147 | value: "image-registry.openshift-image-registry.svc:5000/{{pipeline_namespace}}/cosign-pod" 148 | - name: SIGNATURE_IMAGE 149 | value: "{{ quay_route}}/{{ quay_org_name }}/spring-petclinic-stage" 150 | - name: ARGS 151 | value: 152 | - "sign" 153 | - "--allow-insecure-registry" 154 | - "--key k8s://{{ pipeline_namespace }}/{{ secret_generate_name }}" 155 | - name: image-scan 156 | runAfter: 157 | - build-image 158 | taskRef: 159 | name: rox-image-scan 160 | kind: ClusterTask 161 | params: 162 | - name: image 163 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-stage 164 | - name: rox_api_token 165 | value: roxsecrets 166 | - name: rox_central_endpoint 167 | value: roxsecrets 168 | - name: output_format 169 | value: table 170 | - name: image_digest 171 | value: $(tasks.build-image.results.IMAGE_DIGEST) 172 | - name: image-check 173 | runAfter: 174 | - build-image 175 | taskRef: 176 | name: rox-image-check 177 | kind: ClusterTask 178 | params: 179 | - name: image 180 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-stage 181 | - name: rox_api_token 182 | value: roxsecrets 183 | - name: rox_central_endpoint 184 | value: roxsecrets 185 | - name: image_digest 186 | value: $(tasks.build-image.results.IMAGE_DIGEST) 187 | - name: deploy-check 188 | runAfter: 189 | - build-image 190 | taskRef: 191 | name: rox-deployment-check 192 | kind: ClusterTask 193 | params: 194 | - name: GIT_REPOSITORY 195 | value: "$(params.APP_MANIFESTS_GIT)" 196 | - name: rox_api_token 197 | value: roxsecrets 198 | - name: rox_central_endpoint 199 | value: roxsecrets 200 | - name: file 201 | value: deployment.yaml 202 | - name: deployment_files_path 203 | value: app 204 | workspaces: 205 | - name: workspace 206 | workspace: workspace 207 | - name: update-deployment 208 | runAfter: 209 | - image-sign 210 | - image-scan 211 | - image-check 212 | - deploy-check 213 | taskRef: 214 | name: git-update-deployment 215 | params: 216 | - name: GIT_REPOSITORY 217 | value: "$(params.APP_MANIFESTS_GIT)" 218 | - name: GIT_USERNAME 219 | value: gogs 220 | - name: GIT_PASSWORD 221 | value: gogs 222 | - name: CURRENT_IMAGE 223 | value: quay.io/siamaksade/spring-petclinic:latest 224 | - name: NEW_IMAGE 225 | value: {{ quay_route}}/{{ quay_org_name }}/spring-petclinic-stage 226 | - name: NEW_DIGEST 227 | value: "$(tasks.build-image.results.IMAGE_DIGEST)" 228 | - name: KUSTOMIZATION_PATH 229 | value: environments/stage 230 | workspaces: 231 | - name: workspace 232 | workspace: workspace 233 | - name: wait-application 234 | taskRef: 235 | name: argocd-task-sync-and-wait 236 | runAfter: 237 | - update-deployment 238 | params: 239 | - name: application-name 240 | value: stage-spring-petclinic 241 | - name: perf-tests-clone 242 | taskRef: 243 | name: git-clone 244 | kind: ClusterTask 245 | workspaces: 246 | - name: output 247 | workspace: workspace 248 | runAfter: 249 | - wait-application 250 | params: 251 | - name: url 252 | value: $(params.APP_TESTS_GIT) 253 | - name: subdirectory 254 | value: spring-petclinic-gatling 255 | - name: deleteExisting 256 | value: "true" 257 | - name: pentesting-test 258 | taskRef: 259 | name: zap-proxy 260 | runAfter: 261 | - perf-tests-clone 262 | params: 263 | - name: APP_URL 264 | value: "http://spring-petclinic.$(params.STAGE_NAMESPACE).svc.cluster.local:8080" 265 | workspaces: 266 | - name: workspace 267 | workspace: workspace 268 | - name: performance-test 269 | taskRef: 270 | name: gatling 271 | runAfter: 272 | - perf-tests-clone 273 | params: 274 | - name: APP_URL 275 | value: "http://spring-petclinic.$(params.STAGE_NAMESPACE).svc.cluster.local:8080" 276 | workspaces: 277 | - name: simulations 278 | workspace: workspace 279 | subPath: spring-petclinic-gatling 280 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-install-signing/templates/tektonchain-cr.yaml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: operator.tekton.dev/v1alpha1 2 | kind: TektonChain 3 | metadata: 4 | name: chain 5 | spec: 6 | targetNamespace: {{ tekton_operator_namespace }} -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/files/policies/cvss_7.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "f09f8da1-6111-4ca0-8f49-294a76c65115", 3 | "name": "Fixable CVSS >= 7", 4 | "description": "Alert on deployments with fixable vulnerabilities with a CVSS of at least 7", 5 | "severity": "HIGH_SEVERITY", 6 | "lifecycle_stages": [ 7 | "BUILD", 8 | "DEPLOY" 9 | ], 10 | "categories": [ 11 | "Vulnerability Management" 12 | ], 13 | "enforcementActions": [ 14 | ], 15 | "fields": { 16 | "cvss": { 17 | "op": "GREATER_THAN_OR_EQUALS", 18 | "value": 7 19 | }, 20 | "fixedBy": ".*" 21 | }, 22 | "rationale": "Known vulnerabilities make it easier for adversaries to exploit your application. You can fix these high-severity vulnerabilities by updating to a newer version of the affected component(s).", 23 | "remediation": "Use your package manager to update to a fixed version in future builds or speak with your security team to mitigate the vulnerabilities." 24 | } -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/files/policies/process_uid_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "7760a5f3-bca4-4ca8-94a7-ad89edbc0e2c", 3 | "name": "Process with UID 0", 4 | "description": "Alert on deployments that contain processes running with UID 0", 5 | "rationale": "Processes that are running with UID 0 run as the root user. This can allow for unintended privilege escalation if a container mounts host directories that are owned by the host's root user", 6 | "remediation": "Specify the USER instruction in the Docker image or the runAsUser field within the Pod Security Context", 7 | "categories": [ 8 | "DevOps Best Practices", 9 | "Security Best Practices" 10 | ], 11 | "fields": { 12 | "processPolicy": { 13 | "uid": "0" 14 | } 15 | }, 16 | "lifecycleStages": [ 17 | "RUNTIME" 18 | ], 19 | "disabled": false, 20 | "whitelists": [ 21 | { 22 | "name": "Don't alert on Kube System Namespace", 23 | "deployment": { 24 | "scope": { 25 | "namespace": "kube-system" 26 | } 27 | } 28 | }, 29 | { 30 | "name": "Don't alert on StackRox Namespace", 31 | "deployment": { 32 | "scope": { 33 | "namespace": "stackrox" 34 | } 35 | } 36 | }, 37 | { 38 | "name": "Don't alert on istio-system namespace", 39 | "deployment": { 40 | "scope": { 41 | "namespace": "istio-system" 42 | } 43 | } 44 | } 45 | ], 46 | "scope": [], 47 | "severity": "HIGH_SEVERITY", 48 | "notifiers": [] 49 | } 50 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/files/policies/read_write_root_fs.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "8ac93556-4ad4-4220-a275-3f518db0ceb9", 3 | "name": "Container using read-write root filesystem", 4 | "description": "Alert on deployments with containers with read-write root filesystem", 5 | "severity": "MEDIUM_SEVERITY", 6 | "lifecycle_stages": [ 7 | "DEPLOY" 8 | ], 9 | "categories": [ 10 | "Privileges" 11 | ], 12 | "fields": { 13 | "readOnlyRootFs": false 14 | }, 15 | "disabled": false, 16 | "rationale": "Containers running with read-write root filesystem represent greater post-exploitation risk by allowing an attacker to modify important files in the container.", 17 | "remediation": "Use a read-only root filesystem, and use volume mounts to allow writes to specific sub-directories depending on your application's needs.", 18 | "whitelists": [ 19 | { 20 | "name": "Don't alert on kube-system namespace", 21 | "deployment": { 22 | "scope": { 23 | "namespace": "kube-system" 24 | } 25 | } 26 | }, 27 | { 28 | "name": "Don't alert on openshift-node namespace", 29 | "deployment": { 30 | "scope": { 31 | "namespace": "openshift-node" 32 | } 33 | } 34 | }, 35 | { 36 | "name": "Don't alert on openshift-sdn namespace", 37 | "deployment": { 38 | "scope": { 39 | "namespace": "openshift-sdn" 40 | } 41 | } 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/tasks/main.yaml: -------------------------------------------------------------------------------- 1 | 2 | - import_tasks: post_ci.yaml 3 | #- import_tasks: policies.yaml 4 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/tasks/policies.yaml: -------------------------------------------------------------------------------- 1 | - name: Apply/update policies 2 | uri: 3 | url: "https://{{ f_stackrox_central_addr }}/v1/policies/import" 4 | body: "{{ lookup('file', item ) }}" 5 | method: POST 6 | user: admin 7 | password: "{{ stackrox_central_admin_password }}" 8 | body_format: json 9 | force_basic_auth: true 10 | validate_certs: no 11 | with_fileglob: 12 | - "files/policies/*.json" 13 | 14 | - name: Get policies 15 | uri: 16 | url: "https://{{ f_stackrox_central_addr }}/v1/policies" 17 | method: GET 18 | user: admin 19 | password: "{{ stackrox_central_admin_password }}" 20 | force_basic_auth: true 21 | validate_certs: no 22 | register: r_policies 23 | 24 | - name: Get policy details 25 | uri: 26 | url: "https://{{ f_stackrox_central_addr }}/v1/policies/{{ r_policies.json.policies | json_query(jmesquery) | first }}" 27 | method: GET 28 | user: admin 29 | password: "{{ stackrox_central_admin_password }}" 30 | force_basic_auth: true 31 | validate_certs: no 32 | vars: 33 | jmesquery: "[? name==`{{ item.name }}`].id" 34 | register: r_policy_details 35 | when: r_policies.json.policies | json_query(jmesquery) | first is defined 36 | loop: "{{ ocp4_workload_stackrox_demo_apps_openshift_policy_fixes }}" 37 | 38 | - name: Update policies 39 | uri: 40 | url: "https://{{ f_stackrox_central_addr }}/v1/policies/{{ item.json.id }}" 41 | body: "{{ lookup('template', 'templates/policy.json.j2') }}" 42 | method: PUT 43 | user: admin 44 | password: "{{ stackrox_central_admin_password }}" 45 | body_format: json 46 | force_basic_auth: true 47 | validate_certs: no 48 | # temporarily accept 400s due to ROX-6699 49 | status_code: 200, 400 50 | loop: "{{ r_policy_details.results }}" 51 | when: item.json is defined 52 | loop_control: 53 | label: "{{ item.item.name }}" 54 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/tasks/post_ci.yaml: -------------------------------------------------------------------------------- 1 | - name: Get ACS central route 2 | kubernetes.core.k8s_info: 3 | kind: Route 4 | api_version: route.openshift.io/v1 5 | namespace: stackrox 6 | name: central 7 | register: r_stackrox_central_route 8 | retries: 10 9 | delay: 20 10 | 11 | - name: Store central route as a fact 12 | set_fact: 13 | f_stackrox_central_addr: "{{ r_stackrox_central_route.resources[0].spec.host }}" 14 | 15 | - name: Create ACS Console Link 16 | kubernetes.core.k8s: 17 | state: present 18 | definition: "{{ lookup('template', 'acs-console-link.yml.j2') }}" 19 | 20 | - name: Create API token for access from Pipeline to ACS 21 | uri: 22 | url: "https://{{ f_stackrox_central_addr }}/v1/apitokens/generate" 23 | body: '{"name":"pipelines-ci-token","role":null,"roles":["Continuous Integration"]}' 24 | method: POST 25 | user: admin 26 | password: "{{ stackrox_central_admin_password }}" 27 | body_format: json 28 | force_basic_auth: true 29 | validate_certs: no 30 | register: r_ci_token_json 31 | 32 | - name: Get API token from response 33 | set_fact: 34 | f_rox_api_token: "{{ r_ci_token_json.json.token }}" 35 | 36 | - name: Create ACS API Token secret for using in the pipelines 37 | kubernetes.core.k8s: 38 | state: present 39 | definition: 40 | apiVersion: v1 41 | stringData: 42 | rox_central_endpoint: "{{ f_stackrox_central_addr }}:443" 43 | rox_api_token: "{{ f_rox_api_token }}" 44 | kind: Secret 45 | metadata: 46 | name: roxsecrets 47 | namespace: "{{ ocp4_demo_pipeline_namespace }}" 48 | type: Opaque 49 | 50 | - name: Get secrets in namespace 51 | kubernetes.core.k8s_info: 52 | api_version: v1 53 | kind: Secret 54 | namespace: cicd 55 | register: secrets_info 56 | 57 | #- name: Debug secrets_info variable 58 | # debug: 59 | # var: secrets_info 60 | 61 | - name: Extract secret name using regex 62 | set_fact: 63 | secret_name: "{{ secrets_info.resources | map(attribute='metadata.name') | select('match', regex) | list | first }}" 64 | vars: 65 | regex: ".*pipeline-token.*" 66 | 67 | - name: Display secret name 68 | debug: 69 | var: secret_name 70 | 71 | - name: Get token in the secret for the sa pipeline and decode 72 | kubernetes.core.k8s_info: 73 | kind: Secret 74 | api_version: /v1 75 | name: "{{ secret_name }}" 76 | namespace: cicd 77 | register: r_token_sa_secret 78 | 79 | - debug: 80 | msg: "{{ r_token_sa_secret.resources[0].data.token | b64decode }}" 81 | 82 | - name: define the token secret decoded 83 | set_fact: 84 | pipeline_token: "{{ r_token_sa_secret.resources[0].data.token | b64decode }}" 85 | 86 | - name: Creating ACS Integration with the Openshift Internal Registry 87 | uri: 88 | url: "https://{{ f_stackrox_central_addr }}/v1/imageintegrations" 89 | body: "{{ lookup('template', 'templates/ocp_registry_acs.yml.j2') }}" 90 | method: POST 91 | user: admin 92 | password: "{{ stackrox_central_admin_password }}" 93 | body_format: json 94 | force_basic_auth: true 95 | validate_certs: no 96 | # temporarily accept 400s due to ROX-6699 97 | status_code: 200, 400 98 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/templates/acs-console-link.yml.j2: -------------------------------------------------------------------------------- 1 | apiVersion: console.openshift.io/v1 2 | kind: ConsoleLink 3 | metadata: 4 | name: acs-console-link 5 | spec: 6 | applicationMenu: 7 | imageURL: 'https://upload.wikimedia.org/wikipedia/commons/3/3a/OpenShift-LogoType.svg' 8 | section: Red Hat Applications 9 | href: 'https://{{ f_stackrox_central_addr }}' 10 | location: ApplicationMenu 11 | text: Red Hat Advanced Cluster Security for Kubernetes 12 | -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/templates/ocp_registry_acs.yml.j2: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OCP Registry", 3 | "type": "docker", 4 | "clusters": [], 5 | "categories": ["REGISTRY"], 6 | "docker": { 7 | "endpoint": "image-registry.openshift-image-registry.svc:5000", 8 | "username": "pipeline", 9 | "password": "{{ pipeline_token }}", 10 | "insecure": true 11 | }, 12 | "autogenerated": false, 13 | "clusterId": "", 14 | "skipTestIntegration": false 15 | } -------------------------------------------------------------------------------- /bootstrap/roles/ocp4-post-acs/templates/policy.json.j2: -------------------------------------------------------------------------------- 1 | { 2 | "id": {{ item.json.id | tojson }}, 3 | "name": "{{ item.json.name }}", 4 | "description": {{ item.json.description | tojson }}, 5 | "rationale": {{ item.json.rationale | tojson }}, 6 | "remediation": {{ item.json.remediation | tojson }}, 7 | "disabled": {{ item.json.disabled | lower }}, 8 | "categories": {{ item.json.categories | tojson }}, 9 | "fields": {{ item.json.fields | tojson }}, 10 | "lifecycleStages": {{ item.json.lifecycleStages | tojson }}, 11 | "whitelists": {{ item.json.whitelists | tojson }}, 12 | "exclusions": [ 13 | {% for exclusion in item.json.exclusions %}{{ exclusion | tojson }},{% endfor %} 14 | {% for namespace in item.item.namespaces %} 15 | { 16 | "deployment": { 17 | "name": "", 18 | "scope": { 19 | "cluster": "", 20 | "label": null, 21 | "namespace": "{{ namespace }}" 22 | } 23 | }, 24 | "expiration": null, 25 | "image": null, 26 | "name": "Don't alert on {{ namespace }}" 27 | }{% if not loop.last %} 28 | , 29 | {% endif %} 30 | {% endfor %} 31 | ], 32 | "scope": {{ item.json.scope | tojson }}, 33 | "severity": "{{ item.json.severity }}", 34 | "enforcementActions": {{ item.json.enforcementActions | tojson }}, 35 | "notifiers": {{ item.json.notifiers | tojson }}, 36 | "lastUpdated": null, 37 | "SORTName": "{{ item.json.SORTName }}", 38 | "SORTLifecycleStage": "{{ item.json.SORTLifecycleStage }}", 39 | "SORTEnforcement": {{ item.json.SORTEnforcement | lower}}, 40 | "policyVersion": "{{ item.json.policyVersion }}", 41 | "policySections": {{ item.json.policySections | tojson }} 42 | } -------------------------------------------------------------------------------- /demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e -u -o pipefail 4 | declare -r SCRIPT_DIR=$(cd -P $(dirname $0) && pwd) 5 | declare PRJ_PREFIX="demo" 6 | declare COMMAND="help" 7 | 8 | valid_command() { 9 | local fn=$1; shift 10 | [[ $(type -t "$fn") == "function" ]] 11 | } 12 | 13 | info() { 14 | printf "\n# INFO: $@\n" 15 | } 16 | 17 | err() { 18 | printf "\n# ERROR: $1\n" 19 | exit 1 20 | } 21 | 22 | 23 | while (( "$#" )); do 24 | case "$1" in 25 | start|promote|status|sign-verify) 26 | COMMAND=$1 27 | shift 28 | ;; 29 | --) 30 | shift 31 | break 32 | ;; 33 | -*|--*) 34 | err "Error: Unsupported flag $1" 35 | ;; 36 | *) 37 | break 38 | esac 39 | done 40 | 41 | command.help() { 42 | cat <<-EOF 43 | Usage: 44 | demo [command] [options] 45 | 46 | Example: 47 | demo start 48 | 49 | COMMANDS: 50 | start Starts the deploy DEV pipeline 51 | promote Starts the deploy STAGE pipeline 52 | status Check the resources available for the demo 53 | sign-verify If Tekton Chaining was enabled run Signature Verification On Tasks 54 | help Help about this command 55 | EOF 56 | } 57 | 58 | command.status() { 59 | 60 | info "## GOGS Server - Username/Password: gogs/gogs ##" 61 | GOGS=$(oc get route -n cicd gogs -o jsonpath='{.spec.host}') 62 | printf "http://$GOGS" 63 | echo "" 64 | 65 | info "## Nexus Server - Username/Password: admin/admin123 ##" 66 | NEXUS=$(oc get route -n cicd nexus -o jsonpath='{.spec.host}') 67 | printf "https://$NEXUS" 68 | echo "" 69 | 70 | info "## Sonarqube Server - Username/Password: admin/admin ##" 71 | SONARQUBE=$(oc get route -n cicd sonarqube -o jsonpath='{.spec.host}') 72 | printf "https://$SONARQUBE" 73 | echo "" 74 | 75 | info "## Reports Server - Username/Password: reports/reports ##" 76 | REPORTS=$(oc get route -n cicd reports-repo -o jsonpath='{.spec.host}') 77 | printf "https://$REPORTS" 78 | echo "" 79 | 80 | info "## ACS/Stackrox Server - Username/Password: admin/stackrox ##" 81 | ACS=$(oc get route -n stackrox central -o jsonpath='{.spec.host}') 82 | printf "https://$ACS" 83 | echo "" 84 | 85 | info "## ArgoCD Server - Username/Password: admin/[DEX] ##" 86 | ARGO=$(oc get route -n openshift-gitops openshift-gitops-server -o jsonpath='{.spec.host}') 87 | printf "https://$ARGO" 88 | echo "" 89 | } 90 | 91 | command.start() { 92 | info "## Executing Dev Pipeline... ##" 93 | oc create -f run/pipeline-build-dev-run.yaml -n cicd 94 | OCP_ROUTE=$(oc whoami --show-console) 95 | info "Check the pipeline in: \n$OCP_ROUTE/pipelines/ns/cicd/pipeline-runs" 96 | echo "" 97 | } 98 | 99 | command.promote() { 100 | info "## Executing Stage Pipeline... ##" 101 | oc create -f run/pipeline-build-stage-run.yaml -n cicd 102 | OCP_ROUTE=$(oc whoami --show-console) 103 | info "Check the pipeline in: \n$OCP_ROUTE/pipelines/ns/cicd/pipeline-runs" 104 | echo "" 105 | } 106 | 107 | command.sign-verify() { 108 | info "## Will attempt to verify TaskRuns of Last Pipelinerun" 109 | tekton_chain_namespaces=("cicd") 110 | working_namespace="" 111 | verify_script="verify-pipeline.sh" 112 | 113 | for namespace in ${tekton_chain_namespaces[@]} 114 | do 115 | pod_check=$(oc get pods -n $namespace -l app=cosign-pod 2>&1) 116 | if echo ${pod_check} | grep -iv "No resources found" 117 | then 118 | working_namespace=$namespace 119 | cosign_pod=$(oc get pods -n $namespace -l app=cosign-pod --sort-by=.metadata.creationTimestamp | tail -n 1| awk '{print $1}') 120 | fi 121 | done 122 | 123 | if [ -z "${cosign_pod:-}" ] 124 | then 125 | info "## Cosign Pod not Found,Please make sure to run the deploy_signing.yaml" 126 | exit 1 127 | else 128 | info "## Cosign Pod(${cosign_pod}) found in namespace:${namespace}" 129 | fi 130 | 131 | info "## Copying Verification Script to Cosign Pod(${cosign_pod})" 132 | oc rsync --include=${verify_script} -n $working_namespace ./run/verify $cosign_pod:/workdir > /dev/null 133 | 134 | info "## Attemtpting to run verification script in Pod(${cosign_pod})" 135 | oc exec pod/"$cosign_pod" -n $working_namespace -- /bin/bash -c "chmod ugo+x /workdir/verify/${verify_script}" 136 | oc exec pod/"$cosign_pod" -n $working_namespace -- /bin/bash -c "/workdir/verify/${verify_script} $working_namespace " 137 | 138 | # echo "Obtaining cosign.key" 139 | # oc exec pod/"$cosign_pod" -n openshift-pipelines -- /bin/bash -c "oc get secret/signing-secrets -n openshift-pipelines -o jsonpath='{.data.cosign\.key}' | base64 -d > /test/cosign.key" 140 | # echo "Obtaining cosign.password" 141 | # oc exec pod/"$cosign_pod" -n openshift-pipelines -- /bin/bash -c "oc get secret/signing-secrets -n openshift-pipelines -o jsonpath='{.data.cosign\.password}' | base64 -d > /test/cosign.password" 142 | # echo "Obtaining cosign public key" 143 | # oc exec pod/"$cosign_pod" -n openshift-pipelines -- /bin/bash -c "oc get secret/signing-secrets -n openshift-pipelines -o jsonpath='{.data.cosign\.pub}' | base64 -d > /test/cosign.pub" 144 | 145 | 146 | # signature=$(oc get taskrun/petclinic-build-dev-z8zq7v-build-image -n cicd -o jsonpath='{.metadata.annotations.chains\.tekton\.dev/signature-taskrun-171087b9-512e-4237-ab70-6f01083e9170}') 147 | # payload=$(oc get taskrun/petclinic-build-dev-z8zq7v-build-image -n cicd -o jsonpath='{.metadata.annotations.chains\.tekton\.dev/payload-taskrun-171087b9-512e-4237-ab70-6f01083e9170}') 148 | 149 | # oc run cosign-verify --image=gcr.io/projectsigstore/cosign:v1.9.0 -- verify --key $cosign_key --signature $signature $payload 150 | } 151 | 152 | main() { 153 | local fn="command.$COMMAND" 154 | valid_command "$fn" || { 155 | err "invalid command '$COMMAND'" 156 | } 157 | 158 | cd $SCRIPT_DIR 159 | $fn 160 | return $? 161 | } 162 | 163 | main 164 | -------------------------------------------------------------------------------- /docs/Steps.md: -------------------------------------------------------------------------------- 1 | ## Pipelines Resources 2 | 3 | The pipelines and tasks are located in this folder: 4 | 5 | [Openshift Pipelines](../bootstrap/roles/ocp4-install-pipelines/templates) 6 | 7 | The ArgoCD Apps are located in: 8 | 9 | [ArgoCD Resources](../bootstrap/roles/ocp4-config-gitops/templates) 10 | 11 | ## Pipeline used in the Dev Stage 12 | 13 | In the dev environment the following pipeline is used: 14 | 15 | * [Dev pipeline](../bootstrap/roles/ocp4-install-pipelines/templates/pipeline-build-dev.yaml.j2) 16 | 17 | Check it out! 18 | 19 | ## Source Clone 20 | 21 | - Step for cloning the source code using the workspace designed to persist and share the environment within the whole CICD process 22 | 23 | 24 | 25 | ## Dependency Report 26 | 27 | 28 | 29 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-dependency-report.yaml.j2) 30 | 31 | 32 | 33 | ## Code Analysis (Sonarqube) 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-mvn.yaml.j2) 42 | 43 | ## Unit Tests 44 | 45 | 46 | 47 | NOTE: Sometimes there are some random failures that are caused by maven. Rerun the pipeline and check that run OK. 48 | 49 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-mvn.yaml.j2) 50 | 51 | ## Code Analysis 52 | 53 | 54 | 55 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-mvn.yaml.j2) 56 | 57 | ## Release App 58 | 59 | 60 | 61 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-mvn.yaml.j2) 62 | 63 | ## Build Image 64 | 65 | 66 | 67 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-s2i-java-11.yaml.j2) 68 | 69 | ## Image Scan 70 | 71 | 72 | 73 | - In the logs of this step is there a direct link to the image scan in ACS. Copy and paste it in another tab in order to get more information about the scanned image. 74 | 75 | 76 | 77 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-image-scan-task.yaml.j2) 78 | 79 | ## Image Check 80 | 81 | * Fail CI due to a policy 82 | 83 | 84 | 85 | * Non Failing (just Warning) 86 | 87 | 88 | 89 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-rox-image-check.yaml.j2) 90 | 91 | ## Deployment Check 92 | 93 | * Fail CI due to a Deployment Policy 94 | 95 | 96 | 97 | * Non Failing (just Warning) 98 | 99 | 100 | 101 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-rox-deployment-check.yaml.j2) 102 | 103 | ## Update Deployment 104 | 105 | 106 | 107 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-git-update-deployment.yaml.j2) 108 | 109 | ## Wait Application 110 | 111 | 112 | 113 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-argo-sync-and-wait.yaml.j2) 114 | 115 | ## Performance Tests Clone 116 | 117 | 118 | 119 | ## Pentesting Tests using Zap Proxy 120 | 121 | 122 | 123 | 124 | 125 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-zap-proxy.yaml.j2) 126 | 127 | ## Performance Tests using Gatling 128 | 129 | 130 | 131 | 132 | 133 | [Link to Task](../bootstrap/roles/ocp4-install-pipelines/templates/task-gatling.yaml.j2) 134 | 135 | ## Slack Notifications 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | NOTE: this is a manual tasks. WIP to automated. 144 | -------------------------------------------------------------------------------- /docs/disable_policy_enforcement.md: -------------------------------------------------------------------------------- 1 | ## Disable the Policy Enforcement 2 | 3 | To disable the policy enforcement you need to: 4 | 5 | - Go to the ACS Console 6 | - Platform Configuration Tab 7 | - System Policies 8 | - Fixable CVSS >= 7 9 | - Edit -> Next -> Next -> Next 10 | - Build and Deploy into Enforcement Behavior Off -------------------------------------------------------------------------------- /docs/pics/acs-trusted-signature-violation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/acs-trusted-signature-violation.png -------------------------------------------------------------------------------- /docs/pics/demo_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/demo_overview.png -------------------------------------------------------------------------------- /docs/pics/pipeline-with-sign-task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/pipeline-with-sign-task.png -------------------------------------------------------------------------------- /docs/pics/pipeline1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/pipeline1.png -------------------------------------------------------------------------------- /docs/pics/pipeline2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/pipeline2.png -------------------------------------------------------------------------------- /docs/pics/pipeline3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/pipeline3.png -------------------------------------------------------------------------------- /docs/pics/pipeline4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/pipeline4.png -------------------------------------------------------------------------------- /docs/pics/pipeline5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/pipeline5.png -------------------------------------------------------------------------------- /docs/pics/pipeline6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/pipeline6.png -------------------------------------------------------------------------------- /docs/pics/quay-with-signatures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/quay-with-signatures.png -------------------------------------------------------------------------------- /docs/pics/result0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result0.png -------------------------------------------------------------------------------- /docs/pics/result1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result1.png -------------------------------------------------------------------------------- /docs/pics/result10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result10.png -------------------------------------------------------------------------------- /docs/pics/result11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result11.png -------------------------------------------------------------------------------- /docs/pics/result12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result12.png -------------------------------------------------------------------------------- /docs/pics/result13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result13.png -------------------------------------------------------------------------------- /docs/pics/result14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result14.png -------------------------------------------------------------------------------- /docs/pics/result15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result15.png -------------------------------------------------------------------------------- /docs/pics/result16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result16.png -------------------------------------------------------------------------------- /docs/pics/result17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result17.png -------------------------------------------------------------------------------- /docs/pics/result18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result18.png -------------------------------------------------------------------------------- /docs/pics/result18_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result18_1.png -------------------------------------------------------------------------------- /docs/pics/result19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result19.png -------------------------------------------------------------------------------- /docs/pics/result19_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result19_1.png -------------------------------------------------------------------------------- /docs/pics/result1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result1_1.png -------------------------------------------------------------------------------- /docs/pics/result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result2.png -------------------------------------------------------------------------------- /docs/pics/result20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result20.png -------------------------------------------------------------------------------- /docs/pics/result20_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result20_1.png -------------------------------------------------------------------------------- /docs/pics/result20_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result20_2.png -------------------------------------------------------------------------------- /docs/pics/result20_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result20_3.png -------------------------------------------------------------------------------- /docs/pics/result20_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result20_4.png -------------------------------------------------------------------------------- /docs/pics/result3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result3.png -------------------------------------------------------------------------------- /docs/pics/result4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result4.png -------------------------------------------------------------------------------- /docs/pics/result5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result5.png -------------------------------------------------------------------------------- /docs/pics/result6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result6.png -------------------------------------------------------------------------------- /docs/pics/result7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result7.png -------------------------------------------------------------------------------- /docs/pics/result8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result8.png -------------------------------------------------------------------------------- /docs/pics/result9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result9.png -------------------------------------------------------------------------------- /docs/pics/result99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result99.png -------------------------------------------------------------------------------- /docs/pics/result9_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/result9_1.png -------------------------------------------------------------------------------- /docs/pics/taskrun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcarrata/devsecops-demo/48a23081074075965d73ac662e3f51cd423401c1/docs/pics/taskrun.png -------------------------------------------------------------------------------- /docs/promote.md: -------------------------------------------------------------------------------- 1 | ## Promote environment from Dev to Stage 2 | 3 | TBD 4 | 5 | ### Deploy Stage Pipeline 6 | 7 | TBD -------------------------------------------------------------------------------- /docs/slack_integration.md: -------------------------------------------------------------------------------- 1 | ## Slack Integration 2 | 3 | * Based in the official [Integrate with Slack](https://help.stackrox.com/docs/integrate-with-other-tools/integrate-with-slack/) documentation in Stackrox 4 | 5 | 1. Create a Slack App, enable Incoming Webhooks and get the Webhook URL 6 | 7 | 2. Configure the Stackrox Kubernetes Security Platform 8 | 9 | 10 | 11 | 3. Enable the Notifications in the system policies 12 | 13 | Platform Configuration -> System Policies -> Select Policy -> Actions -> Enable Slack Notifications 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/todo.md: -------------------------------------------------------------------------------- 1 | ## TODO 2 | 3 | - Add documentation about triggers 4 | - Add better branching with GitHub Flow model 5 | - Update images for the infra (nexus, gogs, etc) with the latest versions 6 | - Use Nexus Operator 7 | - Use Quay Operator and Clair 8 | -------------------------------------------------------------------------------- /docs/triggers.md: -------------------------------------------------------------------------------- 1 | ## Triggers in Dev Pipeline 2 | 3 | TBD -------------------------------------------------------------------------------- /docs/tshoot.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting section 2 | 3 | ## Rate limiting issues 4 | 5 | * Issue: 6 | 7 | Rate limiting in DockerHub sometimes prevent to pull the images if your cluster reach the DockerHub limit. 8 | 9 | For example: 10 | 11 | ``` 12 | Failed to pull image "centos": rpc error: code = Unknown desc = Error reading manifest latest in 13 | docker.io/library/centos: toomanyrequests: You have reached your pull rate limit. You may increase 14 | the limit by authenticating and upgrading: 15 | ``` 16 | 17 | * Resolution: 18 | 19 | To prevent this you can [authenticate your docker hub 20 | account](https://developers.redhat.com/blog/2021/02/18/how-to-work-around-dockers-new-download-rate-limit-on-red-hat-openshift#authenticate_to_your_docker_hub_account) 21 | 22 | On the other hand, we'll move all the images to quay.io / registry.redhat.io to prevent this issue. 23 | 24 | ## Code Analysis Failures 25 | 26 | * Issue: 27 | 28 | Sometimes Code Analysis raises an error when mvn is running the maven install 'sonar:sonar': 29 | 30 | ``` 31 | [[1;31mERROR[m] Failed to execute goal 32 | [32morg.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile[m [1m(default-testCompile)[m on 33 | project [36mspring-petclinic[m: [1;31mCompilation failure[m 34 | [[1;31mERROR[m] 35 | [1;31m/workspace/source/spring-petclinic/src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:[30,51] 36 | cannot access org.springframework.samples.petclinic.owner.Pet[m 37 | [[1;31mERROR[m] [1;31m bad class file: 38 | /workspace/source/spring-petclinic/target/classes/org/springframework/samples/petclinic/owner/Pet.class[m 39 | [[1;31mERROR[m] [1;31m class file contains wrong class: 40 | org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest[m 41 | [[1;31mERROR[m] [1;31m Please remove or make sure it appears in the correct subdirectory of the 42 | classpath.[m 43 | [[1;31mERROR[m] [1;31m[m 44 | [[1;31mERROR[m] -> [1m[Help 1][m 45 | [[1;31mERROR[m] 46 | ``` 47 | 48 | * Resolution: 49 | 50 | Just rerun the pipeline and will succeed without changing anything additional. The results will 51 | succeed afterwards: 52 | 53 | ``` 54 | [[1;34mINFO[m] Analyzed bundle 'petclinic' with 20 classes 55 | [[1;34mINFO[m] 56 | [[1;34mINFO[m] [1m--- [0;32mmaven-jar-plugin:3.1.2:jar[m [1m(default-jar)[m @ 57 | [36mspring-petclinic[0;1m ---[m 58 | [[1;34mINFO[m] 59 | [[1;34mINFO[m] [1m--- [0;32mspring-boot-maven-plugin:2.2.5.RELEASE:repackage[m [1m(repackage)[m @ 60 | [36mspring-petclinic[0;1m ---[m 61 | [[1;34mINFO[m] Replacing main artifact with repackaged archive 62 | [[1;34mINFO[m] [1m------------------------------------------------------------------------[m 63 | [[1;34mINFO[m] [1;32mBUILD SUCCESS[m 64 | [[1;34mINFO[m] [1m------------------------------------------------------------------------[m 65 | [[1;34mINFO[m] Total time: 01:55 min 66 | [[1;34mINFO[m] Finished at: 2021-07-23T07:37:09Z 67 | [[1;34mINFO[m] Final Memory: 118M/1245M 68 | [[1;34mINFO[m] [1m------------------------------------------------------------------------[m 69 | ``` 70 | 71 | ## JUnit Tests Failures 72 | 73 | Refer to the Code Analysis. Just rerun and it'll fix it. 74 | -------------------------------------------------------------------------------- /extend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e -u -o pipefail 4 | 5 | valid_command() { 6 | local fn=$1; shift 7 | [[ $(type -t "$fn") == "function" ]] 8 | } 9 | 10 | info() { 11 | printf "\n# INFO: $@\n" 12 | } 13 | 14 | err() { 15 | printf "\n# ERROR: $1\n" 16 | exit 1 17 | } 18 | 19 | info "Installing Demo" 20 | ansible-playbook bootstrap/deploy_signing.yaml -v -------------------------------------------------------------------------------- /fix-image/s2ijava-mgr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | annotations: 5 | tekton.dev/displayName: s2i java 11 6 | tekton.dev/pipelines.minVersion: 0.11.3 7 | tekton.dev/tags: s2i, java, workspace 8 | name: s2i-java-11 9 | spec: 10 | description: s2i-java-11 task clones a Git repository and builds and pushes a container 11 | image using S2I and a Java 11 builder image. 12 | params: 13 | - default: . 14 | description: The location of the path to run s2i from 15 | name: PATH_CONTEXT 16 | type: string 17 | - default: "true" 18 | description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS 19 | registry) 20 | name: TLSVERIFY 21 | type: string 22 | - default: "" 23 | description: Additional Maven arguments 24 | name: MAVEN_ARGS_APPEND 25 | type: string 26 | - default: "false" 27 | description: Remove the Maven repository after the artifact is built 28 | name: MAVEN_CLEAR_REPO 29 | type: string 30 | - default: "" 31 | description: The base URL of a mirror used for retrieving artifacts 32 | name: MAVEN_MIRROR_URL 33 | type: string 34 | - description: Location of the repo where image has to be pushed 35 | name: IMAGE_NAME 36 | type: string 37 | - default: latest 38 | description: The tag of the image to be pushed 39 | name: IMAGE_TAG 40 | type: string 41 | results: 42 | - description: Digest of the image just built. 43 | name: IMAGE_DIGEST 44 | steps: 45 | - args: 46 | - |- 47 | echo "MAVEN_CLEAR_REPO=$(params.MAVEN_CLEAR_REPO)" > env-file 48 | 49 | [[ '$(params.MAVEN_ARGS_APPEND)' != "" ]] && 50 | echo "MAVEN_ARGS_APPEND=$(params.MAVEN_ARGS_APPEND)" >> env-file 51 | 52 | [[ '$(params.MAVEN_MIRROR_URL)' != "" ]] && 53 | echo "MAVEN_MIRROR_URL=$(params.MAVEN_MIRROR_URL)" >> env-file 54 | 55 | echo "Generated Env file" 56 | echo "------------------------------" 57 | cat env-file 58 | echo "------------------------------" 59 | command: 60 | - /bin/sh 61 | - -c 62 | image: registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8@sha256:562dbdac04ae9260e21d457585b3251fd8cc5310966f8fc544fb77dc544c92f8 63 | name: gen-env-file 64 | resources: {} 65 | volumeMounts: 66 | - mountPath: /env-params 67 | name: envparams 68 | workingDir: /env-params 69 | - command: 70 | - s2i 71 | - build 72 | - $(params.PATH_CONTEXT) 73 | - image-registry.openshift-image-registry.svc:5000/openshift/java:11 74 | - --image-scripts-url 75 | - image:///usr/local/s2i 76 | - --as-dockerfile 77 | - /gen-source/Dockerfile.gen 78 | - --environment-file 79 | - /env-params/env-file 80 | image: registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8@sha256:562dbdac04ae9260e21d457585b3251fd8cc5310966f8fc544fb77dc544c92f8 81 | name: generate 82 | resources: {} 83 | volumeMounts: 84 | - mountPath: /gen-source 85 | name: gen-source 86 | - mountPath: /env-params 87 | name: envparams 88 | workingDir: $(workspaces.source.path) 89 | - command: 90 | - buildah 91 | - bud 92 | - --storage-driver=vfs 93 | - --tls-verify=$(params.TLSVERIFY) 94 | - --layers 95 | - -f 96 | - /gen-source/Dockerfile.gen 97 | - -t 98 | - $(params.IMAGE_NAME):$(params.IMAGE_TAG) 99 | - -t 100 | - $(params.IMAGE_NAME):latest 101 | - . 102 | image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 103 | name: build 104 | resources: {} 105 | volumeMounts: 106 | - mountPath: /var/lib/containers 107 | name: varlibcontainers 108 | - mountPath: /gen-source 109 | name: gen-source 110 | workingDir: /gen-source 111 | 112 | - args: 113 | - |- 114 | buildah from --storage-driver=vfs --tls-verify=$(params.TLSVERIFY) '$(params.IMAGE_NAME):$(params.IMAGE_TAG)' > imgname 115 | buildah run --user=root --storage-driver=vfs `cat imgname` -- sh -c 'rpm -e $(rpm -qa *dnf*) $(rpm -qa *libsolv*) $(rpm -qa *hawkey*) $(rpm -qa yum*) $(rpm -qa *dnf*) $(rpm -qa *subscription-manager*)' 116 | buildah run --user=root --storage-driver=vfs `cat imgname` -- sh -c 'rpm -e $(rpm -qa *rpm*)' 117 | buildah commit --storage-driver=vfs --tls-verify=$(params.TLSVERIFY) `cat imgname` '$(params.IMAGE_NAME):$(params.IMAGE_TAG)' 118 | command: 119 | - /bin/sh 120 | - -c 121 | image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 122 | name: remove-package-mgr 123 | resources: {} 124 | volumeMounts: 125 | - mountPath: /var/lib/containers 126 | name: varlibcontainers 127 | - mountPath: /gen-source 128 | name: gen-source 129 | workingDir: /gen-source 130 | 131 | - command: 132 | - buildah 133 | - push 134 | - --storage-driver=vfs 135 | - --tls-verify=$(params.TLSVERIFY) 136 | - --digestfile 137 | - $(workspaces.source.path)/image-digest 138 | - $(params.IMAGE_NAME):$(params.IMAGE_TAG) 139 | - docker://$(params.IMAGE_NAME):$(params.IMAGE_TAG) 140 | image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 141 | name: push-tag 142 | resources: {} 143 | volumeMounts: 144 | - mountPath: /var/lib/containers 145 | name: varlibcontainers 146 | - command: 147 | - buildah 148 | - push 149 | - --storage-driver=vfs 150 | - --tls-verify=$(params.TLSVERIFY) 151 | - --digestfile 152 | - $(workspaces.source.path)/image-digest 153 | - $(params.IMAGE_NAME):$(params.IMAGE_TAG) 154 | - docker://$(params.IMAGE_NAME):latest 155 | image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 156 | name: push-latest 157 | resources: {} 158 | volumeMounts: 159 | - mountPath: /var/lib/containers 160 | name: varlibcontainers 161 | - image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 162 | name: digest-to-results 163 | resources: {} 164 | script: cat $(workspaces.source.path)/image-digest | tee /tekton/results/IMAGE_DIGEST 165 | volumes: 166 | - emptyDir: {} 167 | name: varlibcontainers 168 | - emptyDir: {} 169 | name: gen-source 170 | - emptyDir: {} 171 | name: envparams 172 | workspaces: 173 | - mountPath: /workspace/source 174 | name: source 175 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e -u -o pipefail 4 | 5 | valid_command() { 6 | local fn=$1; shift 7 | [[ $(type -t "$fn") == "function" ]] 8 | } 9 | 10 | info() { 11 | printf "\n# INFO: $@\n" 12 | } 13 | 14 | err() { 15 | printf "\n# ERROR: $1\n" 16 | exit 1 17 | } 18 | 19 | info "Installing Demo" 20 | ansible-playbook bootstrap/deploy_demo.yaml -v 21 | -------------------------------------------------------------------------------- /run/pipeline-build-dev-run.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: PipelineRun 3 | metadata: 4 | generateName: petclinic-build-dev 5 | spec: 6 | pipelineRef: 7 | name: petclinic-build-dev 8 | workspaces: 9 | - name: workspace 10 | persistentVolumeClaim: 11 | claimName: petclinic-build-workspace 12 | - name: maven-settings 13 | configMap: 14 | name: maven-settings 15 | -------------------------------------------------------------------------------- /run/pipeline-build-stage-run.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: PipelineRun 3 | metadata: 4 | generateName: petclinic-build-stage 5 | spec: 6 | pipelineRef: 7 | name: petclinic-build-stage 8 | workspaces: 9 | - name: workspace 10 | persistentVolumeClaim: 11 | claimName: petclinic-build-workspace 12 | - name: maven-settings 13 | configMap: 14 | name: maven-settings 15 | -------------------------------------------------------------------------------- /run/verify/verify-pipeline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "## Verify Starting Script" 4 | 5 | tekton_secret_namespace="${1:-openshift-pipelines}" 6 | cosign_secret_name="${2:-signing-secrets}" 7 | pipeline_namespace="${3:-cicd}" 8 | writable_space="${4:-/workdir}" 9 | pipeline_label="${5:-petclinic-build-dev}" 10 | 11 | #Can get Secrets Directly but will depend on Kubernetes Permission 12 | # if [ ! -f ${writable_space}/cosign.key ] 13 | # then 14 | # oc get secret/${cosign_secret_name} -n ${tekton_secret_namespace} -o jsonpath='{.data.cosign\.key}' | base64 -d > ${writable_space}/cosign.key 15 | # fi 16 | 17 | # if [ ! -f ${writable_space}/cosign.password ] 18 | # then 19 | # oc get secret/${cosign_secret_name} -n ${tekton_secret_namespace} -o jsonpath='{.data.cosign\.password}' | base64 -d > ${writable_space}/cosign.password 20 | # fi 21 | 22 | # if [ ! -f ${writable_space}/cosign.pub ] 23 | # then 24 | # oc get secret/${cosign_secret_name} -n ${tekton_secret_namespace} -o jsonpath='{.data.cosign\.pub}' | base64 -d > ${writable_space}/cosign.pub 25 | # fi 26 | 27 | printf "Getting Most Recent Pipeline Run for ${pipeline_label}\n" 28 | pipelinerun=$(oc get pipelinerun -n ${pipeline_namespace} -l tekton.dev/pipeline=${pipeline_label} --sort-by=.metadata.creationTimestamp | tail -n 1| awk '{print $1}') 29 | printf "Found Pipeline Run ${pipelinerun}\n\n" 30 | 31 | printf "Will attempt to Verify Task Runs for Pipeline Run ${pipelinerun}\n" 32 | for taskrun in $(oc get taskrun -n ${pipeline_namespace} -l tekton.dev/pipelineRun=${pipelinerun} -o name) 33 | do 34 | printf "\n" 35 | printf "Start Verification of TaskRun ${taskrun} in PipelineRun ${pipelinerun}\n" 36 | TASKRUN_UID=$(oc get $taskrun -n ${pipeline_namespace} -o jsonpath='{.metadata.uid}') 37 | oc get $taskrun -n ${pipeline_namespace} -o jsonpath="{.metadata.annotations.chains\.tekton\.dev/signature-taskrun-$TASKRUN_UID}" > ${writable_space}/signature 38 | oc get $taskrun -n ${pipeline_namespace} -o jsonpath="{.metadata.annotations.chains\.tekton\.dev/payload-taskrun-$TASKRUN_UID}" | base64 -d > ${writable_space}/payload 39 | cosign verify-blob -d --key k8s://${tekton_secret_namespace}/${cosign_secret_name} --signature ${writable_space}/signature ${writable_space}/payload 40 | if [ "$?" -eq 0 ] 41 | then 42 | printf "Verified TaskRun ${taskrun} in PipelineRun ${pipelinerun}\n" 43 | printf "\n" 44 | else 45 | printf "Could not verify TaskRun ${taskrun} in PipelineRun ${pipelinerun}" 46 | printf "\n" 47 | fi 48 | done 49 | 50 | -------------------------------------------------------------------------------- /status.sh: -------------------------------------------------------------------------------- 1 | printf "\n## GOGS Server - Username/Password: gogs/gogs ##\n" 2 | GOGS=$(oc get route -n cicd gogs -o jsonpath='{.spec.host}') 3 | printf "http://$GOGS" 4 | printf "\n" 5 | 6 | printf "\n## Nexus Server - Username/Password: admin/admin123 ##\n" 7 | NEXUS=$(oc get route -n cicd nexus -o jsonpath='{.spec.host}') 8 | printf "https://$NEXUS" 9 | printf "\n" 10 | 11 | printf "\n## Sonarqube Server - Username/Password: admin/admin ##\n" 12 | SONARQUBE=$(oc get route -n cicd sonarqube -o jsonpath='{.spec.host}') 13 | printf "https://$SONARQUBE" 14 | printf "\n" 15 | 16 | printf "\n## Reports Server - Username/Password: reports/reports ##\n" 17 | REPORTS=$(oc get route -n cicd reports-repo -o jsonpath='{.spec.host}') 18 | printf "http://$REPORTS" 19 | printf "\n" 20 | 21 | printf "\n## ACS/Stackrox Server - Username/Password: admin/stackrox ##\n" 22 | ACS=$(oc get route -n stackrox central -o jsonpath='{.spec.host}') 23 | printf "https://$ACS" 24 | printf "\n" 25 | 26 | printf "\n## ArgoCD Server - Username/Password: admin/[DEX] ##\n" 27 | ARGO=$(oc get route -n openshift-gitops openshift-gitops-server -o jsonpath='{.spec.host}') 28 | printf "https://$ARGO" 29 | printf "\n" 30 | --------------------------------------------------------------------------------