├── .gitignore ├── LICENSE ├── README.md ├── SUPPORT.md ├── admission-controller ├── README.md ├── rego_rules │ ├── Tests │ │ ├── HostIPCDaemonSet.yaml │ │ ├── HostIPCDeployment.yaml │ │ ├── HostIPCPod.yml │ │ ├── HostIPCStatefulSet.yaml │ │ ├── HostNetworkDaemonSet.yaml │ │ ├── HostNetworkDeployment.yaml │ │ ├── HostNetworkPod.yml │ │ ├── HostNetworkStatefulSet.yaml │ │ ├── HostPathDaemonSet.yaml │ │ ├── HostPathDeployment.yaml │ │ ├── HostPathPod.yml │ │ ├── HostPathStateSet.yml │ │ ├── HostPidDaemonSet.yaml │ │ ├── HostPidDeployment.yaml │ │ ├── HostPidPod.yaml │ │ ├── HostPidStateSet.yaml │ │ ├── HostPortDaemonset.yaml │ │ ├── HostPortDeployment.yaml │ │ ├── HostPortPod.yaml │ │ ├── HostPortStatefulset.yaml │ │ ├── ImagePod.yml │ │ ├── Ingress.yaml │ │ ├── IngressPositive.yaml │ │ ├── NetRawDeployment.yaml │ │ ├── NetRawPod.yaml │ │ ├── PrivEscalationDaemonSet.yaml │ │ ├── PrivEscalationDeployment.yaml │ │ ├── PrivEscalationPod.yml │ │ ├── PrivEscalationStatefulSet.yaml │ │ ├── PrivilegeDaemonSet.yaml │ │ ├── PrivilegeDeployment.yaml │ │ ├── PrivilegePod.yml │ │ ├── PrivilegeStatefulSet.yaml │ │ ├── ProcMountDaemonSet.yaml │ │ ├── ProcMountDeployment.yaml │ │ ├── ProcMountPod.yml │ │ ├── ProcMountStatefulSet.yaml │ │ ├── RootDaemonSet.yaml │ │ ├── RootDeployment.yaml │ │ ├── RootPod.yaml │ │ ├── RootStatefulSet.yaml │ │ ├── RootUserDaemonSet.yaml │ │ ├── RootUserDeployment.yaml │ │ ├── RootUserPod.yml │ │ ├── RootUserStatefulSet.yaml │ │ ├── SecCompProfileDaemonSet.yaml │ │ ├── SecCompProfileDeployment.yaml │ │ ├── SecCompProfilePod.yml │ │ ├── SecCompProfileStatefulset.yaml │ │ ├── SecCompRuntimeDefaultPod.yml │ │ ├── SelinuxPod.yml │ │ ├── SysCtlDaemonset.yaml │ │ ├── SysCtlDeployment.yaml │ │ ├── SysCtlPod.yaml │ │ ├── SysCtlStatefulSet.yaml │ │ ├── allowedVolumeTypesDaemonset.yaml │ │ ├── allowedVolumeTypesDeployment.yaml │ │ ├── allowedVolumeTypesPod.yaml │ │ ├── allowedVolumeTypesStatefulSet.yaml │ │ ├── appArmorDaemonSet.yaml │ │ ├── appArmorDeployment.yaml │ │ ├── appArmorPod.yml │ │ ├── appArmorStatefulSet.yaml │ │ ├── capabilitiesDaemonset.yaml │ │ ├── capabilitiesDeployment.yaml │ │ ├── capabilitiesPod.yaml │ │ └── capabilitiesStatefulset.yaml │ ├── additionalcapabilities-daemonset.rego │ ├── additionalcapabilities-deployment.rego │ ├── additionalcapabilities-pod.rego │ ├── additionalcapabilities-statefulset.rego │ ├── allowedVolumeTypes-daemonset.rego │ ├── allowedVolumeTypes-deployment.rego │ ├── allowedVolumeTypes-pod.rego │ ├── allowedVolumeTypes-statefulset.rego │ ├── appArmor-daemonset.rego │ ├── appArmor-deployment.rego │ ├── appArmor-pod.rego │ ├── appArmor-statefulset.rego │ ├── capabilities-daemonset.rego │ ├── capabilities-deployment.rego │ ├── capabilities-pod.rego │ ├── capabilities-statefulset.rego │ ├── hostipc-daemonset.rego │ ├── hostipc-deployment.rego │ ├── hostipc-pod.rego │ ├── hostipc-statefulset.rego │ ├── hostnetwork-daemonset.rego │ ├── hostnetwork-deployment.rego │ ├── hostnetwork-pod.rego │ ├── hostnetwork-statefulset.rego │ ├── hostpath-daemonset.rego │ ├── hostpath-deployment.rego │ ├── hostpath-pod.rego │ ├── hostpath-statefulset.rego │ ├── hostpid-daemonset.rego │ ├── hostpid-deployment.rego │ ├── hostpid-pod.rego │ ├── hostpid-statefulset.rego │ ├── hostport-daemonset.rego │ ├── hostport-deployment.rego │ ├── hostport-pod.rego │ ├── hostport-statefulset.rego │ ├── imageregistryunauthorized-daemonset.rego │ ├── imageregistryunauthorized-deployment.rego │ ├── imageregistryunauthorized-pod.rego │ ├── imageregistryunauthorized-statefulset.rego │ ├── ingress-pod.rego │ ├── netraw-pod.rego │ ├── privileged-daemonset.rego │ ├── privileged-deployment.rego │ ├── privileged-pod.rego │ ├── privileged-statefulset.rego │ ├── privilegeescalation-daemonset.rego │ ├── privilegeescalation-deployment.rego │ ├── privilegeescalation-pod.rego │ ├── privilegeescalation-statefulset.rego │ ├── procmount-daemonset.rego │ ├── procmount-deployment.rego │ ├── procmount-pod.rego │ ├── procmount-statefulset.rego │ ├── root-daemonset.rego │ ├── root-deployment.rego │ ├── root-pod.rego │ ├── root-statefulset.rego │ ├── rootuser-daemonset.rego │ ├── rootuser-deployment.rego │ ├── rootuser-pod.rego │ ├── rootuser-statefulset.rego │ ├── seccomp-daemonset.rego │ ├── seccomp-deployment.rego │ ├── seccomp-pod.rego │ ├── seccomp-statefulset.rego │ ├── secompprofilesunallowed-daemonset.rego │ ├── secompprofilesunallowed-deployment.rego │ ├── secompprofilesunallowed-pod.rego │ ├── secompprofilesunallowed-statefulset.rego │ ├── secompruntimedefault-pod.rego │ ├── selinux-daemonset.rego │ ├── selinux-deployment.rego │ ├── selinux-pod.rego │ ├── selinux-statefulset.rego │ ├── sensitivehost-deployment.rego │ ├── sensitivehost-pod.rego │ ├── sysctls-daemonset.rego │ ├── sysctls-deployment.rego │ ├── sysctls-pod.rego │ └── sysctls-statefulset.rego └── rules │ ├── container-capabilities.rego │ ├── container-readonly.rego │ ├── image-source.rego │ ├── image-tag.rego │ ├── namespace-creation.rego │ ├── pod-label.rego │ ├── service-external-ip.rego │ ├── service-nodeport.rego │ ├── suspicious-assignment-of-controller-sas.rego │ ├── suspicious-selfsubjectreview.rego │ ├── user-group.rego │ └── user-name.rego ├── api ├── backups │ ├── README.md │ └── runner.py ├── cve-tags │ ├── bulk-tagger.py │ └── tags.csv └── log4j │ ├── .gitignore │ ├── README.md │ ├── impacted_log4j.py │ ├── prisma_cloud_log4j.py │ └── registry_log4j.py ├── cicd ├── README.md ├── aws-devops │ └── README.md ├── azure-devops │ ├── README.md │ └── azure-pipelines.yml ├── buildkite │ ├── .buildkite │ │ └── pipeline.yml │ ├── Dockerfile │ ├── README.md │ ├── build_docker.sh │ ├── cleanup.sh │ ├── download_twistcli.sh │ ├── generate_token.sh │ ├── scan_image.sh │ └── verify_twistcli.sh ├── circleci │ └── README.md ├── codefresh │ ├── README.md │ ├── codefresh-output.png │ ├── codefresh-yml.png │ ├── codefresh.yml │ ├── compute-output.png │ ├── images │ │ ├── codefresh-output.png │ │ ├── codefresh-yml.png │ │ ├── compute-output.png │ │ └── variables.png │ └── variables.png ├── gitlab │ ├── .gitlab-ci.yml │ ├── README.md │ └── images │ │ ├── compute-output1.png │ │ ├── gitlab-ci.png │ │ ├── gitlab-output1.png │ │ ├── gitlab-output2.png │ │ └── variables.png ├── jenkins │ ├── Jenkinsfile │ └── README.md └── travis-ci │ ├── .travis.yml │ ├── README.md │ └── images │ ├── compute-output.png │ ├── travis-output.png │ ├── travis-yml.png │ └── variables.png ├── compliance └── custom-compliance-keys.sh ├── deployment ├── README.md ├── ansible │ ├── README.md │ ├── console-defender-cluster.yaml │ └── linux-host-defender.yaml ├── app-embedded-twistcli │ ├── Dockerfile │ └── protect.sh ├── app-embedded │ ├── Dockerfile │ └── protect.sh ├── azure-service-fabric │ ├── README.md │ └── install_container_defender.ps1 ├── fargate │ ├── NoEntrypointScript │ │ ├── README.md │ │ ├── fargate_use_cmd_for_entry.py │ │ ├── fargate_use_sh_for_entry.py │ │ └── requirements.txt │ ├── fargateProtect.sh │ └── unprotectedTask.json └── shell │ ├── README.md │ ├── daemonset.sh │ ├── ecs-defender.sh │ ├── helm-chart.sh │ ├── linux-container-defender.sh │ ├── linux-host-defender.sh │ └── windows-host-defender.ps1 ├── images └── prisma-cloud-logo.png ├── openshift └── rhpds │ ├── Prisma Cloud Compute RHPDS Lab Guide 2.0.pdf │ └── Prisma Cloud Compute RHPDS Lab Guide.pdf └── reporting ├── reporting-v2 ├── .gitignore ├── README.md ├── create_report.py ├── requirements.txt └── templates │ ├── base.html │ ├── comp_details.html │ ├── comp_summary.html │ ├── cover.html │ ├── executive_summary.html │ ├── static │ ├── css │ │ └── main.css │ ├── images │ │ ├── cloud_panw.png │ │ ├── cover.png │ │ └── none-chart.png │ └── tmp │ │ └── .gitignore │ ├── toc.html │ ├── vuln_details.html │ └── vuln_summary.html └── vuln-reporting-v1 ├── README.md ├── report.html ├── report.py ├── reportCI.html ├── reportCI.py ├── report_body.html.j2 ├── report_body_ci.html.j2 └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | 4 | app_embedded_embed_* 5 | twistlock_defender_app_embedded.tar.gz 6 | protectedTask.json 7 | Dockerfile-defender.zip 8 | twistcli -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prisma Cloud Compute Sample Code 2 | 3 | --- 4 | 5 | **IMPORTANT: Please see [SUPPORT.md](SUPPORT.md) for the official support policy for the contents of this repository.** 6 | 7 | --- 8 | 9 | ![Prisma Cloud logo](images/prisma-cloud-logo.png) 10 | 11 | The new home for [Twistlock Sample Code](https://github.com/twistlock/sample-code)! 12 | 13 | This repository has code samples that focus on automation and enhancing usability. 14 | If you have something that fits in and you think may be useful to others, we encourage you to contribute! 15 | 16 | A few of our projects have outgrown a repository for "sample code", so please check out their dedicated repositories below. 17 | 18 | ## Active projects in other repositories 19 | - [GitHub Action](https://github.com/PaloAltoNetworks/prisma-cloud-scan) - Scan images as they're built in your GitHub workflow and display results directly in your repository. 20 | - [Operator](https://github.com/PaloAltoNetworks/prisma-cloud-compute-operator) - Automatically deploy and set up Console and Defenders in any Kubernetes or OpenShift cluster. 21 | - [Splunk app for incidents and forensics](https://github.com/PaloAltoNetworks/prisma-cloud-compute-splunk) - Fetch runtime incidents and their forensic data and display the information in a Splunk dashboard. 22 | - [Terraform provider](https://github.com/PaloAltoNetworks/terraform-provider-prismacloudcompute) - Fit the management of collections, policies, and more into your GitOps workflows. 23 | 24 | ## Support 25 | Please read [SUPPORT.md](SUPPORT.md) for details on how to get support for this project. 26 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | Community Supported 2 | 3 | The software and templates in the repo are released under an as-is, best effort, 4 | support policy. This software should be seen as community supported and Palo 5 | Alto Networks will contribute our expertise as and when possible. We do not 6 | provide technical support or help in using or troubleshooting the components of 7 | the project through our normal support options such as Palo Alto Networks 8 | support teams, or ASC (Authorized Support Centers) partners and backline support 9 | options. The underlying product used (the VM-Series firewall) by the scripts or 10 | templates are still supported, but the support is only for the product 11 | functionality and not for help in deploying or using the template or script 12 | itself. Unless explicitly tagged, all projects or work posted in our GitHub 13 | repository (at https://github.com/PaloAltoNetworks) or sites other than our 14 | official Downloads page on https://support.paloaltonetworks.com are provided 15 | under the best effort policy. 16 | -------------------------------------------------------------------------------- /admission-controller/README.md: -------------------------------------------------------------------------------- 1 | # Rego policy examples 2 | 3 | With [Prisma Cloud's admission controller](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/access_control/open_policy_agent.html), you can define and enforce policy for 4 | interacting with cluster resources. 5 | You can take action on resource creation, sources and tags of images used in pods, external IPs used by services, and even specific users or groups that do these things. 6 | 7 | The admission controller policies are written in Rego. 8 | This directory is a library of _example_ policies, so not all of them may be suitable for use as they are provided. 9 | 10 | If you've written a rule and would like to share it with the Prisma Cloud community, please submit your work as a pull request. 11 | 12 | ### Notes 13 | #### Operations 14 | Most examples only target the `CREATE` operation, but are structured to allow adding other operations easily. 15 | To add other operations, insert it into the set. 16 | ``` 17 | operations := {"CREATE", "UPDATE"} 18 | operations[input.request.operation] 19 | ``` 20 | 21 | #### Users and groups 22 | The `user-group.rego` and `user-name.rego` examples aren't particularly useful by themselves, but you can combine them with other policies to narrow their scopes. 23 | An example is alerting when a member of a particular group runs a command in or attaches to a container. 24 | 25 | #### Multiple `match` rule definitions 26 | A rule may be defined multiple times with the same name. 27 | This is referred to as an incremental definition because each definition is additive. 28 | An incrementally-defined rule can be understood as ` OR OR ... OR `. 29 | 30 | An example of this can be found in `image-tag.rego` in which the rules will match on the tag `latest` and no tag (which defaults to `latest`). -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostIPCDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: test-daemonset-hostipc 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: test-daemonset-hostnetwork 9 | template: 10 | metadata: 11 | labels: 12 | name: test-daemonset-hostnetwork 13 | spec: 14 | hostIPC: true 15 | containers: 16 | - name: test-daemonset-hostnetwork 17 | image: nginx 18 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostIPCDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-hostipc 5 | spec: 6 | replicas: 0 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | spec: 15 | hostIPC: true 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | ports: 20 | - containerPort: 80 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostIPCPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test-pod-ipc 5 | spec: 6 | hostIPC: true 7 | containers: 8 | - name: nginx 9 | image: nginx:1.16.0 10 | ports: 11 | - containerPort: 80 -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostIPCStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-statefulset-hostipc 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | app: test 11 | template: 12 | metadata: 13 | labels: 14 | app: test 15 | spec: 16 | hostIPC: true 17 | containers: 18 | - name: nginx 19 | image: nginx:1.16.0 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostNetworkDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: test-daemonset-hostnetwork 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: test-daemonset-hostnetwork 9 | template: 10 | metadata: 11 | labels: 12 | name: test-daemonset-hostnetwork 13 | spec: 14 | hostNetwork: true 15 | containers: 16 | - name: test-daemonset-hostnetwork 17 | image: nginx 18 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostNetworkDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-hostnetwork 5 | spec: 6 | replicas: 0 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | spec: 15 | hostNetwork: true 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | ports: 20 | - containerPort: 80 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostNetworkPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test-network 5 | spec: 6 | hostNetwork: true 7 | containers: 8 | - name: nginx 9 | image: nginx:1.16.0 10 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostNetworkStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-statefulset-hostnetwork 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | app: test 11 | template: 12 | metadata: 13 | labels: 14 | app: test 15 | spec: 16 | hostNetwork: true 17 | containers: 18 | - name: nginx 19 | image: nginx:1.16.0 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPathDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: deployment-hostvolume 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: my-deployment 9 | template: 10 | metadata: 11 | labels: 12 | name: my-deployment 13 | spec: 14 | containers: 15 | - name: my-deployment-container 16 | image: nginx:latest 17 | volumeMounts: 18 | - name: my-volume 19 | mountPath: /var/log 20 | volumes: 21 | - name: my-volume 22 | hostPath: 23 | path: / 24 | type: Directory 25 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPathDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-hostpath 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: test 9 | template: 10 | metadata: 11 | labels: 12 | app: test 13 | spec: 14 | containers: 15 | - name: nginx 16 | image: nginx:1.16.0 17 | ports: 18 | - containerPort: 80 19 | volumes: 20 | - name: my-volume 21 | hostPath: 22 | path: / 23 | type: Directory 24 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPathPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test-hostpath-pod 5 | spec: 6 | containers: 7 | - name: test-container 8 | image: nginx 9 | volumeMounts: 10 | - mountPath: /host 11 | name: test-volume 12 | volumes: 13 | - name: test-volume 14 | hostPath: 15 | path: / 16 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPathStateSet.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-hostport-statefulset 5 | spec: 6 | serviceName: "nginx" 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: nginx 11 | template: 12 | metadata: 13 | labels: 14 | app: nginx 15 | spec: 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | ports: 20 | - containerPort: 80 21 | hostPort: 8080 22 | volumes: 23 | - name: my-volume 24 | hostPath: 25 | path: / 26 | type: Directory -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPidDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: daemonset-hostpid 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: daemonset-hostpid 9 | template: 10 | metadata: 11 | labels: 12 | name: daemonset-hostpid 13 | spec: 14 | hostPID: true 15 | containers: 16 | - name: daemonset-hostpid 17 | image: nginx -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPidDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: test 9 | template: 10 | metadata: 11 | labels: 12 | app: test 13 | spec: 14 | hostPID: true 15 | hostIPC: true 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | ports: 20 | - containerPort: 80 21 | securityContext: 22 | runAsNonRoot: true 23 | allowPrivilegeEscalation: true 24 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPidPod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-hostpid 5 | spec: 6 | # hostPID: false 7 | containers: 8 | - name: nginx 9 | image: nginx:1.16.0 10 | ports: 11 | - containerPort: 80 -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPidStateSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-reg 5 | spec: 6 | replicas: 2 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | spec: 15 | hostPID: true 16 | hostIPC: true 17 | containers: 18 | - name: nginx 19 | image: nginx:1.16.0 20 | ports: 21 | - containerPort: 80 22 | volumeMounts: 23 | - name: my-volume 24 | mountPath: /var/log 25 | securityContext: 26 | allowPrivilegeEscalation: true 27 | runAsNonRoot: true 28 | privileged: true 29 | capabilities: 30 | add: ["NET_RAW"] 31 | volumes: 32 | - name: my-volume 33 | hostPath: 34 | path: /var/log 35 | type: Directory 36 | hostNetwork: true 37 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPortDaemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: test-hostport-daemonset 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: nginx 9 | template: 10 | metadata: 11 | labels: 12 | name: nginx 13 | spec: 14 | containers: 15 | - name: nginx 16 | image: nginx:1.16.0 17 | ports: 18 | - containerPort: 80 19 | hostPort: 8080 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPortDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-hostport-deployment 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: nginx 10 | template: 11 | metadata: 12 | labels: 13 | app: nginx 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx:1.16.0 18 | ports: 19 | - containerPort: 80 20 | hostPort: 8080 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPortPod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test-hostport-pod 5 | spec: 6 | containers: 7 | - name: test-container 8 | image: nginx 9 | ports: 10 | - containerPort: 80 11 | hostPort: 8080 12 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/HostPortStatefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-hostport-statefulset 5 | spec: 6 | serviceName: "nginx" 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: nginx 11 | template: 12 | metadata: 13 | labels: 14 | app: nginx 15 | spec: 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | ports: 20 | - containerPort: 80 21 | hostPort: 8080 22 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/ImagePod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: nginx 5 | spec: 6 | securityContext: 7 | sysctls: 8 | - name: kernel.shm_rmid_forc 9 | value: "65536" 10 | containers: 11 | - name: nginx 12 | image: nginx 13 | ports: 14 | - containerPort: 80 -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/Ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: no-tls-ingress 5 | spec: 6 | rules: 7 | - host: no-tls.example.com 8 | http: 9 | paths: 10 | - pathType: Prefix 11 | path: "/" 12 | backend: 13 | service: 14 | name: example-service 15 | port: 16 | number: 80 17 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/IngressPositive.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: tls-ingress 5 | spec: 6 | tls: 7 | - hosts: 8 | - tls.example.com 9 | secretName: example-tls 10 | rules: 11 | - host: tls.example.com 12 | http: 13 | paths: 14 | - pathType: Prefix 15 | path: "/" 16 | backend: 17 | service: 18 | name: example-service 19 | port: 20 | number: 80 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/NetRawDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-net 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: test 9 | template: 10 | metadata: 11 | labels: 12 | app: test 13 | spec: 14 | hostPID: true 15 | hostIPC: true 16 | hostNetwork: true 17 | containers: 18 | - name: nginx 19 | image: nginx:1.16.0 20 | ports: 21 | - containerPort: 80 22 | securityContext: 23 | runAsNonRoot: true 24 | allowPrivilegeEscalation: true 25 | capabilities: 26 | add: ["NET_RAW"] 27 | 28 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/NetRawPod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-net-raw 5 | spec: 6 | containers: 7 | - name: sec-ctx-4 8 | image: gcr.io/google-samples/node-hello:1.0 9 | securityContext: 10 | capabilities: 11 | add: ["NET_RAW"] 12 | 13 | 14 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivEscalationDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: daemonset-priv-escalation 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: daemonset-priv-escalation 9 | template: 10 | metadata: 11 | labels: 12 | name: daemonset-priv-escalation 13 | spec: 14 | containers: 15 | - name: daemonset-priv-escalation 16 | image: nginx 17 | securityContext: 18 | allowPrivilegeEscalation: true -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivEscalationDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-priv 5 | spec: 6 | replicas: 2 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx:1.16.0 18 | ports: 19 | - containerPort: 80 20 | securityContext: 21 | allowPrivilegeEscalation: true 22 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivEscalationPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: nginx 5 | labels: 6 | app: nginx 7 | spec: 8 | containers: 9 | - name: nginx 10 | image: nginx 11 | ports: 12 | - containerPort: 80 13 | securityContext: 14 | allowPrivilegeEscalation: true -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivEscalationStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-statefulset-escalation 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | app: test 11 | template: 12 | metadata: 13 | labels: 14 | app: test 15 | spec: 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | securityContext: 20 | allowPrivilegeEscalation: true 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivilegeDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: daemonset-privileged 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: daemonset-privileged 9 | template: 10 | metadata: 11 | labels: 12 | name: daemonset-privileged 13 | spec: 14 | containers: 15 | - name: daemonset-privileged 16 | image: nginx 17 | securityContext: 18 | privileged: true -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivilegeDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-privileged 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx:1.16.0 18 | ports: 19 | - containerPort: 80 20 | securityContext: 21 | privileged: true 22 | 23 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivilegePod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-privileged 5 | labels: 6 | app: nginx 7 | spec: 8 | containers: 9 | - name: pod-privileged 10 | image: nginx 11 | ports: 12 | - containerPort: 80 13 | securityContext: 14 | privileged: true -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/PrivilegeStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-statefulset-privileged 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | app: test 11 | template: 12 | metadata: 13 | labels: 14 | app: test 15 | spec: 16 | hostIPC: true 17 | containers: 18 | - name: nginx 19 | image: nginx:1.16.0 20 | ports: 21 | - containerPort: 80 22 | securityContext: 23 | privileged: true 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/ProcMountDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: daemonset-procmount 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: my-app 9 | template: 10 | metadata: 11 | labels: 12 | app: my-app 13 | spec: 14 | containers: 15 | - name: container1 16 | image: my-image:tag 17 | securityContext: 18 | procMount: "" 19 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/ProcMountDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: deployment-procmount 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: my-app 10 | template: 11 | metadata: 12 | labels: 13 | app: my-app 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx 18 | securityContext: 19 | procMount: " " 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/ProcMountPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-procmount 5 | labels: 6 | app: nginx 7 | spec: 8 | containers: 9 | - name: nginx1 10 | image: nginx 11 | ports: 12 | - containerPort: 80 13 | securityContext: 14 | procMount: "Default" -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/ProcMountStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: statefulset-procmount 5 | spec: 6 | serviceName: my-service 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: my-app 11 | template: 12 | metadata: 13 | labels: 14 | app: my-app 15 | spec: 16 | containers: 17 | - name: nginx 18 | image: nginx 19 | securityContext: 20 | procMount: " " 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: test-daemonset-root 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: test 9 | template: 10 | metadata: 11 | labels: 12 | app: test 13 | spec: 14 | containers: 15 | - name: nginx 16 | image: nginx:1.16.0 17 | ports: 18 | - containerPort: 80 19 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-root 5 | spec: 6 | replicas: 2 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx:1.16.0 18 | ports: 19 | - containerPort: 80 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootPod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: test-pod-root 5 | spec: 6 | containers: 7 | - name: nginx 8 | image: nginx:1.16.0 9 | ports: 10 | - containerPort: 80 11 | securityContext: 12 | runAsNonRoot: false 13 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-statefulset 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | app: test 11 | template: 12 | metadata: 13 | labels: 14 | app: test 15 | spec: 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | ports: 20 | - containerPort: 80 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootUserDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: daemonset-runasuser 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: my-app 9 | template: 10 | metadata: 11 | labels: 12 | app: my-app 13 | spec: 14 | securityContext: 15 | runAsUser: 0 16 | containers: 17 | - name: nginx 18 | image: nginx 19 | 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootUserDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: deployment-runasuser 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: my-app 10 | template: 11 | metadata: 12 | labels: 13 | app: my-app 14 | spec: 15 | securityContext: 16 | runAsUser: 0 17 | containers: 18 | - name: nginx 19 | image: nginx 20 | 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootUserPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-runasuser 5 | labels: 6 | app: nginx 7 | spec: 8 | securityContext: 9 | runAsUser: 0 10 | containers: 11 | - name: nginx1 12 | image: nginx 13 | ports: 14 | - containerPort: 80 -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/RootUserStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: statefulset-rootuser 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: test 11 | template: 12 | metadata: 13 | labels: 14 | app: test 15 | spec: 16 | securityContext: 17 | runAsUser: 0 18 | containers: 19 | - name: nginx 20 | image: nginx 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SecCompProfileDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: my-daemonset-seccomp 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: my-app 9 | template: 10 | metadata: 11 | labels: 12 | app: my-app 13 | spec: 14 | securityContext: 15 | seccompProfile: 16 | type: Unconfined 17 | containers: 18 | - name: container1 19 | image: my-image:tag 20 | 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SecCompProfileDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: my-deployment-seccomp 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: my-app 10 | template: 11 | metadata: 12 | labels: 13 | app: my-app 14 | spec: 15 | securityContext: 16 | seccompProfile: 17 | type: Unconfined 18 | containers: 19 | - name: nginx 20 | image: nginx 21 | 22 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SecCompProfilePod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-seccomp-allowed 5 | labels: 6 | app: nginx 7 | spec: 8 | securityContext: 9 | seccompProfile: 10 | type: Localhost 11 | localhostProfile: profile3 12 | containers: 13 | - name: nginx1 14 | image: nginx 15 | ports: 16 | - containerPort: 80 -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SecCompProfileStatefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: my-statefulset-seccomp 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: test 11 | template: 12 | metadata: 13 | labels: 14 | app: test 15 | spec: 16 | securityContext: 17 | seccompProfile: 18 | type: Unconfined 19 | containers: 20 | - name: nginx 21 | image: nginx 22 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SecCompRuntimeDefaultPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-seccomp-runtime 5 | spec: 6 | securityContext: 7 | seccompProfile: 8 | type: RuntimeDefault 9 | sysctls: 10 | - name: net.core.somaxconn 11 | value: "1024" 12 | - name: undefined 13 | value: "65536" 14 | containers: 15 | - name: test-container 16 | image: hashicorp/http-echo:0.2.3 17 | args: 18 | - "-text=just made some more syscalls!" 19 | securityContext: 20 | allowPrivilegeEscalation: false -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SelinuxPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-selinux 5 | spec: 6 | containers: 7 | - name: nginx 8 | image: nginx 9 | securityContext: 10 | seLinuxOptions: 11 | type: container_t 12 | user: Undefined 13 | role: Undefined -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SysCtlDaemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: test-daemonset-sysctl 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: test 9 | template: 10 | metadata: 11 | labels: 12 | app: test 13 | spec: 14 | securityContext: 15 | sysctls: 16 | - name: net.ipv4.ping_group_range 17 | value: "65536" 18 | - name: net.core.somaxconn 19 | value: "1024" 20 | containers: 21 | - name: nginx 22 | image: nginx:1.16.0 23 | ports: 24 | - containerPort: 80 25 | 26 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SysCtlDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: test-deployment-ctl 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: nginx 10 | template: 11 | metadata: 12 | labels: 13 | app: nginx 14 | spec: 15 | securityContext: 16 | sysctls: 17 | - name: net.ipv4.ping_group_range 18 | value: "65536" 19 | - name: net.core.somaxconn 20 | value: "1024" 21 | containers: 22 | - name: nginx 23 | image: nginx:1.16.0 24 | ports: 25 | - containerPort: 80 26 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SysCtlPod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod-sysctls 5 | spec: 6 | securityContext: 7 | sysctls: 8 | - name: kernel.shm_rmid_forc 9 | value: "65536" 10 | containers: 11 | - name: nginx 12 | image: nginx 13 | volumes: 14 | - name: my-volume1 15 | hostPath: 16 | path: /var/log 17 | - name: my-volume2 18 | configMap: 19 | name: test 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/SysCtlStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: test-state-sysctl 5 | spec: 6 | serviceName: "test-service" 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: nginx 11 | template: 12 | metadata: 13 | labels: 14 | app: nginx 15 | spec: 16 | securityContext: 17 | sysctls: 18 | - name: net.ipv4.ping_group_range 19 | value: "65536" 20 | - name: net.core.somaxconn 21 | value: "1024" 22 | containers: 23 | - name: nginx 24 | image: nginx:1.16.0 25 | ports: 26 | - containerPort: 80 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/allowedVolumeTypesDaemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: allowedvolumetype-daemonset 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: my-app 9 | template: 10 | metadata: 11 | labels: 12 | app: my-app 13 | spec: 14 | containers: 15 | - name: nginx 16 | image: nginx 17 | volumeMounts: 18 | - name: my-volume 19 | mountPath: /data 20 | volumes: 21 | - name: my-volume 22 | hostPath: 23 | path: /var/log 24 | 25 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/allowedVolumeTypesDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: allowedvolumetype-deployment 5 | spec: 6 | replicas: 0 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | spec: 15 | hostIPC: true 16 | containers: 17 | - name: nginx 18 | image: nginx:1.16.0 19 | volumeMounts: 20 | - name: my-volume 21 | mountPath: /data 22 | volumes: 23 | - name: my-volume 24 | hostPath: 25 | path: /var/log 26 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/allowedVolumeTypesPod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: allowedvolumetype-pod 5 | spec: 6 | containers: 7 | - name: allowed-volume-type-pod 8 | image: nginx 9 | volumeMounts: 10 | - name: my-volume 11 | mountPath: /data 12 | volumes: 13 | - name: my-volume 14 | hostPath: 15 | path: /var/log 16 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/allowedVolumeTypesStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: allowedvolumetype-statefulset 5 | spec: 6 | serviceName: test-service 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: test-app 11 | template: 12 | metadata: 13 | labels: 14 | app: test-app 15 | spec: 16 | containers: 17 | - name: test2 18 | image: nginx:latest 19 | volumeMounts: 20 | - name: my-volume 21 | mountPath: /data 22 | volumes: 23 | - name: my-volume 24 | hostPath: 25 | path: /var/log -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/appArmorDaemonSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: apparmor-daemonset 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: my-app 9 | template: 10 | metadata: 11 | labels: 12 | app: my-app 13 | annotations: 14 | container.apparmor.security.beta.kubernetes.io/test2: unconfined 15 | spec: 16 | containers: 17 | - name: nginx 18 | image: nginx 19 | 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/appArmorDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: apparmor-deployment 5 | spec: 6 | replicas: 0 7 | selector: 8 | matchLabels: 9 | app: test 10 | template: 11 | metadata: 12 | labels: 13 | app: test 14 | annotations: 15 | container.apparmor.security.beta.kubernetes.io/test2: unconfined 16 | spec: 17 | containers: 18 | - name: nginx 19 | image: nginx:1.16.0 -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/appArmorPod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: apparmor-pod 5 | annotations: 6 | container.apparmor.security.beta.kubernetes.io/test2: unconfined 7 | spec: 8 | containers: 9 | - name: apparmor 10 | image: nginx 11 | - name: test2 12 | image: nginx 13 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/appArmorStatefulSet.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: apparmor-statefulset 5 | spec: 6 | serviceName: test-service 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: test-app 11 | template: 12 | metadata: 13 | labels: 14 | app: test-app 15 | annotations: 16 | container.apparmor.security.beta.kubernetes.io/test2: unconfined 17 | spec: 18 | containers: 19 | - name: test2 20 | image: nginx:latest 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/capabilitiesDaemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: daemonset-capabilities 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: my-app 9 | template: 10 | metadata: 11 | labels: 12 | app: my-app 13 | spec: 14 | containers: 15 | - name: nginx 16 | image: nginx 17 | securityContext: 18 | capabilities: 19 | add: ["AUDIT_WRITE"] 20 | 21 | 22 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/capabilitiesDeployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: deployment-capabilities 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: my-app 10 | template: 11 | metadata: 12 | labels: 13 | app: my-app 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx 18 | securityContext: 19 | capabilities: 20 | add: ["AUDIT_WRITE", "SYS"] 21 | 22 | 23 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/capabilitiesPod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: capabilities-pod 5 | spec: 6 | containers: 7 | - name: nginx 8 | image: nginx 9 | securityContext: 10 | capabilities: 11 | add: ["AUDIT_WRITE"] -------------------------------------------------------------------------------- /admission-controller/rego_rules/Tests/capabilitiesStatefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: statefulset-capabilities 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: my-app 10 | template: 11 | metadata: 12 | labels: 13 | app: my-app 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx 18 | securityContext: 19 | capabilities: 20 | add: ["AUDIT_WRITE", "SYS"] 21 | 22 | 23 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/additionalcapabilities-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with containers that run unauthorized additional capabilities 2 | # Description: This policy identifies DaemonSets with containers that run unauthorized additional capabilities 3 | 4 | 5 | 6 | authorizedcapabilities = {"AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD","NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP","SETUID", "SYS_CHROOT"} 7 | 8 | match[{"msg": msg}] { 9 | input.request.operation == "CREATE" 10 | input.request.kind.kind == "DaemonSet" 11 | container := input.request.object.spec.template.spec.containers[_].securityContext 12 | addedcap := {cap | cap := container.capabilities.add[_]} 13 | unauthcapabilities := addedcap - authorizedcapabilities 14 | count(unauthcapabilities) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("DaemonSet with containers using unauthorized capabilities identified in %v", [name]) 17 | } 18 | 19 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/additionalcapabilities-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with containers that run unauthorized additional capabilities 2 | # Description: This policy identifies Deployments with containers that run unauthorized additional capabilities 3 | 4 | 5 | 6 | authorizedcapabilities = {"AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD","NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP","SETUID", "SYS_CHROOT"} 7 | 8 | match[{"msg": msg}] { 9 | input.request.operation == "CREATE" 10 | input.request.kind.kind == "Deployment" 11 | container := input.request.object.spec.template.spec.containers[_].securityContext 12 | addedcap := {cap | cap := container.capabilities.add[_]} 13 | unauthcapabilities := addedcap - authorizedcapabilities 14 | count(unauthcapabilities) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("Deployment with containers using unauthorized capabilities identified in %v", [name]) 17 | } 18 | 19 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/additionalcapabilities-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers that run unauthorized additional capabilities 2 | # Description: This policy identifies Pods with containers that run unauthorized additional capabilities 3 | 4 | 5 | 6 | authorizedcapabilities = {"AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD","NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP","SETUID", "SYS_CHROOT"} 7 | 8 | match[{"msg": msg}] { 9 | input.request.operation == "CREATE" 10 | input.request.kind.kind == "Pod" 11 | container := input.request.object.spec.containers[_].securityContext 12 | addedcap := {cap | cap := container.capabilities.add[_]} 13 | unauthcapabilities := addedcap - authorizedcapabilities 14 | count(unauthcapabilities) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("Pod with containers using unauthorized capabilities identified in %v", [name]) 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/additionalcapabilities-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with containers that run unauthorized additional capabilities 2 | # Description: This policy identifies StatefulSets with containers that run unauthorized additional capabilities 3 | 4 | 5 | 6 | authorizedcapabilities = {"AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD","NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP","SETUID", "SYS_CHROOT"} 7 | 8 | match[{"msg": msg}] { 9 | input.request.operation == "CREATE" 10 | input.request.kind.kind == "StatefulSet" 11 | container := input.request.object.spec.template.spec.containers[_].securityContext 12 | addedcap := {cap | cap := container.capabilities.add[_]} 13 | unauthcapabilities := addedcap - authorizedcapabilities 14 | count(unauthcapabilities) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("StatefulSet with containers using unauthorized capabilities identified in %v", [name]) 17 | } 18 | 19 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/allowedVolumeTypes-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - DaemonSet with containers that use disallowed volume types 2 | # Description: This policy identifies DaemonSets with containers that use disallowed volume types 3 | 4 | # Below are the allowed volume types as mentioned in the Kubernetes documentation 5 | allowedVolumeTypes = {"configMap", "csi", "downwardAPI", "emptyDir","ephemeral","persistentVolumeClaim","projected", "secret"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "DaemonSet" 10 | container := input.request.object.spec.template.spec 11 | volume_fields := {x | container.volumes[_][x]; x != "name"} 12 | notAllowedVolumes := volume_fields - allowedVolumeTypes 13 | count(notAllowedVolumes) != 0 14 | name := input.request.object.metadata.annotations 15 | msg := sprintf("DaemonSet with containers using disallowed volume types identified in %v", [name]) 16 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/allowedVolumeTypes-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Deployment with containers that use disallowed volume types 2 | # Description: This policy identifies Deployments with containers that use disallowed volume types 3 | 4 | # Below are the allowed volume types as mentioned in the Kubernetes documentation 5 | allowedVolumeTypes = {"configMap", "csi", "downwardAPI", "emptyDir","ephemeral","persistentVolumeClaim","projected", "secret"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "Deployment" 10 | container := input.request.object.spec.template.spec 11 | volume_fields := {x | container.volumes[_][x]; x != "name"} 12 | notAllowedVolumes := volume_fields - allowedVolumeTypes 13 | count(notAllowedVolumes) != 0 14 | name := input.request.object.metadata.annotations 15 | msg := sprintf("Deployment with containers using disallowed volume types identified in %v", [name]) 16 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/allowedVolumeTypes-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Pod with containers that use disallowed volume types 2 | # Description: This policy identifies Pods with containers that use disallowed volume types 3 | 4 | # Below are the allowed volume types as mentioned in the Kubernetes documentation 5 | allowedVolumeTypes = {"configMap", "csi", "downwardAPI", "emptyDir","ephemeral","persistentVolumeClaim","projected", "secret"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "Pod" 10 | container := input.request.object.spec 11 | volume_fields := {x | container.volumes[_][x]; x != "name"} 12 | notAllowedVolumes := volume_fields - allowedVolumeTypes 13 | count(notAllowedVolumes) != 0 14 | name := input.request.object.metadata.annotations 15 | msg := sprintf("Pod with containers using disallowed volume types identified in %v", [name]) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/allowedVolumeTypes-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - StatefulSet with containers that use disallowed volume types 2 | # Description: This policy identifies StatefulSets with containers that use disallowed volume types 3 | 4 | 5 | # Below are the allowed volume types as mentioned in the Kubernetes documentation 6 | allowedVolumeTypes = {"configMap", "csi", "downwardAPI", "emptyDir","ephemeral","persistentVolumeClaim","projected", "secret"} 7 | 8 | match[{"msg": msg}] { 9 | input.request.operation == "CREATE" 10 | input.request.kind.kind == "StatefulSet" 11 | container := input.request.object.spec.template.spec 12 | volume_fields := {x | container.volumes[_][x]; x != "name"} 13 | notAllowedVolumes := volume_fields - allowedVolumeTypes 14 | count(notAllowedVolumes) != 0 15 | name := input.request.object.metadata.annotations 16 | msg := sprintf("StatefulSet with containers using disallowed volume types identified in %v", [name]) 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/appArmor-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with containers that use unauthorized AppArmor profiles 2 | # Description: This policy identifies DaemonSets with containers that use unauthorized AppArmor profiles 3 | 4 | allowed_profile_types = {"runtime", "localhost"} 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "DaemonSet" 8 | container := input.request.object.spec.template.spec 9 | containerNames := container.containers 10 | profileName := {name | name := input.request.object.spec.template.metadata.annotations[sprintf("container.apparmor.security.beta.kubernetes.io/%v",[containerNames[_].name])]} 11 | names := profileName[_] 12 | profiles := {i | i := split(names, "/")[0]} 13 | disallowedProfiles := profiles - allowed_profile_types 14 | count(disallowedProfiles) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("DaemonSet with containers using unauthorized AppArmor profiles identified in: %v", [name]) 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/appArmor-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with containers that use unauthorized AppArmor profiles 2 | # Description: This policy identifies Deployments with containers that use unauthorized AppArmor profiles 3 | 4 | allowed_profile_types = {"runtime", "localhost"} 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Deployment" 8 | container := input.request.object.spec.template.spec 9 | containerNames := container.containers 10 | profileName := {name | name := input.request.object.spec.template.metadata.annotations[sprintf("container.apparmor.security.beta.kubernetes.io/%v",[containerNames[_].name])]} 11 | names := profileName[_] 12 | profiles := {i | i := split(names, "/")[0]} 13 | disallowedProfiles := profiles - allowed_profile_types 14 | count(disallowedProfiles) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("Deployment with containers using unauthorized AppArmor profiles identified in: %v", [name]) 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/appArmor-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers that use unauthorized AppArmor profiles 2 | # Description: This policy identifies Pods with containers that use unauthorized AppArmor profiles 3 | 4 | allowed_profile_types = {"runtime", "localhost"} 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Pod" 8 | container := input.request.object.spec 9 | containerNames := container.containers 10 | profileName := {name | name := input.request.object.metadata.annotations[sprintf("container.apparmor.security.beta.kubernetes.io/%v",[containerNames[_].name])]} 11 | names := profileName[_] 12 | profiles := {i | i := split(names, "/")[0]} 13 | disallowedProfiles := profiles - allowed_profile_types 14 | count(disallowedProfiles) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("Pod with containers using unauthorized AppArmor profiles identified in: %v", [name]) 17 | } 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/appArmor-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with containers that use unauthorized AppArmor profiles 2 | # Description: This policy identifies StatefulSets with containers that use unauthorized AppArmor profiles 3 | 4 | allowed_profile_types = {"runtime", "localhost"} 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "StatefulSet" 8 | container := input.request.object.spec.template.spec 9 | containerNames := container.containers 10 | profileName := {name | name := input.request.object.spec.template.metadata.annotations[sprintf("container.apparmor.security.beta.kubernetes.io/%v",[containerNames[_].name])]} 11 | names := profileName[_] 12 | profiles := {i | i := split(names, "/")[0]} 13 | disallowedProfiles := profiles - allowed_profile_types 14 | count(disallowedProfiles) != 0 15 | name := input.request.object.metadata.name 16 | msg := sprintf("StatefulSet with containers using unauthorized AppArmor profiles identified in: %v", [name]) 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/capabilities-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Daemonset with containers that run with restricted capabilities 2 | # Description: This policy identifies Daemonsets with containers that run with restricted capabilities 3 | 4 | authorizedcapabilities = {"NET_BIND_SERVICE"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Daemonset" 9 | container := input.request.object.spec.template.spec.containers[_].securityContext 10 | addedcap := {cap | cap := container.capabilities.add[_]} 11 | unauthcapabilities := addedcap - authorizedcapabilities 12 | count(unauthcapabilities) != 0 13 | name := input.request.object.metadata.name 14 | msg := sprintf("Daemonset with containers using restricted/unauthorized capabilities identified in %v", [name]) 15 | } 16 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/capabilities-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Deployment with containers that run with restricted capabilities 2 | # Description: This policy identifies Deployments with containers that run with restricted capabilities 3 | 4 | authorizedcapabilities = {"NET_BIND_SERVICE"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Deployment" 9 | container := input.request.object.spec.template.spec.containers[_].securityContext 10 | addedcap := {cap | cap := container.capabilities.add[_]} 11 | unauthcapabilities := addedcap - authorizedcapabilities 12 | count(unauthcapabilities) != 0 13 | name := input.request.object.metadata.name 14 | msg := sprintf("Deployment with containers using restricted/unauthorized capabilities identified in %v", [name]) 15 | } 16 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/capabilities-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Pod with containers that run with restricted capabilities 2 | # Description: This policy identifies Pods with containers that run with restricted capabilities 3 | 4 | authorizedcapabilities = {"NET_BIND_SERVICE"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Pod" 9 | container := input.request.object.spec.containers[_].securityContext 10 | addedcap := {cap | cap := container.capabilities.add[_]} 11 | unauthcapabilities := addedcap - authorizedcapabilities 12 | count(unauthcapabilities) != 0 13 | name := input.request.object.metadata.name 14 | msg := sprintf("Pod with containers using restricted/unauthorized capability identified in %v", [name]) 15 | } 16 | 17 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/capabilities-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - StatefulSet with containers that run with restricted capabilities 2 | # Description: This policy identifies StatefulSets with containers that run with restricted capabilities 3 | 4 | authorizedcapabilities = {"NET_BIND_SERVICE"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "StatefulSet" 9 | container := input.request.object.spec.template.spec.containers[_].securityContext 10 | addedcap := {cap | cap := container.capabilities.add[_]} 11 | unauthcapabilities := addedcap - authorizedcapabilities 12 | count(unauthcapabilities) != 0 13 | name := input.request.object.metadata.name 14 | msg := sprintf("StatefulSet with containers using restricted/unauthorized capabilities identified in %v", [name]) 15 | } 16 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostipc-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with container that share host IPC namespace 2 | # Description: This admission rule identifies DaemonSets that run containers that share host IPC namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "DaemonSet" 7 | input.request.object.spec.template.spec.hostIPC == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("DaemonSet with container sharing host IPC is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostipc-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with container that share host IPC namespace 2 | # Description: This admission rule identifies Deployments that run containers that share host IPC namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Deployment" 7 | input.request.object.spec.template.spec.hostIPC == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("Deployment with container sharing host IPC is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostipc-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with container that share host IPC namespace 2 | # Description: This admission rule identifies Pods that run containers that share host IPC namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Pod" 7 | input.request.object.spec.hostIPC == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("Pod with container sharing host IPC is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostipc-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with container that share host IPC namespace 2 | # Description: This admission rule identifies StatefulSets that run containers that share host IPC namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "StatefulSet" 7 | input.request.object.spec.template.spec.hostIPC == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("StatefulSet with container sharing host IPC is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostnetwork-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet that allows containers to share the host network namespace 2 | # Description: This admission rule identifies DaemonSets that allow containers to share the host network namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "DaemonSet" 7 | input.request.object.spec.template.spec.hostNetwork == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("DaemonSet with container sharing host network namespace is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostnetwork-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment that allows containers to share the host network namespace 2 | # Description: This admission rule identifies deployments that allow containers to share the host network namespace 3 | 4 | 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Deployment" 9 | input.request.object.spec.template.spec.hostNetwork == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Deployment with container sharing host network namespace is identified in %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostnetwork-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod that allows containers to share the host network namespace 2 | # Description: This admission rule identifies Pods that allow containers to share the host network namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Pod" 7 | input.request.object.spec.hostNetwork == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("Pod with container sharing host network namespace is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostnetwork-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet that allows containers to share the host network namespace 2 | # Description: This admission rule identifies StatefulSets that allow containers to share the host network namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "StatefulSet" 7 | input.request.object.spec.template.spec.hostNetwork == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("StatefulSet with container sharing host network namespace is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpath-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet that run containers using HostPath volumes 2 | # Description: This admission rule identifies DaemonSets that run containers using HostPath volumes 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "DaemonSet" 7 | volume := input.request.object.spec.template.spec.volumes[_] 8 | volume.hostPath 9 | name := input.request.object.metadata.name 10 | msg := sprintf("DaemonSet with Host Path volume identified in %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpath-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment that run containers using HostPath volumes 2 | # Description: This admission rule identifies Deployment that run containers using HostPath volumes 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Deployment" 7 | volume := input.request.object.spec.template.spec.volumes[_] 8 | volume.hostPath 9 | name := input.request.object.metadata.name 10 | msg := sprintf("Deployment with Host Path volume identified in %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpath-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod that run containers using HostPath volumes 2 | # Description: This admission rule identifies Pods that run containers using HostPath volumes 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Pod" 7 | volume := input.request.object.spec.volumes[_] 8 | volume.hostPath 9 | name := input.request.object.metadata.name 10 | msg := sprintf("Pod with Host Path volume identified in %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpath-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSets that run containers using HostPath volumes 2 | # Description: This admission rule identifies StatefulSets that run containers using HostPath volumes 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "StatefulSet" 7 | volume := input.request.object.spec.template.spec.volumes[_] 8 | volume.hostPath 9 | name := input.request.object.metadata.name 10 | msg := sprintf("StatefulSet with Host Path volume identified in %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpid-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with containers that share host process ID(hostPID) namespace 2 | # Description: This admission rule identifies DaemonSets that run containers that share host process ID namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "DaemonSet" 7 | input.request.object.spec.template.spec.hostPID == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("DaemonSet with container sharing host process ID(hostPID) is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpid-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with containers that share host process ID(hostPID) namespace 2 | # Description: This admission rule identifies Deployments that run containers that share host process ID namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Deployment" 7 | input.request.object.spec.template.spec.hostPID == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("Deployment with container sharing host process ID(hostPID) is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpid-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers that share host process ID(hostPID) namespace 2 | # Description: This admission rule identifies Pods that run containers that share host process ID namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Pod" 7 | input.request.object.spec.hostPID == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("Pod with container sharing host process ID(hostPID) is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostpid-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with containers that share host process ID(hostPID) namespace 2 | # Description: This admission rule identifies StatefulSets that run containers that share host process ID namespace 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "StatefulSet" 7 | input.request.object.spec.template.spec.hostPID == true 8 | name := input.request.object.metadata.name 9 | msg := sprintf("StatefulSet with container sharing host process ID(hostPID) is identified in %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostport-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Daemonset that run containers with hostPorts 2 | # Description: The admission rule identifies Daemonset with container using hostPorts 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "DaemonSet" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | container.ports[_].hostPort 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Daemonset created with HostPort in: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostport-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment that run containers with hostPorts 2 | # Description: The admission rule identifies Deployments with container using hostPorts 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Deployment" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | container.ports[_].hostPort 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Deployment created with HostPort in: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostport-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod that run containers with hostPorts 2 | # Description: The admission rule identifies Pods with container using hostPorts 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Pod" 8 | input.request.object.spec.containers[_].ports[_].hostPort 9 | name := input.request.object.metadata.name 10 | msg := sprintf("Pod created with HostPort in: %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/hostport-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet that run containers with hostPorts 2 | # Description: The admission rule identifies StatefulSets with container using hostPorts 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "StatefulSet" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | container.ports[_].hostPort 10 | name := input.request.object.metadata.name 11 | msg := sprintf("StatefulSet created with HostPort in: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/imageregistryunauthorized-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with containers that using images from unauthorized registries 2 | # Description: This policy identifies DaemonSets with containers using images from unauthorized registries 3 | 4 | # In the below set, add allowed registry sources as needed 5 | allowed_sources := {"registry.example.com"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "DaemonSet" 10 | image := input.request.object.spec.template.spec.containers[_].image 11 | images := {i | i := split(image, "/")[0]} 12 | compliant_images := images - allowed_sources 13 | count(compliant_images) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("DaemonSet with container using images from unauthorized registry found in:: %v", [name]) 16 | 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/imageregistryunauthorized-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with containers that using images from unauthorized registries 2 | # Description: This policy identifies Deployments with containers using images from unauthorized registries 3 | 4 | # In the below set, add allowed registry sources as needed 5 | allowed_sources := {"registry.example.com"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "Deployment" 10 | image := input.request.object.spec.template.spec.containers[_].image 11 | images := {i | i := split(image, "/")[0]} 12 | compliant_images := images - allowed_sources 13 | count(compliant_images) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("Deployment with container using images from unauthorized registry found in:: %v", [name]) 16 | 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/imageregistryunauthorized-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers that using images from unauthorized registries 2 | # Description: This policy identifies pods with containers using images from unauthorized registries 3 | 4 | # In the below set, add allowed registry sources as needed 5 | allowed_sources := {"registry.example.com"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "Pod" 10 | image := input.request.object.spec.containers[_].image 11 | images := {i | src := allowed_sources[_] ; i := split(image, "/")[0]} 12 | compliant_images := images - allowed_sources 13 | count(compliant_images) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("Pod with container using images from unauthorized registry found in: %v", [name]) 16 | 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/imageregistryunauthorized-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with containers that using images from unauthorized registries 2 | # Description: This policy identifies StatefulSets with containers using images from unauthorized registries 3 | 4 | # In the below set, add allowed registry sources as needed 5 | allowed_sources := {"registry.example.com"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "StatefulSet" 10 | image := input.request.object.spec.template.spec.containers[_].image 11 | images := {i | i := split(image, "/")[0]} 12 | compliant_images := images - allowed_sources 13 | count(compliant_images) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("StatefulSet with container using images from unauthorized registry found in:: %v", [name]) 16 | 17 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/ingress-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Kubernetes Ingress without HTTPS traffic 2 | # Description: This admission rules identifies Ingress that allows traffic other than https protocol 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Ingress" 7 | not input.request.object.spec.tls 8 | name := input.request.object.metadata.name 9 | msg := sprintf("Ingress with HTTP Traffic created for: %v",[name]) 10 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/netraw-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod should not run containers with the NET_RAW capability 2 | # Description : This admission rule identifies pods that run containers with NET_RAW Capability 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Pod" 7 | container := input.request.object.spec.containers[_] 8 | capability := container.securityContext.capabilities.add[_] 9 | capability == "NET_RAW" 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Pod with NET_RAW capability identified in: %v",[name]) 12 | } 13 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/privileged-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet should not run privileged containers 2 | # Description: This admission rule identifies DaemonSets that creates privileged containers 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "DaemonSet" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | container.securityContext.privileged == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("DaemonSet with Privileged containers created in: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/privileged-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment should not run privileged containers 2 | # Description: This admission rule identifies deployments that creates privileged containers 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Deployment" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | container.securityContext.privileged == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Deployment with Privileged containers created in: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/privileged-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod should not run privileged containers 2 | # Description: This admission rule identifies Pods that creates privileged containers 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Pod" 8 | input.request.object.spec.containers[_] 9 | container.securityContext.privileged == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Pods with Privileged containers created in: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/privileged-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet should not run privileged containers 2 | # Description: This admission rule identifies StatefulSets that creates privileged containers 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "StatefulSet" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | container.securityContext.privileged == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("StatefulSet with Privileged containers created in: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/privilegeescalation-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - DeamonSet that allow container privilege escalation 2 | # Description: This admission rule identifies DeamonSets with container privilege escalation 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "DeamonSet" 7 | container := input.request.object.spec.template.spec.containers[_] 8 | container.securityContext.allowPrivilegeEscalation == true 9 | name := input.request.object.metadata.name 10 | msg := sprintf("DeamonSet with container with privilege escalation identified in %v",[name]) 11 | 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/privilegeescalation-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Deployment that allow container privilege escalation 2 | # Description: This admission rule identifies Deployments with container privilege escalation 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Deployment" 7 | container := input.request.object.spec.template.spec.containers[_] 8 | container.securityContext.allowPrivilegeEscalation == true 9 | name := input.request.object.metadata.name 10 | msg := sprintf("Deployment with container with privilege escalation identified in %v",[name]) 11 | 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/privilegeescalation-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Pod that allow container privilege escalation 2 | # Description: This admission rule identifies Pods with container privilege escalation 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Pod" 7 | container := input.request.object.spec.containers[_] 8 | container.securityContext.allowPrivilegeEscalation == true 9 | name := input.request.object.metadata.name 10 | msg := sprintf("Pod with container privilege escalation is identified in %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/privilegeescalation-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - StatefulSet that allow container privilege escalation 2 | # Description: This admission rule identifies StatefulSets with container privilege escalation 3 | 4 | 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "StatefulSet" 9 | container := input.request.object.spec.template.spec.containers[_] 10 | container.securityContext.allowPrivilegeEscalation == true 11 | name := input.request.object.metadata.name 12 | msg := sprintf("StatefulSet with container with privilege escalation identified in %v",[name]) 13 | 14 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/procmount-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSets that does not run containers with default proc mount 2 | # Description: This admission rule identifies DaemonSets with containers that does not use default proc mount 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "DaemonSet" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | procValue = container.securityContext.procMount 10 | procValue != "default" 11 | name := input.request.object.metadata.name 12 | msg := sprintf("DaemonSet with container without default proc mount identified in %v", [name]) 13 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/procmount-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment that does not run containers with default proc mount 2 | # Description: This admission rule identifies deployments with containers that does not use default proc mount 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Deployment" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | procValue = container.securityContext.procMount 10 | procValue != "default" 11 | name := input.request.object.metadata.name 12 | msg := sprintf("Deployment with container without default proc mount identified in %v", [name]) 13 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/procmount-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod that does not run containers with default proc mount 2 | # Description: This admission rule identifies Pods with containers that does not use default proc mount 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Pod" 8 | container := input.request.object.spec.containers[_] 9 | procValue = container.securityContext.procMount 10 | procValue != "default" 11 | name := input.request.object.metadata.name 12 | msg := sprintf("Pod with container without default proc mount identified in %v", [name]) 13 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/procmount-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSets that does not run containers with default proc mount 2 | # Description: This admission rule identifies StatefulSets with containers that does not use default proc mount 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "StatefulSet" 8 | container := input.request.object.spec.template.spec.containers[_] 9 | procValue = container.securityContext.procMount 10 | procValue != "default" 11 | name := input.request.object.metadata.name 12 | msg := sprintf("StatefulSet with container without default proc mount identified in %v", [name]) 13 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/root-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - DaemonSet with containers running as root 2 | # Description: This admission rule identifies DaemonSets that are running containers as root 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "DaemonSet" 8 | container = input.request.object.spec.template.spec.containers[_] 9 | container.securityContext.runAsNonRoot == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("DaemonSet with containers running as root identified for: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/root-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Deployment with containers running as root 2 | # Description: This admission rule identifies Deployment that are running containers as root 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Deployment" 8 | container = input.request.object.spec.template.spec.containers[_] 9 | container.securityContext.runAsNonRoot == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Deployment with containers running as root identified for: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/root-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Pod with containers running as root 2 | # Description: This admission rule identifies Pods that are running containers as root 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Pod" 8 | container = input.request.object.spec.containers[_] 9 | container.securityContext.runAsNonRoot == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("Pod with container running as root identified in pod %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/root-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - StatefulSet with containers running as root 2 | # Description: This admission rule identifies StatefulSets that are running containers as root 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "StatefulSet" 8 | container = input.request.object.spec.template.spec.containers[_] 9 | container.securityContext.runAsNonRoot == true 10 | name := input.request.object.metadata.name 11 | msg := sprintf("StatefulSet running containers as root identified for: %v",[name]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/rootuser-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - DaemonSet with containers running as root users 2 | # Description: This admission rule identifies DaemonSets that are running containers as root users 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "DaemonSet" 7 | container = input.request.object.spec.template.spec 8 | container.securityContext.runAsUser == 0 9 | name := input.request.object.metadata.name 10 | msg := sprintf("DaemonSet running containers with root user identified for: %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/rootuser-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Deployment with containers running as root users 2 | # Description: This admission rule identifies Deployments that are running containers as root users 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Deployment" 7 | container = input.request.object.spec.template.spec 8 | container.securityContext.runAsUser == 0 9 | name := input.request.object.metadata.name 10 | msg := sprintf("Deployment running containers with root user identified for: %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/rootuser-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Pod with containers running as root users 2 | # Description: This admission rule identifies Pods that are running containers as root users 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "Pod" 7 | container = input.request.object.spec 8 | container.securityContext.runAsUser == 0 9 | name := input.request.object.metadata.name 10 | msg := sprintf("Pod running containers with root user identified for: %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/rootuser-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - StatefulSet with containers running as root users 2 | # Description: This admission rule identifies StatefulSets that are running containers as root users 3 | 4 | match[{"msg": msg}] { 5 | input.request.operation == "CREATE" 6 | input.request.kind.kind == "StatefulSet" 7 | container = input.request.object.spec.template.spec 8 | container.securityContext.runAsUser == 0 9 | name := input.request.object.metadata.name 10 | msg := sprintf("StatefulSet running containers with root user identified for: %v",[name]) 11 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/seccomp-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with containers that use unauthorized seccomp profiles 2 | # Description: This policy identifies DaemonSets with containers using unauthorized seccomp profiles 3 | 4 | # Add authorized seccomp profiles here 5 | authorized_profile_types = {"profile1", "profile2"} 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "DaemonSet" 9 | container = input.request.object.spec.template.spec.securityContext 10 | localhost := container.seccompProfile.localhostProfile 11 | not authorized_profile_types[localhost] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("DaemonSet with containers using unauthorized seccomp profiles identified in %v", [name]) 14 | } 15 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/seccomp-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with containers that use unauthorized seccomp profiles 2 | # Description: This policy identifies Deployments with containers using unauthorized seccomp profiles 3 | 4 | # Add authorized seccomp profiles here 5 | authorized_profile_types = {"profile1", "profile2"} 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Deployment" 9 | container = input.request.object.spec.template.spec.securityContext 10 | localhost := container.seccompProfile.localhostProfile 11 | not authorized_profile_types[localhost] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("Deployment with containers using unauthorized seccomp profiles identified in %v", [name]) 14 | } 15 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/seccomp-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers that use unauthorized seccomp profiles 2 | # Description: This policy identifies Pods with containers using unauthorized seccomp profiles 3 | 4 | # Add authorized seccomp profiles here 5 | authorized_profile_types = {"profile1", "profile2"} 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Pod" 9 | container = input.request.object.spec.securityContext 10 | localhost := container.seccompProfile.localhostProfile 11 | not authorized_profile_types[localhost] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("Pod with containers using unauthorized seccomp profiles identified in %v", [name]) 14 | } 15 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/seccomp-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with containers that use unauthorized seccomp profiles 2 | # Description: This policy identifies StatefulSets with containers using unauthorized seccomp profiles 3 | 4 | # Add authorized seccomp profiles here 5 | authorized_profile_types = {"profile1", "profile2"} 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "StatefulSet" 9 | container = input.request.object.spec.template.spec.securityContext 10 | localhost := container.seccompProfile.localhostProfile 11 | not authorized_profile_types[localhost] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("StatefulSet with containers using unauthorized seccomp profiles identified in %v", [name]) 14 | } 15 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/secompprofilesunallowed-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - DaemonSet with containers that does not use allowed seccomp profiles 2 | # Description: This policy identifies DaemonSets with containers that does not use allowed secomp profiles. 3 | 4 | allowed_profile_types = {"RuntimeDefault", "Localhost"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "DaemonSet" 9 | container = input.request.object.spec.template.spec.securityContext 10 | proftype := container.seccompProfile.type 11 | not allowed_profile_types[proftype] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("DaemonSet with containers using not allowed seccomp profiles identified in %v", [name]) 14 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/secompprofilesunallowed-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Deployment with containers that does not use allowed seccomp profiles 2 | # Description: This policy identifies Deployments with containers that does not use allowed secomp profiles. 3 | 4 | allowed_profile_types = {"RuntimeDefault", "Localhost"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Deployment" 9 | container = input.request.object.spec.template.spec.securityContext 10 | proftype := container.seccompProfile.type 11 | not allowed_profile_types[proftype] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("Deployment with containers using not allowed seccomp profiles identified in %v", [name]) 14 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/secompprofilesunallowed-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - Pod with containers that does not use allowed seccomp profiles 2 | # Description: This policy identifies pods with containers that does not use allowed secomp profiles. 3 | 4 | allowed_profile_types = {"RuntimeDefault", "Localhost"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "Pod" 9 | container := input.request.object.spec.securityContext 10 | proftype := container.seccompProfile.type 11 | not allowed_profile_types[proftype] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("Pod with containers using not allowed seccomp profiles identified in %v", [name]) 14 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/secompprofilesunallowed-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Restricted - StatefulSet with containers that does not use allowed seccomp profiles 2 | # Description: This policy identifies StatefulSets with containers that does not use allowed secomp profiles. 3 | 4 | allowed_profile_types = {"RuntimeDefault", "Localhost"} 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind == "StatefulSet" 9 | container = input.request.object.spec.template.spec.securityContext 10 | proftype := container.seccompProfile.type 11 | not allowed_profile_types[proftype] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("StatefulSet with containers using not allowed seccomp profiles identified in %v", [name]) 14 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/secompruntimedefault-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers with seccomp profile that is not using RuntimeDefault 2 | # Description: This policy identifies pods with containers using seccomp profiles that are not RuntimeDefault 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind == "Pod" 8 | container := input.request.object.spec.securityContext 9 | not container.seccompProfile.type == "RuntimeDefault" 10 | localhostProfileType := container.seccompProfile.localhostProfile 11 | name := input.request.object.metadata.name 12 | msg := sprintf("Pod with container without runtimeDefault seccomp profile identified in %v", [localhostProfileType]) 13 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/selinux-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with containers using restricted SELinux options 2 | # Description: This policy identifies DaemonSets with containers using restricted SELinux options 3 | 4 | 5 | seLinuxOptionsTypes = {"container_t", "container_init_t", "container_kvm_t"} 6 | 7 | options_verify(seLinuxOptions){ 8 | not seLinuxOptionsTypes[seLinuxOptions.type] 9 | seLinuxOptions.user 10 | seLinuxOptions.role 11 | } 12 | match[{"msg": msg}] { 13 | input.request.operation == "CREATE" 14 | input.request.kind.kind == "DaemonSet" 15 | container := input.request.object.spec.template.spec.containers[_].securityContext.seLinuxOptions 16 | not options_verify(container) 17 | name := input.request.object.metadata.name 18 | msg := sprintf("DaemonSet with containers using restricted SELinuxOptions identified in %v", [name]) 19 | } 20 | 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/selinux-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with containers using restricted SELinux options 2 | # Description: This policy identifies Deployments with containers using restricted SELinux options 3 | 4 | 5 | seLinuxOptionsTypes = {"container_t", "container_init_t", "container_kvm_t"} 6 | 7 | options_verify(seLinuxOptions){ 8 | not seLinuxOptionsTypes[seLinuxOptions.type] 9 | seLinuxOptions.user 10 | seLinuxOptions.role 11 | } 12 | match[{"msg": msg}] { 13 | input.request.operation == "CREATE" 14 | input.request.kind.kind == "Deployment" 15 | container := input.request.object.spec.template.spec.containers[_].securityContext.seLinuxOptions 16 | not options_verify(container) 17 | name := input.request.object.metadata.name 18 | msg := sprintf("Deployment with containers using restricted SELinuxOptions identified in %v", [name]) 19 | } 20 | 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/selinux-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers using restricted SELinux options 2 | # Description: This policy identifies pods with containers using restricted SELinux options 3 | 4 | 5 | seLinuxOptionsTypes = {"container_t", "container_init_t", "container_kvm_t"} 6 | 7 | options_verify(seLinuxOptions){ 8 | not seLinuxOptionsTypes[seLinuxOptions.type] 9 | seLinuxOptions.user 10 | seLinuxOptions.role 11 | } 12 | match[{"msg": msg}] { 13 | input.request.operation == "CREATE" 14 | input.request.kind.kind == "Pod" 15 | container := input.request.object.spec.containers[_].securityContext.seLinuxOptions 16 | not options_verify(container) 17 | name := input.request.object.metadata.name 18 | msg := sprintf("Pod with containers using restricted SELinuxOptions identified in %v", [name]) 19 | } 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/selinux-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with containers using restricted SELinux options 2 | # Description: This policy identifies StatefulSets with containers using restricted SELinux options 3 | 4 | 5 | seLinuxOptionsTypes = {"container_t", "container_init_t", "container_kvm_t"} 6 | 7 | options_verify(seLinuxOptions){ 8 | not seLinuxOptionsTypes[seLinuxOptions.type] 9 | seLinuxOptions.user 10 | seLinuxOptions.role 11 | } 12 | match[{"msg": msg}] { 13 | input.request.operation == "CREATE" 14 | input.request.kind.kind == "StatefulSet" 15 | container := input.request.object.spec.template.spec.containers[_].securityContext.seLinuxOptions 16 | not options_verify(container) 17 | name := input.request.object.metadata.name 18 | msg := sprintf("StatefulSet with containers using restricted SELinuxOptions identified in %v", [name]) 19 | } 20 | 21 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/sensitivehost-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment created with sensitive host file system mount 2 | # Description: This admission rule identifies Deployments with sensitive host file system mount 3 | 4 | 5 | match[{"msg": msg}] { 6 | input.request.operation == "CREATE" 7 | input.request.kind.kind = "Deployment" 8 | hostPath := input.request.object.spec.template.spec.volumes[_].hostPath.path 9 | res := [startswith(hostPath, "/etc"), startswith(hostPath, "/var"), hostPath == "/"] 10 | res[_] 11 | name := input.request.object.metadata.name 12 | msg := sprintf("Deployment with Sensitive host file system mount identified in %v",[name]) 13 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/sensitivehost-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod created with sensitive host file system mount 2 | # Description: This admission rule identifies Pods with sensitive host file system mount 3 | 4 | 5 | 6 | match[{"msg": msg}] { 7 | input.request.operation == "CREATE" 8 | input.request.kind.kind = "Pod" 9 | hostPath := input.request.object.spec.volumes[_].hostPath.path 10 | res := [startswith(hostPath, "/etc"), startswith(hostPath, "/var"), hostPath == "/"] 11 | res[_] 12 | name := input.request.object.metadata.name 13 | msg := sprintf("Pod with Sensitive host file system mount identified in %v",[name]) 14 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/sysctls-daemonset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - DaemonSet with containers that does not use safe sysctls 2 | # Description: This policy identifies DaemonSets with containers that does not use safe sysctls 3 | 4 | # Below are the safe sysctls as per Kubernetes documentation, sysctls can be removed/added as needed 5 | pssBaselineSysctls = {"Undefined", "nil","kernel.shm_rmid_forced","net.ipv4.ip_local_port_range","net.ipv4.ip_unprivileged_port_start","net.ipv4.tcp_syncookies", "net.ipv4.ping_group_range"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "DaemonSet" 10 | container := input.request.object.spec.template.spec 11 | containerSysctls := {sysctl | sysctl := container.securityContext.sysctls[_].name} 12 | unsafeSysctls := pssBaselineSysctls - containerSysctls 13 | count(unsafeSysctls) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("DaemonSet with containers using unsafe sysctls identified in %v", [name]) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/sysctls-deployment.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Deployment with containers that does not use safe sysctls 2 | # Description: This policy identifies Deployments with containers that does not use safe sysctls 3 | 4 | # Below are the safe sysctls as per Kubernetes documentation, sysctls can be removed/added as needed 5 | pssBaselineSysctls = {"Undefined", "nil","kernel.shm_rmid_forced","net.ipv4.ip_local_port_range","net.ipv4.ip_unprivileged_port_start","net.ipv4.tcp_syncookies", "net.ipv4.ping_group_range"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "Deployment" 10 | container := input.request.object.spec.template.spec 11 | containerSysctls := {sysctl | sysctl := container.securityContext.sysctls[_].name} 12 | unsafeSysctls := pssBaselineSysctls - containerSysctls 13 | count(unsafeSysctls) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("Deployment with containers using unsafe sysctls identified in %v", [name]) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /admission-controller/rego_rules/sysctls-pod.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - Pod with containers that does not use safe sysctls 2 | # Description: This policy identifies Pods with containers that does not use safe sysctls 3 | 4 | # Below are the safe sysctls as per Kubernetes documentation, sysctls can be removed/added as needed 5 | pssBaselineSysctls = {"kernel.shm_rmid_forced","net.ipv4.ip_local_port_range","net.ipv4.ip_unprivileged_port_start","net.ipv4.tcp_syncookies", "net.ipv4.ping_group_range"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "Pod" 10 | container := input.request.object.spec 11 | containerSysctls := {sysctl | sysctl := container.securityContext.sysctls[_].name} 12 | unsafeSysctls := containerSysctls - pssBaselineSysctls 13 | count(unsafeSysctls) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("Pod with containers using unsafe sysctls identified in %v", [name]) 16 | } -------------------------------------------------------------------------------- /admission-controller/rego_rules/sysctls-statefulset.rego: -------------------------------------------------------------------------------- 1 | # PolicyName: PSS - Baseline - StatefulSet with containers that does not use safe sysctls 2 | # Description: This policy identifies StatefulSets with containers that does not use safe sysctls 3 | 4 | # Below are the safe sysctls as per Kubernetes documentation, sysctls can be removed/added as needed 5 | pssBaselineSysctls = {"Undefined", "nil","kernel.shm_rmid_forced","net.ipv4.ip_local_port_range","net.ipv4.ip_unprivileged_port_start","net.ipv4.tcp_syncookies", "net.ipv4.ping_group_range"} 6 | 7 | match[{"msg": msg}] { 8 | input.request.operation == "CREATE" 9 | input.request.kind.kind == "StatefulSet" 10 | container := input.request.object.spec.template.spec 11 | containerSysctls := {sysctl | sysctl := container.securityContext.sysctls[_].name} 12 | unsafeSysctls := pssBaselineSysctls - containerSysctls 13 | count(unsafeSysctls) != 0 14 | name := input.request.object.metadata.name 15 | msg := sprintf("StatefulSet with containers using unsafe sysctls identified in %v", [name]) 16 | } 17 | 18 | -------------------------------------------------------------------------------- /admission-controller/rules/container-capabilities.rego: -------------------------------------------------------------------------------- 1 | # Matches when a container adds a specified capability 2 | 3 | match[{"msg": msg}] { 4 | spec := get_pod_spec(input.request.object) 5 | containers := array.concat(object.get(spec, "initContainers", []), object.get(spec, "containers", [])) 6 | container := containers[_] 7 | 8 | denied_capabilities := {"SYS_ADMIN", "NET_ADMIN"} 9 | 10 | present_capabilities := {container.securityContext.capabilities.add[_]} 11 | count(denied_capabilities & present_capabilities) > 0 12 | msg := sprintf("container '%v' is adding one of the following capabilities: %v", [container.name, concat(", ", denied_capabilities)]) 13 | } 14 | 15 | get_pod_spec(obj) = spec { 16 | obj.kind == "Pod" 17 | spec := obj.spec 18 | } { 19 | obj.kind == "CronJob" 20 | spec := obj.spec.jobTemplate.spec.template.spec 21 | } { 22 | obj.kind == "ReplicaSet" 23 | spec := obj.spec.template.spec 24 | } { 25 | obj.kind == "ReplicationController" 26 | spec := obj.spec.template.spec 27 | } { 28 | obj.kind == "Deployment" 29 | spec := obj.spec.template.spec 30 | } { 31 | obj.kind == "StatefulSet" 32 | spec := obj.spec.template.spec 33 | } { 34 | obj.kind == "DaemonSet" 35 | spec := obj.spec.template.spec 36 | } { 37 | obj.kind == "Job" 38 | spec := obj.spec.template.spec 39 | } 40 | -------------------------------------------------------------------------------- /admission-controller/rules/container-readonly.rego: -------------------------------------------------------------------------------- 1 | # Matches when a container in a pod does not have a read-only root filesystem 2 | 3 | match[{"msg": msg}] { 4 | operations := {"CREATE"} 5 | operations[input.request.operation] 6 | input.request.kind.kind == "Pod" 7 | 8 | containers := input.request.object.spec.containers[_] 9 | 10 | not containers.securityContext.readOnlyRootFilesystem 11 | msg := sprintf("container '%v' does not have a read only root filesystem", [containers.name]) 12 | } 13 | -------------------------------------------------------------------------------- /admission-controller/rules/image-source.rego: -------------------------------------------------------------------------------- 1 | # Matches when an image used in a pod is not from an allowed source 2 | # This is virtually a copycat of the trusted images feature 3 | # https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/compliance/trusted_images.html 4 | 5 | match[{"msg": msg}] { 6 | operations := {"CREATE"} 7 | operations[input.request.operation] 8 | input.request.kind.kind == "Pod" 9 | 10 | # Example of using list of allowed or expected items 11 | # See image-tag for an example of the opposite 12 | allowed_sources := {"registry.example.com"} 13 | image := input.request.object.spec.containers[_].image 14 | 15 | # Read as "add image to set if image starts with an allowed source" 16 | compliant_images := [i | src := allowed_sources[_] ; i := startswith(image, src)] 17 | not all(compliant_images) 18 | msg := sprintf("image '%v' is not from one of the following sources: %v", [image, concat(", ", allowed_sources)]) 19 | } 20 | -------------------------------------------------------------------------------- /admission-controller/rules/image-tag.rego: -------------------------------------------------------------------------------- 1 | # Matches when an image used in a pod use a specified tag or is not tagged 2 | 3 | match[{"msg": msg}] { 4 | operations := {"CREATE"} 5 | operations[input.request.operation] 6 | input.request.kind.kind == "Pod" 7 | 8 | # Example of using list of denied or anomalous items 9 | # See image-repo for an example of the opposite 10 | denied_tags := {"latest", "bad"} 11 | image := input.request.object.spec.containers[_].image 12 | 13 | # Read as "add image to set if image ends with a denied tag" 14 | noncompliant_images := [i | tag := denied_tags[_] ; i := endswith(image, concat(":", ["", tag]))] 15 | any(noncompliant_images) 16 | msg := sprintf("image '%v' is using one of the following tags: %v", [image, concat(", ", denied_tags)]) 17 | } 18 | 19 | match[{"msg": msg}] { 20 | operations := {"CREATE"} 21 | operations[input.request.operation] 22 | input.request.kind.kind == "Pod" 23 | 24 | image := input.request.object.spec.containers[_].image 25 | 26 | not re_match("^.+:[-._0-9A-Za-z]+$", image) 27 | msg := sprintf("image '%v' does not have a tag", [image]) 28 | } -------------------------------------------------------------------------------- /admission-controller/rules/namespace-creation.rego: -------------------------------------------------------------------------------- 1 | # Matches namespace creation events 2 | 3 | match[{"msg": msg}] { 4 | input.request.operation == "CREATE" 5 | input.request.kind.kind == "Namespace" 6 | 7 | msg := sprintf("namespace '%v' created", [input.request.object.metadata.name]) 8 | } 9 | -------------------------------------------------------------------------------- /admission-controller/rules/pod-label.rego: -------------------------------------------------------------------------------- 1 | # Matches when a pod does not have all specified labels 2 | 3 | match[{"msg": msg}] { 4 | operations := {"CREATE"} 5 | operations[input.request.operation] 6 | input.request.kind.kind == "Pod" 7 | 8 | pod_metadata := input.request.object.metadata 9 | present_labels := {label | pod_metadata.labels[label]} 10 | required_labels := {"env", "owner"} 11 | 12 | count(required_labels - present_labels) > 0 13 | msg := sprintf("pod '%v' is missing one or more of the following labels: %v", [pod_metadata.name, concat(", ", required_labels)]) 14 | } 15 | -------------------------------------------------------------------------------- /admission-controller/rules/service-external-ip.rego: -------------------------------------------------------------------------------- 1 | # Matches when a service uses an externalIP outside of the specified IP range 2 | 3 | match[{"msg": msg}] { 4 | operations := {"CREATE"} 5 | operations[input.request.operation] 6 | input.request.kind.kind == "Service" 7 | 8 | external_ip := input.request.object.spec.externalIPs[_] 9 | allowed_cidr := "35.35.35.0/24" 10 | 11 | not net.cidr_contains(allowed_cidr, external_ip) 12 | msg := sprintf("service '%v' has IP '%v'", [input.request.object.metadata.name, external_ip]) 13 | } 14 | -------------------------------------------------------------------------------- /admission-controller/rules/service-nodeport.rego: -------------------------------------------------------------------------------- 1 | # Matches when a service is of type NodePort 2 | 3 | match[{"msg": msg}] { 4 | operations := {"CREATE", "UPDATE"} 5 | operations[input.request.operation] 6 | input.request.kind.kind == "Service" 7 | 8 | input.request.object.spec.type == "NodePort" 9 | msg := sprintf("service '%v' is of type NodePort", [input.request.object.metadata.name]) 10 | } 11 | -------------------------------------------------------------------------------- /admission-controller/rules/suspicious-selfsubjectreview.rego: -------------------------------------------------------------------------------- 1 | # --- Exceptions Start --- # 2 | 3 | # Allow requests from certain users, e.g. "admin@company.com", "system:serviceaccount:my-priv-ns:my-priv-sa" 4 | allowed_users := [] 5 | # Allow requests from users in certain groups, e.g. "system:nodes" 6 | allowed_groups := [] 7 | # Allow requests from serviceaccounts in the kube-system namespace 8 | allow_kubesystem_serviceaccounts := false 9 | 10 | # --- Exceptions End --- # 11 | 12 | 13 | match[{"msg": msg}] { 14 | is_self_review(input.request.kind.kind) 15 | not_allowed_request(allowed_users, allowed_groups, allow_kubesystem_serviceaccounts, input.request.userInfo) 16 | user_suspicious[{"msg": msg}] 17 | } 18 | 19 | user_suspicious[{"msg": msg}] { 20 | startswith(input.request.userInfo.username, "system:serviceaccount:") 21 | msg := sprintf("Service account '%v' issued a suspicious %v request, querying its permissions", [input.request.userInfo.username, input.request.kind.kind]) 22 | } { 23 | startswith(input.request.userInfo.username, "system:node:") 24 | msg := sprintf("Node '%v' issued a suspicious %v request, querying its permissions", [input.request.userInfo.username, input.request.kind.kind]) 25 | } 26 | 27 | is_self_review(kind) { 28 | kind == "SelfSubjectAccessReview" 29 | } { 30 | kind == "SelfSubjectRulesReview" 31 | } 32 | 33 | not_allowed_request(allowed_users, allowed_groups, allow_kubesystem_serviceaccounts, userInfo) { 34 | not array_has_value(allowed_users, userInfo.username) 35 | groupNames := {grp | grp := userInfo.groups[_]} 36 | allowedGroupNames := {grp | grp := allowed_groups[_]} 37 | matching := groupNames & allowedGroupNames 38 | count(matching) == 0 39 | not allowed_kubesystem_sa(allow_kubesystem_serviceaccounts, userInfo.username) 40 | } 41 | 42 | allowed_kubesystem_sa(allow_kubesystem_serviceaccounts, username) { 43 | allow_kubesystem_serviceaccounts 44 | startswith(username, "system:serviceaccount:kube-system:") 45 | } 46 | 47 | array_has_value(arr, val) { 48 | arr_val := arr[_] 49 | val == arr_val 50 | } 51 | -------------------------------------------------------------------------------- /admission-controller/rules/user-group.rego: -------------------------------------------------------------------------------- 1 | # Matches when the user is a member of a specified group 2 | 3 | match[{"msg": msg}] { 4 | operations := {"CREATE"} 5 | operations[input.request.operation] 6 | 7 | denied_groups := {"group1", "group2"} 8 | present_groups := input.request.userInfo.groups[_] 9 | 10 | count(denied_users & present_groups) > 0 11 | msg := sprintf("a member of one of the following groups created resource: %v", [concat(", ", denied_groups)]) 12 | } -------------------------------------------------------------------------------- /admission-controller/rules/user-name.rego: -------------------------------------------------------------------------------- 1 | # Matches when the user is a specified user 2 | 3 | match[{"msg": msg}] { 4 | operations := {"CREATE"} 5 | operations[input.request.operation] 6 | 7 | denied_users := {"user1", "user2"} 8 | user := {input.request.userInfo.username} 9 | 10 | count(denied_users & user) == 1 11 | msg := sprintf("user %v created resource", [concat("", user)]) 12 | } -------------------------------------------------------------------------------- /api/backups/README.md: -------------------------------------------------------------------------------- 1 | # Backup 2 | 3 | Python script that wraps all backup API endpoints. 4 | -------------------------------------------------------------------------------- /api/backups/runner.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | 4 | 5 | def login_api(): 6 | global prisma_token 7 | global base_url 8 | 9 | base_url = '' # fill in URL for talking to Compute Console 10 | 11 | login_info_hash = { 12 | 'username': '', #access key or username 13 | 'password': '' #access key secret or password 14 | } 15 | headers = {'Content-Type': 'application/json'} 16 | 17 | login_info = json.dumps(login_info_hash) 18 | #had to add verify=False due to PyCharm 19 | response_json = requests.post(base_url + '/api/v1/authenticate', login_info, headers=headers, verify=False) 20 | 21 | prisma_token = response_json.json()['token'] 22 | 23 | auth_headers = {'Content-Type': 'application/json', 24 | 'Authorization': 'Bearer ' + prisma_token} 25 | return auth_headers 26 | 27 | def list_backups(auth_headers): 28 | # List all known backups (including built-in backups) 29 | url = '/api/v1/backups' 30 | response = requests.get(base_url + url, headers=auth_headers, verify=False) 31 | count=0 32 | print ("Backups:") 33 | for backup in response.json(): 34 | print("Name: {}".format(backup['name'])) 35 | print("Release: {}".format(backup['release'])) 36 | print("Time: {}".format(backup['time'])) 37 | print("Id: {}\n".format(backup['id'])) 38 | count +=1 39 | print ("Total backups: {}".format(count)) 40 | 41 | 42 | def create_backup(auth_headers): 43 | #Create backup with name: eddie_test2 44 | url = '/api/v1/backups' 45 | payload = '"eddie_test2"' #name of backup file 46 | response = requests.post(base_url + url, data=payload, headers=auth_headers, verify=False) 47 | print (response.json()) 48 | 49 | def download_backup(auth_headers): 50 | url = '/api/v1/backups/' 51 | id = 'eddie_test2-20.04.177-1594329052.tar.gz' #id which is the file name set when a backup is run 52 | response = requests.get(base_url + url + id, headers=auth_headers, verify=False) 53 | filename = id 54 | print(filename) 55 | with open(filename, 'wb') as f: 56 | f.write(response.content) 57 | 58 | def delete_backup(auth_headers): 59 | url = '/api/v1/backups/' 60 | id = 'eddie_test2-20.04.177-1594329089.tar.gz' #id aka filename to delete 61 | response = requests.delete(base_url + url + id, headers=auth_headers, verify=False) 62 | print(response.status_code) 63 | 64 | if __name__ == '__main__': 65 | auth_headers=login_api() 66 | list_backups(auth_headers) 67 | create_backup(auth_headers) 68 | download_backup(auth_headers) 69 | delete_backup(auth_headers) 70 | -------------------------------------------------------------------------------- /api/cve-tags/tags.csv: -------------------------------------------------------------------------------- 1 | tag,cve,packageName,comment,timeAdded 2 | testing-High,CVE-2020-12243,openldap,, 3 | testing-Critical,CVE-2020-12399,nss,My comment, 4 | -------------------------------------------------------------------------------- /api/log4j/.gitignore: -------------------------------------------------------------------------------- 1 | env -------------------------------------------------------------------------------- /api/log4j/README.md: -------------------------------------------------------------------------------- 1 | # How to use this script 2 | 3 | ## Authentication 4 | 5 | Create an access key from Settings then Access key 6 | Get the path to console from Compute tab, System, Utilities 7 | 8 | Create a file into home directory .prismacloud/credentials.json with the following structure 9 | 10 | ```json 11 | { 12 | "pcc_api_endpoint": "__REDACTED__", 13 | "access_key_id": "__REDACTED__", 14 | "secret_key": "__REDACTED__" 15 | } 16 | ``` 17 | 18 | ## Setup 19 | 20 | Create Python virtual environment 21 | 22 | ```console 23 | cd api/log4j 24 | python3 -m venv env 25 | source env/bin/activate 26 | pip install requests 27 | ``` 28 | 29 | 30 | ## Run the script 31 | 32 | ```console 33 | python3 registry_log4j.py 34 | ``` 35 | 36 | It should generate a CSV file with all the licenses per package. -------------------------------------------------------------------------------- /api/log4j/impacted_log4j.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | import os 4 | import requests 5 | from re import search 6 | 7 | def getData(base_url, token, image_id = None): 8 | CVE="CVE-2021-44228" 9 | 10 | url = "https://%s/api/v1/stats/vulnerabilities/impacted-resources?cve=%s" % ( base_url ,CVE) 11 | 12 | headers = {"content-type": "application/json; charset=UTF-8", 'Authorization': 'Bearer ' + token } 13 | response = requests.get(url, headers=headers) 14 | 15 | items = response.json() 16 | 17 | if items: 18 | for item in items["riskTree"]: 19 | image=items["riskTree"][item] 20 | for i in image: 21 | #print(i) 22 | print("Image={};Container={};Host={};".format(i["image"],i["container"],i["host"])) 23 | 24 | 25 | def login(base_url, access_key, secret_key): 26 | url = "https://%s/api/v1/authenticate" % ( base_url ) 27 | 28 | payload = json.dumps({ 29 | "username": access_key, 30 | "password": secret_key 31 | }) 32 | headers = {"content-type": "application/json; charset=UTF-8"} 33 | response = requests.post(url, headers=headers, data=payload) 34 | return response.json()["token"] 35 | 36 | def getParamFromJson(config_file): 37 | f = open(config_file,) 38 | params = json.load(f) 39 | pcc_api_endpoint = params["pcc_api_endpoint"] 40 | access_key_id = params["access_key_id"] 41 | secret_key = params["secret_key"] 42 | # Closing file 43 | f.close() 44 | return pcc_api_endpoint, access_key_id, secret_key; 45 | 46 | def main(): 47 | CONFIG_FILE= os.environ['HOME'] + "/.prismacloud/credentials.json" 48 | PCC_API_ENDPOINT, ACCESS_KEY_ID, SECRET_KEY = getParamFromJson(CONFIG_FILE) 49 | token = login(PCC_API_ENDPOINT, ACCESS_KEY_ID, SECRET_KEY) 50 | 51 | getData(PCC_API_ENDPOINT, token) 52 | 53 | if __name__ == "__main__": 54 | main() -------------------------------------------------------------------------------- /api/log4j/prisma_cloud_log4j.py: -------------------------------------------------------------------------------- 1 | __author__ = "Simon Melotte" 2 | 3 | import json 4 | import os 5 | import requests 6 | from re import search 7 | 8 | def getLicenses(base_url, token, image_id = None): 9 | if (image_id): 10 | url = "https://%s/api/v1/images?id=%s" % ( base_url, image_id ) 11 | else: 12 | url = "https://%s/api/v1/images" % ( base_url ) 13 | 14 | headers = {"content-type": "application/json; charset=UTF-8", 'Authorization': 'Bearer ' + token } 15 | response = requests.get(url, headers=headers) 16 | images = response.json() 17 | 18 | 19 | csv = open("applications-running-log4j.csv", "w") 20 | csv.write("Image;Id;Namespace;osDistro;Package;License\n") 21 | 22 | for image in images: 23 | for pkgs in image["packages"]: 24 | for pkg in pkgs["pkgs"]: 25 | if ("log4j" in pkg['name']): 26 | csv.write("{};{};{};{};{};{}\n".format(image['instances'][0]['image'], image['_id'], image['namespaces'], image['installedProducts']['osDistro'], pkg['name'], pkg['license']) ) 27 | print("Image={}, id={}, Namespace={}, osDistro={}, Package={}, License={}".format(image['instances'][0]['image'], image['_id'], image['namespaces'], image['installedProducts']['osDistro'], pkg['name'], pkg['license']) ) 28 | 29 | 30 | 31 | csv.close() 32 | 33 | def login(base_url, access_key, secret_key): 34 | url = "https://%s/api/v1/authenticate" % ( base_url ) 35 | 36 | payload = json.dumps({ 37 | "username": access_key, 38 | "password": secret_key 39 | }) 40 | headers = {"content-type": "application/json; charset=UTF-8"} 41 | response = requests.post(url, headers=headers, data=payload) 42 | return response.json()["token"] 43 | 44 | def getParamFromJson(config_file): 45 | f = open(config_file,) 46 | params = json.load(f) 47 | pcc_api_endpoint = params["pcc_api_endpoint"] 48 | access_key_id = params["access_key_id"] 49 | secret_key = params["secret_key"] 50 | # Closing file 51 | f.close() 52 | return pcc_api_endpoint, access_key_id, secret_key; 53 | 54 | def main(): 55 | CONFIG_FILE= os.environ['HOME'] + "/.prismacloud/credentials.json" 56 | PCC_API_ENDPOINT, ACCESS_KEY_ID, SECRET_KEY = getParamFromJson(CONFIG_FILE) 57 | token = login(PCC_API_ENDPOINT, ACCESS_KEY_ID, SECRET_KEY) 58 | getLicenses(PCC_API_ENDPOINT, token) 59 | #getLicenses(PCC_API_ENDPOINT, token, "sha256:07a2849f2f074010c643bf04305e462515d1b9a3615d578b4365f46a005721e3") 60 | 61 | if __name__ == "__main__": 62 | main() -------------------------------------------------------------------------------- /api/log4j/registry_log4j.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | import os 4 | import requests 5 | from re import search 6 | 7 | def getData(base_url, token, image_id = None): 8 | 9 | url = "https://%s/api/v1/registry?limit=0" % ( base_url ) 10 | 11 | headers = {"content-type": "application/json; charset=UTF-8", 'Authorization': 'Bearer ' + token } 12 | response = requests.get(url, headers=headers) 13 | totalCount=response.headers["Total-Count"] 14 | print("Total Images in Registry = {}".format(totalCount) ) 15 | 16 | CVE="CVE-2021-44228" 17 | regex="log4j" 18 | offset=0 19 | limit=50 20 | items = True 21 | 22 | 23 | while items: 24 | 25 | url = "https://%s/api/v1/registry?limit=%s&offset=%s" % ( base_url,limit,offset ) 26 | print(url) 27 | offset=offset+limit 28 | response = requests.get(url, headers=headers) 29 | 30 | items = response.json() 31 | 32 | if items: 33 | 34 | for image in items: 35 | if image["vulnerabilities"] != None: 36 | for vulns in image["vulnerabilities"]: 37 | if vulns["cve"] == CVE: 38 | print("Image={}".format(image['instances'][0]['image']) ) 39 | for packags in image["packages"]: 40 | for pkgs in packags["pkgs"]: 41 | if "path" in pkgs and regex in pkgs["path"]: 42 | print("Path={};Version={};".format(pkgs["path"],pkgs["version"])) 43 | 44 | 45 | def login(base_url, access_key, secret_key): 46 | url = "https://%s/api/v1/authenticate" % ( base_url ) 47 | 48 | payload = json.dumps({ 49 | "username": access_key, 50 | "password": secret_key 51 | }) 52 | headers = {"content-type": "application/json; charset=UTF-8"} 53 | response = requests.post(url, headers=headers, data=payload) 54 | return response.json()["token"] 55 | 56 | def getParamFromJson(config_file): 57 | f = open(config_file,) 58 | params = json.load(f) 59 | pcc_api_endpoint = params["pcc_api_endpoint"] 60 | access_key_id = params["access_key_id"] 61 | secret_key = params["secret_key"] 62 | # Closing file 63 | f.close() 64 | return pcc_api_endpoint, access_key_id, secret_key; 65 | 66 | def main(): 67 | CONFIG_FILE= os.environ['HOME'] + "/.prismacloud/credentials.json" 68 | PCC_API_ENDPOINT, ACCESS_KEY_ID, SECRET_KEY = getParamFromJson(CONFIG_FILE) 69 | token = login(PCC_API_ENDPOINT, ACCESS_KEY_ID, SECRET_KEY) 70 | 71 | getData(PCC_API_ENDPOINT, token) 72 | 73 | if __name__ == "__main__": 74 | main() -------------------------------------------------------------------------------- /cicd/README.md: -------------------------------------------------------------------------------- 1 | # CI platform integrations 2 | 3 | As you browse these subdirectories, you may notice a common theme with the examples: most of them are wrappers around [`twistcli`'s](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/tools/twistcli_scan_images.html) scanning functions. 4 | 5 | `twistcli` is a statically-built program that can scan hosts, container images, serverless functions, and IaC files. 6 | Because of this, dropping it into a build pipeline is generally as simple as pulling it from your Prisma Cloud Compute Console's API, making it executable, and running it. 7 | Furthermore, many pipelines share a similar syntax, so adapting one of these examples to a platform not covered here may be relatively straightforward. 8 | 9 | If there are any platforms or use cases not covered here that are important to you and you feel should be represented, please feel free to open an issue or pull request. 10 | -------------------------------------------------------------------------------- /cicd/aws-devops/README.md: -------------------------------------------------------------------------------- 1 | # AWS DevOps (CodePipeline and CodeBuild) 2 | 3 | Prisma Cloud has an [AWS DevOps extension](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin/prisma-cloud-devops-security/use-the-prisma-cloud-extension-for-aws-devops.html) that covers scanning IaC templates and container images. 4 | -------------------------------------------------------------------------------- /cicd/azure-devops/azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Docker 2 | # Build a Docker image 3 | # https://docs.microsoft.com/azure/devops/pipelines/languages/docker 4 | 5 | trigger: 6 | - main 7 | 8 | resources: 9 | - repo: self 10 | 11 | variables: 12 | tag: 'latest' 13 | image_name: 'testimg' 14 | PCC_USER: '' 15 | PCC_PASS: '' 16 | PCC_CONSOLE_URL: '' 17 | 18 | stages: 19 | - stage: PrismaComputeScan 20 | displayName: Prisma Compute Scan 21 | jobs: 22 | 23 | - job: ComputeScan 24 | displayName: Compute Scan 25 | pool: 26 | vmImage: 'ubuntu-latest' 27 | steps: 28 | 29 | - task: CmdLine@2 30 | inputs: 31 | script: | 32 | mkdir testimg 33 | touch testimg/Dockerfile 34 | echo "FROM adoptopenjdk/openjdk11-openj9:jre-11.0.11_9_openj9-0.26.0-alpine 35 | 36 | # Map to host user with specified group with its uid:guid 37 | ARG USER_ID=5050 38 | ARG GROUP_ID=5050 39 | 40 | #RUN addgroup -S spring && adduser -S spring -G spring 41 | RUN apk update && apk upgrade && apk add --no-cache jq tzdata && addgroup -g 5050 spring && adduser -S -u 5050 -g spring spring && install -d -m 0755 -o spring -g spring /home/spring 42 | USER spring:spring 43 | ENV TZ=America/Chicago" > testimg/Dockerfile 44 | echo $(image_name) 45 | echo Tag 46 | echo $(tag) 47 | cat testimg/Dockerfile 48 | 49 | - task: Docker@2 50 | displayName: Build an image 51 | inputs: 52 | command: 'build' 53 | Dockerfile: 'testimg/Dockerfile' 54 | repository: $(image_name) 55 | tags: | 56 | $(tag) 57 | 58 | - task: CmdLine@2 59 | inputs: 60 | script: | 61 | echo Image name 62 | echo $(image_name) 63 | echo Tag 64 | echo $(tag) 65 | 66 | - task: CmdLine@2 67 | inputs: 68 | script: | 69 | curl -k -u 3317/ -u $(PCC_USER):$(PCC_PASS) --output ./twistcli $(PCC_CONSOLE_URL)/api/v1/util/twistcli 70 | 71 | mkdir twistcli-scan 72 | mv ./twistcli twistcli-scan/twistcli 73 | chmod a+x twistcli-scan/twistcli 74 | 75 | ls twistcli-scan 76 | 77 | ./twistcli-scan/twistcli images scan --address $(PCC_CONSOLE_URL) -u $(PCC_USER) -p $(PCC_PASS) --details $(image_name):$(tag) 78 | displayName: 'Twistcli scan' 79 | -------------------------------------------------------------------------------- /cicd/buildkite/.buildkite/pipeline.yml: -------------------------------------------------------------------------------- 1 | env: 2 | USERNAME: "" 3 | PASSWORD: "" 4 | CONSOLE: "https://" 5 | APPNAME: "" 6 | 7 | steps: 8 | - command: "generate_token.sh" 9 | label: "Generate Token" 10 | 11 | - command: "download_twistcli.sh" 12 | label: "download twistcli" 13 | - command: "verify_twistcli.sh" 14 | label: "verify twistcli" 15 | - command: "build_docker.sh" 16 | label: "Build Docker image" 17 | - command: "scan_image.sh" 18 | label: "Scan image" 19 | - command: "cleanup.sh" 20 | label: "Cleanup Environment" 21 | -------------------------------------------------------------------------------- /cicd/buildkite/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | LABEL owner_email="email@example.com" 4 | LABEL product="sample" 5 | LABEL env="Dev" 6 | LABEL team="Team A" 7 | 8 | RUN apt-get update 9 | RUN apt-get -y install curl git nmap dnsutils 10 | CMD apt-get -y install httpd 11 | 12 | 13 | -------------------------------------------------------------------------------- /cicd/buildkite/README.md: -------------------------------------------------------------------------------- 1 | # Example of a buildkite pipeline for scanning docker images 2 | 3 | * Results of the scans will be vulnerability and compliance findings. 4 | * Update .buildkite/pipeline.yml with the Console credentials and address. -------------------------------------------------------------------------------- /cicd/buildkite/build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | docker build . -t $APPNAME:$BUILDKITE_BUILD_NUMBER 6 | 7 | -------------------------------------------------------------------------------- /cicd/buildkite/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | 6 | docker rmi $APPNAME:$BUILDKITE_BUILD_NUMBER 7 | -------------------------------------------------------------------------------- /cicd/buildkite/download_twistcli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | buildkite-agent artifact download token . 6 | 7 | TOKEN=`cat token` 8 | 9 | curl -vk -H "Authorization: Bearer $TOKEN" "$CONSOLE/api/v1/util/twistcli" > twistcli 10 | 11 | buildkite-agent artifact upload twistcli 12 | -------------------------------------------------------------------------------- /cicd/buildkite/generate_token.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | curl -sk -H "Content-Type: application/json" -d "{\"username\":\"$USERNAME\", \"password\":\"$PASSWORD\"}" $CONSOLE/api/v1/authenticate | jq -r .token > token 6 | 7 | buildkite-agent artifact upload token 8 | -------------------------------------------------------------------------------- /cicd/buildkite/scan_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | buildkite-agent artifact download twistcli . 6 | buildkite-agent artifact download token . 7 | 8 | TOKEN=`cat token` 9 | 10 | chmod u+x twistcli 11 | 12 | JOB_NAME="JobName" 13 | BUILD_ID="BuildName" 14 | NODE_NAME="NodeName" 15 | GIT_BRANCH="GITBranch" 16 | 17 | ./twistcli images scan --token $TOKEN --address $CONSOLE --details --output-file results.json --publish --custom-labels $APPNAME:$BUILDKITE_BUILD_NUMBER 18 | 19 | buildkite-agent artifact upload results.json 20 | -------------------------------------------------------------------------------- /cicd/buildkite/verify_twistcli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eu 4 | 5 | buildkite-agent artifact download twistcli . 6 | 7 | chmod u+x twistcli 8 | 9 | ./twistcli -v 10 | 11 | 12 | -------------------------------------------------------------------------------- /cicd/circleci/README.md: -------------------------------------------------------------------------------- 1 | # CircleCI 2 | 3 | Prisma Cloud has a [CircleCI orb](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin/prisma-cloud-devops-security/use-the-prisma-cloud-plugin-for-circleci.html) that covers scanning IaC templates and container images. 4 | -------------------------------------------------------------------------------- /cicd/codefresh/codefresh-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/codefresh-output.png -------------------------------------------------------------------------------- /cicd/codefresh/codefresh-yml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/codefresh-yml.png -------------------------------------------------------------------------------- /cicd/codefresh/codefresh.yml: -------------------------------------------------------------------------------- 1 | version: "1.0" 2 | 3 | steps: 4 | main_clone: 5 | title: Cloning repository 6 | type: git-clone 7 | repo: ${{CF_REPO_OWNER}}/${{CF_REPO_NAME}} 8 | revision: ${{CF_REVISION}} 9 | git: github 10 | 11 | # Dedicated twistcli step to ensure twistcli can be pulled (in case target image doesn't have wget). 12 | # Pulls twistcli to shared volume (the current work directory) which is automatically mounted in target image. 13 | get_twistcli: 14 | title: Pulling twistcli from Console 15 | image: alpine 16 | commands: 17 | - | 18 | wget --header "Authorization: Basic $(echo -n $PCC_USER:$PCC_PASS | base64 | tr -d '\n')" "$PCC_CONSOLE_URL/api/v1/util/twistcli" 19 | chmod a+x ./twistcli 20 | 21 | build_image: 22 | title: Building image 23 | type: build 24 | working_directory: . 25 | dockerfile: Dockerfile 26 | image_name: ${{CF_REPO_OWNER}}/${{CF_REPO_NAME}} 27 | tag: ${{CF_REVISION}} 28 | 29 | scan_image: 30 | title: Scanning image with Prisma Cloud Compute 31 | image: ${{build_image}} 32 | commands: 33 | # --containerized is used because Codefresh SaaS runtime environment doesn't allow access to the Docker socket 34 | # https://support.codefresh.io/hc/en-us/articles/360017901040-How-to-Access-the-Docker-Daemon-in-a-Codefresh-build 35 | - ./twistcli images scan --address $PCC_CONSOLE_URL --user $PCC_USER --password $PCC_PASS --containerized --details ${{steps.build_image.imageName}}:${{CF_REVISION}} 36 | -------------------------------------------------------------------------------- /cicd/codefresh/compute-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/compute-output.png -------------------------------------------------------------------------------- /cicd/codefresh/images/codefresh-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/images/codefresh-output.png -------------------------------------------------------------------------------- /cicd/codefresh/images/codefresh-yml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/images/codefresh-yml.png -------------------------------------------------------------------------------- /cicd/codefresh/images/compute-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/images/compute-output.png -------------------------------------------------------------------------------- /cicd/codefresh/images/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/images/variables.png -------------------------------------------------------------------------------- /cicd/codefresh/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/codefresh/variables.png -------------------------------------------------------------------------------- /cicd/gitlab/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | IMAGE_NAME: $CI_PROJECT_PATH:$CI_COMMIT_SHA 3 | 4 | image: docker:19.03 5 | services: 6 | - docker:19.03-dind 7 | 8 | # Jobs are ran independently from each other, so build and scan needs to be in a single job. 9 | build-and-scan: 10 | script: 11 | - | 12 | wget --header "Authorization: Basic $(echo -n $PCC_USER:$PCC_PASS | base64 | tr -d '\n')" "$PCC_CONSOLE_URL/api/v1/util/twistcli" 13 | chmod a+x ./twistcli 14 | docker build -t $IMAGE_NAME . 15 | ./twistcli images scan --docker-address http://docker:2375 --address $PCC_CONSOLE_URL --user $PCC_USER --password $PCC_PASS --details $IMAGE_NAME 16 | -------------------------------------------------------------------------------- /cicd/gitlab/README.md: -------------------------------------------------------------------------------- 1 | This directory contains an example of a basic [GitLab pipeline](https://docs.gitlab.com/ee/ci/pipelines/pipeline_architectures.html#basic-pipelines) that integrates container image scanning for vulnerabilities and compliance issues directly into GitLab. 2 | 3 | This example only builds an image using the Dockerfile at the repository's root and scans the resultant image. 4 | The intent is to demonstrate how `twistcli` may fit into your GitLab pipeline. 5 | 6 | ## Requirements 7 | To use this GitLab pipeline, you will need 8 | * a functional Prisma Cloud Compute Console that is reachable from a [GitLab runner](https://docs.gitlab.com/ee/ci/runners/README.html) 9 | * credentials for a Compute user ([CI User](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/authentication/user_roles.html) or [Build and Deploy Security](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/authentication/prisma_cloud_user_roles.html) role with "Only Access Key" selected is recommended) 10 | 11 | ## Setup 12 | 1. Create the variables used by the pipeline (`PCC_USER`, `PCC_PASS`, and `PCC_CONSOLE_URL`). 13 | See [GitLab's documentation](https://docs.gitlab.com/ee/ci/variables/README.html#create-a-custom-variable-in-the-ui) for instructions on how to create these. 14 | 15 | If you are using Prisma Cloud Compute Edition (self-hosted), `PCC_USER` and `PCC_PASS` will likely just be your normal username and password of the user with CI User role. 16 | `PCC_CONSOLE_URL` will be the address you use to access the Compute Console. 17 | 18 | If you are using Prisma Cloud Enterprise Edition (SaaS), `PCC_USER` and `PCC_PASS` will be your [access key and secret key](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/authentication/access_keys.html) pair created with the Build and Deploy Security role. 19 | `PCC_CONSOLE_URL` will be the address found at **Compute > Manage > System > Downloads** under the **Path to Console** heading. 20 | 21 | 22 | 23 | 2. Add the `.gitlab-ci.yml` file to the root of your repository. 24 | 25 | 26 | 27 | The image will be built, tagged, and scanned using `owner/repository:commit`. 28 | This is the image name under which the scan results will be displayed in the Compute Console. 29 | You can adjust this with the `IMAGE_NAME` variable in `.gitlab-ci.yml`. 30 | 31 | Here is a sample of the output in GitLab: 32 | 33 | 34 | 35 | 36 | ... and the corresponding output in Compute: 37 | 38 | 39 | The image scan policy (including failure thresholds) is managed in the Compute Console at 40 | * **Defend > Vulnerabilities > Images > CI** 41 | * **Defend > Compliance > Containers and images > CI** 42 | 43 | If you are using a self-signed certificate on the Compute Console, you may have to add `--no-check-certificate` to the `wget` command. 44 | For example: 45 | 46 | ```'wget --header "Authorization: Basic $(echo -n $PCC_USER:$PCC_PASS | base64 | tr -d '\n')" --no-check-certificate $PCC_CONSOLE_URL/api/v1/util/twistcli'``` 47 | -------------------------------------------------------------------------------- /cicd/gitlab/images/compute-output1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/gitlab/images/compute-output1.png -------------------------------------------------------------------------------- /cicd/gitlab/images/gitlab-ci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/gitlab/images/gitlab-ci.png -------------------------------------------------------------------------------- /cicd/gitlab/images/gitlab-output1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/gitlab/images/gitlab-output1.png -------------------------------------------------------------------------------- /cicd/gitlab/images/gitlab-output2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/gitlab/images/gitlab-output2.png -------------------------------------------------------------------------------- /cicd/gitlab/images/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/gitlab/images/variables.png -------------------------------------------------------------------------------- /cicd/jenkins/Jenkinsfile: -------------------------------------------------------------------------------- 1 | // Example declarative pipeline that utilizes the Prisma Cloud Compute plugin. 2 | // You can run as is this pipeline as is. 3 | // Commented-out stages are included as examples. 4 | 5 | pipeline { 6 | agent any 7 | environment { 8 | DOCKER_ADDR = 'unix:///var/run/docker.sock' 9 | IMAGE_NAME = 'ubuntu_test' 10 | REGISTRY_ADDR = 'my.registry.com' 11 | } 12 | 13 | stages{ 14 | // stage('Clone repository') { 15 | // checkout scm 16 | // } 17 | 18 | stage('Build image') { 19 | steps { 20 | // Remove the line below if you intend to checkout from a repository 21 | sh 'echo "FROM ubuntu:18.04\nLABEL env=dev" > Dockerfile' 22 | script { 23 | docker.withServer("${env.DOCKER_ADDR}") { 24 | image = docker.build("${env.IMAGE_NAME}:${env.BUILD_NUMBER}") 25 | } 26 | } 27 | } 28 | } 29 | 30 | stage('Scan image') { 31 | steps { 32 | // Scan policy is managed in the Compute Console 33 | prismaCloudScanImage ca: '', 34 | cert: '', 35 | dockerAddress: "${env.DOCKER_ADDR}", 36 | ignoreImageBuildTime: true, 37 | image: "${env.IMAGE_NAME}:${env.BUILD_NUMBER}", 38 | key: '', 39 | logLevel: 'debug', 40 | podmanPath: '', 41 | project: '', 42 | resultsFile: 'prisma_cloud_scan_results.json' 43 | } 44 | } 45 | 46 | stage('Test image') { 47 | steps { 48 | //Ideally, we would run a test framework against our image. 49 | script { 50 | docker.withServer("${env.DOCKER_ADDR}") { 51 | image.inside { 52 | sh 'echo "Tests passed"' 53 | } 54 | } 55 | } 56 | } 57 | } 58 | 59 | // stage('Push image') { 60 | // // Push image to registry with two tags: the build number and 'latest' 61 | // docker.withRegistry("${env.REGISTRY_ADDR}") { 62 | // image.push("${env.BUILD_NUMBER}") 63 | // image.push('latest') 64 | // } 65 | // } 66 | // } 67 | } 68 | 69 | post { 70 | always { 71 | // Always publish scan results, regardless of 72 | prismaCloudPublish resultsFilePattern: 'prisma_cloud_scan_results.json' 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /cicd/jenkins/README.md: -------------------------------------------------------------------------------- 1 | This directory contains an example declarative pipeline that uses our official Jenkins plugin. It is intended to show how the Prisma Cloud Compute steps may fit into a pipeline. 2 | 3 | You can find more examples of its usage in our [documentation](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/continuous_integration/jenkins_plugin.html). 4 | -------------------------------------------------------------------------------- /cicd/travis-ci/.travis.yml: -------------------------------------------------------------------------------- 1 | language: minimal 2 | 3 | services: 4 | - docker 5 | 6 | env: 7 | global: 8 | - IMAGE_NAME: "$TRAVIS_REPO_SLUG:$TRAVIS_COMMIT" 9 | 10 | script: 11 | - curl --user $PCC_USER:$PCC_PASS --output ./twistcli $PCC_CONSOLE_URL/api/v1/util/twistcli 12 | - chmod a+x ./twistcli 13 | - docker build -t $IMAGE_NAME . 14 | - ./twistcli images scan --address $PCC_CONSOLE_URL --user $PCC_USER --password $PCC_PASS --details $IMAGE_NAME 15 | -------------------------------------------------------------------------------- /cicd/travis-ci/README.md: -------------------------------------------------------------------------------- 1 | This directory contains an example of a basic [Travis CI build config](https://docs.travis-ci.com/user/tutorial/) that integrates container image scanning for vulnerabilities and compliance issues directly into Travis CI. 2 | 3 | This example only builds an image using the Dockerfile at the repository's root and scans the resultant image. 4 | The intent is to demonstrate how `twistcli` may fit into your Travis CI build config. 5 | 6 | ## Requirements 7 | To use this Travis CI build config, you will need 8 | * a functional Prisma Cloud Compute Console that is reachable from the Travis CI build environment 9 | * credentials for a Compute user ([CI User](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/authentication/user_roles.html) or [Build and Deploy Security](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/authentication/prisma_cloud_user_roles.html) role with "Only Access Key" selected is recommended) 10 | 11 | ## Setup 12 | 1. Create the variables used by the build config (`PCC_USER`, `PCC_PASS`, and `PCC_CONSOLE_URL`). 13 | See [Travis CI's documentation](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings) for instructions on how to create these. 14 | 15 | If you are using Prisma Cloud Compute Edition (self-hosted), `PCC_USER` and `PCC_PASS` will likely just be your normal username and password of the user with CI User role. 16 | `PCC_CONSOLE_URL` will be the address you use to access the Compute Console. 17 | 18 | If you are using Prisma Cloud Enterprise Edition (SaaS), `PCC_USER` and `PCC_PASS` will be your [access key and secret key](https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin-compute/authentication/access_keys.html) pair created with the Build and Deploy Security role. 19 | `PCC_CONSOLE_URL` will be the address found at **Compute > Manage > System > Downloads** under the **Path to Console** heading. 20 | 21 | 22 | 23 | 2. Add the `.travis.yml` file to the root of your repository. 24 | 25 | 26 | 27 | The image will be built, tagged, and scanned using `owner/repository:commit`. 28 | This is the image name under which the scan results will be displayed in the Compute Console. 29 | You can adjust this with the `IMAGE_NAME` variable in `.travis.yml`. 30 | 31 | Here is a sample of the output in Travis CI: 32 | 33 | 34 | ... and the corresponding output in the Compute Console: 35 | 36 | 37 | The image scan policy (including failure thresholds) is managed in the Compute Console at 38 | * **Defend > Vulnerabilities > Images > CI** 39 | * **Defend > Compliance > Containers and images > CI** 40 | 41 | If you are using a self-signed certificate on the Compute Console, you may have to add `--insecure` to the `curl` command. 42 | For example: 43 | 44 | ```curl --user $PCC_USER:$PCC_PASS --output ./twistcli --insecure $PCC_CONSOLE_URL/api/v1/util/twistcli``` 45 | -------------------------------------------------------------------------------- /cicd/travis-ci/images/compute-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/travis-ci/images/compute-output.png -------------------------------------------------------------------------------- /cicd/travis-ci/images/travis-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/travis-ci/images/travis-output.png -------------------------------------------------------------------------------- /cicd/travis-ci/images/travis-yml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/travis-ci/images/travis-yml.png -------------------------------------------------------------------------------- /cicd/travis-ci/images/variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/cicd/travis-ci/images/variables.png -------------------------------------------------------------------------------- /compliance/custom-compliance-keys.sh: -------------------------------------------------------------------------------- 1 | #Safe cert List 2 | #This list of keys will be ignored in the compliance check if found 3 | safe_cert="/etc/1.key /etc/2.key" 4 | #All certs in "/etc" 5 | certs=$(find /etc -type f -name '*.key') 6 | output="" 7 | flag="" 8 | 9 | #if certs exist in the path 10 | if [ $(echo "$certs"|wc -l) -gt 0 ] 11 | then 12 | #for each cert see if they are in the safe_cert list 13 | for i in $certs; do 14 | for j in $safe_cert; do 15 | if [ X"$i" = X"$j" ]; then 16 | flag="MATCH" 17 | fi 18 | done 19 | if [ "$flag" != "MATCH" ]; then 20 | output="${output}${i} " 21 | fi 22 | flag=0 23 | done 24 | if [ "$output" != "" ]; then 25 | echo "Found: $output"; 26 | exit 1 27 | fi 28 | else 29 | echo "Not Found"; 30 | fi 31 | -------------------------------------------------------------------------------- /deployment/README.md: -------------------------------------------------------------------------------- 1 | # Automated Deployment Samples 2 | This repo contains sample ansible playbooks and scripts for the deployment of Prisma Cloud Compute. 3 | These playbooks are intended to help with your understanding in the Infrastructure as Code deployment of Prisma Cloud Compute. 4 | Use of these deployment examples does not imply any rights to Palo Alto Networks products and/or services. 5 | 6 | ## Important links 7 | - [Running Ansible playbooks using EC2 Systems Manager](https://aws.amazon.com/blogs/mt/running-ansible-playbooks-using-ec2-systems-manager-run-command-and-state-manager/) 8 | - [Ansible for managing AWS](https://docs.ansible.com/ansible/latest/scenario_guides/guide_aws.html) 9 | -------------------------------------------------------------------------------- /deployment/ansible/README.md: -------------------------------------------------------------------------------- 1 | ### Deploy Console and Defenders within a Kubernetes cluster 2 | The [console-defender-cluster.yaml](console-defender-cluster.yaml) Ansible playbook demonstrates the deployment of both the Console and Defenders within a Kubernetes cluster. 3 | 4 | ### Deploy Defenders from an existing Console 5 | The [linux-host-defender.yaml](linux-host-defender.yaml) Ansible playbook demonstrates the deployment of host Defenders from an existing Console using a shell script. 6 | -------------------------------------------------------------------------------- /deployment/ansible/linux-host-defender.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | become: true 4 | vars: 5 | console_addr: console.example.com 6 | username: defender_installer 7 | password: password 8 | 9 | tasks: 10 | - name: Create Installation Directory 11 | tempfile: 12 | state: directory 13 | suffix: pcc 14 | register: tempdir 15 | 16 | - name: Generate auth token 17 | uri: 18 | url: "https://{{ console_addr }}/api/v1/authenticate" 19 | body_format: json 20 | body: { 21 | "username": "{{ username }}", 22 | "password": "{{ password }}" 23 | } 24 | method: POST 25 | register: auth 26 | 27 | - name: Get Defender installation script 28 | uri: 29 | url: "https://{{ console_addr }}/api/v1/scripts/defender.sh" 30 | method: POST 31 | headers: 32 | Authorization: Bearer {{ auth.json.token }} 33 | dest: "{{ tempdir.path }}/defender.sh" 34 | mode: 0755 35 | 36 | - name: Install Defender 37 | command: "{{ tempdir.path }}/defender.sh -c {{ console_addr }} -d none --install-host" 38 | -------------------------------------------------------------------------------- /deployment/app-embedded-twistcli/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tomcat:7 2 | 3 | ARG struts2_version=2.3.12 4 | ARG owner_email=tomcat@paloaltonetworks.com 5 | 6 | RUN apt-get update 7 | RUN apt-get -y install curl git nmap dnsutils 8 | RUN set -ex \ 9 | && rm -rf /usr/local/tomcat/webapps/* \ 10 | && chmod a+x /usr/local/tomcat/bin/*.sh 11 | RUN curl -o /usr/local/tomcat/webapps/ROOT.war https://repo1.maven.org/maven2/org/apache/struts/struts2-showcase/${struts2_version}/struts2-showcase-${struts2_version}.war 12 | EXPOSE 8080 13 | 14 | ENTRYPOINT ["catalina.sh", "run"] 15 | 16 | 17 | -------------------------------------------------------------------------------- /deployment/app-embedded-twistcli/protect.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # The command "jq" is required for this script to execute 4 | 5 | # API Docs 6 | # https://prisma.pan.dev/api/cloud/cwpp/defenders#operation/post-defenders-fargate.json 7 | 8 | # This Bash script can be used to deploy a Container Defender. 9 | # To use, update the 4 variables prefixed with `PCC_` below. 10 | 11 | # If using SaaS, PCC_USER and PCC_PASS will be an access key and secret key. 12 | # Can also set environment variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN 13 | ACCESS_KEY="" 14 | SECRET_KEY="" 15 | 16 | # PCC_URL should be the exact value copied from 17 | # Compute > Manage > System > Utilities > Path to Console 18 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 19 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com 20 | 21 | #Specifiy regional proxy here 22 | PROXY="" #http://proxy.address 23 | NOPROXY="" # 169.254.169.254 comma separated list, if needed 24 | 25 | #The following variables can be set to customize the embedded function 26 | APPID="app-name" 27 | DATA="/data" 28 | 29 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 30 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 31 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 32 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 33 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 34 | 35 | 36 | #This command will generate an authorization token (Only valid for 1 hour) 37 | json_auth_data="$(printf '{ "username": "%s", "password": "%s" }' "${PCC_USER}" "${PCC_PASS}")" 38 | token=$(curl -sSLk -d "$json_auth_data" -H 'content-type: application/json' "$PCC_URL/api/v1/authenticate" | python3 -c 'import sys, json; print(json.load(sys.stdin)["token"])') 39 | 40 | #Download the linux version of twistcli 41 | #curl -sSLk -H "Authorization: Bearer $token" "$PCC_URL/api/v1/util/twistcli" > twistcli; chmod a+x twistcli; 42 | 43 | #Download the macOS version of twistcli 44 | curl -sSLk -H "Authorization: Bearer $token" "$PCC_URL/api/v1/util/osx/twistcli" > twistcli; chmod a+x twistcli; 45 | 46 | generate_proxy_data() 47 | { 48 | cat < Manage > System > Utilities > Path to Console 18 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 19 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com 20 | 21 | #Specifiy regional proxy here 22 | PROXY="" #http://proxy.address 23 | NOPROXY="" # 169.254.169.254 comma separated list, if needed 24 | 25 | #The following variables can be set to customize the embedded function 26 | APPID="app-name" 27 | DATA="/data" 28 | 29 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 30 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 31 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 32 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 33 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 34 | 35 | 36 | #This command will generate an authorization token (Only valid for 1 hour) 37 | json_auth_data="$(printf '{ "username": "%s", "password": "%s" }' "${PCC_USER}" "${PCC_PASS}")" 38 | token=$(curl -sSLk -d "$json_auth_data" -H 'content-type: application/json' "$PCC_URL/api/v1/authenticate" | python3 -c 'import sys, json; print(json.load(sys.stdin)["token"])') 39 | 40 | generate_proxy_data() 41 | { 42 | cat <”;“password”=“”;} 3 | 4 | # Address to the Console 5 | $console = 'https://:8083' 6 | 7 | # authenticate Endpoint 8 | $request = $console + '/api/v1/authenticate' 9 | 10 | # Initial request for token and save into variable 11 | add-type "using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy{ public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; }}"; [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy; 12 | 13 | $response = Invoke-WebRequest $request -Body ($params|ConvertTo-Json) -ContentType "application/json" -Method POST 14 | $token = ConvertFrom-Json $([String]::new($response.Content)) 15 | 16 | # Windows Defender endpoint and call 17 | $request2 = $console + '/api/v1/scripts/defender.ps1' 18 | Invoke-WebRequest $request2 -Headers @{"authorization" = 'Bearer ' + $token.token } -OutFile defender.ps1; 19 | 20 | # file will be saved as defender.ps1 in the current directory 21 | 22 | #remove docker engine prerequisite 23 | (Get-Content -path defender.ps1) -replace ' -DependsOn "docker"' | Set-Content -Path defender.ps1 24 | 25 | #Install Twistlock 26 | .\defender.ps1 -type dockerWindows -consoleCN -install 27 | 28 | 29 | -------------------------------------------------------------------------------- /deployment/fargate/NoEntrypointScript/README.md: -------------------------------------------------------------------------------- 1 | # About 2 | This is some proof of concept code to be used to build a CI/CD pipeline action to derive the Entrypoint and CMD of a given docker image. If no Entrypoint is found either `/bin/sh -c` or the CMD output is used, depending on the script. 3 | 4 | # Why? 5 | When creating Fargate Tasks, it is sometimes necessary to explicitly add a EntryPoint. This code offers two solutions: Use `/bin/sh -c` or use the CMD output. 6 | 7 | # Requirements 8 | The `docker` python library must be installed 9 | 10 | ``` 11 | pip install -r requirements.txt 12 | ``` 13 | 14 | This script assumes that the image being passed is already on the system, as it would be as part of a build pipeline. 15 | 16 | # Usage 17 | `python fargate_use_sh_for_entry.py [Docker Image]` 18 | 19 | # Example: 20 | ``` 21 | $ python get_exec_params.py timekillerj/twistlock-fargate 22 | { 23 | "EntryPoint": [ 24 | "/bin/sh", 25 | "-c" 26 | ], 27 | "Command": [ 28 | "entry.sh" 29 | ] 30 | } 31 | ``` -------------------------------------------------------------------------------- /deployment/fargate/NoEntrypointScript/fargate_use_cmd_for_entry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import logging 4 | import json 5 | import docker 6 | 7 | 8 | def inspect_image(docker_image): 9 | client = docker.APIClient() 10 | try: 11 | data = client.inspect_image(docker_image) 12 | except docker.errors.ImageNotFound: 13 | logging.error(f'ERROR: Image on found locally. Try `docker pull {docker_image}`') 14 | sys.exit(1) 15 | return data 16 | 17 | def print_exec_params(docker_data): 18 | if not docker_data.get("Config", {}).get("Entrypoint"): 19 | entrypoint = docker_data.get("Config", {}).get("Cmd") 20 | cmd = None 21 | else: 22 | entrypoint = docker_data.get("Config", {}).get("Entrypoint") 23 | cmd = docker_data.get("Config", {}).get("Cmd") 24 | 25 | exec_params = { 26 | "entryPoint": entrypoint, 27 | "command": cmd 28 | } 29 | print(json.dumps(exec_params, indent=4)) 30 | 31 | if __name__ == "__main__": 32 | docker_image = sys.argv[1] 33 | docker_data = inspect_image(docker_image) 34 | print_exec_params(docker_data) 35 | -------------------------------------------------------------------------------- /deployment/fargate/NoEntrypointScript/fargate_use_sh_for_entry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import logging 4 | import json 5 | import docker 6 | 7 | 8 | def inspect_image(docker_image): 9 | client = docker.APIClient() 10 | try: 11 | data = client.inspect_image(docker_image) 12 | except docker.errors.ImageNotFound: 13 | logging.error(f'ERROR: Image on found locally. Try `docker pull {docker_image}`') 14 | sys.exit(1) 15 | return data 16 | 17 | def print_exec_params(docker_data): 18 | if not docker_data.get("Config", {}).get("Entrypoint"): 19 | entrypoint = ["/bin/sh", "-c"] 20 | else: 21 | entrypoint = docker_data.get("Config", {}).get("Entrypoint") 22 | cmd = docker_data.get("Config", {}).get("Cmd") 23 | 24 | exec_params = { 25 | "EntryPoint": entrypoint, 26 | "Command": cmd 27 | } 28 | print(json.dumps(exec_params, indent=4)) 29 | 30 | if __name__ == "__main__": 31 | docker_image = sys.argv[1] 32 | docker_data = inspect_image(docker_image) 33 | print_exec_params(docker_data) -------------------------------------------------------------------------------- /deployment/fargate/NoEntrypointScript/requirements.txt: -------------------------------------------------------------------------------- 1 | docker==4.3.1 -------------------------------------------------------------------------------- /deployment/fargate/fargateProtect.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # API Docs 4 | # https://prisma.pan.dev/api/cloud/cwpp/defenders#operation/post-defenders-fargate.json 5 | 6 | # This Bash script can be used to deploy a Container Defender. 7 | # To use, update the 4 variables prefixed with `PCC_` below. 8 | 9 | # If using SaaS, PCC_USER and PCC_PASS will be an access key and secret key. 10 | # Can also set environment variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN 11 | ACCESS_KEY="" 12 | SECRET_KEY="" 13 | 14 | # PCC_URL should be the exact value copied from 15 | # Compute > Manage > System > Utilities > Path to Console 16 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 17 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com 18 | 19 | #Specifiy regional proxy here 20 | PROXY="" #http://proxy.address 21 | NOPROXY="" # 169.254.169.254 comma separated list, if needed 22 | 23 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 24 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 25 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 26 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 27 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 28 | 29 | 30 | #This command will generate an authorization token (Only valid for 1 hour) 31 | json_auth_data="$(printf '{ "username": "%s", "password": "%s" }' "${PCC_USER}" "${PCC_PASS}")" 32 | token=$(curl -sSLk -d "$json_auth_data" -H 'content-type: application/json' "$PCC_URL/api/v1/authenticate" | python3 -c 'import sys, json; print(json.load(sys.stdin)["token"])') 33 | 34 | generate_proxy_data() 35 | { 36 | cat < Manage > System > Utilities > Path to Console 12 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 13 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com #twistlock-console 14 | 15 | #Specifiy local private image for Defender depolyment, or leave blank and we will use the public registry 16 | PRIVATE_IMAGE="" #registry.address/twistlock/defender:defender_21_08_880 17 | 18 | #Specifiy regional proxy here 19 | PROXY="" #http://proxy.address 20 | NOPROXY="" # 169.254.169.254 comma separated list, if needed 21 | 22 | #Specifiy cluster name here (This is optional but a good practice to control the radar views) 23 | CLUSTER_NAME="my-cluster" 24 | 25 | SUPERVISOR="Central Console" 26 | 27 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 28 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 29 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 30 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 31 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 32 | 33 | 34 | #This command will generate an authorization token (Only valid for 1 hour) 35 | json_auth_data="$(printf '{ "username": "%s", "password": "%s" }' "${PCC_USER}" "${PCC_PASS}")" 36 | token=$(curl -sSLk -d "$json_auth_data" -H 'content-type: application/json' "$PCC_URL/api/v1/authenticate" | python3 -c 'import sys, json; print(json.load(sys.stdin)["token"])') 37 | 38 | #This curl command will generate a daemonset.yaml, that can be deploymed in clusters 39 | PUBLIC_IMAGE=$(curl -sSLk -H "authorization: Bearer $token" "$PCC_URL/api/v1/defenders/image-name"| tr -d '"') 40 | 41 | [[ -z "${PRIVATE_IMAGE}" ]] && IMAGE="${PUBLIC_IMAGE}" || IMAGE="${PRIVATE_IMAGE}" 42 | 43 | #URL Encode the project/supervisor name 44 | project=`jq -rn --arg x "$SUPERVISOR" '$x|@uri'` 45 | 46 | #This will generate the post data that will be sent to the defenders/daemonset.yaml API endpoint 47 | generate_post_data() 48 | { 49 | cat < Manage > System > Utilities > Path to Console 12 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 13 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com 14 | 15 | #Specifiy local private image for Defender depolyment, or leave blank and we will use the public registry 16 | PRIVATE_IMAGE="" #registry.address/twistlock/defender:defender_21_08_880 17 | 18 | #Specifiy regional proxy here 19 | PROXY="" #http://proxy.address 20 | NOPROXY="" # 169.254.169.254 comma separated list, if needed 21 | 22 | #Specifiy cluster name here (This is optional but a good practice to control the radar views) 23 | CLUSTER_NAME="my-cluster" 24 | 25 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 26 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 27 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 28 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 29 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 30 | 31 | 32 | #This command will generate an authorization token (Only valid for 1 hour) 33 | json_auth_data="$(printf '{ "username": "%s", "password": "%s" }' "${PCC_USER}" "${PCC_PASS}")" 34 | token=$(curl -sSLk -d "$json_auth_data" -H 'content-type: application/json' "$PCC_URL/api/v1/authenticate" | python -c 'import sys, json; print(json.load(sys.stdin)["token"])') 35 | 36 | #This curl command will generate a daemonset.yaml, that can be deploymed in clusters 37 | PUBLIC_IMAGE=$(curl -sSLk -H "authorization: Bearer $token" "$PCC_URL/api/v1/defenders/image-name"| tr -d '"') 38 | 39 | [[ -z "${PRIVATE_IMAGE}" ]] && IMAGE="${PUBLIC_IMAGE}" || IMAGE="${PRIVATE_IMAGE}" 40 | 41 | 42 | #This will generate the post data that will be sent to the defenders/daemonset.yaml API endpoint 43 | generate_post_data() 44 | { 45 | cat < Manage > System > Utilities > Path to Console 12 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 13 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com 14 | 15 | #Specifiy local private image for Defender depolyment, or leave blank and we will use the public registry 16 | PRIVATE_IMAGE="" #registry.address/twistlock/defender:defender_21_08_880 17 | 18 | #Specifiy regional proxy here 19 | PROXY="" #http://proxy.address 20 | NOPROXY="" # 169.254.169.254 comma separated list, if needed 21 | 22 | #Specifiy cluster name here (This is optional but a good practice to control the radar views) 23 | CLUSTER_NAME="my-cluster" 24 | 25 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 26 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 27 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 28 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 29 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 30 | 31 | 32 | #This command will generate an authorization token (Only valid for 1 hour) 33 | json_auth_data="$(printf '{ "username": "%s", "password": "%s" }' "${PCC_USER}" "${PCC_PASS}")" 34 | token=$(curl -sSLk -d "$json_auth_data" -H 'content-type: application/json' "$PCC_URL/api/v1/authenticate" | python3 -c 'import sys, json; print(json.load(sys.stdin)["token"])') 35 | 36 | #This curl command will generate a daemonset.yaml, that can be deploymed in clusters 37 | PUBLIC_IMAGE=$(curl -sSLk -H "authorization: Bearer $token" "$PCC_URL/api/v1/defenders/image-name"| tr -d '"') 38 | 39 | [[ -z "${PRIVATE_IMAGE}" ]] && IMAGE="${PUBLIC_IMAGE}" || IMAGE="${PRIVATE_IMAGE}" 40 | 41 | 42 | #This will generate the post data that will be sent to the defenders/daemonset.yaml API endpoint 43 | generate_post_data() 44 | { 45 | cat < Manage > System > Utilities > Path to Console 13 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 14 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com 15 | 16 | #Specifiy regional proxy here 17 | PROXY="http://proxy.address" #http://proxy.address 18 | NOPROXY="169.254.169.254" # 169.254.169.254 comma separated list, if needed 19 | 20 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 21 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 22 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 23 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 24 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 25 | 26 | 27 | #This will generate the post data that will be sent to the defenders/daemonset.yaml API endpoint 28 | generate_post_data() 29 | { 30 | cat < Manage > System > Utilities > Path to Console 13 | CONSOLE_ADDRESS="" #https://us-west1.cloud.twistlock.com/us-3-xxxxxxxxx 14 | CONSOLE_SAN="" #us-west1.cloud.twistlock.com 15 | 16 | #Specifiy regional proxy here 17 | PROXY="http://proxy.address" #http://proxy.address 18 | NOPROXY="169.254.169.254" # 169.254.169.254 comma separated list, if needed 19 | 20 | #Will leverage env variables PCC_USER or PCC_PASS or PCC_URL or PCC_SAN if set. 21 | [[ -z "${PCC_USER}" ]] && PCC_USER="${ACCESS_KEY}" || PCC_USER="${PCC_USER}" 22 | [[ -z "${PCC_PASS}" ]] && PCC_PASS="${SECRET_KEY}" || PCC_PASS="${PCC_PASS}" 23 | [[ -z "${PCC_URL}" ]] && PCC_URL="${CONSOLE_ADDRESS}" || PCC_URL="${PCC_URL}" 24 | [[ -z "${PCC_SAN}" ]] && PCC_SAN="${CONSOLE_SAN}" || PCC_SAN="${PCC_SAN}" 25 | 26 | 27 | #This will generate the post data that will be sent to the defenders/daemonset.yaml API endpoint 28 | generate_post_data() 29 | { 30 | cat < 2 | 3 | 4 | Compute Report 5 | 6 | 7 | 8 |
9 | {% include "cover.html" %} 10 | {% include "toc.html" %} 11 | {% include "executive_summary.html" %} 12 | {% if not comp_only %} 13 | {% include "vuln_summary.html" %} 14 | {% endif %} 15 | {% if not vuln_only %} 16 | {% include "comp_summary.html" %} 17 | {% endif %} 18 | {% if not summary %} 19 | {% if not comp_only %} 20 | {% include "vuln_details.html" %} 21 | {% endif %} 22 | {% if not vuln_only %} 23 | {% include "comp_details.html" %} 24 | {% endif %} 25 | {% endif %} 26 |
27 | 28 | -------------------------------------------------------------------------------- /reporting/reporting-v2/templates/comp_details.html: -------------------------------------------------------------------------------- 1 |
Compliance Issues
2 | 3 | {% for id, compliance_issue in compliance_issues.items() %} 4 |
5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 53 | 54 |
 {{ compliance_issue.get('title')|e }}
14 | Description
15 | {{ compliance_issue.get('description')|e }} 16 |
21 |
22 | Failing Resources ({{ compliance_issue.get('failed_resources')|length }}) 23 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {% for instance in compliance_issue.get('failed_resources') %} 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | {% endfor %} 50 | 51 |
HostImageRegistryRepoTagModified
{{ instance.get('host') }}{{ instance.get('image') }}{{ instance.get('registry') }}{{ instance.get('repo') }}{{ instance.get('tag') }}{{ instance.get('modified') }}
52 |
55 | 56 |
57 |

58 |
59 | {% endfor %} 60 |
-------------------------------------------------------------------------------- /reporting/reporting-v2/templates/comp_summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% for compliance_issue in compliance_list %} 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | 24 |
Compliance Summary
TitleFailing ResourcesPercentage
 {{ compliance_issue.get("title")|e }}{{ compliance_issue.get('failed_resources')|length }}{{ compliance_issue.get('percentage_failed') }}%
25 |
-------------------------------------------------------------------------------- /reporting/reporting-v2/templates/cover.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |

6 | 7 | Prisma Cloud Compute Report
8 |
9 | Generated On: {{ timestamp }}
10 | Compute Console: {{ console_address }}

11 | Scan Type:
12 | 13 | {% if image_type == "deployed" %} 14 | Deployed 15 | {% elif image_type == "registry" %} 16 | Registry 17 | {% elif image_type == "ci" %} 18 | CI 19 | {% endif %} 20 |

21 | Report Type:
22 | 23 | {% if not comp_only %} 24 | Vulnerability, 25 | {% endif %} 26 | {% if not vuln_only %} 27 | Compliance, 28 | {% endif %} 29 | {% if not summary %} 30 | Detailed Report 31 | {% else %} 32 | Summary 33 | {% endif %} 34 | {% if collections %} 35 |

36 | Collections:
37 | 38 | {% for collection in collections %} 39 | {{ collection }}{% if not loop.last %},{% endif %} 40 | {% endfor %} 41 | 42 | {% endif %} 43 | 44 |
45 |
46 |
-------------------------------------------------------------------------------- /reporting/reporting-v2/templates/executive_summary.html: -------------------------------------------------------------------------------- 1 |
Executive Summary
2 |

3 | 4 | 5 | 6 | 7 | {% if not comp_only %} 8 | 9 | {% endif %} 10 | {% if not vuln_only %} 11 | 12 | {% endif %} 13 | 14 | 15 |
Resources Monitored
{{ resource_count }}
Vulnerability Count
{{ vulnerability_count }}
Compliance Issue Count
{{ compliance_issue_count }}
16 |
17 | 18 | 19 | 20 | {% if not comp_only %} 21 | 25 | {% endif %} 26 | {% if not vuln_only %} 27 | 31 | {% endif %} 32 | 33 | 34 |
22 | Vulnerability Distribution
23 | 24 |
28 | Compliance Issue Distribution
29 | 30 |
35 |
36 |
-------------------------------------------------------------------------------- /reporting/reporting-v2/templates/static/images/cloud_panw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/reporting/reporting-v2/templates/static/images/cloud_panw.png -------------------------------------------------------------------------------- /reporting/reporting-v2/templates/static/images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/reporting/reporting-v2/templates/static/images/cover.png -------------------------------------------------------------------------------- /reporting/reporting-v2/templates/static/images/none-chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaloAltoNetworks/prisma-cloud-compute-sample-code/aae966de93c54c215c79e513a84583c1988acc4b/reporting/reporting-v2/templates/static/images/none-chart.png -------------------------------------------------------------------------------- /reporting/reporting-v2/templates/static/tmp/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /reporting/reporting-v2/templates/toc.html: -------------------------------------------------------------------------------- 1 |
Table of Contents
2 | 3 |
4 | Executive Summary 5 |
6 |
7 | {% if not comp_only %} 8 |
9 | Vulnerability Summary 10 |
11 | {% endif %} 12 | {% if not vuln_only %} 13 |
14 |
15 | Compliance Summary 16 |
17 |
18 | {% endif %} 19 | {% if not summary %} 20 | {% if not comp_only %} 21 |
22 | Vulnerabilities 23 |
24 |
25 | {% endif %} 26 | {% if not vuln_only %} 27 |
28 | Compliance Issues 29 |
30 |
31 | {% endif %} 32 | {% endif %} 33 |
-------------------------------------------------------------------------------- /reporting/reporting-v2/templates/vuln_summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for vulnerability in vulnerability_list %} 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% endfor %} 22 | 23 |
Vulnerability Summary
CVEFailing ResourcesPercentage
 {{ vulnerability.get("cve") }}{{ vulnerability.get('failed_resources')|length }}{{ vulnerability.get('percentage_failed') }}%
24 |
-------------------------------------------------------------------------------- /reporting/vuln-reporting-v1/README.md: -------------------------------------------------------------------------------- 1 | This pulls the images data from a Twistlock console and formats it as an HTML vulnerability report per image. 2 | 3 | It expects environment variables for Twistlock config: 4 | 5 | * TL_CONSOLE: URL of the console (`https://twistlock.console.com:8083`) 6 | * TL_USER: Username to use for generating the report. Must have the Auditor role or higher 7 | * TL_USER_PW: Password for TL_USER 8 | 9 | 10 | 11 | ## Setup 12 | First clone this repo: 13 | 14 | ``` 15 | git https://github.com/twistlock/sample-code.git 16 | ``` 17 | 18 | It is recommended you create a virtual environment to keep installed python packages isolated from the rest of your system: 19 | 20 | ``` 21 | cd sample-code/Reporting/VulnReporting-v1 22 | python3 -m venv env 23 | ``` 24 | Activate it: 25 | 26 | ``` 27 | source env/bin/activate 28 | ``` 29 | 30 | Next you will need to install the required python packages: 31 | 32 | ``` 33 | pip install -r requirements.txt 34 | ``` 35 | 36 | ## Usage Examples 37 | * report.py for a report on deployed images 38 | * reportCI.py for a report on CI scanned images -------------------------------------------------------------------------------- /reporting/vuln-reporting-v1/report.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import getpass 5 | import argparse 6 | import json 7 | import os 8 | import requests 9 | from requests.auth import HTTPBasicAuth 10 | from jinja2 import Template 11 | 12 | 13 | class imgRequestError(Exception): 14 | pass 15 | 16 | 17 | def parse_args(): 18 | """ 19 | CLI argument handling 20 | """ 21 | 22 | desc = 'Generate an HTML report of CVEs per image, displaying the data to STDOUT/n' 23 | 24 | epilog = 'The console and user arguments can be supplied using the environment variables TL_CONSOLE and TL_USER.' 25 | epilog += ' The password can be passed using the environment variable TL_USER_PW.' 26 | epilog += ' The user will be prompted for the password when the TL_USER_PW variable is not set.' 27 | epilog += ' Environment variables override CLI arguments.' 28 | 29 | p = argparse.ArgumentParser(description=desc,epilog=epilog) 30 | p.add_argument('-c','--console',metavar='TL_CONSOLE', help='query the API of this Console') 31 | p.add_argument('-u','--user',metavar='TL_USER',help='Console username') 32 | p.add_argument('-p','--password',metavar='TL_USER_PW',help='Console Password') 33 | 34 | args = p.parse_args() 35 | 36 | # Populate args by env vars if they're set 37 | envvar_map = {'TL_USER':'user','TL_CONSOLE':'console','TL_USER_PW':'password'} 38 | for evar in envvar_map.keys(): 39 | evar_val = os.environ.get(evar,None) 40 | if evar_val is not None: 41 | setattr(args,envvar_map[evar],evar_val) 42 | 43 | arg_errs = [] 44 | if getattr(args,'console',None) is None: 45 | arg_errs.append('console (-c,--console)') 46 | if getattr(args,'user',None) is None: 47 | arg_errs.append('user (-u,--user)') 48 | if getattr(args,'password',None) is None: 49 | arg_errs.append('user (-p,--password)') 50 | 51 | if len(arg_errs) > 0: 52 | err_msg = 'Missing argument(s): {}'.format(', '.join(arg_errs)) 53 | p.error(err_msg) 54 | 55 | if getattr(args,'password',None) is None: 56 | args.password = getpass.getpass('Enter password: ') 57 | 58 | return args 59 | 60 | def generate_html(images_json): 61 | "This converts the images API output to HTML" 62 | report_body_template = open("report_body.html.j2").read() 63 | template = Template(report_body_template) 64 | output_html = template.render(images=images_json) 65 | return output_html 66 | 67 | def get_images_json(console,user,password): 68 | api_endpt = '/api/v1/images?search=twistlock/private:defender_21_11_815' 69 | request_url = console + api_endpt 70 | image_req = requests.get(request_url, verify=False, auth=HTTPBasicAuth(user,password)) 71 | if image_req.status_code != 200: 72 | # This means something went wrong. 73 | raise imgRequestError('GET /api/v1/images {} {}'.format(image_req.status_code,image_req.reason)) 74 | return image_req.json() 75 | 76 | def main(): 77 | 78 | args = parse_args() 79 | 80 | try: 81 | images_json = get_images_json(args.console,args.user,args.password) 82 | 83 | except imgRequestError as e: 84 | print("Error querying API: {}".format(e)) 85 | return 3 86 | 87 | output_html = generate_html(images_json) 88 | print(output_html, file=open("report.html", "w")) 89 | 90 | return 0 91 | 92 | if __name__ == '__main__': 93 | sys.exit(main()) 94 | -------------------------------------------------------------------------------- /reporting/vuln-reporting-v1/reportCI.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import getpass 5 | import argparse 6 | import json 7 | import os 8 | import requests 9 | from requests.auth import HTTPBasicAuth 10 | from jinja2 import Template 11 | 12 | 13 | class imgRequestError(Exception): 14 | pass 15 | 16 | 17 | def parse_args(): 18 | """ 19 | CLI argument handling 20 | """ 21 | 22 | desc = 'Generate an HTML report of CVEs per image, displaying the data to STDOUT/n' 23 | 24 | epilog = 'The console and user arguments can be supplied using the environment variables TL_CONSOLE and TL_USER.' 25 | epilog += ' The password can be passed using the environment variable TL_USER_PW.' 26 | epilog += ' The user will be prompted for the password when the TL_USER_PW variable is not set.' 27 | epilog += ' Environment variables override CLI arguments.' 28 | 29 | p = argparse.ArgumentParser(description=desc,epilog=epilog) 30 | p.add_argument('-c','--console',metavar='TL_CONSOLE', help='query the API of this Console') 31 | p.add_argument('-u','--user',metavar='TL_USER',help='Console username') 32 | p.add_argument('-p','--password',metavar='TL_USER_PW',help='Console Password') 33 | 34 | args = p.parse_args() 35 | 36 | # Populate args by env vars if they're set 37 | envvar_map = {'TL_USER':'user','TL_CONSOLE':'console','TL_USER_PW':'password'} 38 | for evar in envvar_map.keys(): 39 | evar_val = os.environ.get(evar,None) 40 | if evar_val is not None: 41 | setattr(args,envvar_map[evar],evar_val) 42 | 43 | arg_errs = [] 44 | if getattr(args,'console',None) is None: 45 | arg_errs.append('console (-c,--console)') 46 | if getattr(args,'user',None) is None: 47 | arg_errs.append('user (-u,--user)') 48 | if getattr(args,'password',None) is None: 49 | arg_errs.append('user (-p,--password)') 50 | 51 | if len(arg_errs) > 0: 52 | err_msg = 'Missing argument(s): {}'.format(', '.join(arg_errs)) 53 | p.error(err_msg) 54 | 55 | if getattr(args,'password',None) is None: 56 | args.password = getpass.getpass('Enter password: ') 57 | 58 | return args 59 | 60 | def generate_html(images_json): 61 | "This converts the images API output to HTML" 62 | report_body_template = open("report_body_ci.html.j2").read() 63 | template = Template(report_body_template) 64 | output_html = template.render(images=images_json) 65 | return output_html 66 | 67 | def get_images_json(console,user,password): 68 | api_endpt = '/api/v1/scans?type=ciImage&jobNameHello-Node&limit=1&offset=0' 69 | request_url = console + api_endpt 70 | image_req = requests.get(request_url, verify=False, auth=HTTPBasicAuth(user,password)) 71 | if image_req.status_code != 200: 72 | # This means something went wrong. 73 | raise imgRequestError('GET /api/v1/scans {} {}'.format(image_req.status_code,image_req.reason)) 74 | return image_req.json() 75 | 76 | def main(): 77 | 78 | args = parse_args() 79 | 80 | try: 81 | images_json = get_images_json(args.console,args.user,args.password) 82 | 83 | except imgRequestError as e: 84 | print("Error querying API: {}".format(e)) 85 | return 3 86 | 87 | 88 | 89 | 90 | #print(images_json) 91 | 92 | output_html = generate_html(images_json) 93 | print(output_html, file=open("reportCI.html", "w")) 94 | 95 | return 0 96 | 97 | if __name__ == '__main__': 98 | sys.exit(main()) 99 | -------------------------------------------------------------------------------- /reporting/vuln-reporting-v1/report_body.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | Twistlock Images Report 4 | 41 | 42 | 43 | 44 |
45 |

Twistlock Images Report

46 | {% for image in images %} 47 | {% if image.vulnerabilities is not none -%} 48 |

image: {{ image.tags[0].repo }}:{{ image.tags[0].tag }}

49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {% for vuln in image.vulnerabilities %} 61 | 62 | 63 | 64 | 65 | 66 | 67 | {% endfor %} 68 | 69 |
CVEDescriptionSeverityStatus
{{ vuln.cve }}{{ vuln.description }}{{ vuln.severity }}{{ vuln.status }}
70 | {% endif -%} 71 | {% endfor %} 72 |
73 | 74 | 75 | -------------------------------------------------------------------------------- /reporting/vuln-reporting-v1/report_body_ci.html.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | Prisma Cloud Compute Images Report 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |

Twistlock CI Scan Report

18 | {% for scans in images %} 19 |

Job Name (Build Number): {{ scans.jobName }} ({{ scans.build }})

20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | {% for vuln in scans.entityInfo.vulnerabilities %} 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {% endfor %} 41 | 42 |
CVESeverityStatusDescription
{{ vuln.cve }}{{ vuln.severity }}{{ vuln.status }}{{ vuln.description }}
43 | {% endfor %} 44 |
45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /reporting/vuln-reporting-v1/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2020.12.5 2 | chardet==4.0.0 3 | cycler==0.10.0 4 | idna==2.10 5 | Jinja2==2.11.3 6 | kiwisolver==1.3.1 7 | MarkupSafe==1.1.1 8 | matplotlib==3.4.1 9 | numpy==1.21.0 10 | pdfkit==0.6.1 11 | Pillow==9.0.0 12 | pyparsing==2.4.7 13 | python-dateutil==2.8.1 14 | requests==2.25.1 15 | six==1.15.0 16 | urllib3==1.26.5 17 | --------------------------------------------------------------------------------