{"id":15222066,"url":"https://github.com/googlecloudplatform/cloud-build-software-delivery","last_synced_at":"2025-10-20T01:30:40.101Z","repository":{"id":65014353,"uuid":"545773776","full_name":"GoogleCloudPlatform/cloud-build-software-delivery","owner":"GoogleCloudPlatform","description":"A walkthrough of setting up a secure CI/CD pipeline for a containerized workloads using Google Cloud Build","archived":false,"fork":false,"pushed_at":"2024-05-01T17:56:21.000Z","size":410,"stargazers_count":24,"open_issues_count":2,"forks_count":10,"subscribers_count":13,"default_branch":"main","last_synced_at":"2024-12-18T08:39:57.438Z","etag":null,"topics":["cicd","cloud-build","google","google-cloud"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GoogleCloudPlatform.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-10-05T00:33:24.000Z","updated_at":"2024-06-27T02:37:14.000Z","dependencies_parsed_at":"2024-03-18T01:29:14.056Z","dependency_job_id":"deedb7d3-a7bd-4321-bd93-f6a124fef2b4","html_url":"https://github.com/GoogleCloudPlatform/cloud-build-software-delivery","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-build-software-delivery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-build-software-delivery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-build-software-delivery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleCloudPlatform%2Fcloud-build-software-delivery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GoogleCloudPlatform","download_url":"https://codeload.github.com/GoogleCloudPlatform/cloud-build-software-delivery/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237243005,"owners_count":19278060,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cicd","cloud-build","google","google-cloud"],"created_at":"2024-09-28T15:10:13.573Z","updated_at":"2025-10-20T01:30:34.804Z","avatar_url":"https://github.com/GoogleCloudPlatform.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Securing software supply chain\n\n## Introduction\n\nThe purpose of this document is to provide a step by step guide and related artifacts to set up a secured CI/CD pipeline for a containerized workload. While the overall ecosystem security involves multiple layers, from securing underline physical infrastructure to actual code, this document focuses on the Application/Container security that can be automated in the CI/CD pipeline.\n\n![alt_text](images/LayeredSecurity.png \"Layered Security\")\n\n## System Overview\n\nIn this demo, we are using a simple java application (with Gradle build tool) that is containerized using Dockerfile and CI/CD pipeline is configured using cloudbuild.yaml. Other technologies/services used to implement this CI/CD pipelines are:\n\n1. [Cloud Source Repository](https://cloud.google.com/container-registry/docs)\n2. [Artifact Registry](https://cloud.google.com/artifact-registry/docs)\n3. [CloudBuild](https://cloud.google.com/build/docs/concepts)\n4. [Container Analysis](https://cloud.google.com/container-analysis/docs/container-analysis)\n5. [Binary Authorization](https://cloud.google.com/binary-authorization/docs)\n6. [Hadolint](https://github.com/hadolint/hadolint)\n7. [Kubesec](https://kubesec.io/)\n8. [Conftest](https://www.conftest.dev/)\n9. [SonarQube](https://www.sonarqube.org/)\n\n\n# Standard CI/CD Pipeline\n\nA standard CI/CD pipeline generally consists of 4-5 stages. For example, Build, Test, Static code Analysis and QA stage. These stages are more developer focused and It only makes sure code builds successfully, it follows general coding guidelines and it fulfills functional requirements.\n\n![alt_text](images/CICD.png \"Basic CI/CD Pipeline\")\nArtifacts used in these stages are the following:\n\n* Application code\n* Dockerfile\n* Container Image\n* Kubernetes Manifest files\n\nAll of these artifacts are vulnerable to security lapses. Following is the list of vulnerabilities they can introduce:\n\n**Application Code**\n\n* SQL Injection\n* Cross site scripting\n* Code Injection\n* Sensitive Cookies without “HttpOnly” flag\n* and many more\n\nScanning tool: [SonarQube](https://www.sonarqube.org/)\n\n**Dockerfile**\n\n* Unnecessary library and packages that increase attack surface\n* Unofficial base image that can be vulnerable\n* Image without tag make application inconsistent\n* and many more\n\n Scanning tool: [Hadolint](https://github.com/hadolint/hadolint), [Confest](https://www.conftest.dev/)\n\n**Container Image**\n\n* Buffer Overflow that can lead to Denial of service\n* Integer overflow that can impact confidentiality\n* Command Injection\n* and many more\n\n Scanning tool: [Container Analysis](https://cloud.google.com/container-analysis/docs/container-analysis)\n\n**Kubermetes manifest file**\n\n* Least privilege principle violation\n* Mutable file system increase attack surface area\n* No limit on CPU \u0026 memory can lead to DOS via resource exhaustion\n* Unnecessary capability given to a container can lead to increase syscall attack surface\n\nScanning tool: [Kubesec](https://kubesec.io/), [Confest](https://www.conftest.dev/)\n\n# Secured CI/CD Pipeline\n\nWith a little more effort, we can handle mitigate the vulnerabilities discussed in the previous section.\n\n\n![alt_text](images/SecureCICD.png \"Secure CI CD Pipeline\")\n\n# Demo scope \u0026 output\n\nCI/CD pipeline for this demo consists of 11 steps and out of them 7 steps are created to make this supply chain more secure.\n\nBuild steps can be broken down into categories like:\n\n1. Static code analysis\n2. Build+Push\n3. Vulnerability Scanning\n4. Attestation\n5. Generate Kubernetes Manifest\n6. Deploy\n\n\n![alt_text](images/CloudBuildSteps.png \"Succesful Cloud Build steps of Secure Pipeline\")\n\n\n# Demo setup\n\n## Prerequisites\n\n1. A Google Cloud Project\n2. A GKE cluster with --enable-binauthz,\n3. An Artifact Repository\n4. Set project variables, by replacing the example, below:\n\n```\n\n# Set environment variables on Mac/Linux\nPROJECT\\_ID=sec-soft-chain\nREGION=australia-southeast1\nZONE=australia-southeast1-b\n\n# Set your project as the current project\ngcloud config set project $PROJECT_ID\n\n# Or if you want a new project, Create a project and set as default\ngcloud projects create $PROJECT\\_ID –set-as-default \n\n# Enable the Required API’s\ngcloud services enable container.googleapis.com\ngcloud services enable artifactregistry.googleapis.com\ngcloud services enable ondemandscanning.googleapis.com\ngcloud services enable cloudkms.googleapis.com\ngcloud services enable binaryauthorization.googleapis.com\n\n# Create a cluster for this demo, these commands do not provision a production ready cluster\ngcloud beta container --project $PROJECT_ID clusters create \"software-secure-supply\" --no-enable-basic-auth --cluster-version \"1.27.8-gke.1067004\" --release-channel \"regular\" --machine-type \"e2-medium\" --image-type \"COS_CONTAINERD\" --disk-type \"pd-balanced\" --disk-size \"100\" --metadata disable-legacy-endpoints=true --scopes \"https://www.googleapis.com/auth/devstorage.read_only\",\"https://www.googleapis.com/auth/logging.write\",\"https://www.googleapis.com/auth/monitoring\",\"https://www.googleapis.com/auth/servicecontrol\",\"https://www.googleapis.com/auth/service.management.readonly\",\"https://www.googleapis.com/auth/trace.append\" --num-nodes \"3\" --logging=SYSTEM,WORKLOAD --monitoring=SYSTEM --enable-ip-alias --network \"projects/$PROJECT_ID/global/networks/default\" --subnetwork \"projects/$PROJECT_ID/regions/$REGION/subnetworks/default\" --no-enable-intra-node-visibility --default-max-pods-per-node \"110\" --security-posture=standard --workload-vulnerability-scanning=disabled --no-enable-master-authorized-networks --addons GcePersistentDiskCsiDriver --enable-autoupgrade --enable-autorepair --max-surge-upgrade 1 --max-unavailable-upgrade 1   --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE --enable-shielded-nodes --node-locations $REGION\n\n# Create an Artifact Repository\ngcloud artifacts repositories create \"$PROJECT_ID-repo\" --location=$REGION  --repository-format=docker\n\n# Allow the Cloud Build Service Account to run scans\ngcloud projects add-iam-policy-binding $PROJECT_ID  --member=serviceAccount:$(gcloud projects describe $PROJECT_ID --format=\"value(projectNumber)\")@cloudbuild.gserviceaccount.com --role=roles/ondemandscanning.admin \n\n# Allow the Cloud Build Service Account to deploy to GKE\ngcloud projects add-iam-policy-binding $PROJECT_ID  --member=serviceAccount:$(gcloud projects describe $PROJECT_ID --format=\"value(projectNumber)\")@cloudbuild.gserviceaccount.com --role=roles/container.developer\n\n# Allow Cloud Build Service Account the permission to attest\ngcloud projects add-iam-policy-binding $PROJECT_ID  --member=serviceAccount:$(gcloud projects describe $PROJECT_ID --format=\"value(projectNumber)\")@cloudbuild.gserviceaccount.com --role=roles/containeranalysis.notes.attacher\n```\n\n## Setup Cloud Source Repository\n\n1. Clone the following [repository](https://github.com/GoogleCloudPlatform/cloud-build-software-delivery) to your local machine\n\n```\ngit clone \u003chttps://github.com/GoogleCloudPlatform/cloud-build-software-delivery\u003e\n```\n2. Push the cloned repo to your own [Cloud Source](https://source.cloud.google.com/repo/create) repository.\n```\n# Create a repo called sec-soft-chain\ngcloud source repos create sec-soft-chain\n\n# Configure credentials\ngcloud init \u0026\u0026 git config --global credential.https://source.developers.google.com.helper gcloud.sh\n\n# Add your new repo as a remote repo called google\ngit remote add google https://source.developers.google.com/p/$PROJECT_ID/r/sec-soft-chain\n\n# Push code to the new repo called google\ngit push --all google\n```\n\n## Create the Cloud Build trigger\n\n1. In the Cloud console, go to the Cloud Build Triggers page\n2. Enable the API\n3. [Go to Triggers](https://console.cloud.google.com/cloud-build/triggers)\n4. Click Create Trigger.\n5. In the Trigger Settings window, enter the following details:\n    * In the Name field, enter build-vulnz-deploy.\n    * For Event choose Push to a branch.\n    * In the Repository field, choose your repo from the menu.\n    * In the Branch field, enter main.\n    * For Configuration, select Cloud Build configuration file (yaml or json).\n    * In the Location, select Repository enter the default value /cloudbuild.yaml.\n6. Add the following Substitution Variable pairs:\n    * \\_IMAGE\\_NAME with the image from Cloud Artifact Registry this should be \u003cREGION\u003e-docker.pkg.dev/\u003cPROJECT\\_ID\u003e/\u003cPROJECT\\_ID\u003e-repo/image\n    * e.g. australia-southeast1-docker.pkg.dev/sec-soft-chain/sec-soft-chain-repo/image \\_COMPUTE\\_REGION with the value: us-central1 (or the region you chose in the beginning)\n    * \\_KMS\\_KEYRING with the value: binauthz\n    * \\_KMS\\_LOCATION with the value: us-central1 (or the region you chose in the beginning)\n    * \\_VULNZ\\_ATTESTOR with the value: vulnz-attesto\n    * \\_VULNZ\\_KMS\\_KEY with the value: vulnz-signer\n    * \\_VULNZ\\_KMS\\_KEY\\_VERSION with the value: 1\n    * \\_SONAR\\_LOGIN can be blank for now\n    * \\_SONAR\\_PROJECT can be blank for now\n    * \\_SONAR\\_ORG can be blank for now\n7. Click Create\n\n![alt_text](images/SubstiutionVars.png \"2 highlighted steps\")\n\nCongratulations!!!\n\nyou have successfully configured most of the stages (other than a couple, highlighted in yellow). You can very easily replicate this in your actual project by just copying a couple of files (with a little modification).\n\nPlease note that you will have to comment these two stages if you want to test till this point.\n\n\n\n![alt_text](images/CICD2steps.png \"2 highlighted steps\")\n\nThe remaining two stages will require some more configurations outside the code, let us see how can we set them up one by one:\n\n## Modify cloudbuild.yaml\n\nThe Cloudbuild.yaml file in the repo needs a few changes these can be done manually by replacing each instance of the following variables:\n\n* \\\u003cZONE\u003e\n* \\\u003cREGION\u003e\n* \\\u003cREPO\u003e\n* \\\u003cIMAGE\u003e\n* \\\u003cPROJECT\\_ID\u003e\n\nOr the below scripts should set these as per the variables configured previously:giot\n```\nsed -i \"s/\u003cZONE\u003e/$ZONE/g\" cloudbuild.yaml\nsed -i \"s/\u003cREGION\u003e/$REGION/g\" cloudbuild.yaml\nsed -i \"s/\u003cPROJECT\\_ID\u003e/$PROJECT\\_ID/g\" cloudbuild.yaml\nsed -i \"s/\u003cREPO\u003e/$PROJECT\\_ID-repo/g\" cloudbuild.yaml\nsed -i \"s/\u003cIMAGE\u003e/image/g\" cloudbuild.yaml\n```\n\n## Setup Sonarqube\n\n\u003chttps://github.com/GoogleCloudPlatform/cloud-builders-community/tree/master/sonarqube\u003e\n\n1. Clone \u003chttps://github.com/GoogleCloudPlatform/cloud-builders-community\u003e repository.\n```\n    git clone https://github.com/GoogleCloudPlatform/cloud-builders-community \n```\n2. Create custom builder by running following commands:\n```\n    cd cloud-builders-community/sonarqube/\n    gcloud builds submit .\n```\n3. Configure sonarqube (we will configure sonarqube online, but you can set up your own sonarqube server and configure that too).\n\n Login to \u003chttps://sonarcloud.io\u003e with your github account\n\n* Create a token by navigating to Account page then click on security tab\n* Next we need to use the \"Analyze New Project\" option to set up the project in sonarcloud. Note: Use setup manually option\n* Note down the token you created, project key and the organization name\n* Update the Cloud Build Trigger Variables for:\n  * _SONAR_ORG\n  * _SONAR_PROJECT\n  * _SONAR_LOGIN\n\n\n## Binary Authorization\n\nNote: Given below is the list of stripped down actions borrowed from following link:\n\n\u003chttps://cloud.google.com/architecture/binary-auth-with-cloud-build-and-gke\u003e\n\n### Build and register the custom build step with Cloud Build\n\n1. Clone the Google Cloud build community repo:\n```\n    git clone \u003chttps://github.com/GoogleCloudPlatform/gke-binary-auth-tools\u003e ~/binauthz-tools\n```\n2. Configure the Binary Authorization signer for Cloud Build: \\\nBefore use, the code for the custom build step must be built into a container and pushed to Cloud Build. To do this, run the following commands:\n```\n    gcloud builds submit --project $PROJECT\\_ID --tag \"gcr.io/$PROJECT\\_ID/cloudbuild-attestor\" ~/binauthz-tools\n```\n3. The custom build step was pushed to your current project's Google Container Registry and is now ready for use\n\n### Create Cloud KMS [asymmetric key](https://cloud.google.com/kms/docs/create-validate-signatures) for signing attestations\n\n1. In Cloud Shell, create a Cloud KMS key ring named binauthz:\n```\n    gcloud kms keyrings create \"binauthz\" \\\n    --project \"${PROJECT\\_ID}\" \\\n    --location \"${REGION}\"\n```\n2. Create an asymmetric Cloud KMS key named vulnz-signer which will be used to sign and verify vulnerability scan attestations:\n```\n    gcloud kms keys create \"vulnz-signer\" \\\n    --project \"${PROJECT_ID}\" \\\n     --location \"${REGION}\" \\\n     --keyring \"binauthz\" \\\n     --purpose \"asymmetric-signing\" \\\n     --default-algorithm \"rsa-sign-pkcs1-4096-sha512\"\n```\n\n### Create a Container Analysis note named vulnz-note\n```\n    curl \"https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=vulnz-note\" \\\n    --request \"POST\" \\\n    --header \"Content-Type: application/json\" \\\n    --header \"Authorization: Bearer $(gcloud auth print-access-token)\" \\\n    --header \"X-Goog-User-Project: ${PROJECT_ID}\" \\\n    --data-binary @- \u003c\u003cEOF\n        {\n        \"name\": \"projects/${PROJECT_ID}/notes/vulnz-note\",\n        \"attestation\": {\n            \"hint\": {\n            \"human_readable_name\": \"Vulnerability scan note\"\n            }\n        }\n        }\n    EOF\n```\n\n### Give CloudBuild Service account name permission on note\n```\n    export CLOUD_BUILD_SA_EMAIL=$(gcloud projects describe $PROJECT_ID --format=\"value(projectNumber)\")@cloudbuild.gserviceaccount.com\n\n    ​​curl \"https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/vulnz-note:setIamPolicy\" \\\n    --request POST \\\n    --header \"Content-Type: application/json\" \\\n    --header \"Authorization: Bearer $(gcloud auth print-access-token)\" \\\n    --header \"X-Goog-User-Project: ${PROJECT_ID}\" \\\n    --data-binary @- \u003c\u003cEOF\n        {\n        \"resource\": \"projects/${PROJECT_ID}/notes/vulnz-note\",\n        \"policy\": {\n            \"bindings\": [\n            {\n                \"role\": \"roles/containeranalysis.notes.occurrences.viewer\",\n                \"members\": [\n                \"serviceAccount:${CLOUD_BUILD_SA_EMAIL}\"\n                ]\n            },\n            {\n                \"role\": \"roles/containeranalysis.notes.attacher\",\n                \"members\": [\n                \"serviceAccount:${CLOUD_BUILD_SA_EMAIL}\"\n                ]\n            }\n            ]\n        }\n        }\n    EOF\n```\n\n### Create the vulnerability scan attestor\n```\n    gcloud container binauthz attestors create \"vulnz-attestor\" \\_\n        --project \"${PROJECT\\_ID}\" \\\n        --attestation-authority-note-project \"${PROJECT\\_ID}\" \\\n        --attestation-authority-note \"vulnz-note\" \\\n        --description \"Vulnerability scan attestor\"\n```\n### Add the public key for the attestor's signing key\n```\n    gcloud beta container binauthz attestors public-keys add \\\n    --project \"${PROJECT\\_ID}\" \\\n    --attestor \"vulnz-attestor\" \\ \n    --keyversion \"1\" \\ \n    --keyversion-key \"vulnz-signer\" \\ \n    --keyversion-keyring \"binauthz\" \\ \n    --keyversion-location \"${REGION}\" \\ \n    --keyversion-project \"${PROJECT\\_ID}\"\n```\n### Grant the Cloud Build service account permission to verify attestations made by vulnz-attestor\n```\n      gcloud container binauthz attestors add-iam-policy-binding \"vulnz-attestor\" \\\n      --project \"${PROJECT\\_ID}\" \\\n      --member=serviceAccount:$(gcloud projects describe $PROJECT\\_ID --format=\"value(projectNumber)\")@cloudbuild.gserviceaccount.com \\\n      --role \"roles/binaryauthorization.attestorsViewer\"\n```\n### Grant the Cloud Build service account permission to sign objects using the vulnz-signer key\n```\n    gcloud kms keys add-iam-policy-binding \"vulnz-signer\" \\\n    --project \"${PROJECT\\_ID}\" \\\n    --location \"${REGION}\" \\ \n    --keyring \"binauthz\" \\ \n    --member serviceAccount:$(gcloud projects describe $PROJECT\\_ID --format=\"value(projectNumber)\")@cloudbuild.gserviceaccount.com \\\n    --role 'roles/cloudkms.signerVerifier'\n```\n### Configure Binary Authorization default policy like below\n\n\n![alt_text](images/BinAuthPolicy.png \"Binary Auth Default Rule\")\n\nFrom [Binary Authorization Policy](https://console.cloud.google.com/security/binary-authorization/policy) page you can add the project and Attestor name as shown:\n\n\n## Further considerations\n\n1. Purpose built OS images\n2. Reducing Attack surface (limiting/disabling Port/user/services/packages)\n3. Kernel Hardening with AppArmor \u0026 Seccomp\n4. Behavioural Analytics/Falco\n5. Managing Secrets\n6. Regular Upgrade\n7. Restrict API Server Access\n8. Least privilege access using RBAC\n9. Exercise caution with Service accounts\n10. CIS Benchmarking\n11. Secure Dashboard\n12. Secure Ingress to Cluster\n13. Network Policies\n14. Auditing","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgooglecloudplatform%2Fcloud-build-software-delivery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgooglecloudplatform%2Fcloud-build-software-delivery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgooglecloudplatform%2Fcloud-build-software-delivery/lists"}