|
@@ -0,0 +1,172 @@
|
|
|
+#!/bin/bash
|
|
|
+#
|
|
|
+# Generate modified policies. Patch existing modified policies to disable them.
|
|
|
+#
|
|
|
+# Need files:
|
|
|
+# policyexport (a dump of all policies)
|
|
|
+# roxctl-token (api auth token)
|
|
|
+#
|
|
|
+E=central-rhacs.apps.ocp4.example.com
|
|
|
+T=$(cat roxctl-token)
|
|
|
+
|
|
|
+DISABLED_POLICY_LIST=(
|
|
|
+ "ADD Command used instead of COPY"
|
|
|
+ "Container using read-write root filesystem"
|
|
|
+ "Curl in Image"
|
|
|
+ "Docker CIS 4.4: Ensure images are scanned and rebuilt to include security patches"
|
|
|
+ "Docker CIS 5.21: Ensure the default seccomp profile is not disabled"
|
|
|
+ "Fixable CVSS >= 7"
|
|
|
+ "Images with no scans"
|
|
|
+ "Login Binaries"
|
|
|
+ "Password Binaries"
|
|
|
+ "Process with UID 0"
|
|
|
+ "Required Annotation: Email"
|
|
|
+ "Required Annotation: Owner/Team"
|
|
|
+ "Required Image Label"
|
|
|
+ "Required Label: Owner/Team"
|
|
|
+ "Secret Mounted as Environment Variable"
|
|
|
+ "SetUID Processes"
|
|
|
+ "Shadow File Modification"
|
|
|
+ "Shell Management"
|
|
|
+ "Wget in Image"
|
|
|
+ )
|
|
|
+
|
|
|
+ENABLED_POLICY_LIST=(
|
|
|
+ "30-Day Scan Age"
|
|
|
+ "Alpine Linux Package Manager Execution"
|
|
|
+ "Apache Struts: CVE-2017-5638"
|
|
|
+ "CAP_SYS_ADMIN capability added"
|
|
|
+ "Compiler Tool Execution"
|
|
|
+ "Cryptocurrency Mining Process Execution"
|
|
|
+ "Docker CIS 4.7: Alert on Update Instruction"
|
|
|
+ "Docker CIS 5.1 Ensure that, if applicable, an AppArmor Profile is enabled"
|
|
|
+ "Docker CIS 5.19: Ensure mount propagation mode is not enabled"
|
|
|
+ "Emergency Deployment Annotation"
|
|
|
+ "Improper Usage of Orchestrator Secrets Volume"
|
|
|
+ "Insecure specified in CMD"
|
|
|
+ "Iptables Executed in Privileged Container"
|
|
|
+ "Kubernetes Actions: Exec into Pod"
|
|
|
+ "Kubernetes Actions: Port Forward to Pod"
|
|
|
+ "Kubernetes Dashboard Deployed"
|
|
|
+ "Latest tag"
|
|
|
+ "Linux Group Add Execution"
|
|
|
+ "Linux User Add Execution"
|
|
|
+ "Log4Shell: log4j Remote Code Execution vulnerability"
|
|
|
+ "Netcat Execution Detected"
|
|
|
+ "Network Management Execution"
|
|
|
+ "OpenShift: Advanced Cluster Security Central Admin Secret Accessed"
|
|
|
+ "OpenShift: Kubeadmin Secret Accessed"
|
|
|
+ "OpenShift: Kubernetes Secret Accessed by an Impersonated User"
|
|
|
+ "Process Targeting Cluster Kubelet Endpoint"
|
|
|
+ "Process Targeting Cluster Kubernetes Docker Stats Endpoint"
|
|
|
+ "Process Targeting Kubernetes Service Endpoint"
|
|
|
+ "Red Hat Package Manager Execution"
|
|
|
+ "Remote File Copy Binary Execution"
|
|
|
+ "Secure Shell (ssh) Port Exposed"
|
|
|
+ "Secure Shell (ssh) Port Exposed in Image"
|
|
|
+ "Secure Shell Server (sshd) Execution"
|
|
|
+ "Shell Spawned by Java Application"
|
|
|
+ "Ubuntu Package Manager Execution"
|
|
|
+ "Ubuntu Package Manager in Image"
|
|
|
+ "Unauthorized Network Flow"
|
|
|
+ "Unauthorized Process Execution"
|
|
|
+ "chkconfig Execution"
|
|
|
+ "crontab Execution"
|
|
|
+ "iptables Execution"
|
|
|
+ "nmap Execution"
|
|
|
+ "systemctl Execution"
|
|
|
+ "systemd Execution"
|
|
|
+ )
|
|
|
+
|
|
|
+FIX_POLICY_LIST=(
|
|
|
+ "90-Day Image Age"
|
|
|
+ "Alpine Linux Package Manager (apk) in Image"
|
|
|
+ "Docker CIS 4.1: Ensure That a User for the Container Has Been Created"
|
|
|
+ "Docker CIS 5.15: Ensure that the host's process namespace is not shared"
|
|
|
+ "Docker CIS 5.16: Ensure that the host's IPC namespace is not shared"
|
|
|
+ "Docker CIS 5.7: Ensure privileged ports are not mapped within containers"
|
|
|
+ "Docker CIS 5.9 and 5.20: Ensure that the host's network namespace is not shared"
|
|
|
+ "Environment Variable Contains Secret"
|
|
|
+ "Fixable CVSS >= 6 and Privileged"
|
|
|
+ "Fixable Severity at least Important"
|
|
|
+ "Mount Container Runtime Socket"
|
|
|
+ "Mounting Sensitive Host Directories"
|
|
|
+ "No resource requests or limits specified"
|
|
|
+ "Pod Service Account Token Automatically Mounted"
|
|
|
+ "Privileged Container"
|
|
|
+ "Red Hat Package Manager in Image"
|
|
|
+ )
|
|
|
+
|
|
|
+echo "Fixed policies: ${#FIX_POLICY_LIST[*]}"
|
|
|
+echo "Enabled policies: ${#ENABLED_POLICY_LIST[*]}"
|
|
|
+echo "Disabled policies: ${#DISABLED_POLICY_LIST[*]}"
|
|
|
+
|
|
|
+# Export current policies.
|
|
|
+# TODO: decide when to use backup and when to use current state
|
|
|
+# XXX: can't delete system policies anyway
|
|
|
+
|
|
|
+oldIFS="${IFS}"
|
|
|
+newIFS='
|
|
|
+'
|
|
|
+IFS="${newIFS}"
|
|
|
+for p in ${DISABLED_POLICY_LIST[*]}; do
|
|
|
+ id="$(jq -r '.policies[] | select(.name == "'${p}'") | .id' < policyexport)"
|
|
|
+ if [ -z "${id}" ]; then
|
|
|
+ echo "ERROR: Could not look up ID of \"${p}\"!"
|
|
|
+ continue
|
|
|
+ fi
|
|
|
+ echo -n "Disabling \"${p}\" ($id)... "
|
|
|
+ curl -ks -XPATCH -H "Authorization: Bearer ${T}" -d '{"id": "'${id}'", "disabled": true}' https://${E}/v1/policies/${id}
|
|
|
+ echo
|
|
|
+done
|
|
|
+
|
|
|
+for p in ${ENABLED_POLICY_LIST[*]}; do
|
|
|
+ id="$(jq -r '.policies[] | select(.name == "'${p}'") | .id' < policyexport)"
|
|
|
+ if [ -z "${id}" ]; then
|
|
|
+ echo "ERROR: Could not look up ID of \"${p}\"!"
|
|
|
+ continue
|
|
|
+ fi
|
|
|
+ echo -n "Enabling \"${p}\" ($id)... "
|
|
|
+ curl -ks -XPATCH -H "Authorization: Bearer ${T}" -d '{"id": "'${id}'", "disabled": false}' https://${E}/v1/policies/${id}
|
|
|
+ echo
|
|
|
+done
|
|
|
+
|
|
|
+for p in ${FIX_POLICY_LIST[*]}; do
|
|
|
+ # find matching policies
|
|
|
+ ids="$(jq -r '.policies[] | select(.name | test("(?i)^'${p//[()]/.}'")) | .id' < policyexport)"
|
|
|
+ if [ -z "${ids}" ]; then
|
|
|
+ echo "ERROR: Could not look up ID(s) of \"${p//[()]/.}\"!"
|
|
|
+ continue
|
|
|
+ fi
|
|
|
+ # how many?
|
|
|
+ nmatch=$(echo "${ids}" | wc -l | tr -d '[[:space:]]')
|
|
|
+ echo "Found ${nmatch} policies matching \"${p}\"..."
|
|
|
+ if [ ${nmatch} -gt 1 ]; then
|
|
|
+ # delete the one(s) that are not an exact match
|
|
|
+ id="$(jq -r '.policies[] | select(.name == "'${p}'") | .id' < policyexport)"
|
|
|
+ if [ -z "${id}" ]; then
|
|
|
+ echo "ERROR: Could not find exact match for \"${p}\"!"
|
|
|
+ continue
|
|
|
+ fi
|
|
|
+ xtraids="$(echo "${ids}" | grep -v ${id})"
|
|
|
+ for rmid in ${xtraids}; do
|
|
|
+ echo -n " - removing: ${rmid}"
|
|
|
+ curl -ks -XDELETE -H "Authorization: Bearer ${T}" https://${E}/v1/policies/${rmid}
|
|
|
+ echo
|
|
|
+ done
|
|
|
+ else
|
|
|
+ id="${ids}"
|
|
|
+ fi
|
|
|
+
|
|
|
+ echo " - keeping: ${id}"
|
|
|
+ echo -n " disabling... "
|
|
|
+ curl -ks -XPATCH -H "Authorization: Bearer ${T}" -d '{"id": "'${id}'", "disabled": true}' https://${E}/v1/policies/${id}
|
|
|
+ echo
|
|
|
+ echo -n " creating patched copy... "
|
|
|
+ PAYLOAD="$(jq '.policies[] | select(.id == "'${id}'") | .exclusions |= [ { "name": "Skip system namespaces", "deployment": { "name": "", "scope": { "cluster": "", "namespace": "^kube-.*|^openshift-.*|^istio-.*|^rhacs$|^stackrox$", "label": null } }, "image": null, "expiration": null } ] | .name |= . + " (non-system)" | .id |= "" | .disabled |= false' < policyexport)"
|
|
|
+ curl -ks -XPOST -H "Authorization: Bearer ${T}" -d "${PAYLOAD}" https://${E}/v1/policies
|
|
|
+ echo
|
|
|
+done
|
|
|
+IFS="${oldIFS}"
|
|
|
+unset oldIFS newIFS
|
|
|
+
|