#!/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 Execution" "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