aquasecurity / kube-bench

Checks whether Kubernetes is deployed according to security best practices as defined in the CIS Kubernetes Benchmark
Apache License 2.0
7.08k stars 1.23k forks source link

CIS 1.9 Kubernetes Policies Checks 5.1.6 returns an error when run inside a pod #1654

Closed winkrs closed 1 month ago

winkrs commented 3 months ago

Overview

      - id: 5.1.6
        text: "Ensure that Service Account Tokens are only mounted where necessary (Automated)"
        audit: |
          kubectl get pods --all-namespaces -o custom-columns=POD_NAMESPACE:.metadata.namespace,POD_NAME:.metadata.name,POD_SERVICE_ACCOUNT:.spec.serviceAccount,POD_IS_AUTOMOUNTSERVICEACCOUNTTOKEN:.spec.automountServiceAccountToken --no-headers | while read -r pod_namespace pod_name pod_service_account pod_is_automountserviceaccounttoken
          do
            # Retrieve automountServiceAccountToken's value for ServiceAccount and Pod, set to notset if null or <none>.
            svacc_is_automountserviceaccounttoken=$(kubectl get serviceaccount -n ${pod_namespace} ${pod_service_account} -o json | jq -r '.automountServiceAccountToken' | sed -e 's/<none>/notset/g' -e 's/null/notset/g')
            pod_is_automountserviceaccounttoken=$(echo ${pod_is_automountserviceaccounttoken} | sed -e 's/<none>/notset/g' -e 's/null/notset/g')
            if [[ "${svacc_is_automountserviceaccounttoken}" == "false" && ( "${pod_is_automountserviceaccounttoken}" == "false" || "${pod_is_automountserviceaccounttoken}" == "notset" ) ]]; then
              is_compliant="true"
            elif [[ "${svacc_is_automountserviceaccounttoken}" == "true" && "${pod_is_automountserviceaccounttoken}" == "false" ]]; then
              is_compliant="true"
            else
              is_compliant="false"
            fi
            echo "**namespace: ${pod_namespace} pod_name: ${pod_name} service_account: ${pod_service_account} pod_is_automountserviceaccounttoken: ${pod_is_automountserviceaccounttoken} svacc_is_automountServiceAccountToken: ${svacc_is_automountserviceaccounttoken} is_compliant: ${is_compliant}"
          done
        use_multiple_values: true
        tests:
          test_items:
            - flag: "is_compliant"
              compare:
                op: eq
                value: true
        remediation: |
          Modify the definition of ServiceAccounts and Pods which do not need to mount service
          account tokens to disable it, with `automountServiceAccountToken: false`.
          If both the ServiceAccount and the Pod's .spec specify a value for automountServiceAccountToken, the Pod spec takes precedence.
          Condition: Pod is_compliant to true when
            - ServiceAccount is automountServiceAccountToken: false and Pod is automountServiceAccountToken: false or notset
            - ServiceAccount is automountServiceAccountToken: true notset and Pod is automountServiceAccountToken: false
        scored: true

The audit script failed to run due to syntax issue.

How did you run kube-bench?

I'm running kube-bench inside a pod using the job.yaml. command used: kube-bench --json --check=5.1.6

What happened?

The audit script return error with the following reason:

failed to run: "kubectl get pods --all-namespaces -o custom-columns=POD_NAMESPACE:.metadata.namespace,POD_NAME:.metadata.name,POD_SERVICE_ACCOUNT:.spec.serviceAccount,POD_IS_AUTOMOUNTSERVICEACCOUNTTOKEN:.spec.automountServiceAccountToken --no-headers | while read -r pod_namespace pod_name pod_service_account pod_is_automountserviceaccounttoken
do
  # Retrieve automountServiceAccountToken's value for ServiceAccount and Pod, set to notset if null or <none>.
  svacc_is_automountserviceaccounttoken=$(kubectl get serviceaccount -n ${pod_namespace} ${pod_service_account} -o json | jq -r '.automountServiceAccountToken' | sed -e 's/<none>/notset/g' -e 's/null/notset/g')
  pod_is_automountserviceaccounttoken=$(echo ${pod_is_automountserviceaccounttoken} | sed -e 's/<none>/notset/g' -e 's/null/notset/g')
  if [[ \"${svacc_is_automountserviceaccounttoken}\" == \"false\" && ( \"${pod_is_automountserviceaccounttoken}\" == \"false\" || \"${pod_is_automountserviceaccounttoken}\" == \"notset\" ) ]]; then
    is_compliant=\"true\"
  elif [[ \"${svacc_is_automountserviceaccounttoken}\" == \"true\" && \"${pod_is_automountserviceaccounttoken}\" == \"false\" ]]; then
    is_compliant=\"true\"
  else
    is_compliant=\"false\"
  fi
  echo \"**namespace: ${pod_namespace} pod_name: ${pod_name} service_account: ${pod_service_account} pod_is_automountserviceaccounttoken: ${pod_is_automountserviceaccounttoken} svacc_is_automountServiceAccountToken: ${svacc_is_automountserviceaccounttoken} is_compliant: ${is_compliant}\"
done", output: "/bin/sh: syntax error: unexpected \"(\" (expecting \"then\")
", error: exit status 2

Here is log from the pod in json format.

{
    "Controls": [
        {
            "id": "4",
            "version": "cis-1.9",
            "detected_version": "1.27",
            "text": "Worker Node Security Configuration",
            "node_type": "node",
            "tests": null,
            "total_pass": 0,
            "total_fail": 0,
            "total_warn": 0,
            "total_info": 0
        },
        {
            "id": "5",
            "version": "cis-1.9",
            "detected_version": "1.27",
            "text": "Kubernetes Policies",
            "node_type": "policies",
            "tests": [
                {
                    "section": "5.1",
                    "type": "",
                    "pass": 0,
                    "fail": 1,
                    "warn": 0,
                    "info": 0,
                    "desc": "RBAC and Service Accounts",
                    "results": [
                        {
                            "test_number": "5.1.6",
                            "test_desc": "Ensure that Service Account Tokens are only mounted where necessary (Automated)",
                            "audit": "kubectl get pods --all-namespaces -o custom-columns=POD_NAMESPACE:.metadata.namespace,POD_NAME:.metadata.name,POD_SERVICE_ACCOUNT:.spec.serviceAccount,POD_IS_AUTOMOUNTSERVICEACCOUNTTOKEN:.spec.automountServiceAccountToken --no-headers | while read -r pod_namespace pod_name pod_service_account pod_is_automountserviceaccounttoken\ndo\n  # Retrieve automountServiceAccountToken's value for ServiceAccount and Pod, set to notset if null or \u003cnone\u003e.\n  svacc_is_automountserviceaccounttoken=$(kubectl get serviceaccount -n ${pod_namespace} ${pod_service_account} -o json | jq -r '.automountServiceAccountToken' | sed -e 's/\u003cnone\u003e/notset/g' -e 's/null/notset/g')\n  pod_is_automountserviceaccounttoken=$(echo ${pod_is_automountserviceaccounttoken} | sed -e 's/\u003cnone\u003e/notset/g' -e 's/null/notset/g')\n  if [[ \"${svacc_is_automountserviceaccounttoken}\" == \"false\" \u0026\u0026 ( \"${pod_is_automountserviceaccounttoken}\" == \"false\" || \"${pod_is_automountserviceaccounttoken}\" == \"notset\" ) ]]; then\n    is_compliant=\"true\"\n  elif [[ \"${svacc_is_automountserviceaccounttoken}\" == \"true\" \u0026\u0026 \"${pod_is_automountserviceaccounttoken}\" == \"false\" ]]; then\n    is_compliant=\"true\"\n  else\n    is_compliant=\"false\"\n  fi\n  echo \"**namespace: ${pod_namespace} pod_name: ${pod_name} service_account: ${pod_service_account} pod_is_automountserviceaccounttoken: ${pod_is_automountserviceaccounttoken} svacc_is_automountServiceAccountToken: ${svacc_is_automountserviceaccounttoken} is_compliant: ${is_compliant}\"\ndone\n",
                            "AuditEnv": "",
                            "AuditConfig": "",
                            "type": "",
                            "remediation": "Modify the definition of ServiceAccounts and Pods which do not need to mount service\naccount tokens to disable it, with `automountServiceAccountToken: false`.\nIf both the ServiceAccount and the Pod's .spec specify a value for automountServiceAccountToken, the Pod spec takes precedence.\nCondition: Pod is_compliant to true when\n  - ServiceAccount is automountServiceAccountToken: false and Pod is automountServiceAccountToken: false or notset\n  - ServiceAccount is automountServiceAccountToken: true notset and Pod is automountServiceAccountToken: false\n",
                            "test_info": [
                                "Modify the definition of ServiceAccounts and Pods which do not need to mount service\naccount tokens to disable it, with `automountServiceAccountToken: false`.\nIf both the ServiceAccount and the Pod's .spec specify a value for automountServiceAccountToken, the Pod spec takes precedence.\nCondition: Pod is_compliant to true when\n  - ServiceAccount is automountServiceAccountToken: false and Pod is automountServiceAccountToken: false or notset\n  - ServiceAccount is automountServiceAccountToken: true notset and Pod is automountServiceAccountToken: false\n"
                            ],
                            "status": "FAIL",
                            "actual_value": "",
                            "scored": true,
                            "IsMultiple": true,
                            "expected_result": "",
                            "reason": "failed to run: \"kubectl get pods --all-namespaces -o custom-columns=POD_NAMESPACE:.metadata.namespace,POD_NAME:.metadata.name,POD_SERVICE_ACCOUNT:.spec.serviceAccount,POD_IS_AUTOMOUNTSERVICEACCOUNTTOKEN:.spec.automountServiceAccountToken --no-headers | while read -r pod_namespace pod_name pod_service_account pod_is_automountserviceaccounttoken\ndo\n  # Retrieve automountServiceAccountToken's value for ServiceAccount and Pod, set to notset if null or \u003cnone\u003e.\n  svacc_is_automountserviceaccounttoken=$(kubectl get serviceaccount -n ${pod_namespace} ${pod_service_account} -o json | jq -r '.automountServiceAccountToken' | sed -e 's/\u003cnone\u003e/notset/g' -e 's/null/notset/g')\n  pod_is_automountserviceaccounttoken=$(echo ${pod_is_automountserviceaccounttoken} | sed -e 's/\u003cnone\u003e/notset/g' -e 's/null/notset/g')\n  if [[ \\\"${svacc_is_automountserviceaccounttoken}\\\" == \\\"false\\\" \u0026\u0026 ( \\\"${pod_is_automountserviceaccounttoken}\\\" == \\\"false\\\" || \\\"${pod_is_automountserviceaccounttoken}\\\" == \\\"notset\\\" ) ]]; then\n    is_compliant=\\\"true\\\"\n  elif [[ \\\"${svacc_is_automountserviceaccounttoken}\\\" == \\\"true\\\" \u0026\u0026 \\\"${pod_is_automountserviceaccounttoken}\\\" == \\\"false\\\" ]]; then\n    is_compliant=\\\"true\\\"\n  else\n    is_compliant=\\\"false\\\"\n  fi\n  echo \\\"**namespace: ${pod_namespace} pod_name: ${pod_name} service_account: ${pod_service_account} pod_is_automountserviceaccounttoken: ${pod_is_automountserviceaccounttoken} svacc_is_automountServiceAccountToken: ${svacc_is_automountserviceaccounttoken} is_compliant: ${is_compliant}\\\"\ndone\", output: \"/bin/sh: syntax error: unexpected \\\"(\\\" (expecting \\\"then\\\")\n\", error: exit status 2"
                        }
                    ]
                }
            ],
            "total_pass": 0,
            "total_fail": 1,
            "total_warn": 0,
            "total_info": 0
        }
    ],
    "Totals": {
        "total_pass": 0,
        "total_fail": 1,
        "total_warn": 0,
        "total_info": 0
    }
}

What did you expect to happen:

The audit script to run successfully as it did when run outside the pod.

Environment

kube-bench version: v1.8.0 kubectl version: v1.27.15

Fix:

Need to update audit script as below to run correctly inside the pod.

      - id: 5.1.6
        text: "Ensure that Service Account Tokens are only mounted where necessary (Automated)"
        audit: |
          kubectl get pods --all-namespaces -o custom-columns=POD_NAMESPACE:.metadata.namespace,POD_NAME:.metadata.name,POD_SERVICE_ACCOUNT:.spec.serviceAccount,POD_IS_AUTOMOUNTSERVICEACCOUNTTOKEN:.spec.automountServiceAccountToken --no-headers | while read -r pod_namespace pod_name pod_service_account pod_is_automountserviceaccounttoken
          do
            # Retrieve automountServiceAccountToken's value for ServiceAccount and Pod, set to notset if null or <none>.
            svacc_is_automountserviceaccounttoken=$(kubectl get serviceaccount -n "${pod_namespace}" "${pod_service_account}" -o json | jq -r '.automountServiceAccountToken' | sed -e 's/<none>/notset/g' -e 's/null/notset/g')
            pod_is_automountserviceaccounttoken=$(echo "${pod_is_automountserviceaccounttoken}" | sed -e 's/<none>/notset/g' -e 's/null/notset/g')
            if [ "${svacc_is_automountserviceaccounttoken}" = "false" ] && ( [ "${pod_is_automountserviceaccounttoken}" = "false" ] || [ "${pod_is_automountserviceaccounttoken}" = "notset" ] ); then
              is_compliant="true"
            elif [ "${svacc_is_automountserviceaccounttoken}" = "true" ] && [ "${pod_is_automountserviceaccounttoken}" = "false" ]; then
              is_compliant="true"
            else
              is_compliant="false"
            fi
            echo "**namespace: ${pod_namespace} pod_name: ${pod_name} service_account: ${pod_service_account} pod_is_automountserviceaccounttoken: ${pod_is_automountserviceaccounttoken} svacc_is_automountServiceAccountToken: ${svacc_is_automountserviceaccounttoken} is_compliant: ${is_compliant}"
          done
afdesk commented 1 month ago

in favor #1655