From a937d3603e13b1119e590fc1fe3b34d8ad652687 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Tue, 11 Jul 2023 11:24:51 +0300 Subject: [PATCH 01/11] add categories to ctrls Signed-off-by: Daniel Grunberger --- .../C-0001-forbiddencontainerregistries.json | 5 ++++- controls/C-0002-execintocontainer.json | 5 ++++- .../C-0004-resourcesmemorylimitandrequest.json | 5 ++++- .../C-0005-apiserverinsecureportisenabled.json | 5 ++++- controls/C-0007-datadestruction.json | 5 ++++- controls/C-0009-resourcelimits.json | 5 ++++- ...icationscredentialsinconfigurationfiles.json | 5 ++++- controls/C-0013-nonrootcontainers.json | 5 ++++- controls/C-0014-accesskubernetesdashboard.json | 5 ++++- controls/C-0015-listkubernetessecrets.json | 5 ++++- controls/C-0016-allowprivilegeescalation.json | 5 ++++- .../C-0017-immutablecontainerfilesystem.json | 5 ++++- controls/C-0018-configuredreadinessprobe.json | 5 ++++- controls/C-0020-mountserviceprincipal.json | 5 ++++- controls/C-0021-exposedsensitiveinterfaces.json | 5 ++++- controls/C-0026-kubernetescronjob.json | 5 ++++- controls/C-0030-ingressandegressblocked.json | 5 ++++- controls/C-0031-deletekubernetesevents.json | 5 ++++- ...C-0034-automaticmappingofserviceaccount.json | 5 ++++- controls/C-0035-clusteradminbinding.json | 5 ++++- ...-maliciousadmissioncontrollervalidating.json | 5 ++++- controls/C-0037-corednspoisoning.json | 5 ++++- controls/C-0038-hostpidipcprivileges.json | 5 ++++- ...39-maliciousadmissioncontrollermutating.json | 5 ++++- controls/C-0041-hostnetworkaccess.json | 5 ++++- .../C-0042-sshserverrunninginsidecontainer.json | 5 ++++- controls/C-0044-containerhostport.json | 5 ++++- controls/C-0045-writablehostpathmount.json | 5 ++++- controls/C-0046-insecurecapabilities.json | 5 ++++- controls/C-0048-hostpathmount.json | 5 ++++- controls/C-0049-networkmapping.json | 5 ++++- .../C-0050-resourcescpulimitandrequest.json | 5 ++++- controls/C-0052-instancemetadataapi.json | 5 ++++- .../C-0053-accesscontainerserviceaccount.json | 7 +++++-- controls/C-0054-clusterinternalnetworking.json | 5 ++++- controls/C-0055-linuxhardening.json | 5 ++++- controls/C-0056-configuredlivenessprobe.json | 5 ++++- controls/C-0057-privilegedcontainer.json | 5 ++++- ...symlinkforarbitraryhostfilesystemaccess.json | 5 ++++- ...nxingresssnippetannotationvulnerability.json | 5 ++++- controls/C-0061-podsindefaultnamespace.json | 5 ++++- controls/C-0062-sudoincontainerentrypoint.json | 5 ++++- controls/C-0063-portforwardingprivileges.json | 5 ++++- controls/C-0065-noimpersonation.json | 5 ++++- .../C-0066-secretetcdencryptionenabled.json | 5 ++++- controls/C-0067-auditlogsenabled.json | 5 ++++- controls/C-0068-pspenabled.json | 5 ++++- ...-disableanonymousaccesstokubeletservice.json | 5 ++++- ...0-enforcekubeletclienttlsauthentication.json | 7 +++++-- controls/C-0073-nakedpods.json | 5 ++++- controls/C-0075-imagepullpolicyonlatesttag.json | 5 ++++- controls/C-0076-labelusageforresources.json | 5 ++++- controls/C-0077-k8scommonlabelsusage.json | 5 ++++- controls/C-0078-imagesfromallowedregistry.json | 5 ++++- ...9-cve20220185linuxkernelcontainerescape.json | 5 ++++- .../C-0081-cve202224348argocddirtraversal.json | 5 ++++- ...vulnerabilitiesexposedtoexternaltraffic.json | 5 ++++- ...vulnerabilitiesexposedtoexternaltraffic.json | 5 ++++- ...adswithexcessiveamountofvulnerabilities.json | 5 ++++- ...-0086-cve20220492cgroupscontainerescape.json | 5 ++++- .../C-0087-cve202223648containerdfsescape.json | 5 ++++- controls/C-0088-rbacenabled.json | 5 ++++- ...-cve20223172aggregatedapiserverredirect.json | 5 ++++- .../C-0090-cve202239328grafanaauthbypass.json | 5 ++++- ...0091-cve202247633kyvernosignaturebypass.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...ecificationfileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...ecificationfileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...ecificationfileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...ecificationfileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...rkinterfacefileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto700ormorerestrictive.json | 5 ++++- ...cddatadirectoryownershipissettoetcdetcd.json | 5 ++++- ...ttheadminconffilepermissionsaresetto600.json | 5 ++++- ...headminconffileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...hedulerconffileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...managerconffileownershipissettorootroot.json | 5 ++++- ...irectoryandfileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...ernetespkikeyfilepermissionsaresetto600.json | 5 ++++- ...serveranonymousauthargumentissettofalse.json | 5 ++++- ...apiservertokenauthfileparameterisnotset.json | 5 ++++- ...apiserverdenyserviceexternalipsisnotset.json | 5 ++++- ...etclientkeyargumentsaresetasappropriate.json | 5 ++++- ...cateauthorityargumentissetasappropriate.json | 5 ++++- ...zationmodeargumentisnotsettoalwaysallow.json | 5 ++++- ...erauthorizationmodeargumentincludesnode.json | 5 ++++- ...erauthorizationmodeargumentincludesrbac.json | 5 ++++- ...missioncontrolplugineventratelimitisset.json | 5 ++++- ...missioncontrolpluginalwaysadmitisnotset.json | 5 ++++- ...ssioncontrolpluginalwayspullimagesisset.json | 5 ++++- ...xtdenyissetifpodsecuritypolicyisnotused.json | 5 ++++- ...missioncontrolpluginserviceaccountisset.json | 5 ++++- ...ioncontrolpluginnamespacelifecycleisset.json | 5 ++++- ...issioncontrolpluginnoderestrictionisset.json | 5 ++++- ...eapiserversecureportargumentisnotsetto0.json | 5 ++++- ...eapiserverprofilingargumentissettofalse.json | 5 ++++- ...attheapiserverauditlogpathargumentisset.json | 5 ++++- ...gmaxageargumentissetto30orasappropriate.json | 5 ++++- ...xbackupargumentissetto10orasappropriate.json | 5 ++++- ...axsizeargumentissetto100orasappropriate.json | 5 ++++- ...equesttimeoutargumentissetasappropriate.json | 5 ++++- ...serviceaccountlookupargumentissettotrue.json | 5 ++++- ...ccountkeyfileargumentissetasappropriate.json | 5 ++++- ...etcdkeyfileargumentsaresetasappropriate.json | 5 ++++- ...vatekeyfileargumentsaresetasappropriate.json | 5 ++++- ...rclientcafileargumentissetasappropriate.json | 5 ++++- ...veretcdcafileargumentissetasappropriate.json | 5 ++++- ...roviderconfigargumentissetasappropriate.json | 5 ++++- ...tionprovidersareappropriatelyconfigured.json | 5 ++++- ...nlymakesuseofstrongcryptographicciphers.json | 5 ++++- ...odgcthresholdargumentissetasappropriate.json | 5 ++++- ...lermanagerprofilingargumentissettofalse.json | 5 ++++- ...ceaccountcredentialsargumentissettotrue.json | 5 ++++- ...rivatekeyfileargumentissetasappropriate.json | 5 ++++- ...gerrootcafileargumentissetasappropriate.json | 5 ++++- ...letservercertificateargumentissettotrue.json | 5 ++++- ...managerbindaddressargumentissetto127001.json | 5 ++++- ...eschedulerprofilingargumentissettofalse.json | 5 ++++- ...hedulerbindaddressargumentissetto127001.json | 5 ++++- ...eandkeyfileargumentsaresetasappropriate.json | 5 ++++- ...hattheclientcertauthargumentissettotrue.json | 5 ++++- ...urethattheautotlsargumentisnotsettotrue.json | 5 ++++- ...peerkeyfileargumentsaresetasappropriate.json | 5 ++++- ...hepeerclientcertauthargumentissettotrue.json | 5 ++++- ...hatthepeerautotlsargumentisnotsettotrue.json | 5 ++++- ...uniquecertificateauthorityisusedforetcd.json | 5 ++++- ...-ensurethataminimalauditpolicyiscreated.json | 5 ++++- ...theauditpolicycoverskeysecurityconcerns.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...eletservicefileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...ileexistsensureownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...kubeletconffileownershipissettorootroot.json | 5 ++++- ...permissionsaresetto600ormorerestrictive.json | 5 ++++- ...authoritiesfileownershipissettorootroot.json | 5 ++++- ...atepermissionssetto600ormorerestrictive.json | 5 ++++- ...sedvalidatefileownershipissettorootroot.json | 5 ++++- ...hattheanonymousauthargumentissettofalse.json | 5 ++++- ...zationmodeargumentisnotsettoalwaysallow.json | 5 ++++- ...eclientcafileargumentissetasappropriate.json | 5 ++++- ...rifythatthereadonlyportargumentissetto0.json | 5 ++++- ...onnectionidletimeoutargumentisnotsetto0.json | 5 ++++- ...rotectkerneldefaultsargumentissettotrue.json | 5 ++++- ...keiptablesutilchainsargumentissettotrue.json | 5 ++++- ...thatthehostnameoverrideargumentisnotset.json | 5 ++++- ...evelwhichensuresappropriateeventcapture.json | 5 ++++- ...vatekeyfileargumentsaresetasappropriate.json | 5 ++++- ...tatecertificatesargumentisnotsettofalse.json | 5 ++++- ...letservercertificateargumentissettotrue.json | 5 ++++- ...nlymakesuseofstrongcryptographicciphers.json | 5 ++++- ...clusteradminroleisonlyusedwhererequired.json | 5 ++++- controls/C-0186-minimizeaccesstosecrets.json | 5 ++++- ...nimizewildcarduseinrolesandclusterroles.json | 5 ++++- controls/C-0188-minimizeaccesstocreatepods.json | 5 ++++- ...efaultserviceaccountsarenotactivelyused.json | 5 ++++- ...counttokensareonlymountedwherenecessary.json | 5 ++++- ...calatepermissionsinthekubernetescluster.json | 5 ++++- ...toneactivepolicycontrolmechanisminplace.json | 5 ++++- ...imizetheadmissionofprivilegedcontainers.json | 5 ++++- ...wishingtosharethehostprocessidnamespace.json | 5 ++++- ...ainerswishingtosharethehostipcnamespace.json | 5 ++++- ...rswishingtosharethehostnetworknamespace.json | 5 ++++- ...fcontainerswithallowprivilegeescalation.json | 5 ++++- ...98-minimizetheadmissionofrootcontainers.json | 5 ++++- ...ionofcontainerswiththenet_rawcapability.json | 5 ++++- ...issionofcontainerswithaddedcapabilities.json | 5 ++++- ...ionofcontainerswithcapabilitiesassigned.json | 5 ++++- ...admissionofwindowshostprocesscontainers.json | 5 ++++- ...3-minimizetheadmissionofhostpathvolumes.json | 5 ++++- ...eadmissionofcontainerswhichusehostports.json | 5 ++++- ...ethatthecniinusesupportsnetworkpolicies.json | 5 ++++- ...allnamespaceshavenetworkpoliciesdefined.json | 5 ++++- ...sfilesoversecretsasenvironmentvariables.json | 5 ++++- .../C-0208-considerexternalsecretstorage.json | 10 +++++++--- ...undariesbetweenresourcesusingnamespaces.json | 5 ++++- ...ssettodockerdefaultinyourpoddefinitions.json | 5 ++++- ...ysecuritycontexttoyourpodsandcontainers.json | 17 ++++++++++------- ...0212-thedefaultnamespaceshouldnotbeused.json | 5 ++++- controls/C-0236-verifyimagesignature.json | 8 +++++--- controls/C-0237-hasimagesignature.json | 8 +++++--- 188 files changed, 765 insertions(+), 202 deletions(-) diff --git a/controls/C-0001-forbiddencontainerregistries.json b/controls/C-0001-forbiddencontainerregistries.json index 8ef165e2e..e72ae4e4d 100644 --- a/controls/C-0001-forbiddencontainerregistries.json +++ b/controls/C-0001-forbiddencontainerregistries.json @@ -28,5 +28,8 @@ "test": "Checking image from pod spec, if the registry of the image is from the list of blocked registries we raise an alert.", "controlID": "C-0001", "baseScore": 7.0, - "example": "@controls/examples/c001.yaml" + "example": "@controls/examples/c001.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0002-execintocontainer.json b/controls/C-0002-execintocontainer.json index ddfb27964..60278b9de 100644 --- a/controls/C-0002-execintocontainer.json +++ b/controls/C-0002-execintocontainer.json @@ -21,5 +21,8 @@ "test": "Check which subjects have RBAC permissions to exec into pods\u2013 if they have the \u201cpods/exec\u201d verb.", "controlID": "C-0002", "baseScore": 5.0, - "example": "@controls/examples/c002.yaml" + "example": "@controls/examples/c002.yaml", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0004-resourcesmemorylimitandrequest.json b/controls/C-0004-resourcesmemorylimitandrequest.json index 3ff49fd30..b9f78ee69 100644 --- a/controls/C-0004-resourcesmemorylimitandrequest.json +++ b/controls/C-0004-resourcesmemorylimitandrequest.json @@ -23,5 +23,8 @@ ], "controlID": "C-0004", "example": "@controls/examples/c004.yaml", - "baseScore": 8.0 + "baseScore": 8.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0005-apiserverinsecureportisenabled.json b/controls/C-0005-apiserverinsecureportisenabled.json index ccf847108..24e2f72f1 100644 --- a/controls/C-0005-apiserverinsecureportisenabled.json +++ b/controls/C-0005-apiserverinsecureportisenabled.json @@ -23,5 +23,8 @@ "long_description": "The control plane is the core of Kubernetes and gives users the ability to view containers, schedule new Pods, read Secrets, and execute commands in the cluster. Therefore, it should be protected. It is recommended to avoid control plane exposure to the Internet or to an untrusted network. The API server runs on ports 6443 and 8080. We recommend to block them in the firewall. Note also that port 8080, when accessed through the local machine, does not require TLS encryption, and the requests bypass authentication and authorization modules.", "test": "Check if the insecure-port flag is set (in case of cloud vendor hosted Kubernetes service this verification will not be effective).", "controlID": "C-0005", - "baseScore": 9.0 + "baseScore": 9.0, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0007-datadestruction.json b/controls/C-0007-datadestruction.json index 0344045b8..b158aabfb 100644 --- a/controls/C-0007-datadestruction.json +++ b/controls/C-0007-datadestruction.json @@ -20,5 +20,8 @@ "test": "Check which subjects have delete/deletecollection RBAC permissions on workloads.", "controlID": "C-0007", "baseScore": 5.0, - "example": "@controls/examples/c007.yaml" + "example": "@controls/examples/c007.yaml", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0009-resourcelimits.json b/controls/C-0009-resourcelimits.json index a7b1671aa..0cf064514 100644 --- a/controls/C-0009-resourcelimits.json +++ b/controls/C-0009-resourcelimits.json @@ -23,5 +23,8 @@ "test": " Check for each container if there is a \u2018limits\u2019 field defined for both cpu and memory", "controlID": "C-0009", "baseScore": 7.0, - "example": "@controls/examples/c009.yaml" + "example": "@controls/examples/c009.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0012-applicationscredentialsinconfigurationfiles.json b/controls/C-0012-applicationscredentialsinconfigurationfiles.json index 2514cbe92..5bd205e92 100644 --- a/controls/C-0012-applicationscredentialsinconfigurationfiles.json +++ b/controls/C-0012-applicationscredentialsinconfigurationfiles.json @@ -36,5 +36,8 @@ "long_description": "Developers store secrets in the Kubernetes configuration files, such as environment variables in the pod configuration. Such behavior is commonly seen in clusters that are monitored by Azure Security Center. Attackers who have access to those configurations, by querying the API server or by accessing those files on the developer\u2019s endpoint, can steal the stored secrets and use them.", "test": "Check if the pod has sensitive information in environment variables, by using list of known sensitive key names. Check if there are configmaps with sensitive information.", "controlID": "C-0012", - "baseScore": 8.0 + "baseScore": 8.0, + "categories": [ + "Secrets" + ] } \ No newline at end of file diff --git a/controls/C-0013-nonrootcontainers.json b/controls/C-0013-nonrootcontainers.json index 29274949c..ab6b2dad8 100644 --- a/controls/C-0013-nonrootcontainers.json +++ b/controls/C-0013-nonrootcontainers.json @@ -24,5 +24,8 @@ "test": "Verify if runAsUser and runAsGroup are set to a user id greater than 999. Check that the allowPrivilegeEscalation field is set to false. Check all the combinations with PodSecurityContext and SecurityContext (for containers).", "controlID": "C-0013", "baseScore": 6.0, - "example": "@controls/examples/c013.yaml" + "example": "@controls/examples/c013.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0014-accesskubernetesdashboard.json b/controls/C-0014-accesskubernetesdashboard.json index 6aa8284ea..a71e0d732 100644 --- a/controls/C-0014-accesskubernetesdashboard.json +++ b/controls/C-0014-accesskubernetesdashboard.json @@ -21,5 +21,8 @@ "long_description": "The Kubernetes dashboard is a web-based UI that is used for monitoring and managing the Kubernetes cluster. The dashboard allows users to perform actions in the cluster using its service account (Kubernetes-dashboard) with the permissions that are determined by the binding or cluster-binding for this service account. Attackers who gain access to a container in the cluster, can use its network access to the dashboard pod. Consequently, attackers may retrieve information about the various resources in the cluster using the dashboard\u2019s identity.", "test": "Check who is associated with the dashboard service account or bound to dashboard role/clusterrole.", "controlID": "C-0014", - "baseScore": 2.0 + "baseScore": 2.0, + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0015-listkubernetessecrets.json b/controls/C-0015-listkubernetessecrets.json index d2013e573..584c5ff01 100644 --- a/controls/C-0015-listkubernetessecrets.json +++ b/controls/C-0015-listkubernetessecrets.json @@ -29,5 +29,8 @@ "test": "Alerting on users which have get/list/watch RBAC permissions on secrets. ", "controlID": "C-0015", "baseScore": 7.0, - "example": "@controls/examples/c015.yaml" + "example": "@controls/examples/c015.yaml", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0016-allowprivilegeescalation.json b/controls/C-0016-allowprivilegeescalation.json index 3b87271b7..6b90cf0e9 100644 --- a/controls/C-0016-allowprivilegeescalation.json +++ b/controls/C-0016-allowprivilegeescalation.json @@ -23,5 +23,8 @@ "test": " Check that the allowPrivilegeEscalation field in securityContext of container is set to false. ", "controlID": "C-0016", "baseScore": 6.0, - "example": "@controls/examples/allowprivilegeescalation.yaml" + "example": "@controls/examples/allowprivilegeescalation.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0017-immutablecontainerfilesystem.json b/controls/C-0017-immutablecontainerfilesystem.json index 8f886dfca..003110e34 100644 --- a/controls/C-0017-immutablecontainerfilesystem.json +++ b/controls/C-0017-immutablecontainerfilesystem.json @@ -25,5 +25,8 @@ "test": "Check whether the readOnlyRootFilesystem field in the SecurityContext is set to true. ", "controlID": "C-0017", "baseScore": 3.0, - "example": "@controls/examples/c017.yaml" + "example": "@controls/examples/c017.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0018-configuredreadinessprobe.json b/controls/C-0018-configuredreadinessprobe.json index bb4de61dd..432430134 100644 --- a/controls/C-0018-configuredreadinessprobe.json +++ b/controls/C-0018-configuredreadinessprobe.json @@ -14,5 +14,8 @@ "long_description": "Readiness probe is intended to ensure that workload is ready to process network traffic. It is highly recommended to define readiness probe for every worker container. This control finds all the PODs where the readiness probe is not configured.", "controlID": "C-0018", "example": "@controls/examples/c018.yaml", - "baseScore": 3 + "baseScore": 3, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0020-mountserviceprincipal.json b/controls/C-0020-mountserviceprincipal.json index 31d308a09..ffd895390 100644 --- a/controls/C-0020-mountserviceprincipal.json +++ b/controls/C-0020-mountserviceprincipal.json @@ -18,5 +18,8 @@ "long_description": "When the cluster is deployed in the cloud, in some cases attackers can leverage their access to a container in the cluster to gain cloud credentials. For example, in AKS each node contains service principal credential.", "test": "Check which workloads have volumes with potential access to known cloud credentials folders or files in node, like \u201c/etc/kubernetes/azure.json\u201d for Azure.", "controlID": "C-0020", - "baseScore": 4.0 + "baseScore": 4.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0021-exposedsensitiveinterfaces.json b/controls/C-0021-exposedsensitiveinterfaces.json index 1c29ae771..5e2f0cc23 100644 --- a/controls/C-0021-exposedsensitiveinterfaces.json +++ b/controls/C-0021-exposedsensitiveinterfaces.json @@ -19,5 +19,8 @@ "long_description": "Exposing a sensitive interface to the internet poses a security risk. Some popular frameworks were not intended to be exposed to the internet, and therefore don\u2019t require authentication by default. Thus, exposing them to the internet allows unauthenticated access to a sensitive interface which might enable running code or deploying containers in the cluster by a malicious actor. Examples of such interfaces that were seen exploited include Apache NiFi, Kubeflow, Argo Workflows, Weave Scope, and the Kubernetes dashboard.", "test": "Checking if a service of type nodeport/loadbalancer to one of the known exploited interfaces (Apache NiFi, Kubeflow, Argo Workflows, Weave Scope Kubernetes dashboard) exists. Needs to add user config", "controlID": "C-0021", - "baseScore": 6.0 + "baseScore": 6.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0026-kubernetescronjob.json b/controls/C-0026-kubernetescronjob.json index 38c4fe702..1774e4c72 100644 --- a/controls/C-0026-kubernetescronjob.json +++ b/controls/C-0026-kubernetescronjob.json @@ -17,5 +17,8 @@ "long_description": "Kubernetes Job is a controller that creates one or more pods and ensures that a specified number of them successfully terminate. Kubernetes Job can be used to run containers that perform finite tasks for batch jobs. Kubernetes CronJob is used to schedule Jobs. Attackers may use Kubernetes CronJob for scheduling execution of malicious code that would run as a container in the cluster.", "test": "We list all CronJobs that exist in cluster for the user to approve.", "controlID": "C-0026", - "baseScore": 1.0 + "baseScore": 1.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0030-ingressandegressblocked.json b/controls/C-0030-ingressandegressblocked.json index 93c081227..5952d72e6 100644 --- a/controls/C-0030-ingressandegressblocked.json +++ b/controls/C-0030-ingressandegressblocked.json @@ -15,5 +15,8 @@ "test": "Check for each Pod whether there is an ingress and egress policy defined (whether using Pod or Namespace). ", "controlID": "C-0030", "baseScore": 6.0, - "example": "@controls/examples/c030.yaml" + "example": "@controls/examples/c030.yaml", + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0031-deletekubernetesevents.json b/controls/C-0031-deletekubernetesevents.json index 761679ded..8f916970e 100644 --- a/controls/C-0031-deletekubernetesevents.json +++ b/controls/C-0031-deletekubernetesevents.json @@ -29,5 +29,8 @@ "test": "List who has delete/deletecollection RBAC permissions on events.", "controlID": "C-0031", "baseScore": 4.0, - "example": "@controls/examples/c031.yaml" + "example": "@controls/examples/c031.yaml", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0034-automaticmappingofserviceaccount.json b/controls/C-0034-automaticmappingofserviceaccount.json index 54cb98f04..d28fc9ff8 100644 --- a/controls/C-0034-automaticmappingofserviceaccount.json +++ b/controls/C-0034-automaticmappingofserviceaccount.json @@ -25,5 +25,8 @@ "test": "Check all service accounts on which automount is not disabled. Check all workloads on which they and their service account don't disable automount ", "controlID": "C-0034", "baseScore": 6.0, - "example": "@controls/examples/c034.yaml" + "example": "@controls/examples/c034.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0035-clusteradminbinding.json b/controls/C-0035-clusteradminbinding.json index 61441e542..617d9569c 100644 --- a/controls/C-0035-clusteradminbinding.json +++ b/controls/C-0035-clusteradminbinding.json @@ -29,5 +29,8 @@ "long_description": "Role-based access control (RBAC) is a key security feature in Kubernetes. RBAC can restrict the allowed actions of the various identities in the cluster. Cluster-admin is a built-in high privileged role in Kubernetes. Attackers who have permissions to create bindings and cluster-bindings in the cluster can create a binding to the cluster-admin ClusterRole or to other high privileges roles.", "test": "Check which subjects have cluster-admin RBAC permissions \u2013 either by being bound to the cluster-admin clusterrole, or by having equivalent high privileges. ", "controlID": "C-0035", - "baseScore": 6.0 + "baseScore": 6.0, + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0036-maliciousadmissioncontrollervalidating.json b/controls/C-0036-maliciousadmissioncontrollervalidating.json index 484ead36d..117df6551 100644 --- a/controls/C-0036-maliciousadmissioncontrollervalidating.json +++ b/controls/C-0036-maliciousadmissioncontrollervalidating.json @@ -25,5 +25,8 @@ "list-all-validating-webhooks" ], "controlID": "C-0036", - "baseScore": 3.0 + "baseScore": 3.0, + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0037-corednspoisoning.json b/controls/C-0037-corednspoisoning.json index ca840cc52..274d61263 100644 --- a/controls/C-0037-corednspoisoning.json +++ b/controls/C-0037-corednspoisoning.json @@ -26,5 +26,8 @@ "long_description": "CoreDNS is a modular Domain Name System (DNS) server written in Go, hosted by Cloud Native Computing Foundation (CNCF). CoreDNS is the main DNS service that is being used in Kubernetes. The configuration of CoreDNS can be modified by a file named corefile. In Kubernetes, this file is stored in a ConfigMap object, located at the kube-system namespace. If attackers have permissions to modify the ConfigMap, for example by using the container\u2019s service account, they can change the behavior of the cluster\u2019s DNS, poison it, and take the network identity of other services.", "test": "Check who has update/patch RBAC permissions on \u2018coredns\u2019 configmaps, or to all configmaps.", "controlID": "C-0037", - "baseScore": 4.0 + "baseScore": 4.0, + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0038-hostpidipcprivileges.json b/controls/C-0038-hostpidipcprivileges.json index fb897a3e2..f143c0649 100644 --- a/controls/C-0038-hostpidipcprivileges.json +++ b/controls/C-0038-hostpidipcprivileges.json @@ -23,5 +23,8 @@ "long_description": "Containers should be isolated from the host machine as much as possible. The hostPID and hostIPC fields in deployment yaml may allow cross-container influence and may expose the host itself to potentially malicious or destructive actions. This control identifies all PODs using hostPID or hostIPC privileges.", "controlID": "C-0038", "baseScore": 7.0, - "example": "@controls/examples/c038.yaml" + "example": "@controls/examples/c038.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0039-maliciousadmissioncontrollermutating.json b/controls/C-0039-maliciousadmissioncontrollermutating.json index e947da4de..faac48634 100644 --- a/controls/C-0039-maliciousadmissioncontrollermutating.json +++ b/controls/C-0039-maliciousadmissioncontrollermutating.json @@ -24,5 +24,8 @@ "list-all-mutating-webhooks" ], "controlID": "C-0039", - "baseScore": 4.0 + "baseScore": 4.0, + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0041-hostnetworkaccess.json b/controls/C-0041-hostnetworkaccess.json index 10092c3e7..7f6d5374d 100644 --- a/controls/C-0041-hostnetworkaccess.json +++ b/controls/C-0041-hostnetworkaccess.json @@ -26,5 +26,8 @@ "test": "", "controlID": "C-0041", "baseScore": 7.0, - "example": "@controls/examples/c041.yaml" + "example": "@controls/examples/c041.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0042-sshserverrunninginsidecontainer.json b/controls/C-0042-sshserverrunninginsidecontainer.json index 9a1ef0ab9..1d3e4a820 100644 --- a/controls/C-0042-sshserverrunninginsidecontainer.json +++ b/controls/C-0042-sshserverrunninginsidecontainer.json @@ -18,5 +18,8 @@ "long_description": "SSH server that is running inside a container may be used by attackers. If attackers gain valid credentials to a container, whether by brute force attempts or by other methods (such as phishing), they can use it to get remote access to the container by SSH.", "test": "Check if service connected to some workload has an SSH port (22/2222). If so we raise an alert. ", "controlID": "C-0042", - "baseScore": 3.0 + "baseScore": 3.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0044-containerhostport.json b/controls/C-0044-containerhostport.json index bd74818c7..d6d065ec2 100644 --- a/controls/C-0044-containerhostport.json +++ b/controls/C-0044-containerhostport.json @@ -25,5 +25,8 @@ "test": "Check for each workload (with container) if it exists inside the container hostPort.\u00a0\u00a0", "controlID": "C-0044", "baseScore": 4.0, - "example": "@controls/examples/c044.yaml" + "example": "@controls/examples/c044.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0045-writablehostpathmount.json b/controls/C-0045-writablehostpathmount.json index 4663cbffb..dca6b4bf5 100644 --- a/controls/C-0045-writablehostpathmount.json +++ b/controls/C-0045-writablehostpathmount.json @@ -31,5 +31,8 @@ "test": "Checking in POD spec if there is a hostPath volume, if it has the section mount.readOnly == false (or doesn\u2019t exist) we raise an alert.", "controlID": "C-0045", "baseScore": 8.0, - "example": "@controls/examples/c045.yaml" + "example": "@controls/examples/c045.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0046-insecurecapabilities.json b/controls/C-0046-insecurecapabilities.json index 67f74af50..d885935ed 100644 --- a/controls/C-0046-insecurecapabilities.json +++ b/controls/C-0046-insecurecapabilities.json @@ -25,5 +25,8 @@ "test": "Check capabilities given against a configurable blacklist of insecure capabilities (https://man7.org/linux/man-pages/man7/capabilities.7.html). ", "controlID": "C-0046", "baseScore": 7.0, - "example": "@controls/examples/c046.yaml" + "example": "@controls/examples/c046.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0048-hostpathmount.json b/controls/C-0048-hostpathmount.json index acbdb0f89..40dfd33e3 100644 --- a/controls/C-0048-hostpathmount.json +++ b/controls/C-0048-hostpathmount.json @@ -25,5 +25,8 @@ "alert-any-hostpath" ], "controlID": "C-0048", - "baseScore": 7.0 + "baseScore": 7.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0049-networkmapping.json b/controls/C-0049-networkmapping.json index 59d93fb62..49bb25faf 100644 --- a/controls/C-0049-networkmapping.json +++ b/controls/C-0049-networkmapping.json @@ -27,5 +27,8 @@ "test": "Check for each namespace if there is a network policy defined.", "controlID": "C-0049", "baseScore": 3.0, - "example": "@controls/examples/c049.yaml" + "example": "@controls/examples/c049.yaml", + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0050-resourcescpulimitandrequest.json b/controls/C-0050-resourcescpulimitandrequest.json index 1867e8cef..7e422ba75 100644 --- a/controls/C-0050-resourcescpulimitandrequest.json +++ b/controls/C-0050-resourcescpulimitandrequest.json @@ -14,5 +14,8 @@ "resources-cpu-limit-and-request" ], "controlID": "C-0050", - "baseScore": 8.0 + "baseScore": 8.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0052-instancemetadataapi.json b/controls/C-0052-instancemetadataapi.json index cbec46c46..635f10c40 100644 --- a/controls/C-0052-instancemetadataapi.json +++ b/controls/C-0052-instancemetadataapi.json @@ -28,5 +28,8 @@ "long_description": "Cloud providers provide instance metadata service for retrieving information about the virtual machine, such as network configuration, disks, and SSH public keys. This service is accessible to the VMs via a non-routable IP address that can be accessed from within the VM only. Attackers who gain access to a container, may query the metadata API service for getting information about the underlying node. For example, in Azure, the following request would retrieve all the metadata information of an instance: http:///metadata/instance?api-version=2019-06-01\\n\\n", "test": "Check which nodes have access to instance metadata services. The check is for AWS, GCP and Azure.", "controlID": "C-0052", - "baseScore": 7.0 + "baseScore": 7.0, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0053-accesscontainerserviceaccount.json b/controls/C-0053-accesscontainerserviceaccount.json index bc8e87b03..edde0d810 100644 --- a/controls/C-0053-accesscontainerserviceaccount.json +++ b/controls/C-0053-accesscontainerserviceaccount.json @@ -29,5 +29,8 @@ "long_description": "Service account (SA) represents an application identity in Kubernetes. By default, an SA is mounted to every created pod in the cluster. Using the SA, containers in the pod can send requests to the Kubernetes API server. Attackers who get access to a pod can access the SA token (located in /var/run/secrets/kubernetes.io/serviceaccount/token) and perform actions in the cluster, according to the SA permissions. If RBAC is not enabled, the SA has unlimited permissions in the cluster. If RBAC is enabled, its permissions are determined by the RoleBindings\\\\ClusterRoleBindings that are associated with it.", "test": "Control checks if RBAC is enabled. If it's not, the SA has unlimited permissions. If RBAC is enabled, it lists all permissions for each SA.", "controlID": "C-0053", - "baseScore": 6.0 -} + "baseScore": 6.0, + "categories": [ + "Access control" + ] +} \ No newline at end of file diff --git a/controls/C-0054-clusterinternalnetworking.json b/controls/C-0054-clusterinternalnetworking.json index affbd4791..27c68445a 100644 --- a/controls/C-0054-clusterinternalnetworking.json +++ b/controls/C-0054-clusterinternalnetworking.json @@ -27,5 +27,8 @@ "long_description": "Kubernetes networking behavior allows traffic between pods in the cluster as a default behavior. Attackers who gain access to a single container may use it for network reachability to another container in the cluster.", "test": "Check for each namespace if there is a network policy defined.", "controlID": "C-0054", - "baseScore": 4.0 + "baseScore": 4.0, + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0055-linuxhardening.json b/controls/C-0055-linuxhardening.json index eb7b16462..abafc315b 100644 --- a/controls/C-0055-linuxhardening.json +++ b/controls/C-0055-linuxhardening.json @@ -23,5 +23,8 @@ "long_description": "In order to reduce the attack surface, it is recommend, when it is possible, to harden your application using security services such as SELinux\u00ae, AppArmor\u00ae, and seccomp. Starting from Kubernetes version 22, SELinux is enabled by default. ", "test": "Check if there is AppArmor or Seccomp or SELinux or Capabilities are defined in the securityContext of container and pod. If none of these fields are defined for both the container and pod, alert.", "controlID": "C-0055", - "baseScore": 4.0 + "baseScore": 4.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0056-configuredlivenessprobe.json b/controls/C-0056-configuredlivenessprobe.json index 19a68f45a..f4566cd7f 100644 --- a/controls/C-0056-configuredlivenessprobe.json +++ b/controls/C-0056-configuredlivenessprobe.json @@ -13,5 +13,8 @@ ], "long_description": "Liveness probe is intended to ensure that workload remains healthy during its entire execution lifecycle, or otherwise restrat the container. It is highly recommended to define liveness probe for every worker container. This control finds all the PODs where the Liveness probe is not configured.", "controlID": "C-0056", - "baseScore": 4 + "baseScore": 4, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0057-privilegedcontainer.json b/controls/C-0057-privilegedcontainer.json index df30b9532..ecf009dac 100644 --- a/controls/C-0057-privilegedcontainer.json +++ b/controls/C-0057-privilegedcontainer.json @@ -26,5 +26,8 @@ "long_description": "A privileged container is a container that has all the capabilities of the host machine, which lifts all the limitations regular containers have. Practically, this means that privileged containers can do almost every action that can be performed directly on the host. Attackers who gain access to a privileged container or have permissions to create a new privileged container (by using the compromised pod\u2019s service account, for example), can get access to the host\u2019s resources.", "test": "Check in POD spec if securityContext.privileged == true, if so raise an alert.", "controlID": "C-0057", - "baseScore": 8.0 + "baseScore": 8.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json b/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json index fb536dcb2..e27c6e8c6 100644 --- a/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json +++ b/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json @@ -22,5 +22,8 @@ "Symlink-Exchange-Can-Allow-Host-Filesystem-Access" ], "controlID": "C-0058", - "baseScore": 6.0 + "baseScore": 6.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json b/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json index be5501eea..9e827915c 100644 --- a/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json +++ b/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json @@ -23,5 +23,8 @@ "nginx-ingress-snippet-annotation-vulnerability" ], "controlID": "C-0059", - "baseScore": 8.0 + "baseScore": 8.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0061-podsindefaultnamespace.json b/controls/C-0061-podsindefaultnamespace.json index 5233973f8..e2bd0b938 100644 --- a/controls/C-0061-podsindefaultnamespace.json +++ b/controls/C-0061-podsindefaultnamespace.json @@ -15,5 +15,8 @@ "long_description": "It is recommended to avoid running PODs in cluster without explicit namespace assignment. This may lead to wrong capabilities and permissions assignment and potential compromises. This control identifies all the PODs running in the default namespace.", "test": "Check that there are no pods in the 'default' namespace", "controlID": "C-0061", - "baseScore": 3 + "baseScore": 3, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0062-sudoincontainerentrypoint.json b/controls/C-0062-sudoincontainerentrypoint.json index b8346d6d1..7a524b576 100644 --- a/controls/C-0062-sudoincontainerentrypoint.json +++ b/controls/C-0062-sudoincontainerentrypoint.json @@ -23,5 +23,8 @@ "test": "Check that there is no 'sudo' in the container entrypoint", "controlID": "C-0062", "baseScore": 5.0, - "example": "@controls/examples/c062.yaml" + "example": "@controls/examples/c062.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0063-portforwardingprivileges.json b/controls/C-0063-portforwardingprivileges.json index 2e37c4ac0..7e9eabe57 100644 --- a/controls/C-0063-portforwardingprivileges.json +++ b/controls/C-0063-portforwardingprivileges.json @@ -28,5 +28,8 @@ "test": "Check which subjects have RBAC permissions to portforward into pods\u2013 if they have the \u201cpods/portforward\u201d resource.", "controlID": "C-0063", "baseScore": 5.0, - "example": "@controls/examples/c063.yaml" + "example": "@controls/examples/c063.yaml", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0065-noimpersonation.json b/controls/C-0065-noimpersonation.json index 183b96c64..f49f2c5c9 100644 --- a/controls/C-0065-noimpersonation.json +++ b/controls/C-0065-noimpersonation.json @@ -26,5 +26,8 @@ ], "controlID": "C-0065", "baseScore": 6.0, - "example": "@controls/examples/c065.yaml" + "example": "@controls/examples/c065.yaml", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0066-secretetcdencryptionenabled.json b/controls/C-0066-secretetcdencryptionenabled.json index 45c4ccbf2..2bfface12 100644 --- a/controls/C-0066-secretetcdencryptionenabled.json +++ b/controls/C-0066-secretetcdencryptionenabled.json @@ -24,5 +24,8 @@ "long_description": "etcd is a consistent and highly-available key value store used as Kubernetes' backing store for all cluster data. All object data in Kubernetes, like secrets, are stored there. This is the reason why it is important to protect the contents of etcd and use its data encryption feature.", "test": "Reading the cluster description from the managed cloud API (EKS, GKE), or the API server pod configuration for native K8s and checking if etcd encryption is enabled", "controlID": "C-0066", - "baseScore": 6.0 + "baseScore": 6.0, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0067-auditlogsenabled.json b/controls/C-0067-auditlogsenabled.json index f79363ddd..c39b272c2 100644 --- a/controls/C-0067-auditlogsenabled.json +++ b/controls/C-0067-auditlogsenabled.json @@ -24,5 +24,8 @@ "long_description": "Audit logging is an important security feature in Kubernetes, it enables the operator to track requests to the cluster. It is important to use it so the operator has a record of events happened in Kubernetes", "test": "Reading the cluster description from the managed cloud API (EKS, GKE), or the API server pod configuration for native K8s and checking if audit logging is enabled", "controlID": "C-0067", - "baseScore": 5.0 + "baseScore": 5.0, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0068-pspenabled.json b/controls/C-0068-pspenabled.json index 107e81181..23607b524 100644 --- a/controls/C-0068-pspenabled.json +++ b/controls/C-0068-pspenabled.json @@ -24,5 +24,8 @@ "long_description": "Pod Security Policies enable fine-grained authorization of pod creation and updates and it extends authorization beyond RBAC. It is an important to use PSP to control the creation of sensitive PODs in your cluster.", "test": "Reading the cluster description from the managed cloud API (EKS, GKE), or the API server pod configuration for native K8s and checking if PSP is enabled", "controlID": "C-0068", - "baseScore": 1.0 + "baseScore": 1.0, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0069-disableanonymousaccesstokubeletservice.json b/controls/C-0069-disableanonymousaccesstokubeletservice.json index b082227b7..adfc2f79f 100644 --- a/controls/C-0069-disableanonymousaccesstokubeletservice.json +++ b/controls/C-0069-disableanonymousaccesstokubeletservice.json @@ -23,5 +23,8 @@ "long_description": "By default, requests to the kubelet's HTTPS endpoint that are not rejected by other configured authentication methods are treated as anonymous requests, and given a username of system:anonymous and a group of system:unauthenticated.", "test": "Reading the kubelet command lines and configuration file looking for anonymous-auth configuration. If this configuration is set on both, the command line values take precedence over it.", "controlID": "C-0069", - "baseScore": 10 + "baseScore": 10, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0070-enforcekubeletclienttlsauthentication.json b/controls/C-0070-enforcekubeletclienttlsauthentication.json index 9a70d3746..43d2a5971 100644 --- a/controls/C-0070-enforcekubeletclienttlsauthentication.json +++ b/controls/C-0070-enforcekubeletclienttlsauthentication.json @@ -23,5 +23,8 @@ "long_description": "Kubelets are the node level orchestrator in Kubernetes control plane. They are publishing service port 10250 where they accept commands from API server. Operator must make sure that only API server is allowed to submit commands to Kubelet. This is done through client certificate verification, must configure Kubelet with client CA file to use for this purpose.", "test": "Reading the kubelet command lines and configuration file looking for client TLS configuration.", "controlID": "C-0070", - "baseScore": 9.0 -} + "baseScore": 9.0, + "categories": [ + "Control plane" + ] +} \ No newline at end of file diff --git a/controls/C-0073-nakedpods.json b/controls/C-0073-nakedpods.json index 4ead9b663..804aa50db 100644 --- a/controls/C-0073-nakedpods.json +++ b/controls/C-0073-nakedpods.json @@ -14,5 +14,8 @@ "long_description": "It is not recommended to create PODs without parental Deployment, ReplicaSet, StatefulSet etc.Manual creation if PODs may lead to a configuration drifts and other untracked changes in the system. Such PODs won't be automatically rescheduled by Kubernetes in case of a crash or infrastructure failure. This control identifies every POD that does not have corresponding parental object.", "test": "Test if PODs are not associated with Deployment, ReplicaSet etc. If not, fail.", "controlID": "C-0073", - "baseScore": 3 + "baseScore": 3, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0075-imagepullpolicyonlatesttag.json b/controls/C-0075-imagepullpolicyonlatesttag.json index d932795ca..3b95877fc 100644 --- a/controls/C-0075-imagepullpolicyonlatesttag.json +++ b/controls/C-0075-imagepullpolicyonlatesttag.json @@ -14,5 +14,8 @@ "long_description": "While usage of the latest tag is not generally recommended, in some cases this is necessary. If it is, the ImagePullPolicy must be set to Always, otherwise Kubernetes may run an older image with the same name that happens to be present in the node cache. Note that using Always will not cause additional image downloads because Kubernetes will check the image hash of the local local against the registry and only pull the image if this hash has changed, which is exactly what users want when use the latest tag. This control will identify all PODs with latest tag that have ImagePullSecret not set to Always. Note as well that some vendors don't use the word latest in the tag. Some other word may also behave like the latest. For example, Redis uses redis:alpine to signify the latest. Therefore, this control treats any word that does not contain digits as the latest. If no tag is specified, the image is treated as latests too.", "test": "If imagePullPolicy = always pass, else fail.", "controlID": "C-0075", - "baseScore": 2 + "baseScore": 2, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0076-labelusageforresources.json b/controls/C-0076-labelusageforresources.json index 472286603..d8c86a165 100644 --- a/controls/C-0076-labelusageforresources.json +++ b/controls/C-0076-labelusageforresources.json @@ -15,5 +15,8 @@ "long_description": "It is recommended to set labels that identify semantic attributes of your application or deployment. For example, { app: myapp, tier: frontend, phase: test, deployment: v3 }. These labels can used to assign policies to logical groups of the deployments as well as for presentation and tracking purposes. This control helps you find deployments without any of the expected labels.", "test": "Test will check if a certain set of labels is defined, this is a configurable control. Initial list: app, tier, phase, version, owner, env.", "controlID": "C-0076", - "baseScore": 2 + "baseScore": 2, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0077-k8scommonlabelsusage.json b/controls/C-0077-k8scommonlabelsusage.json index 1726e62ae..e9487d57e 100644 --- a/controls/C-0077-k8scommonlabelsusage.json +++ b/controls/C-0077-k8scommonlabelsusage.json @@ -15,5 +15,8 @@ "long_description": "Kubernetes common labels help manage and monitor Kubernetes cluster using different tools such as kubectl, dashboard and others in an interoperable way. Refer to https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ for more information. This control helps you find objects that don't have any of these labels defined.", "test": "Test will check if the list of label that start with app.kubernetes.io/ are defined.", "controlID": "C-0077", - "baseScore": 2.0 + "baseScore": 2.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0078-imagesfromallowedregistry.json b/controls/C-0078-imagesfromallowedregistry.json index fe6e3497d..e44588dc5 100644 --- a/controls/C-0078-imagesfromallowedregistry.json +++ b/controls/C-0078-imagesfromallowedregistry.json @@ -28,5 +28,8 @@ "long_description": "If attackers get access to the cluster, they can re-point kubernetes to a compromized container repository. This control is intended to ensure that all the container images are taken from the authorized repositories only. User should list all the approved repositories in the parameters of this control so that any potential dangerous image can be identified.", "test": "Checks if image is from allowed listed registry.", "controlID": "C-0078", - "baseScore": 5.0 + "baseScore": 5.0, + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0079-cve20220185linuxkernelcontainerescape.json b/controls/C-0079-cve20220185linuxkernelcontainerescape.json index b13c9d924..227f97a11 100644 --- a/controls/C-0079-cve20220185linuxkernelcontainerescape.json +++ b/controls/C-0079-cve20220185linuxkernelcontainerescape.json @@ -24,5 +24,8 @@ "test": "Checking Linux kernel version of the Node objects, if it is above 5.1 or below 5.16.2 it fires an alert", "controlID": "C-0079", "baseScore": 4.0, - "example": "" + "example": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0081-cve202224348argocddirtraversal.json b/controls/C-0081-cve202224348argocddirtraversal.json index acc49d027..cccb508be 100644 --- a/controls/C-0081-cve202224348argocddirtraversal.json +++ b/controls/C-0081-cve202224348argocddirtraversal.json @@ -23,5 +23,8 @@ "test": "Checking Linux kernel version of the Node objects, if it is above 5.1 or below 5.16.2 it fires an alert", "controlID": "C-0081", "baseScore": 4.0, - "example": "" + "example": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json b/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json index 1d3865a44..b72394f5c 100644 --- a/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json +++ b/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json @@ -24,5 +24,8 @@ "test": "This control enumerates external facing workloads, that have LoadBalancer or NodePort services and checks image vulnerability information to see if the image has critical vulnerabilities.", "controlID": "C-0083", "baseScore": 8.0, - "example": "@controls/examples/c83.yaml" + "example": "@controls/examples/c83.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json b/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json index 716bdb8a0..436569c68 100644 --- a/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json +++ b/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json @@ -25,5 +25,8 @@ "test": "This control enumerates external facing workloads, that have LoadBalancer or NodePort service and checks the image vulnerability information for the RCE vulnerability.", "controlID": "C-0084", "baseScore": 8.0, - "example": "@controls/examples/c84.yaml" + "example": "@controls/examples/c84.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json b/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json index 21bff4fb5..de0af548d 100644 --- a/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json +++ b/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json @@ -26,5 +26,8 @@ "test": "This control enumerates workloads and checks if they have excessive amount of vulnerabilities in their container images. The threshold of \u201cexcessive number\u201d is configurable.", "controlID": "C-0085", "baseScore": 6.0, - "example": "@controls/examples/c85.yaml" + "example": "@controls/examples/c85.yaml", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0086-cve20220492cgroupscontainerescape.json b/controls/C-0086-cve20220492cgroupscontainerescape.json index 87adce633..313b1be64 100644 --- a/controls/C-0086-cve20220492cgroupscontainerescape.json +++ b/controls/C-0086-cve20220492cgroupscontainerescape.json @@ -24,5 +24,8 @@ "test": "This control checks whether the container is running with high privileges (root or CAP_DAC_OVERRIDE capability) and doesn't have SELinux or AppArmor enabled. In case where the container is running with CAP_DAC_OVERRIDE capability, we also check for Seccomp, as it's enough to prevent the exploitation in this case.", "controlID": "C-0086", "baseScore": 4.0, - "example": "" + "example": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0087-cve202223648containerdfsescape.json b/controls/C-0087-cve202223648containerdfsescape.json index 3afc61495..23f6353a5 100644 --- a/controls/C-0087-cve202223648containerdfsescape.json +++ b/controls/C-0087-cve202223648containerdfsescape.json @@ -24,5 +24,8 @@ "test": "Checking containerd version to see if it is a vulnerable version (where the container runtime is containerd)", "controlID": "C-0087", "baseScore": 7.0, - "example": "" + "example": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0088-rbacenabled.json b/controls/C-0088-rbacenabled.json index f7de64162..b2ef0737a 100644 --- a/controls/C-0088-rbacenabled.json +++ b/controls/C-0088-rbacenabled.json @@ -25,5 +25,8 @@ "long_description": "RBAC is the most advanced and well accepted mode of authorizing users of the Kubernetes API", "test": "Testing API server or managed Kubernetes vendor API to determine if RBAC is enabled", "controlID": "C-0088", - "baseScore": 7.0 + "baseScore": 7.0, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0089-cve20223172aggregatedapiserverredirect.json b/controls/C-0089-cve20223172aggregatedapiserverredirect.json index 55ee727bc..682833537 100644 --- a/controls/C-0089-cve20223172aggregatedapiserverredirect.json +++ b/controls/C-0089-cve20223172aggregatedapiserverredirect.json @@ -16,5 +16,8 @@ "test": "List the aggregated-API-server services that could potentially be used to redirect client traffic to any URL, if the API server version is vulnerable to CVE-2022-3172", "controlID": "C-0089", "baseScore": 3.0, - "example": "" + "example": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0090-cve202239328grafanaauthbypass.json b/controls/C-0090-cve202239328grafanaauthbypass.json index a1473241c..7c0172342 100644 --- a/controls/C-0090-cve202239328grafanaauthbypass.json +++ b/controls/C-0090-cve202239328grafanaauthbypass.json @@ -24,5 +24,8 @@ "test": "This control test for vulnerable versions of Grafana (between 9.2 and 9.2.3)", "controlID": "C-0090", "baseScore": 9.0, - "example": "" + "example": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0091-cve202247633kyvernosignaturebypass.json b/controls/C-0091-cve202247633kyvernosignaturebypass.json index 60ef7dd8b..8d1a21803 100644 --- a/controls/C-0091-cve202247633kyvernosignaturebypass.json +++ b/controls/C-0091-cve202247633kyvernosignaturebypass.json @@ -24,5 +24,8 @@ "test": "This control test for vulnerable versions of Grafana (between 1.8.3 and 1.8.4)", "controlID": "C-0091", "baseScore": 8.0, - "example": "" + "example": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json index 29c505749..ce1442467 100644 --- a/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, the `kube-apiserver.yaml` file has permissions of `640`." + "default_value": "By default, the `kube-apiserver.yaml` file has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json b/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json index 037c1d45b..add86fd06 100644 --- a/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, the `kube-apiserver.yaml` file ownership is set to `root:root`." + "default_value": "By default, the `kube-apiserver.yaml` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json index 5262f94db..70b048b65 100644 --- a/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, the `kube-controller-manager.yaml` file has permissions of `640`." + "default_value": "By default, the `kube-controller-manager.yaml` file has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json b/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json index 0fe521751..111723c60 100644 --- a/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `kube-controller-manager.yaml` file ownership is set to `root:root`." + "default_value": "By default, `kube-controller-manager.yaml` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json index 1e42e9d83..fae7bab0b 100644 --- a/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `kube-scheduler.yaml` file has permissions of `640`." + "default_value": "By default, `kube-scheduler.yaml` file has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json b/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json index 78968d9d6..fe04c769d 100644 --- a/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `kube-scheduler.yaml` file ownership is set to `root:root`." + "default_value": "By default, `kube-scheduler.yaml` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json index d24d46f3e..4061abf66 100644 --- a/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `/etc/kubernetes/manifests/etcd.yaml` file has permissions of `640`." + "default_value": "By default, `/etc/kubernetes/manifests/etcd.yaml` file has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json b/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json index 54816d4f9..88575d203 100644 --- a/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `/etc/kubernetes/manifests/etcd.yaml` file ownership is set to `root:root`." + "default_value": "By default, `/etc/kubernetes/manifests/etcd.yaml` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json b/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json index fcd1438cc..1d3fb4be3 100644 --- a/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "NA" + "default_value": "NA", + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json b/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json index b3aefb8d6..7c9d6fdd2 100644 --- a/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json +++ b/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "NA" + "default_value": "NA", + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json b/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json index 497a65361..88172e390 100644 --- a/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json +++ b/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 7, "impact_statement": "None", - "default_value": "By default, etcd data directory has permissions of `755`." + "default_value": "By default, etcd data directory has permissions of `755`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json b/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json index bbade40f5..f7d3e174a 100644 --- a/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json +++ b/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "None", - "default_value": "By default, etcd data directory ownership is set to `etcd:etcd`." + "default_value": "By default, etcd data directory ownership is set to `etcd:etcd`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json b/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json index b9feeccda..4ae419af9 100644 --- a/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json +++ b/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json @@ -16,5 +16,8 @@ }, "baseScore": 7, "impact_statement": "None.", - "default_value": "By default, admin.conf has permissions of `600`." + "default_value": "By default, admin.conf has permissions of `600`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json b/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json index 0196d372a..c5388b21d 100644 --- a/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json +++ b/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 7, "impact_statement": "None.", - "default_value": "By default, `admin.conf` file ownership is set to `root:root`." + "default_value": "By default, `admin.conf` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json b/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json index 5163d0d6c..796dc02fb 100644 --- a/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `scheduler.conf` has permissions of `640`." + "default_value": "By default, `scheduler.conf` has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json b/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json index f916fea2e..91f870624 100644 --- a/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json +++ b/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `scheduler.conf` file ownership is set to `root:root`." + "default_value": "By default, `scheduler.conf` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json b/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json index af87f8a4f..0c037d0e0 100644 --- a/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `controller-manager.conf` has permissions of `640`." + "default_value": "By default, `controller-manager.conf` has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json b/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json index db995d88a..9534b5637 100644 --- a/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json +++ b/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `controller-manager.conf` file ownership is set to `root:root`." + "default_value": "By default, `controller-manager.conf` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json b/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json index 2a0c384da..0a567c477 100644 --- a/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json +++ b/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 8, "impact_statement": "None", - "default_value": "By default, the /etc/kubernetes/pki/ directory and all of the files and directories contained within it, are set to be owned by the root user." + "default_value": "By default, the /etc/kubernetes/pki/ directory and all of the files and directories contained within it, are set to be owned by the root user.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json b/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json index efa3e7de8..9bf26e508 100644 --- a/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 8, "impact_statement": "None", - "default_value": "By default, the certificates used by Kubernetes are set to have permissions of `644`" + "default_value": "By default, the certificates used by Kubernetes are set to have permissions of `644`", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json b/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json index 9fdd0a8c9..dba32ba7d 100644 --- a/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json +++ b/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json @@ -16,5 +16,8 @@ }, "baseScore": 8, "impact_statement": "None", - "default_value": "By default, the keys used by Kubernetes are set to have permissions of `600`" + "default_value": "By default, the keys used by Kubernetes are set to have permissions of `600`", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json b/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json index f92a9c7ca..d9e8d2536 100644 --- a/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json +++ b/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "Anonymous requests will be rejected.", - "default_value": "By default, anonymous access is enabled." + "default_value": "By default, anonymous access is enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json b/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json index 41b561dea..3d238d057 100644 --- a/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json +++ b/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "You will have to configure and use alternate authentication mechanisms such as certificates. Static token based authentication could not be used.", - "default_value": "By default, `--token-auth-file` argument is not set." + "default_value": "By default, `--token-auth-file` argument is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json b/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json index b62a9c2a4..365b9da22 100644 --- a/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json +++ b/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "When enabled, users of the cluster may not create new Services which use externalIPs and may not add new values to externalIPs on existing Service objects.", - "default_value": "By default, `--token-auth-file` argument is not set." + "default_value": "By default, `--token-auth-file` argument is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json b/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json index 2b59db188..4047956d7 100644 --- a/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json +++ b/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "You require TLS to be configured on apiserver as well as kubelets.", - "default_value": "By default, certificate-based kubelet authentication is not set." + "default_value": "By default, certificate-based kubelet authentication is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json b/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json index 800c407fa..e859ef701 100644 --- a/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json +++ b/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "You require TLS to be configured on apiserver as well as kubelets.", - "default_value": "By default, `--kubelet-certificate-authority` argument is not set." + "default_value": "By default, `--kubelet-certificate-authority` argument is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json b/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json index fe54c562a..4278d7cca 100644 --- a/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json +++ b/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "Only authorized requests will be served.", - "default_value": "By default, `AlwaysAllow` is not enabled." + "default_value": "By default, `AlwaysAllow` is not enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json b/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json index d7979cd8f..6d05724ad 100644 --- a/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json +++ b/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "None", - "default_value": "By default, `Node` authorization is not enabled." + "default_value": "By default, `Node` authorization is not enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json b/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json index 61b308466..9b1b55b5f 100644 --- a/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json +++ b/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "When RBAC is enabled you will need to ensure that appropriate RBAC settings (including Roles, RoleBindings and ClusterRoleBindings) are configured to allow appropriate access.", - "default_value": "By default, `RBAC` authorization is not enabled." + "default_value": "By default, `RBAC` authorization is not enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json b/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json index 3c16cb29b..b7a0817b1 100644 --- a/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json +++ b/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "You need to carefully tune in limits as per your environment.", - "default_value": "By default, `EventRateLimit` is not set." + "default_value": "By default, `EventRateLimit` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json b/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json index 691cd0478..8995f799d 100644 --- a/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json +++ b/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "Only requests explicitly allowed by the admissions control plugins would be served.", - "default_value": "`AlwaysAdmit` is not in the list of default admission plugins." + "default_value": "`AlwaysAdmit` is not in the list of default admission plugins.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json b/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json index 5d6c3d5c1..ccf0cf7c0 100644 --- a/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json +++ b/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "Credentials would be required to pull the private images every time. Also, in trusted environments, this might increases load on network, registry, and decreases speed.\n\n This setting could impact offline or isolated clusters, which have images pre-loaded and do not have access to a registry to pull in-use images. This setting is not appropriate for clusters which use this configuration.", - "default_value": "By default, `AlwaysPullImages` is not set." + "default_value": "By default, `AlwaysPullImages` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json b/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json index 39ee86e50..b81933a67 100644 --- a/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json +++ b/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "This admission controller should only be used where Pod Security Policies cannot be used on the cluster, as it can interact poorly with certain Pod Security Policies", - "default_value": "By default, `SecurityContextDeny` is not set." + "default_value": "By default, `SecurityContextDeny` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json b/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json index 9787d8963..e0c125597 100644 --- a/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json +++ b/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "None.", - "default_value": "By default, `ServiceAccount` is set." + "default_value": "By default, `ServiceAccount` is set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json b/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json index 8f988da56..62dd3c8f5 100644 --- a/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json +++ b/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "None", - "default_value": "By default, `NamespaceLifecycle` is set." + "default_value": "By default, `NamespaceLifecycle` is set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json b/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json index 15e846b00..f7b5d375f 100644 --- a/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json +++ b/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "By default, `NodeRestriction` is not set." + "default_value": "By default, `NodeRestriction` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json b/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json index 5fedbcf2b..1d191cd3f 100644 --- a/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json +++ b/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "You need to set the API Server up with the right TLS certificates.", - "default_value": "By default, port 6443 is used as the secure port." + "default_value": "By default, port 6443 is used as the secure port.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json b/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json index 4273db688..838e314f1 100644 --- a/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json +++ b/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "Profiling information would not be available.", - "default_value": "By default, profiling is enabled." + "default_value": "By default, profiling is enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json b/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json index a40c906e0..2ce31766d 100644 --- a/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json +++ b/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "None", - "default_value": "By default, auditing is not enabled." + "default_value": "By default, auditing is not enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json b/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json index 7c7e13a24..d9ee2d6d5 100644 --- a/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json +++ b/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "By default, auditing is not enabled." + "default_value": "By default, auditing is not enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json b/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json index ff49b3837..3a01de52b 100644 --- a/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json +++ b/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "By default, auditing is not enabled." + "default_value": "By default, auditing is not enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json b/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json index 0f72ae0e8..db6ed3f2a 100644 --- a/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json +++ b/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "By default, auditing is not enabled." + "default_value": "By default, auditing is not enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json b/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json index 102cd3048..ff32dfc25 100644 --- a/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json +++ b/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "By default, `--request-timeout` is set to 60 seconds." + "default_value": "By default, `--request-timeout` is set to 60 seconds.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json b/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json index 512dc2c50..0614fea1f 100644 --- a/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json +++ b/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `--service-account-lookup` argument is set to `true`." + "default_value": "By default, `--service-account-lookup` argument is set to `true`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json b/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json index 86e12f6e2..f61aa6eed 100644 --- a/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json +++ b/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "The corresponding private key must be provided to the controller manager. You would need to securely maintain the key file and rotate the keys based on your organization's key rotation policy.", - "default_value": "By default, `--service-account-key-file` argument is not set." + "default_value": "By default, `--service-account-key-file` argument is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json b/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json index 8dd8fbfd9..f50c4fe8d 100644 --- a/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json +++ b/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for etcd.", - "default_value": "By default, `--etcd-certfile` and `--etcd-keyfile` arguments are not set" + "default_value": "By default, `--etcd-certfile` and `--etcd-keyfile` arguments are not set", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json b/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json index 0ff4b2f10..0dc320fd6 100644 --- a/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json +++ b/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for your Kubernetes cluster deployment.", - "default_value": "By default, `--tls-cert-file` and `--tls-private-key-file` arguments are not set." + "default_value": "By default, `--tls-cert-file` and `--tls-private-key-file` arguments are not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json b/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json index 61b2ad914..3b6ac688f 100644 --- a/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json +++ b/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for your Kubernetes cluster deployment.", - "default_value": "By default, `--client-ca-file` argument is not set." + "default_value": "By default, `--client-ca-file` argument is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json b/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json index 5e3dd28c0..89ced3789 100644 --- a/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json +++ b/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for etcd.", - "default_value": "By default, `--etcd-cafile` is not set." + "default_value": "By default, `--etcd-cafile` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json b/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json index 5148b3b4b..5ded1cc7a 100644 --- a/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json +++ b/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "None", - "default_value": "By default, `--encryption-provider-config` is not set." + "default_value": "By default, `--encryption-provider-config` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json b/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json index f5b7f3161..5eccc3d4d 100755 --- a/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json +++ b/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "None", - "default_value": "By default, no encryption provider is set." + "default_value": "By default, no encryption provider is set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json b/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json index 05d130de9..528f47a68 100644 --- a/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json +++ b/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "API server clients that cannot support modern cryptographic ciphers will not be able to make connections to the API server.", - "default_value": "By default the Kubernetes API server supports a wide range of TLS ciphers" + "default_value": "By default the Kubernetes API server supports a wide range of TLS ciphers", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json b/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json index 02deb93a9..67d03a9a1 100644 --- a/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json +++ b/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "By default, `--terminated-pod-gc-threshold` is set to `12500`." + "default_value": "By default, `--terminated-pod-gc-threshold` is set to `12500`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json b/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json index d131c166e..982c033b8 100644 --- a/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json +++ b/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "Profiling information would not be available.", - "default_value": "By default, profiling is enabled." + "default_value": "By default, profiling is enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json b/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json index 201741a3b..123bc36e9 100644 --- a/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json +++ b/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "Whatever authorizer is configured for the cluster, it must grant sufficient permissions to the service accounts to perform their intended tasks. When using the RBAC authorizer, those roles are created and bound to the appropriate service accounts in the `kube-system` namespace automatically with default roles and rolebindings that are auto-reconciled on startup.\n\n If using other authorization methods (ABAC, Webhook, etc), the cluster deployer is responsible for granting appropriate permissions to the service accounts (the required permissions can be seen by inspecting the `controller-roles.yaml` and `controller-role-bindings.yaml` files for the RBAC roles.", - "default_value": "By default, `--use-service-account-credentials` is set to false." + "default_value": "By default, `--use-service-account-credentials` is set to false.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json b/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json index 34391e981..ccc12a7a0 100644 --- a/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json +++ b/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "You would need to securely maintain the key file and rotate the keys based on your organization's key rotation policy.", - "default_value": "By default, `--service-account-private-key-file` it not set." + "default_value": "By default, `--service-account-private-key-file` it not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json b/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json index 732efea67..7829302a9 100644 --- a/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json +++ b/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "You need to setup and maintain root certificate authority file.", - "default_value": "By default, `--root-ca-file` is not set." + "default_value": "By default, `--root-ca-file` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json b/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json index 1857ebfae..0c8ad21c7 100644 --- a/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json +++ b/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `RotateKubeletServerCertificate` is set to \"true\" this recommendation verifies that it has not been disabled." + "default_value": "By default, `RotateKubeletServerCertificate` is set to \"true\" this recommendation verifies that it has not been disabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json b/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json index 7a945a54d..f9fdc8a60 100644 --- a/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json +++ b/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "None", - "default_value": "By default, the `--bind-address` parameter is set to 0.0.0.0" + "default_value": "By default, the `--bind-address` parameter is set to 0.0.0.0", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json b/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json index 130765e2f..ed1be2be4 100644 --- a/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json +++ b/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "Profiling information would not be available.", - "default_value": "By default, profiling is enabled." + "default_value": "By default, profiling is enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json b/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json index e0307b832..6f99be38a 100644 --- a/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json +++ b/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "None", - "default_value": "By default, the `--bind-address` parameter is set to 0.0.0.0" + "default_value": "By default, the `--bind-address` parameter is set to 0.0.0.0", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json b/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json index 8660ac500..73030037e 100644 --- a/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json +++ b/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "Client connections only over TLS would be served.", - "default_value": "By default, TLS encryption is not set." + "default_value": "By default, TLS encryption is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json b/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json index e7293c739..7c88271a2 100644 --- a/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json +++ b/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "All clients attempting to access the etcd server will require a valid client certificate.", - "default_value": "By default, the etcd service can be queried by unauthenticated clients." + "default_value": "By default, the etcd service can be queried by unauthenticated clients.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json b/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json index 1deb05e24..aa69f1817 100644 --- a/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json +++ b/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "Clients will not be able to use self-signed certificates for TLS.", - "default_value": "By default, `--auto-tls` is set to `false`." + "default_value": "By default, `--auto-tls` is set to `false`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json b/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json index 9d3e870e2..7d1b1f004 100644 --- a/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json +++ b/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "etcd cluster peers would need to set up TLS for their communication.", - "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, peer communication over TLS is not configured." + "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, peer communication over TLS is not configured.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json b/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json index 9bd42cf2b..aaf75a8ff 100644 --- a/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json +++ b/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "All peers attempting to communicate with the etcd server will require a valid client certificate for authentication.", - "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, `--peer-client-cert-auth` argument is set to `false`." + "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, `--peer-client-cert-auth` argument is set to `false`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json b/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json index f42310f52..865c467ec 100644 --- a/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json +++ b/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "All peers attempting to communicate with the etcd server will require a valid client certificate for authentication.", - "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, `--peer-auto-tls` argument is set to `false`." + "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, `--peer-auto-tls` argument is set to `false`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json b/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json index 33930b336..8503a619d 100644 --- a/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json +++ b/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "Additional management of the certificates and keys for the dedicated certificate authority will be required.", - "default_value": "By default, no etcd certificate is created and used." + "default_value": "By default, no etcd certificate is created and used.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0160-ensurethataminimalauditpolicyiscreated.json b/controls/C-0160-ensurethataminimalauditpolicyiscreated.json index ea5c87132..fd1dc95fe 100644 --- a/controls/C-0160-ensurethataminimalauditpolicyiscreated.json +++ b/controls/C-0160-ensurethataminimalauditpolicyiscreated.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Audit logs will be created on the master nodes, which will consume disk space. Care should be taken to avoid generating too large volumes of log information as this could impact the available of the cluster nodes.", - "default_value": "Unless the `--audit-policy-file` flag is specified, no auditing will be carried out." + "default_value": "Unless the `--audit-policy-file` flag is specified, no auditing will be carried out.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json b/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json index c3e5561c3..345f50a97 100644 --- a/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json +++ b/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Increasing audit logging will consume resources on the nodes or other log destination.", - "default_value": "By default Kubernetes clusters do not log audit information." + "default_value": "By default Kubernetes clusters do not log audit information.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json b/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json index dad6b4b7a..1a28677c3 100644 --- a/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "By default, the `kubelet` service file has permissions of `640`." + "default_value": "By default, the `kubelet` service file has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json b/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json index dc6dd7929..d7afcb3d7 100644 --- a/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json +++ b/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `kubelet` service file ownership is set to `root:root`." + "default_value": "By default, `kubelet` service file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json b/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json index 0b3b06476..865e5d7f6 100644 --- a/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, proxy file has permissions of `640`." + "default_value": "By default, proxy file has permissions of `640`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json b/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json index d07a91bec..dd0221f6a 100644 --- a/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json +++ b/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `proxy` file ownership is set to `root:root`." + "default_value": "By default, `proxy` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json b/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json index 3bf43c320..67f3fc339 100644 --- a/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `kubelet.conf` file has permissions of `600`." + "default_value": "By default, `kubelet.conf` file has permissions of `600`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json b/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json index d33811b28..3683fd9c4 100644 --- a/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json +++ b/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 6, "impact_statement": "None", - "default_value": "By default, `kubelet.conf` file ownership is set to `root:root`." + "default_value": "By default, `kubelet.conf` file ownership is set to `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json index a63d14440..38d1712c4 100644 --- a/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 7, "impact_statement": "None", - "default_value": "By default no `--client-ca-file` is specified." + "default_value": "By default no `--client-ca-file` is specified.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json b/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json index 1871fadbd..bf3ade848 100644 --- a/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json +++ b/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 7, "impact_statement": "None", - "default_value": "By default no `--client-ca-file` is specified." + "default_value": "By default no `--client-ca-file` is specified.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json b/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json index 4b7a4aaf8..82a58698b 100644 --- a/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json +++ b/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json @@ -16,5 +16,8 @@ }, "baseScore": 7, "impact_statement": "None", - "default_value": "By default, the /var/lib/kubelet/config.yaml file as set up by `kubeadm` has permissions of 600." + "default_value": "By default, the /var/lib/kubelet/config.yaml file as set up by `kubeadm` has permissions of 600.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json b/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json index a28421267..66b7a52b3 100644 --- a/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json +++ b/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json @@ -16,5 +16,8 @@ }, "baseScore": 7, "impact_statement": "None", - "default_value": "By default, `/var/lib/kubelet/config.yaml` file as set up by `kubeadm` is owned by `root:root`." + "default_value": "By default, `/var/lib/kubelet/config.yaml` file as set up by `kubeadm` is owned by `root:root`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json b/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json index 36fdc47c8..49ac206f3 100644 --- a/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json +++ b/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "Anonymous requests will be rejected.", - "default_value": "By default, anonymous access is enabled." + "default_value": "By default, anonymous access is enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json b/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json index dafe7c479..403867f8b 100644 --- a/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json +++ b/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "Unauthorized requests will be denied.", - "default_value": "By default, `--authorization-mode` argument is set to `AlwaysAllow`." + "default_value": "By default, `--authorization-mode` argument is set to `AlwaysAllow`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json b/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json index a53f72938..52abb5eb6 100644 --- a/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json +++ b/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "You require TLS to be configured on apiserver as well as kubelets.", - "default_value": "By default, `--client-ca-file` argument is not set." + "default_value": "By default, `--client-ca-file` argument is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0175-verifythatthereadonlyportargumentissetto0.json b/controls/C-0175-verifythatthereadonlyportargumentissetto0.json index 36df8f3ea..9f39a7492 100644 --- a/controls/C-0175-verifythatthereadonlyportargumentissetto0.json +++ b/controls/C-0175-verifythatthereadonlyportargumentissetto0.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "Removal of the read-only port will require that any service which made use of it will need to be re-configured to use the main Kubelet API.", - "default_value": "By default, `--read-only-port` is set to `10255/TCP`. However, if a config file is specified by `--config` the default value for `readOnlyPort` is 0." + "default_value": "By default, `--read-only-port` is set to `10255/TCP`. However, if a config file is specified by `--config` the default value for `readOnlyPort` is 0.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json b/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json index 2565a0401..6b8a66569 100644 --- a/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json +++ b/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "Long-lived connections could be interrupted.", - "default_value": "By default, `--streaming-connection-idle-timeout` is set to 4 hours." + "default_value": "By default, `--streaming-connection-idle-timeout` is set to 4 hours.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json b/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json index 38163513b..b3b389730 100644 --- a/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json +++ b/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 2, "impact_statement": "You would have to re-tune kernel parameters to match kubelet parameters.", - "default_value": "By default, `--protect-kernel-defaults` is not set." + "default_value": "By default, `--protect-kernel-defaults` is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json b/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json index c6d33426b..21dbbf367 100644 --- a/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json +++ b/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "Kubelet would manage the iptables on the system and keep it in sync. If you are using any other iptables management solution, then there might be some conflicts.", - "default_value": "By default, `--make-iptables-util-chains` argument is set to `true`." + "default_value": "By default, `--make-iptables-util-chains` argument is set to `true`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json b/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json index 1251bbca8..707a2163e 100644 --- a/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json +++ b/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json @@ -16,5 +16,8 @@ ], "baseScore": 3, "impact_statement": "Some cloud providers may require this flag to ensure that hostname matches names issued by the cloud provider. In these environments, this recommendation should not apply.", - "default_value": "By default, `--hostname-override` argument is not set." + "default_value": "By default, `--hostname-override` argument is not set.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json b/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json index 7725b08a3..a86633725 100644 --- a/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json +++ b/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json @@ -16,5 +16,8 @@ ], "baseScore": 2, "impact_statement": "Setting this parameter to `0` could result in a denial of service condition due to excessive events being created. The cluster's event processing and storage systems should be scaled to handle expected event loads.", - "default_value": "By default, `--event-qps` argument is set to `5`." + "default_value": "By default, `--event-qps` argument is set to `5`.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json b/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json index 00e21479d..73902fd8e 100644 --- a/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json +++ b/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "", - "default_value": "" + "default_value": "", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json b/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json index c029c9820..9118523d6 100644 --- a/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json +++ b/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "By default, kubelet client certificate rotation is enabled." + "default_value": "By default, kubelet client certificate rotation is enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json b/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json index f9ed078ce..aa36f41b9 100644 --- a/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json +++ b/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "None", - "default_value": "By default, kubelet server certificate rotation is enabled." + "default_value": "By default, kubelet server certificate rotation is enabled.", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json b/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json index 3638f1bba..ce1ce2abf 100644 --- a/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json +++ b/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Kubelet clients that cannot support modern cryptographic ciphers will not be able to make connections to the Kubelet API.", - "default_value": "By default the Kubernetes API server supports a wide range of TLS ciphers" + "default_value": "By default the Kubernetes API server supports a wide range of TLS ciphers", + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json b/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json index f9e375f5b..6a0ae554c 100644 --- a/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json +++ b/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json @@ -17,5 +17,8 @@ ], "baseScore": 8, "impact_statement": "Care should be taken before removing any `clusterrolebindings` from the environment to ensure they were not required for operation of the cluster. Specifically, modifications should not be made to `clusterrolebindings` with the `system:` prefix as they are required for the operation of system components.", - "default_value": "By default a single `clusterrolebinding` called `cluster-admin` is provided with the `system:masters` group as its principal." + "default_value": "By default a single `clusterrolebinding` called `cluster-admin` is provided with the `system:masters` group as its principal.", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0186-minimizeaccesstosecrets.json b/controls/C-0186-minimizeaccesstosecrets.json index 91e986267..90b8197cf 100644 --- a/controls/C-0186-minimizeaccesstosecrets.json +++ b/controls/C-0186-minimizeaccesstosecrets.json @@ -17,5 +17,8 @@ ], "baseScore": 6, "impact_statement": "Care should be taken not to remove access to secrets to system components which require this for their operation", - "default_value": "By default in a kubeadm cluster the following list of principals have `get` privileges on `secret` objects\n\n \n```\nCLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE\ncluster-admin system:masters Group \nsystem:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system\nsystem:controller:expand-controller expand-controller ServiceAccount kube-system\nsystem:controller:generic-garbage-collector generic-garbage-collector ServiceAccount kube-system\nsystem:controller:namespace-controller namespace-controller ServiceAccount kube-system\nsystem:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system\nsystem:kube-controller-manager system:kube-controller-manager User \n\n```" + "default_value": "By default in a kubeadm cluster the following list of principals have `get` privileges on `secret` objects\n\n \n```\nCLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE\ncluster-admin system:masters Group \nsystem:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system\nsystem:controller:expand-controller expand-controller ServiceAccount kube-system\nsystem:controller:generic-garbage-collector generic-garbage-collector ServiceAccount kube-system\nsystem:controller:namespace-controller namespace-controller ServiceAccount kube-system\nsystem:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system\nsystem:kube-controller-manager system:kube-controller-manager User \n\n```", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json b/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json index cf87adde5..b0820d0e4 100644 --- a/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json +++ b/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json @@ -17,5 +17,8 @@ ], "baseScore": 7, "impact_statement": "", - "default_value": "" + "default_value": "", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0188-minimizeaccesstocreatepods.json b/controls/C-0188-minimizeaccesstocreatepods.json index e1180d360..7011f324c 100644 --- a/controls/C-0188-minimizeaccesstocreatepods.json +++ b/controls/C-0188-minimizeaccesstocreatepods.json @@ -17,5 +17,8 @@ ], "baseScore": 5, "impact_statement": "Care should be taken not to remove access to pods to system components which require this for their operation", - "default_value": "By default in a kubeadm cluster the following list of principals have `create` privileges on `pod` objects\n\n \n```\nCLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE\ncluster-admin system:masters Group \nsystem:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system\nsystem:controller:daemon-set-controller daemon-set-controller ServiceAccount kube-system\nsystem:controller:job-controller job-controller ServiceAccount kube-system\nsystem:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system\nsystem:controller:replicaset-controller replicaset-controller ServiceAccount kube-system\nsystem:controller:replication-controller replication-controller ServiceAccount kube-system\nsystem:controller:statefulset-controller statefulset-controller ServiceAccount kube-system\n\n```" + "default_value": "By default in a kubeadm cluster the following list of principals have `create` privileges on `pod` objects\n\n \n```\nCLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE\ncluster-admin system:masters Group \nsystem:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system\nsystem:controller:daemon-set-controller daemon-set-controller ServiceAccount kube-system\nsystem:controller:job-controller job-controller ServiceAccount kube-system\nsystem:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system\nsystem:controller:replicaset-controller replicaset-controller ServiceAccount kube-system\nsystem:controller:replication-controller replication-controller ServiceAccount kube-system\nsystem:controller:statefulset-controller statefulset-controller ServiceAccount kube-system\n\n```", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json b/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json index 47a5118cf..2278e03c6 100644 --- a/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json +++ b/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json @@ -18,5 +18,8 @@ ], "baseScore": 5, "impact_statement": "All workloads which require access to the Kubernetes API will require an explicit service account to be created.", - "default_value": "By default the `default` service account allows for its service account token to be mounted in pods in its namespace." + "default_value": "By default the `default` service account allows for its service account token to be mounted in pods in its namespace.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json b/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json index e09f66ea9..b985df847 100644 --- a/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json +++ b/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json @@ -17,5 +17,8 @@ ], "baseScore": 5, "impact_statement": "Pods mounted without service account tokens will not be able to communicate with the API server, except where the resource is available to unauthenticated principals.", - "default_value": "By default, all pods get a service account token mounted in them." + "default_value": "By default, all pods get a service account token mounted in them.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json b/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json index 8e6c0a96b..1242fdc5e 100644 --- a/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json +++ b/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json @@ -17,5 +17,8 @@ ], "baseScore": 6, "impact_statement": "There are some cases where these permissions are required for cluster service operation, and care should be taken before removing these permissions from system service accounts.", - "default_value": "In a default kubeadm cluster, the system:masters group and clusterrole-aggregation-controller service account have access to the escalate privilege. The system:masters group also has access to bind and impersonate." + "default_value": "In a default kubeadm cluster, the system:masters group and clusterrole-aggregation-controller service account have access to the escalate privilege. The system:masters group also has access to bind and impersonate.", + "categories": [ + "Access control" + ] } \ No newline at end of file diff --git a/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json b/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json index 094941636..11457c7b7 100644 --- a/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json +++ b/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json @@ -17,5 +17,8 @@ ], "baseScore": 4, "impact_statement": "Where policy control systems are in place, there is a risk that workloads required for the operation of the cluster may be stopped from running. Care is required when implementing admission control policies to ensure that this does not occur.", - "default_value": "By default, Pod Security Admission is enabled but no policies are in place." + "default_value": "By default, Pod Security Admission is enabled but no policies are in place.", + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json b/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json index d39da0d2c..a3cc4a4cd 100644 --- a/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json +++ b/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json @@ -16,5 +16,8 @@ ], "baseScore": 8, "impact_statement": "Pods defined with `spec.containers[].securityContext.privileged: true`, `spec.initContainers[].securityContext.privileged: true` and `spec.ephemeralContainers[].securityContext.privileged: true` will not be permitted.", - "default_value": "By default, there are no restrictions on the creation of privileged containers." + "default_value": "By default, there are no restrictions on the creation of privileged containers.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json b/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json index 17485c735..23de1b4de 100644 --- a/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json +++ b/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Pods defined with `spec.hostPID: true` will not be permitted unless they are run under a specific policy.", - "default_value": "By default, there are no restrictions on the creation of `hostPID` containers." + "default_value": "By default, there are no restrictions on the creation of `hostPID` containers.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json b/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json index b35c89718..bc60fdc3a 100644 --- a/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json +++ b/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Pods defined with `spec.hostIPC: true` will not be permitted unless they are run under a specific policy.", - "default_value": "By default, there are no restrictions on the creation of `hostIPC` containers." + "default_value": "By default, there are no restrictions on the creation of `hostIPC` containers.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json b/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json index 5428a8b9d..9b44aba60 100644 --- a/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json +++ b/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Pods defined with `spec.hostNetwork: true` will not be permitted unless they are run under a specific policy.", - "default_value": "By default, there are no restrictions on the creation of `hostNetwork` containers." + "default_value": "By default, there are no restrictions on the creation of `hostNetwork` containers.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json b/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json index 2007bce78..c08c00539 100644 --- a/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json +++ b/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "Pods defined with `spec.allowPrivilegeEscalation: true` will not be permitted unless they are run under a specific policy.", - "default_value": "By default, there are no restrictions on contained process ability to escalate privileges, within the context of the container." + "default_value": "By default, there are no restrictions on contained process ability to escalate privileges, within the context of the container.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0198-minimizetheadmissionofrootcontainers.json b/controls/C-0198-minimizetheadmissionofrootcontainers.json index 6f7e958f7..e4fe4aa73 100644 --- a/controls/C-0198-minimizetheadmissionofrootcontainers.json +++ b/controls/C-0198-minimizetheadmissionofrootcontainers.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "Pods with containers which run as the root user will not be permitted.", - "default_value": "By default, there are no restrictions on the use of root containers and if a User is not specified in the image, the container will run as root." + "default_value": "By default, there are no restrictions on the use of root containers and if a User is not specified in the image, the container will run as root.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json b/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json index c0103bb87..deb58c43b 100644 --- a/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json +++ b/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "Pods with containers which run with the NET\\_RAW capability will not be permitted.", - "default_value": "By default, there are no restrictions on the creation of containers with the `NET_RAW` capability." + "default_value": "By default, there are no restrictions on the creation of containers with the `NET_RAW` capability.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json b/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json index 0b761a97a..67a261fee 100644 --- a/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json +++ b/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Pods with containers which require capabilities outwith the default set will not be permitted.", - "default_value": "By default, there are no restrictions on adding capabilities to containers." + "default_value": "By default, there are no restrictions on adding capabilities to containers.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json b/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json index b237ff336..6fe20d6c5 100644 --- a/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json +++ b/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json @@ -16,5 +16,8 @@ ], "baseScore": 5, "impact_statement": "Pods with containers require capabilities to operate will not be permitted.", - "default_value": "By default, there are no restrictions on the creation of containers with additional capabilities" + "default_value": "By default, there are no restrictions on the creation of containers with additional capabilities", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json b/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json index 582c3d493..f92984c88 100644 --- a/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json +++ b/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json @@ -16,5 +16,8 @@ ], "baseScore": 7, "impact_statement": "Pods defined with `securityContext.windowsOptions.hostProcess: true` will not be permitted unless they are run under a specific policy.", - "default_value": "By default, there are no restrictions on the creation of `hostProcess` containers." + "default_value": "By default, there are no restrictions on the creation of `hostProcess` containers.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0203-minimizetheadmissionofhostpathvolumes.json b/controls/C-0203-minimizetheadmissionofhostpathvolumes.json index e51df920e..5e1a09232 100644 --- a/controls/C-0203-minimizetheadmissionofhostpathvolumes.json +++ b/controls/C-0203-minimizetheadmissionofhostpathvolumes.json @@ -16,5 +16,8 @@ ], "baseScore": 6, "impact_statement": "Pods defined which make use of `hostPath` volumes will not be permitted unless they are run under a spefific policy.", - "default_value": "By default, there are no restrictions on the creation of `hostPath` volumes." + "default_value": "By default, there are no restrictions on the creation of `hostPath` volumes.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json b/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json index 2c40e37a1..dbd28b742 100644 --- a/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json +++ b/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "Pods defined with `hostPort` settings in either the container, initContainer or ephemeralContainer sections will not be permitted unless they are run under a specific policy.", - "default_value": "By default, there are no restrictions on the use of HostPorts." + "default_value": "By default, there are no restrictions on the use of HostPorts.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json b/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json index d1741718a..e3d60c6be 100644 --- a/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json +++ b/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json @@ -16,5 +16,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "This will depend on the CNI plugin in use." + "default_value": "This will depend on the CNI plugin in use.", + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json b/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json index c5656d2ac..aff7af7e5 100644 --- a/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json +++ b/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json @@ -17,5 +17,8 @@ ], "baseScore": 4, "impact_statement": "Once network policies are in use within a given namespace, traffic not explicitly allowed by a network policy will be denied. As such it is important to ensure that, when introducing network policies, legitimate traffic is not blocked.", - "default_value": "By default, network policies are not created." + "default_value": "By default, network policies are not created.", + "categories": [ + "Network" + ] } \ No newline at end of file diff --git a/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json b/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json index eebf58006..39cf71035 100644 --- a/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json +++ b/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json @@ -17,5 +17,8 @@ ], "baseScore": 4, "impact_statement": "Application code which expects to read secrets in the form of environment variables would need modification", - "default_value": "By default, secrets are not defined" + "default_value": "By default, secrets are not defined", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0208-considerexternalsecretstorage.json b/controls/C-0208-considerexternalsecretstorage.json index f9058c757..58f0032ed 100644 --- a/controls/C-0208-considerexternalsecretstorage.json +++ b/controls/C-0208-considerexternalsecretstorage.json @@ -1,4 +1,3 @@ - { "name": "Consider external secret storage", "controlID": "C-0208", @@ -15,6 +14,11 @@ "attributes": { "armoBuiltin": true }, - "rulesNames": ["external-secret-storage"], - "baseScore": 5 + "rulesNames": [ + "external-secret-storage" + ], + "baseScore": 5, + "categories": [ + "Control plane" + ] } \ No newline at end of file diff --git a/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json b/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json index cada4c4a2..8ce3a126b 100644 --- a/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json +++ b/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json @@ -17,5 +17,8 @@ ], "baseScore": 5, "impact_statement": "You need to switch between namespaces for administration.", - "default_value": "By default, Kubernetes starts with two initial namespaces:\n\n 1. `default` - The default namespace for objects with no other namespace\n2. `kube-system` - The namespace for objects created by the Kubernetes system\n3. `kube-node-lease` - Namespace used for node heartbeats\n4. `kube-public` - Namespace used for public information in a cluster" + "default_value": "By default, Kubernetes starts with two initial namespaces:\n\n 1. `default` - The default namespace for objects with no other namespace\n2. `kube-system` - The namespace for objects created by the Kubernetes system\n3. `kube-node-lease` - Namespace used for node heartbeats\n4. `kube-public` - Namespace used for public information in a cluster", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json b/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json index bcdaf0e8b..7000e8999 100644 --- a/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json +++ b/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json @@ -17,5 +17,8 @@ ], "baseScore": 4, "impact_statement": "If the `docker/default` seccomp profile is too restrictive for you, you would have to create/manage your own seccomp profiles.", - "default_value": "By default, seccomp profile is set to `unconfined` which means that no seccomp profiles are enabled." + "default_value": "By default, seccomp profile is set to `unconfined` which means that no seccomp profiles are enabled.", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json b/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json index c092391d0..defc6627d 100644 --- a/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json +++ b/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json @@ -19,13 +19,16 @@ "drop-capability-netraw", "set-seLinuxOptions", "set-seccomp-profile", - "set-procmount-default", - "set-fsgroup-value", - "set-fsgroupchangepolicy-value", - "set-systctls-params", - "set-supplementalgroups-values" + "set-procmount-default", + "set-fsgroup-value", + "set-fsgroupchangepolicy-value", + "set-systctls-params", + "set-supplementalgroups-values" ], "baseScore": 8, "impact_statement": "If you incorrectly apply security contexts, you may have trouble running the pods.", - "default_value": "By default, no security contexts are automatically applied to pods." -} + "default_value": "By default, no security contexts are automatically applied to pods.", + "categories": [ + "Workload" + ] +} \ No newline at end of file diff --git a/controls/C-0212-thedefaultnamespaceshouldnotbeused.json b/controls/C-0212-thedefaultnamespaceshouldnotbeused.json index fe4774531..6020eef8b 100644 --- a/controls/C-0212-thedefaultnamespaceshouldnotbeused.json +++ b/controls/C-0212-thedefaultnamespaceshouldnotbeused.json @@ -24,5 +24,8 @@ ], "baseScore": 4, "impact_statement": "None", - "default_value": "Unless a namespace is specific on object creation, the `default` namespace will be used" + "default_value": "Unless a namespace is specific on object creation, the `default` namespace will be used", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0236-verifyimagesignature.json b/controls/C-0236-verifyimagesignature.json index 3502fe442..266dd3755 100644 --- a/controls/C-0236-verifyimagesignature.json +++ b/controls/C-0236-verifyimagesignature.json @@ -5,8 +5,7 @@ "long_description": "Verifies the signature of each image with given public keys", "remediation": "Replace the image with an image that is signed correctly", "manual_test": "", - "references": [ - ], + "references": [], "attributes": { "actionRequired": "configuration", "armoBuiltin": true @@ -16,5 +15,8 @@ ], "baseScore": 7, "impact_statement": "", - "default_value": "" + "default_value": "", + "categories": [ + "Workload" + ] } \ No newline at end of file diff --git a/controls/C-0237-hasimagesignature.json b/controls/C-0237-hasimagesignature.json index 2830dc6c7..e181b2074 100644 --- a/controls/C-0237-hasimagesignature.json +++ b/controls/C-0237-hasimagesignature.json @@ -5,8 +5,7 @@ "long_description": "Verifies that each image is signed", "remediation": "Replace the image with a signed image", "manual_test": "", - "references": [ - ], + "references": [], "attributes": { "armoBuiltin": true }, @@ -15,5 +14,8 @@ ], "baseScore": 7, "impact_statement": "", - "default_value": "" + "default_value": "", + "categories": [ + "Workload" + ] } \ No newline at end of file From abeea54c9eaa2fe6a9e42d7a92188504a2ffea1e Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Tue, 11 Jul 2023 11:33:49 +0300 Subject: [PATCH 02/11] rename ctrl Signed-off-by: Daniel Grunberger --- controls/C-0036-maliciousadmissioncontrollervalidating.json | 2 +- controls/C-0039-maliciousadmissioncontrollermutating.json | 2 +- frameworks/__YAMLscan.json | 4 ++-- frameworks/allcontrols.json | 4 ++-- frameworks/mitre.json | 4 ++-- rules/list-all-mutating-webhooks/rule.metadata.json | 2 +- rules/list-all-validating-webhooks/rule.metadata.json | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/controls/C-0036-maliciousadmissioncontrollervalidating.json b/controls/C-0036-maliciousadmissioncontrollervalidating.json index 117df6551..b3e1c1a8b 100644 --- a/controls/C-0036-maliciousadmissioncontrollervalidating.json +++ b/controls/C-0036-maliciousadmissioncontrollervalidating.json @@ -1,5 +1,5 @@ { - "name": "Malicious admission controller (validating)", + "name": "Validate admission controller (validating)", "attributes": { "armoBuiltin": true, "microsoftMitreColumns": [ diff --git a/controls/C-0039-maliciousadmissioncontrollermutating.json b/controls/C-0039-maliciousadmissioncontrollermutating.json index faac48634..c93655e94 100644 --- a/controls/C-0039-maliciousadmissioncontrollermutating.json +++ b/controls/C-0039-maliciousadmissioncontrollermutating.json @@ -1,5 +1,5 @@ { - "name": "Malicious admission controller (mutating)", + "name": "Validate admission controller (mutating)", "attributes": { "armoBuiltin": true, "microsoftMitreColumns": [ diff --git a/frameworks/__YAMLscan.json b/frameworks/__YAMLscan.json index 7e94493b6..2e3f7fff8 100644 --- a/frameworks/__YAMLscan.json +++ b/frameworks/__YAMLscan.json @@ -25,10 +25,10 @@ "Access tiller endpoint", "Automatic mapping of service account", "Cluster-admin binding", - "Malicious admission controller (validating)", + "Validate admission controller (validating)", "CoreDNS poisoning", "Host PID/IPC privileges", - "Malicious admission controller (mutating)", + "Validate admission controller (mutating)", "HostNetwork access", "SSH server running inside container", "Container hostPort", diff --git a/frameworks/allcontrols.json b/frameworks/allcontrols.json index e2287f62c..a5c57be96 100644 --- a/frameworks/allcontrols.json +++ b/frameworks/allcontrols.json @@ -129,7 +129,7 @@ { "controlID": "C-0036", "patch": { - "name": "Malicious admission controller (validating)" + "name": "Validate admission controller (validating)" } }, { @@ -141,7 +141,7 @@ { "controlID": "C-0039", "patch": { - "name": "Malicious admission controller (mutating)" + "name": "Validate admission controller (mutating)" } }, { diff --git a/frameworks/mitre.json b/frameworks/mitre.json index da29b4568..af1323a13 100644 --- a/frameworks/mitre.json +++ b/frameworks/mitre.json @@ -69,7 +69,7 @@ { "controlID": "C-0036", "patch": { - "name": "Malicious admission controller (validating)" + "name": "Validate admission controller (validating)" } }, { @@ -81,7 +81,7 @@ { "controlID": "C-0039", "patch": { - "name": "Malicious admission controller (mutating)" + "name": "Validate admission controller (mutating)" } }, { diff --git a/rules/list-all-mutating-webhooks/rule.metadata.json b/rules/list-all-mutating-webhooks/rule.metadata.json index 741f9c10f..f2fed196a 100644 --- a/rules/list-all-mutating-webhooks/rule.metadata.json +++ b/rules/list-all-mutating-webhooks/rule.metadata.json @@ -1,7 +1,7 @@ { "name": "list-all-mutating-webhooks", "attributes": { - "m$K8sThreatMatrix": "Persistence::Malicious admission controller", + "m$K8sThreatMatrix": "Persistence::Validate admission controller", "armoBuiltin": true }, "ruleLanguage": "Rego", diff --git a/rules/list-all-validating-webhooks/rule.metadata.json b/rules/list-all-validating-webhooks/rule.metadata.json index 773466655..d14d41057 100644 --- a/rules/list-all-validating-webhooks/rule.metadata.json +++ b/rules/list-all-validating-webhooks/rule.metadata.json @@ -1,7 +1,7 @@ { "name": "list-all-validating-webhooks", "attributes": { - "m$K8sThreatMatrix": "Credential Access::Malicious admission controller", + "m$K8sThreatMatrix": "Credential Access::Validate admission controller", "armoBuiltin": true }, "ruleLanguage": "Rego", From 2c0d1ea77aa85946648d9746c52bcd469b1bcf39 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Tue, 11 Jul 2023 11:46:50 +0300 Subject: [PATCH 03/11] rename ctrl Signed-off-by: Daniel Grunberger --- controls/C-0074-containersmountingdockersocket.json | 2 +- frameworks/__YAMLscan.json | 2 +- frameworks/allcontrols.json | 2 +- frameworks/devopsbest.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/controls/C-0074-containersmountingdockersocket.json b/controls/C-0074-containersmountingdockersocket.json index f0e2ca8ef..7e97eb4f6 100644 --- a/controls/C-0074-containersmountingdockersocket.json +++ b/controls/C-0074-containersmountingdockersocket.json @@ -1,5 +1,5 @@ { - "name": "Containers mounting Docker socket", + "name": "Container runtime socket mounted", "attributes": { "armoBuiltin": true, "controlTypeTags": [ diff --git a/frameworks/__YAMLscan.json b/frameworks/__YAMLscan.json index 2e3f7fff8..53265b690 100644 --- a/frameworks/__YAMLscan.json +++ b/frameworks/__YAMLscan.json @@ -47,7 +47,7 @@ "Portforwarding privileges", "No impersonation", "Naked PODs", - "Containers mounting Docker socket", + "Container runtime socket mounted", "Image pull policy on latest tag", "Label usage for resources", "K8s common labels usage", diff --git a/frameworks/allcontrols.json b/frameworks/allcontrols.json index a5c57be96..d56b651e9 100644 --- a/frameworks/allcontrols.json +++ b/frameworks/allcontrols.json @@ -303,7 +303,7 @@ { "controlID": "C-0074", "patch": { - "name": "Containers mounting Docker socket" + "name": "Container runtime socket mounted" } }, { diff --git a/frameworks/devopsbest.json b/frameworks/devopsbest.json index 2c7d3adfb..1222bb021 100644 --- a/frameworks/devopsbest.json +++ b/frameworks/devopsbest.json @@ -51,7 +51,7 @@ { "controlID": "C-0074", "patch": { - "name": "Containers mounting Docker socket" + "name": "Container runtime socket mounted" } }, { From 49626012af5b0653387ede6b121d612c92c37ee1 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Wed, 19 Jul 2023 09:28:10 +0300 Subject: [PATCH 04/11] merge master --- FWName_CID_CName.csv | 6 - README.md | 8 - attack-tracks/container.json | 54 --- attack-tracks/kubeapi.json | 39 -- attack-tracks/service-destruction.json | 18 + ...node.json => workload-external-track.json} | 25 +- controls/C-0255-workloadwithsecretaccess.json | 23 ++ controls/C-0256-exposuretointernet.json | 29 ++ controls/C-0257-pvcaccess.json | 23 ++ controls/C-0258-configmapaccess.json | 23 ++ .../C-0259-workloadwithcredentialaccess.json | 23 ++ controls/C-0260-missingnetworkpolicy.json | 23 ++ controls/C-0261-satokenmounted.json | 23 ++ controls/C-0262-anonymousaccessisenabled.json | 15 + frameworks/__YAMLscan.json | 1 - frameworks/allcontrols.json | 24 +- frameworks/armobest.json | 18 - frameworks/security.json | 96 ++++- go.work.sum | 18 +- rules/RBAC-enabled/raw.rego | 74 ---- rules/access-tiller-endpoint/filter.rego | 20 - rules/access-tiller-endpoint/raw.rego | 21 - .../access-tiller-endpoint/rule.metadata.json | 25 -- .../test/test/expected.json | 26 -- .../test/test/input/deployment.yaml | 23 -- rules/anonymous-access-enabled/raw.rego | 30 ++ .../rule.metadata.json | 25 ++ .../test/fail/expected.json | 24 ++ .../test/fail/input/clusterrolebinding.yaml | 19 + .../test/success}/expected.json | 0 .../test/success}/input/rolebinding.yaml | 4 +- rules/deny-RCE-vuln-image-pods/raw.rego | 346 ---------------- rules/deny-vuln-image-pods/raw.rego | 141 ------- rules/deny-vuln-image-pods/rule.metadata.json | 59 --- .../input/rolebinding.yaml | 6 +- .../raw.rego | 37 -- .../rule.metadata.json | 36 -- .../test/failed/expected.json | 365 ---------------- .../test/failed/input/1.json | 109 ----- .../test/failed/input/2.json | 109 ----- .../test/failed/input/3.json | 109 ----- .../test/passed/input/1.json | 96 ----- .../raw.rego | 78 ++++ .../rule.metadata.json | 61 +++ .../expected.json | 23 ++ .../input/cronjob.yaml | 17 + .../input/network_policy.yaml | 12 + .../expected.json | 26 ++ .../input/deployment.yaml | 19 + .../input/network_policy.yaml | 12 + .../failed_pod_no_matched_label/expected.json | 26 ++ .../input/network_policy.yaml | 12 + .../input/network_policy2.yaml | 13 + .../input/pod.yaml | 10 + .../failed_pod_no_networkpolicy/expected.json | 23 ++ .../input/pod.yaml | 23 ++ .../expected.json | 0 .../input/cronjob.yaml | 17 + .../input/network_policy.yaml | 12 + .../expected.json | 0 .../input/deployment.yaml | 19 + .../input/network_policy.yaml | 12 + .../success_pod_label_match}/expected.json | 0 .../input/network_policy.yaml | 12 + .../success_pod_label_match/input/pod.yaml | 10 + .../expected.json | 0 .../input/network_policy.yaml | 10 + .../input/pod.yaml | 10 + .../expected.json | 0 .../input/network_policy.yaml | 11 + .../input/pod.yaml | 11 + rules/exposure-to-internet/raw.rego | 89 ++++ .../rule.metadata.json | 28 +- .../test/failed_with_ingress/expected.json | 56 +++ .../failed_with_ingress/input/deployment.yaml | 20 + .../failed_with_ingress/input/ingress.yaml | 17 + .../failed_with_ingress/input/service.yaml | 11 + .../expected.json | 59 +++ .../input/deployment.yaml | 20 + .../input/service.yaml | 6 +- .../expected.json | 49 +++ .../input/deployment.yaml | 20 + .../input/service.yaml | 12 + .../test/success_with_ingress/expected.json | 1 + .../input/deployment.yaml | 20 + .../success_with_ingress/input/ingress.yaml | 17 + .../success_with_ingress/input/service.yaml | 11 + rules/has-critical-vulnerability/filter.rego | 121 ------ rules/has-critical-vulnerability/raw.rego | 141 ------- .../rule.metadata.json | 71 ---- .../test/test-fail/expected.json | 136 ------ .../test/test-fail/input/pod.yaml | 21 - .../test/test-fail/input/resource.json | 87 ---- rules/image-pull-secrets/raw.rego | 22 - rules/image-pull-secrets/rule.metadata.json | 25 -- .../test/test/expected.json | 13 - .../test/test/input/serviceaccount1.yaml | 9 - .../test/test/input/serviceaccount2.yaml | 9 - .../rule.metadata.json | 36 +- rules/more-than-one-replicas/raw.rego | 47 --- .../more-than-one-replicas/rule.metadata.json | 27 -- .../test/deployment/expected.json | 23 -- .../test/deployment/input/wl.yaml | 22 - .../test/deployment/input/wl2.yaml | 21 - .../test/statefulset/expected.json | 17 - .../test/statefulset/input/statefulset.yaml | 35 -- rules/pod-specific-version-tag/raw.rego | 63 --- .../test/cronjob/expected.json | 44 -- .../test/cronjob/input/cronjob.yaml | 33 -- .../test/pod/expected.json | 26 -- .../test/pod/input/pod.yaml | 16 - .../test/workload/expected.json | 26 -- .../test/workload/input/workload.yaml | 26 -- .../rule.metadata.json | 28 +- .../rule.metadata.json | 4 +- rules/rule-access-kubelet-API/raw.rego | 21 - .../rule.metadata.json | 25 -- .../test/test/input/wl.yaml | 20 - .../raw.rego | 89 ---- .../rule.metadata.json | 66 --- .../rule-can-bind-escalate/rule.metadata.json | 4 +- .../raw.rego | 163 -------- .../rule.metadata.json | 30 -- .../expected.json | 144 ------- .../input/clusterrole.yaml | 9 - .../input/clusterrolebinding.yaml | 15 - .../test/role-rolebinding/expected.json | 89 ---- .../test/role-rolebinding/input/role.yaml | 9 - .../role-rolebinding/input/rolebinding.yaml | 13 - .../raw.rego | 389 ------------------ .../rule.metadata.json | 34 -- rules/rule-can-create-modify-pod-v1/raw.rego | 64 --- .../rule.metadata.json | 30 -- .../input/clusterrole.yaml | 8 - .../input/clusterrolebinding.yaml | 15 - .../clusterrole-rolebinding/expected.json | 44 -- .../input/cluterrole.yaml | 8 - .../test/role-rolebinding/expected.json | 45 -- .../test/role-rolebinding/input/role.yaml | 9 - rules/rule-can-create-modify-pod/raw.rego | 156 ------- .../rule.metadata.json | 34 -- .../raw.rego | 77 ---- .../rule.metadata.json | 30 -- .../expected.json | 142 ------- .../input/clusterrole.yaml | 8 - .../input/clusterrolebinding.yaml | 15 - .../clusterrole-rolebinding/expected.json | 68 --- .../input/cluterrole.yaml | 8 - .../input/rolebinding.yaml | 13 - .../test/role-rolebinding/expected.json | 45 -- .../test/role-rolebinding/input/role.yaml | 9 - .../role-rolebinding/input/rolebinding.yaml | 13 - .../rule-can-create-pod-kube-system/raw.rego | 141 ------- .../rule.metadata.json | 34 -- rules/rule-can-create-pod/rule.metadata.json | 4 +- .../raw.rego | 64 --- .../rule.metadata.json | 30 -- .../expected.json | 142 ------- .../input/clusterrole.yaml | 8 - .../input/clusterrolebinding.yaml | 15 - .../clusterrole-rolebinding/expected.json | 44 -- .../input/cluterrole.yaml | 8 - .../input/rolebinding.yaml | 13 - .../test/role-rolebinding/expected.json | 45 -- .../test/role-rolebinding/input/role.yaml | 9 - .../role-rolebinding/input/rolebinding.yaml | 13 - rules/rule-can-delete-create-service/raw.rego | 137 ------ .../rule.metadata.json | 34 -- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- rules/rule-can-delete-logs-v1/raw.rego | 64 --- .../rule.metadata.json | 30 -- .../expected.json | 142 ------- .../input/clusterrole.yaml | 8 - .../input/clusterrolebinding.yaml | 15 - .../clusterrole-rolebinding/expected.json | 44 -- .../input/cluterrole.yaml | 8 - .../input/rolebinding.yaml | 13 - .../test/role-rolebinding/expected.json | 45 -- .../test/role-rolebinding/input/role.yaml | 9 - .../role-rolebinding/input/rolebinding.yaml | 13 - rules/rule-can-delete-logs/raw.rego | 146 ------- rules/rule-can-delete-logs/rule.metadata.json | 34 -- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- rules/rule-can-portforward/rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- rules/rule-exposed-dashboard-v1/filter.rego | 45 -- rules/rule-exposed-dashboard-v1/raw.rego | 46 --- .../rule.metadata.json | 27 -- .../test/test/expected.json | 51 --- .../test/test/input/deployment.yaml | 63 --- rules/rule-exposed-dashboard/raw.rego | 40 -- .../rule-exposed-dashboard/rule.metadata.json | 27 -- .../rule.metadata.json | 36 +- .../rule.metadata.json | 36 +- .../rule.metadata.json | 4 +- .../rule.metadata.json | 4 +- rules/rule-name-similarity/raw.rego | 28 -- rules/rule-name-similarity/rule.metadata.json | 37 -- .../test/job/expected.json | 23 -- .../test/job/input/job.yaml | 13 - .../test/pod/expected.json | 26 -- .../test/pod/input/pod.yaml | 10 - .../test/replicaset/expected.json | 27 -- .../test/replicaset/input/replicaset.yaml | 22 - rules/security-context-in-pod/raw.rego | 87 ---- .../test/cronjob/input/cronjob.yaml | 27 -- .../test/pod/expected.json | 29 -- .../test/pod/input/pod.yaml | 22 - .../test/workloads/expected.json | 56 --- .../test/workloads/input/deployment.yaml | 32 -- rules/serviceaccount-token-mount/raw.rego | 131 ++++++ .../rule.metadata.json | 64 +++ .../test/both-mount-default/expected.json | 1 + .../test/both-mount-default/input/file.yaml | 15 + .../input/serviceaccount.json | 16 + .../test/both-mount/expected.json | 2 + .../test/both-mount/input/file.yaml | 17 + .../test/both-mount/input/sa.json | 17 + .../test/pod-mount-and-rb-bind/expected.json | 20 + .../pod-mount-and-rb-bind/input/file.yaml | 17 + .../input/rolebinding.yaml | 14 +- .../input/serviceaccount.json | 17 + .../test/pod-mount}/expected.json | 0 .../test/pod-mount/input/file.yaml | 16 + .../test/pod-mount/input/serviceaccount.json | 17 + .../test/sa-mount/expected.json | 1 + .../test/sa-mount/input/file.yaml | 16 + .../test/sa-mount/input/serviceaccount.json | 17 + rules/sidecar-injection/raw.rego | 122 ------ rules/sidecar-injection/rule.metadata.json | 31 -- rules/strict-file-owners-root/filter.rego | 23 -- rules/strict-file-owners-root/raw.rego | 91 ---- .../rule.metadata.json | 39 -- .../test/invalid-group/data.json | 7 - .../test/invalid-group/expected.json | 31 -- .../invalid-group/input/kubelet-info.json | 18 - .../test/invalid-user/data.json | 7 - .../test/invalid-user/expected.json | 31 -- .../test/invalid-user/input/kubelet-info.json | 18 - .../test/valid/data.json | 7 - .../test/valid/input/kubelet-info.json | 18 - rules/strict-file-permissions-600/filter.rego | 23 -- rules/strict-file-permissions-600/raw.rego | 93 ----- .../rule.metadata.json | 39 -- .../test/invalid-everyone/data.json | 7 - .../test/invalid-everyone/expected.json | 31 -- .../input/kube-proxy-info.json | 18 - .../test/invalid-group/data.json | 7 - .../test/invalid-group/expected.json | 31 -- .../invalid-group/input/kubelet-info.json | 18 - .../test/valid/data.json | 7 - .../test/valid/input/kubelet-info.json | 18 - rules/strict-file-permissions-700/filter.rego | 23 -- rules/strict-file-permissions-700/raw.rego | 93 ----- .../rule.metadata.json | 39 -- .../test/invalid-everyone/data.json | 7 - .../test/invalid-everyone/expected.json | 31 -- .../input/kube-proxy-info.json | 18 - .../test/invalid-group/data.json | 7 - .../test/invalid-group/expected.json | 31 -- .../invalid-group/input/kubelet-info.json | 18 - .../test/valid/data.json | 7 - .../test/valid/input/kubelet-info.json | 18 - rules/user-id-less-than-thousands/raw.rego | 172 -------- .../test/cronjob/expected.json | 23 -- .../test/cronjob/input/cronjob.yaml | 32 -- .../test/pod/expected.json | 26 -- .../test/pod/input/pod.yaml | 16 - .../test/workloads/expected.json | 50 --- .../test/workloads/input/deployment.yaml | 39 -- rules/workload-mounted-configmap/raw.rego | 99 +++++ .../rule.metadata.json | 11 +- .../test/failed_pod/expected.json | 24 ++ .../test/failed_pod/input/configmap.yaml | 8 + .../test/failed_pod/input/pod.yaml | 23 ++ .../expected.json | 1 + .../input/configmap.yaml | 8 + .../input/pod.yaml | 23 ++ .../test/success_no_configmap/expected.json | 1 + .../test/success_no_configmap/input/pod.yaml | 18 + rules/workload-mounted-pvc/raw.rego | 97 +++++ .../rule.metadata.json | 11 +- .../test/failed_pod_mounted/expected.json | 24 ++ .../test/failed_pod_mounted/input/PVC.yaml | 17 + .../test/failed_pod_mounted/input/pod.yaml | 15 + .../expected.json | 1 + .../input/PVC.yaml | 17 + .../input/pod.yaml | 16 + .../test/success_no_PVC/expected.json | 1 + .../test/success_no_PVC/input/pod.yaml | 18 + .../expected.json | 1 + .../input/PVC.yaml | 17 + .../input/pod.yaml | 15 + rules/workload-mounted-secrets/raw.rego | 96 +++++ .../rule.metadata.json | 17 +- .../test/failed/expected.json | 23 ++ .../test/failed/input/pod.yaml | 18 + .../test/failed/input/secret.yaml | 8 + .../test/success/expected.json | 1 + .../test/success/input/pod.yaml | 16 + scripts/init-rule.py | 2 +- scripts/validations.py | 16 +- testrunner/go.mod | 3 + testrunner/go.sum | 4 + testrunner/opaprocessor/processorutils.go | 42 +- 312 files changed, 2545 insertions(+), 8342 deletions(-) delete mode 100644 attack-tracks/container.json delete mode 100644 attack-tracks/kubeapi.json create mode 100644 attack-tracks/service-destruction.json rename attack-tracks/{node.json => workload-external-track.json} (57%) create mode 100644 controls/C-0255-workloadwithsecretaccess.json create mode 100644 controls/C-0256-exposuretointernet.json create mode 100644 controls/C-0257-pvcaccess.json create mode 100644 controls/C-0258-configmapaccess.json create mode 100644 controls/C-0259-workloadwithcredentialaccess.json create mode 100644 controls/C-0260-missingnetworkpolicy.json create mode 100644 controls/C-0261-satokenmounted.json create mode 100644 controls/C-0262-anonymousaccessisenabled.json delete mode 100644 rules/RBAC-enabled/raw.rego delete mode 100644 rules/access-tiller-endpoint/filter.rego delete mode 100644 rules/access-tiller-endpoint/raw.rego delete mode 100644 rules/access-tiller-endpoint/rule.metadata.json delete mode 100644 rules/access-tiller-endpoint/test/test/expected.json delete mode 100644 rules/access-tiller-endpoint/test/test/input/deployment.yaml create mode 100644 rules/anonymous-access-enabled/raw.rego create mode 100644 rules/anonymous-access-enabled/rule.metadata.json create mode 100644 rules/anonymous-access-enabled/test/fail/expected.json create mode 100644 rules/anonymous-access-enabled/test/fail/input/clusterrolebinding.yaml rename rules/{ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/passed => anonymous-access-enabled/test/success}/expected.json (100%) rename rules/{rule-can-create-modify-pod-v1/test/role-rolebinding => anonymous-access-enabled/test/success}/input/rolebinding.yaml (77%) delete mode 100644 rules/deny-RCE-vuln-image-pods/raw.rego delete mode 100644 rules/deny-vuln-image-pods/raw.rego delete mode 100644 rules/deny-vuln-image-pods/rule.metadata.json delete mode 100644 rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/raw.rego delete mode 100644 rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/rule.metadata.json delete mode 100644 rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/expected.json delete mode 100644 rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/1.json delete mode 100644 rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/2.json delete mode 100644 rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/3.json delete mode 100644 rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/passed/input/1.json create mode 100644 rules/ensure_network_policy_configured_in_labels/raw.rego create mode 100644 rules/ensure_network_policy_configured_in_labels/rule.metadata.json create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/expected.json create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/cronjob.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/network_policy.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/expected.json create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/deployment.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/network_policy.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/expected.json create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy2.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/pod.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/expected.json create mode 100644 rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/input/pod.yaml rename rules/{rule-access-kubelet-API/test/test => ensure_network_policy_configured_in_labels/test/success_cronjob_label_match}/expected.json (100%) create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/cronjob.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/network_policy.yaml rename rules/{rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding => ensure_network_policy_configured_in_labels/test/success_deployment_label_match}/expected.json (100%) create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/deployment.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/network_policy.yaml rename rules/{security-context-in-pod/test/cronjob => ensure_network_policy_configured_in_labels/test/success_pod_label_match}/expected.json (100%) create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/network_policy.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/pod.yaml rename rules/{strict-file-owners-root/test/valid => ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector}/expected.json (100%) create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/network_policy.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/pod.yaml rename rules/{strict-file-permissions-600/test/valid => ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns}/expected.json (100%) create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/network_policy.yaml create mode 100644 rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/pod.yaml create mode 100644 rules/exposure-to-internet/raw.rego rename rules/{deny-RCE-vuln-image-pods => exposure-to-internet}/rule.metadata.json (60%) create mode 100644 rules/exposure-to-internet/test/failed_with_ingress/expected.json create mode 100644 rules/exposure-to-internet/test/failed_with_ingress/input/deployment.yaml create mode 100644 rules/exposure-to-internet/test/failed_with_ingress/input/ingress.yaml create mode 100644 rules/exposure-to-internet/test/failed_with_ingress/input/service.yaml create mode 100644 rules/exposure-to-internet/test/failed_with_service_loadbalancer/expected.json create mode 100644 rules/exposure-to-internet/test/failed_with_service_loadbalancer/input/deployment.yaml rename rules/{rule-exposed-dashboard-v1/test/test => exposure-to-internet/test/failed_with_service_loadbalancer}/input/service.yaml (71%) create mode 100644 rules/exposure-to-internet/test/failed_with_service_nodeport/expected.json create mode 100644 rules/exposure-to-internet/test/failed_with_service_nodeport/input/deployment.yaml create mode 100644 rules/exposure-to-internet/test/failed_with_service_nodeport/input/service.yaml create mode 100644 rules/exposure-to-internet/test/success_with_ingress/expected.json create mode 100644 rules/exposure-to-internet/test/success_with_ingress/input/deployment.yaml create mode 100644 rules/exposure-to-internet/test/success_with_ingress/input/ingress.yaml create mode 100644 rules/exposure-to-internet/test/success_with_ingress/input/service.yaml delete mode 100644 rules/has-critical-vulnerability/filter.rego delete mode 100644 rules/has-critical-vulnerability/raw.rego delete mode 100644 rules/has-critical-vulnerability/rule.metadata.json delete mode 100644 rules/has-critical-vulnerability/test/test-fail/expected.json delete mode 100644 rules/has-critical-vulnerability/test/test-fail/input/pod.yaml delete mode 100644 rules/has-critical-vulnerability/test/test-fail/input/resource.json delete mode 100644 rules/image-pull-secrets/raw.rego delete mode 100644 rules/image-pull-secrets/rule.metadata.json delete mode 100644 rules/image-pull-secrets/test/test/expected.json delete mode 100644 rules/image-pull-secrets/test/test/input/serviceaccount1.yaml delete mode 100644 rules/image-pull-secrets/test/test/input/serviceaccount2.yaml delete mode 100644 rules/more-than-one-replicas/raw.rego delete mode 100644 rules/more-than-one-replicas/rule.metadata.json delete mode 100644 rules/more-than-one-replicas/test/deployment/expected.json delete mode 100644 rules/more-than-one-replicas/test/deployment/input/wl.yaml delete mode 100644 rules/more-than-one-replicas/test/deployment/input/wl2.yaml delete mode 100644 rules/more-than-one-replicas/test/statefulset/expected.json delete mode 100644 rules/more-than-one-replicas/test/statefulset/input/statefulset.yaml delete mode 100644 rules/pod-specific-version-tag/raw.rego delete mode 100644 rules/pod-specific-version-tag/test/cronjob/expected.json delete mode 100644 rules/pod-specific-version-tag/test/cronjob/input/cronjob.yaml delete mode 100644 rules/pod-specific-version-tag/test/pod/expected.json delete mode 100644 rules/pod-specific-version-tag/test/pod/input/pod.yaml delete mode 100644 rules/pod-specific-version-tag/test/workload/expected.json delete mode 100644 rules/pod-specific-version-tag/test/workload/input/workload.yaml delete mode 100644 rules/rule-access-kubelet-API/raw.rego delete mode 100644 rules/rule-access-kubelet-API/rule.metadata.json delete mode 100644 rules/rule-access-kubelet-API/test/test/input/wl.yaml delete mode 100644 rules/rule-can-bash-cmd-inside-container/raw.rego delete mode 100644 rules/rule-can-bash-cmd-inside-container/rule.metadata.json delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/raw.rego delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/rule.metadata.json delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/expected.json delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/expected.json delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/role.yaml delete mode 100644 rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/rolebinding.yaml delete mode 100644 rules/rule-can-create-bind-escalate-role/raw.rego delete mode 100644 rules/rule-can-create-bind-escalate-role/rule.metadata.json delete mode 100644 rules/rule-can-create-modify-pod-v1/raw.rego delete mode 100644 rules/rule-can-create-modify-pod-v1/rule.metadata.json delete mode 100644 rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml delete mode 100644 rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml delete mode 100644 rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/expected.json delete mode 100644 rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/input/cluterrole.yaml delete mode 100644 rules/rule-can-create-modify-pod-v1/test/role-rolebinding/expected.json delete mode 100644 rules/rule-can-create-modify-pod-v1/test/role-rolebinding/input/role.yaml delete mode 100644 rules/rule-can-create-modify-pod/raw.rego delete mode 100644 rules/rule-can-create-modify-pod/rule.metadata.json delete mode 100644 rules/rule-can-create-pod-kube-system-v1/raw.rego delete mode 100644 rules/rule-can-create-pod-kube-system-v1/rule.metadata.json delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/expected.json delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/expected.json delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/cluterrole.yaml delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/rolebinding.yaml delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/expected.json delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/role.yaml delete mode 100644 rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/rolebinding.yaml delete mode 100644 rules/rule-can-create-pod-kube-system/raw.rego delete mode 100644 rules/rule-can-create-pod-kube-system/rule.metadata.json delete mode 100644 rules/rule-can-delete-create-service-v1/raw.rego delete mode 100644 rules/rule-can-delete-create-service-v1/rule.metadata.json delete mode 100644 rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/expected.json delete mode 100644 rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml delete mode 100644 rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml delete mode 100644 rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/expected.json delete mode 100644 rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/cluterrole.yaml delete mode 100644 rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/rolebinding.yaml delete mode 100644 rules/rule-can-delete-create-service-v1/test/role-rolebinding/expected.json delete mode 100644 rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/role.yaml delete mode 100644 rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/rolebinding.yaml delete mode 100644 rules/rule-can-delete-create-service/raw.rego delete mode 100644 rules/rule-can-delete-create-service/rule.metadata.json delete mode 100644 rules/rule-can-delete-logs-v1/raw.rego delete mode 100644 rules/rule-can-delete-logs-v1/rule.metadata.json delete mode 100644 rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/expected.json delete mode 100644 rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml delete mode 100644 rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml delete mode 100644 rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/expected.json delete mode 100644 rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/cluterrole.yaml delete mode 100644 rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/rolebinding.yaml delete mode 100644 rules/rule-can-delete-logs-v1/test/role-rolebinding/expected.json delete mode 100644 rules/rule-can-delete-logs-v1/test/role-rolebinding/input/role.yaml delete mode 100644 rules/rule-can-delete-logs-v1/test/role-rolebinding/input/rolebinding.yaml delete mode 100644 rules/rule-can-delete-logs/raw.rego delete mode 100644 rules/rule-can-delete-logs/rule.metadata.json delete mode 100644 rules/rule-exposed-dashboard-v1/filter.rego delete mode 100644 rules/rule-exposed-dashboard-v1/raw.rego delete mode 100644 rules/rule-exposed-dashboard-v1/rule.metadata.json delete mode 100644 rules/rule-exposed-dashboard-v1/test/test/expected.json delete mode 100644 rules/rule-exposed-dashboard-v1/test/test/input/deployment.yaml delete mode 100644 rules/rule-exposed-dashboard/raw.rego delete mode 100644 rules/rule-exposed-dashboard/rule.metadata.json delete mode 100644 rules/rule-name-similarity/raw.rego delete mode 100644 rules/rule-name-similarity/rule.metadata.json delete mode 100644 rules/rule-name-similarity/test/job/expected.json delete mode 100644 rules/rule-name-similarity/test/job/input/job.yaml delete mode 100644 rules/rule-name-similarity/test/pod/expected.json delete mode 100644 rules/rule-name-similarity/test/pod/input/pod.yaml delete mode 100644 rules/rule-name-similarity/test/replicaset/expected.json delete mode 100644 rules/rule-name-similarity/test/replicaset/input/replicaset.yaml delete mode 100644 rules/security-context-in-pod/raw.rego delete mode 100644 rules/security-context-in-pod/test/cronjob/input/cronjob.yaml delete mode 100644 rules/security-context-in-pod/test/pod/expected.json delete mode 100644 rules/security-context-in-pod/test/pod/input/pod.yaml delete mode 100644 rules/security-context-in-pod/test/workloads/expected.json delete mode 100644 rules/security-context-in-pod/test/workloads/input/deployment.yaml create mode 100644 rules/serviceaccount-token-mount/raw.rego create mode 100644 rules/serviceaccount-token-mount/rule.metadata.json create mode 100644 rules/serviceaccount-token-mount/test/both-mount-default/expected.json create mode 100644 rules/serviceaccount-token-mount/test/both-mount-default/input/file.yaml create mode 100644 rules/serviceaccount-token-mount/test/both-mount-default/input/serviceaccount.json create mode 100644 rules/serviceaccount-token-mount/test/both-mount/expected.json create mode 100644 rules/serviceaccount-token-mount/test/both-mount/input/file.yaml create mode 100644 rules/serviceaccount-token-mount/test/both-mount/input/sa.json create mode 100644 rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/expected.json create mode 100644 rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/file.yaml rename rules/{rule-can-create-modify-pod-v1/test/clusterrole-rolebinding => serviceaccount-token-mount/test/pod-mount-and-rb-bind}/input/rolebinding.yaml (56%) create mode 100644 rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/serviceaccount.json rename rules/{strict-file-permissions-700/test/valid => serviceaccount-token-mount/test/pod-mount}/expected.json (100%) create mode 100644 rules/serviceaccount-token-mount/test/pod-mount/input/file.yaml create mode 100644 rules/serviceaccount-token-mount/test/pod-mount/input/serviceaccount.json create mode 100644 rules/serviceaccount-token-mount/test/sa-mount/expected.json create mode 100644 rules/serviceaccount-token-mount/test/sa-mount/input/file.yaml create mode 100644 rules/serviceaccount-token-mount/test/sa-mount/input/serviceaccount.json delete mode 100644 rules/sidecar-injection/raw.rego delete mode 100644 rules/sidecar-injection/rule.metadata.json delete mode 100644 rules/strict-file-owners-root/filter.rego delete mode 100644 rules/strict-file-owners-root/raw.rego delete mode 100644 rules/strict-file-owners-root/rule.metadata.json delete mode 100644 rules/strict-file-owners-root/test/invalid-group/data.json delete mode 100644 rules/strict-file-owners-root/test/invalid-group/expected.json delete mode 100644 rules/strict-file-owners-root/test/invalid-group/input/kubelet-info.json delete mode 100644 rules/strict-file-owners-root/test/invalid-user/data.json delete mode 100644 rules/strict-file-owners-root/test/invalid-user/expected.json delete mode 100644 rules/strict-file-owners-root/test/invalid-user/input/kubelet-info.json delete mode 100644 rules/strict-file-owners-root/test/valid/data.json delete mode 100644 rules/strict-file-owners-root/test/valid/input/kubelet-info.json delete mode 100644 rules/strict-file-permissions-600/filter.rego delete mode 100644 rules/strict-file-permissions-600/raw.rego delete mode 100644 rules/strict-file-permissions-600/rule.metadata.json delete mode 100644 rules/strict-file-permissions-600/test/invalid-everyone/data.json delete mode 100644 rules/strict-file-permissions-600/test/invalid-everyone/expected.json delete mode 100644 rules/strict-file-permissions-600/test/invalid-everyone/input/kube-proxy-info.json delete mode 100644 rules/strict-file-permissions-600/test/invalid-group/data.json delete mode 100644 rules/strict-file-permissions-600/test/invalid-group/expected.json delete mode 100644 rules/strict-file-permissions-600/test/invalid-group/input/kubelet-info.json delete mode 100644 rules/strict-file-permissions-600/test/valid/data.json delete mode 100644 rules/strict-file-permissions-600/test/valid/input/kubelet-info.json delete mode 100644 rules/strict-file-permissions-700/filter.rego delete mode 100644 rules/strict-file-permissions-700/raw.rego delete mode 100644 rules/strict-file-permissions-700/rule.metadata.json delete mode 100644 rules/strict-file-permissions-700/test/invalid-everyone/data.json delete mode 100644 rules/strict-file-permissions-700/test/invalid-everyone/expected.json delete mode 100644 rules/strict-file-permissions-700/test/invalid-everyone/input/kube-proxy-info.json delete mode 100644 rules/strict-file-permissions-700/test/invalid-group/data.json delete mode 100644 rules/strict-file-permissions-700/test/invalid-group/expected.json delete mode 100644 rules/strict-file-permissions-700/test/invalid-group/input/kubelet-info.json delete mode 100644 rules/strict-file-permissions-700/test/valid/data.json delete mode 100644 rules/strict-file-permissions-700/test/valid/input/kubelet-info.json delete mode 100644 rules/user-id-less-than-thousands/raw.rego delete mode 100644 rules/user-id-less-than-thousands/test/cronjob/expected.json delete mode 100644 rules/user-id-less-than-thousands/test/cronjob/input/cronjob.yaml delete mode 100644 rules/user-id-less-than-thousands/test/pod/expected.json delete mode 100644 rules/user-id-less-than-thousands/test/pod/input/pod.yaml delete mode 100644 rules/user-id-less-than-thousands/test/workloads/expected.json delete mode 100644 rules/user-id-less-than-thousands/test/workloads/input/deployment.yaml create mode 100644 rules/workload-mounted-configmap/raw.rego rename rules/{pod-specific-version-tag => workload-mounted-configmap}/rule.metadata.json (74%) create mode 100644 rules/workload-mounted-configmap/test/failed_pod/expected.json create mode 100644 rules/workload-mounted-configmap/test/failed_pod/input/configmap.yaml create mode 100644 rules/workload-mounted-configmap/test/failed_pod/input/pod.yaml create mode 100644 rules/workload-mounted-configmap/test/success_different_namespaces/expected.json create mode 100644 rules/workload-mounted-configmap/test/success_different_namespaces/input/configmap.yaml create mode 100644 rules/workload-mounted-configmap/test/success_different_namespaces/input/pod.yaml create mode 100644 rules/workload-mounted-configmap/test/success_no_configmap/expected.json create mode 100644 rules/workload-mounted-configmap/test/success_no_configmap/input/pod.yaml create mode 100644 rules/workload-mounted-pvc/raw.rego rename rules/{security-context-in-pod => workload-mounted-pvc}/rule.metadata.json (73%) create mode 100644 rules/workload-mounted-pvc/test/failed_pod_mounted/expected.json create mode 100644 rules/workload-mounted-pvc/test/failed_pod_mounted/input/PVC.yaml create mode 100644 rules/workload-mounted-pvc/test/failed_pod_mounted/input/pod.yaml create mode 100644 rules/workload-mounted-pvc/test/success_different_namespaces/expected.json create mode 100644 rules/workload-mounted-pvc/test/success_different_namespaces/input/PVC.yaml create mode 100644 rules/workload-mounted-pvc/test/success_different_namespaces/input/pod.yaml create mode 100644 rules/workload-mounted-pvc/test/success_no_PVC/expected.json create mode 100644 rules/workload-mounted-pvc/test/success_no_PVC/input/pod.yaml create mode 100644 rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/expected.json create mode 100644 rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/PVC.yaml create mode 100644 rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/pod.yaml create mode 100644 rules/workload-mounted-secrets/raw.rego rename rules/{user-id-less-than-thousands => workload-mounted-secrets}/rule.metadata.json (67%) create mode 100644 rules/workload-mounted-secrets/test/failed/expected.json create mode 100644 rules/workload-mounted-secrets/test/failed/input/pod.yaml create mode 100644 rules/workload-mounted-secrets/test/failed/input/secret.yaml create mode 100644 rules/workload-mounted-secrets/test/success/expected.json create mode 100644 rules/workload-mounted-secrets/test/success/input/pod.yaml diff --git a/FWName_CID_CName.csv b/FWName_CID_CName.csv index 1d346dabe..51a00a66e 100644 --- a/FWName_CID_CName.csv +++ b/FWName_CID_CName.csv @@ -55,9 +55,6 @@ AllControls,C-0077,K8s common labels usage AllControls,C-0078,Images from allowed registry AllControls,C-0079,CVE-2022-0185-linux-kernel-container-escape AllControls,C-0081,CVE-2022-24348-argocddirtraversal -AllControls,C-0083,Workloads with Critical vulnerabilities exposed to external traffic -AllControls,C-0084,Workloads with RCE vulnerabilities exposed to external traffic -AllControls,C-0085,Workloads with excessive amount of vulnerabilities AllControls,C-0086,CVE-2022-0492-cgroups-container-escape AllControls,C-0087,CVE-2022-23648-containerd-fs-escape AllControls,C-0088,RBAC enabled @@ -96,9 +93,6 @@ ArmoBest,C-0070,Enforce Kubelet client TLS authentication ArmoBest,C-0078,Images from allowed registry ArmoBest,C-0079,CVE-2022-0185-linux-kernel-container-escape ArmoBest,C-0081,CVE-2022-24348-argocddirtraversal -ArmoBest,C-0083,Workloads with Critical vulnerabilities exposed to external traffic -ArmoBest,C-0084,Workloads with RCE vulnerabilities exposed to external traffic -ArmoBest,C-0085,Workloads with excessive amount of vulnerabilities ArmoBest,C-0086,CVE-2022-0492-cgroups-container-escape ArmoBest,C-0087,CVE-2022-23648-containerd-fs-escape ArmoBest,C-0089,CVE-2022-3172-aggregated-API-server-redirect diff --git a/README.md b/README.md index 929ba25ee..5eb8cd968 100644 --- a/README.md +++ b/README.md @@ -299,14 +299,6 @@ The following rules are not supported in the OPA bundles: - exposed-critical-pods -#### Controls -The following controls are not supported in the OPA bundles: - -- C-0085 - Workloads with excessive amount of vulnerabilities -- C-0084 - Workloads with RCE vulnerabilities exposed to external traffic -- C-0083 - Workloads with critical vulnerabilities exposed to external traffic - - ## Support & Communication Reach out if you have any questions: diff --git a/attack-tracks/container.json b/attack-tracks/container.json deleted file mode 100644 index 3774587f4..000000000 --- a/attack-tracks/container.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "apiVersion": "regolibrary.kubescape/v1alpha1", - "kind": "AttackTrack", - "metadata": { - "name": "container" - }, - "spec": { - "version": "1.0", - "data": { - "name": "Initial access", - "subSteps": [ - { - "name": "Execution", - "subSteps": [ - { - "name": "Privilege escalation" - }, - { - "name": "Credential access", - "subSteps": [ - { - "name": "Impact - service access" - }, - { - "name": "Impact - K8s API access", - "subSteps": [ - { - "name": "Defense evasion - KubeAPI" - } - ] - } - ] - }, - { - "name": "Discovery" - }, - { - "name": "Lateral movement" - }, - { - "name": "Impact - Data access in container" - }, - { - "name": "Persistence" - } - ] - }, - { - "name": "Impact - service destruction" - } - ] - } - } -} \ No newline at end of file diff --git a/attack-tracks/kubeapi.json b/attack-tracks/kubeapi.json deleted file mode 100644 index 26d79ec47..000000000 --- a/attack-tracks/kubeapi.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "apiVersion": "regolibrary.kubescape/v1alpha1", - "kind": "AttackTrack", - "metadata": { - "name": "kubeapi" - }, - "spec": { - "version": "1.0", - "data": { - "name": "Initial access", - "subSteps": [ - { - "name": "Persistence" - }, - { - "name": "Privilege escalation" - }, - { - "name": "Credential access" - }, - { - "name": "Discovery" - }, - { - "name": "Lateral movement" - }, - { - "name": "Defense evasion" - }, - { - "name": "Impact - data destruction" - }, - { - "name": "Impact - service injection" - } - ] - } - } -} diff --git a/attack-tracks/service-destruction.json b/attack-tracks/service-destruction.json new file mode 100644 index 000000000..745b81164 --- /dev/null +++ b/attack-tracks/service-destruction.json @@ -0,0 +1,18 @@ +{ + "apiVersion": "regolibrary.kubescape/v1alpha1", + "kind": "AttackTrack", + "metadata": { + "name": "service-destruction" + }, + "spec": { + "version": "1.0", + "data": { + "name": "Workload Exposure", + "subSteps": [ + { + "name": "Service Destruction" + } + ] + } + } +} \ No newline at end of file diff --git a/attack-tracks/node.json b/attack-tracks/workload-external-track.json similarity index 57% rename from attack-tracks/node.json rename to attack-tracks/workload-external-track.json index 6b931eab9..0203face5 100644 --- a/attack-tracks/node.json +++ b/attack-tracks/workload-external-track.json @@ -2,39 +2,34 @@ "apiVersion": "regolibrary.kubescape/v1alpha1", "kind": "AttackTrack", "metadata": { - "name": "node" + "name": "workload-external-track" }, "spec": { "version": "1.0", "data": { - "name": "Initial access", + "name": "Workload Exposure", "subSteps": [ { - "name": "Execution", + "name": "Vulnerable Image", + "checksVulnerabilities": true, "subSteps": [ { - "name": "Persistence" - }, - { - "name": "Credential access" + "name": "Data Access" }, { - "name": "Defense evasion" + "name": "Secret Access" }, { - "name": "Discovery" - }, - { - "name": "Lateral movement" + "name": "Credential access" }, { - "name": "Impact - data theft" + "name": "Potential Node exposure" }, { - "name": "Impact - data destruction" + "name": "Persistence" }, { - "name": "Impact - service injection" + "name": "Network" } ] } diff --git a/controls/C-0255-workloadwithsecretaccess.json b/controls/C-0255-workloadwithsecretaccess.json new file mode 100644 index 000000000..54098517e --- /dev/null +++ b/controls/C-0255-workloadwithsecretaccess.json @@ -0,0 +1,23 @@ +{ + "name": "Workload with secret access", + "attributes": { + "armoBuiltin": true, + "controlTypeTags": [ + "security" + ], + "attackTracks": [ + { + "attackTrack": "workload-external-track", + "categories": [ + "Secret Access" + ] + } + ] + }, + "description": "This control identifies workloads that have mounted secrets. Workloads with secret access can potentially expose sensitive information and increase the risk of unauthorized access to critical resources.", + "remediation": "Review the workloads identified by this control and assess whether it's necessary to mount these secrets. Remove secret access from workloads that don't require it or ensure appropriate access controls are in place to protect sensitive information.", + "rulesNames": ["workload-mounted-secrets"], + "test": "Check if any workload has mounted secrets by inspecting their specifications and verifying if secret volumes are defined.", + "controlID": "C-0255", + "baseScore": 8.0 +} \ No newline at end of file diff --git a/controls/C-0256-exposuretointernet.json b/controls/C-0256-exposuretointernet.json new file mode 100644 index 000000000..35ebe5a93 --- /dev/null +++ b/controls/C-0256-exposuretointernet.json @@ -0,0 +1,29 @@ +{ + "name": "Exposure to internet", + "attributes": { + "armoBuiltin": true, + "controlTypeTags": [ + "security" + ], + "attackTracks": [ + { + "attackTrack": "workload-external-track", + "categories": [ + "Workload Exposure" + ] + }, + { + "attackTrack": "", + "categories": [ + "" + ] + } + ] + }, + "description": "This control detect workloads that are exposed on Internet through a Service (NodePort or LoadBalancer) or Ingress. It fails in case it find workloads connected with these resources.", + "remediation": "The user can evaluate its exposed resources and apply relevant changes wherever needed.", + "rulesNames": ["exposure-to-internet"], + "test": "Checks if workloads are exposed through the use of NodePort, LoadBalancer or Ingress", + "controlID": "C-0256", + "baseScore": 7.0 +} diff --git a/controls/C-0257-pvcaccess.json b/controls/C-0257-pvcaccess.json new file mode 100644 index 000000000..d2ee83a1b --- /dev/null +++ b/controls/C-0257-pvcaccess.json @@ -0,0 +1,23 @@ +{ + "name": "Workload with PVC access", + "attributes": { + "armoBuiltin": true, + "controlTypeTags": [ + "security" + ], + "attackTracks": [ + { + "attackTrack": "workload-external-track", + "categories": [ + "Data Access" + ] + } + ] + }, + "description": "This control detects workloads that have mounted PVC. Workloads with PVC access can potentially expose sensitive information and elevate the risk of unauthorized access to critical resources.", + "remediation": "Review the workloads identified by this control and assess whether it's necessary to mount these PVCs. Remove PVC access from workloads that don't require it or ensure appropriate access controls are in place to protect sensitive information.", + "rulesNames": ["workload-mounted-pvc"], + "test": "Check if any workload has mounted PVCs by inspecting their specifications and verifying if PVC volumes are defined", + "controlID": "C-0257", + "baseScore": 4.0 +} \ No newline at end of file diff --git a/controls/C-0258-configmapaccess.json b/controls/C-0258-configmapaccess.json new file mode 100644 index 000000000..cf0e62870 --- /dev/null +++ b/controls/C-0258-configmapaccess.json @@ -0,0 +1,23 @@ +{ + "name": "Workload with ConfigMap access", + "attributes": { + "armoBuiltin": true, + "controlTypeTags": [ + "security" + ], + "attackTracks": [ + { + "attackTrack": "workload-external-track", + "categories": [ + "Data Access" + ] + } + ] + }, + "description": "This control detects workloads that have mounted ConfigMaps. Workloads with ConfigMap access can potentially expose sensitive information and elevate the risk of unauthorized access to critical resources.", + "remediation": "Review the workloads identified by this control and assess whether it's necessary to mount these configMaps. Remove configMaps access from workloads that don't require it or ensure appropriate access controls are in place to protect sensitive information.", + "rulesNames": ["workload-mounted-configmap"], + "test": "Check if any workload has mounted secrets by inspecting their specifications and verifying if secret volumes are defined", + "controlID": "C-0258", + "baseScore": 5.0 +} \ No newline at end of file diff --git a/controls/C-0259-workloadwithcredentialaccess.json b/controls/C-0259-workloadwithcredentialaccess.json new file mode 100644 index 000000000..ef60a80fe --- /dev/null +++ b/controls/C-0259-workloadwithcredentialaccess.json @@ -0,0 +1,23 @@ +{ + "name": "Workload with credential access", + "attributes": { + "armoBuiltin": true, + "controlTypeTags": [ + "security" + ], + "attackTracks": [ + { + "attackTrack": "workload-external-track", + "categories": [ + "Credential access" + ] + } + ] + }, + "description": "This control checks if workloads specifications have sensitive information in their environment variables.", + "remediation": "Use Kubernetes secrets or Key Management Systems to store credentials.", + "rulesNames": ["rule-credentials-in-env-var"], + "test": "Check if the workload has sensitive information in environment variables, by using list of known sensitive key names.", + "controlID": "C-0259", + "baseScore": 8.0 +} \ No newline at end of file diff --git a/controls/C-0260-missingnetworkpolicy.json b/controls/C-0260-missingnetworkpolicy.json new file mode 100644 index 000000000..a2efffdbd --- /dev/null +++ b/controls/C-0260-missingnetworkpolicy.json @@ -0,0 +1,23 @@ +{ + "name": "Missing network policy", + "attributes": { + "armoBuiltin": true, + "controlTypeTags": [ + "security" + ], + "attackTracks": [ + { + "attackTrack": "workload-external-track", + "categories": [ + "Network" + ] + } + ] + }, + "description": "This control detects workloads that has no NetworkPolicy configured in labels. If a network policy is not configured, it means that your applications might not have necessary control over the traffic to and from the pods, possibly leading to a security vulnerability.", + "remediation": "Review the workloads identified by this control and assess whether it's necessary to configure a network policy for them.", + "rulesNames": ["ensure_network_policy_configured_in_labels"], + "test": "Check that all workloads has a network policy configured in labels.", + "controlID": "C-0260", + "baseScore": 5.0 +} \ No newline at end of file diff --git a/controls/C-0261-satokenmounted.json b/controls/C-0261-satokenmounted.json new file mode 100644 index 000000000..f2216f5e6 --- /dev/null +++ b/controls/C-0261-satokenmounted.json @@ -0,0 +1,23 @@ +{ + "name": "ServiceAccount token mounted", + "attributes": { + "armoBuiltin": true, + "controlTypeTags": [ + "security" + ], + "attackTracks": [ + { + "attackTrack": "workload-external-track", + "categories": [ + "Credential access" + ] + } + ] + }, + "description": "Potential attacker may gain access to a workload and steal its ServiceAccount token. Therefore, it is recommended to disable automatic mapping of the ServiceAccount tokens in ServiceAccount configuration. Enable it only for workloads that need to use them and ensure that this ServiceAccount is not bound to an unnecessary ClusterRoleBinding or RoleBinding.", + "remediation": "Disable automatic mounting of service account tokens to pods at the workload level, by specifying automountServiceAccountToken: false. Enable it only for workloads that need to use them and ensure that this ServiceAccount doesn't have unnecessary permissions", + "rulesNames": ["serviceaccount-token-mount"], + "test": "test if ServiceAccount token is mounted on workload and it has at least one binding.", + "controlID": "C-0261", + "baseScore": 7.0 +} diff --git a/controls/C-0262-anonymousaccessisenabled.json b/controls/C-0262-anonymousaccessisenabled.json new file mode 100644 index 000000000..4f6ed8aa0 --- /dev/null +++ b/controls/C-0262-anonymousaccessisenabled.json @@ -0,0 +1,15 @@ +{ + "controlID": "C-0262", + "name": "Anonymous access enabled", + "description": "Granting permissions to the system:unauthenticated or system:anonymous user is generally not recommended and can introduce security risks. Allowing unauthenticated access to your Kubernetes cluster can lead to unauthorized access, potential data breaches, and abuse of cluster resources.", + "remediation": "Review and modify your cluster's RBAC configuration to ensure that only authenticated and authorized users have appropriate permissions based on their roles and responsibilities within your system.", + "test": "Checks if ClusterRoleBinding/RoleBinding resources give permissions to anonymous user. Also checks in the apiserver if the --anonymous-auth flag is set to false", + "attributes": { + "armoBuiltin": true + }, + "rulesNames": [ + "ensure-that-the-api-server-anonymous-auth-argument-is-set-to-false", + "anonymous-access-enabled" + ], + "baseScore": 5 +} diff --git a/frameworks/__YAMLscan.json b/frameworks/__YAMLscan.json index 53265b690..ca515531f 100644 --- a/frameworks/__YAMLscan.json +++ b/frameworks/__YAMLscan.json @@ -53,7 +53,6 @@ "K8s common labels usage", "Images from allowed registry", "CVE-2022-24348-argocddirtraversal", - "Workloads with excessive amount of vulnerabilities", "CVE-2022-0492-cgroups-container-escape" ] } \ No newline at end of file diff --git a/frameworks/allcontrols.json b/frameworks/allcontrols.json index d56b651e9..f8d41531a 100644 --- a/frameworks/allcontrols.json +++ b/frameworks/allcontrols.json @@ -342,24 +342,6 @@ "name": "CVE-2022-24348-argocddirtraversal" } }, - { - "controlID": "C-0083", - "patch": { - "name": "Workloads with Critical vulnerabilities exposed to external traffic" - } - }, - { - "controlID": "C-0084", - "patch": { - "name": "Workloads with RCE vulnerabilities exposed to external traffic" - } - }, - { - "controlID": "C-0085", - "patch": { - "name": "Workloads with excessive amount of vulnerabilities" - } - }, { "controlID": "C-0086", "patch": { @@ -389,6 +371,12 @@ "patch": { "name": "CVE-2022-47633-kyverno-signature-bypass" } + }, + { + "controlID": "C-0262", + "patch": { + "name": "Anonymous access enabled" + } } ] } \ No newline at end of file diff --git a/frameworks/armobest.json b/frameworks/armobest.json index e9273bc4c..d0626178a 100644 --- a/frameworks/armobest.json +++ b/frameworks/armobest.json @@ -204,24 +204,6 @@ "name": "CVE-2022-24348-argocddirtraversal" } }, - { - "controlID": "C-0083", - "patch": { - "name": "Workloads with Critical vulnerabilities exposed to external traffic" - } - }, - { - "controlID": "C-0084", - "patch": { - "name": "Workloads with RCE vulnerabilities exposed to external traffic" - } - }, - { - "controlID": "C-0085", - "patch": { - "name": "Workloads with excessive amount of vulnerabilities" - } - }, { "controlID": "C-0086", "patch": { diff --git a/frameworks/security.json b/frameworks/security.json index db877b2b1..f3cec24b5 100644 --- a/frameworks/security.json +++ b/frameworks/security.json @@ -4,13 +4,105 @@ "attributes": { "armoBuiltin": true }, - "typeTags": ["security"], + "typeTags": [ + "security" + ], "activeControls": [ + { + "controlID": "C-0009", + "patch": { + "name": "Resource limits" + } + }, { "controlID": "C-0017", "patch": { "name": "Immutable container filesystem" } + }, + { + "controlID": "C-0256", + "patch": { + "name": "Exposure to Internet" + } + }, + { + "controlID": "C-0259", + "patch": { + "name": "Workload with credential access" + } + }, + { + "controlID": "C-0258", + "patch": { + "name": "Workload with configMap access" + } + }, + { + "controlID": "C-0257", + "patch": { + "name": "Workload with PVC access" + } + }, + { + "controlID": "C-0260", + "patch": { + "name": "Missing network policy" + } + }, + { + "controlID": "C-0261", + "patch": { + "name": "ServiceAccount token mounted" + } + }, + { + "controlID": "C-0255", + "patch": { + "name": "Workload with secret access" + } + }, + { + "controlID": "C-0041", + "patch": { + "name": "HostNetwork access" + } + }, + { + "controlID": "C-0044", + "patch": { + "name": "Container hostPort" + } + }, + { + "controlID": "C-0045", + "patch": { + "name": "Writable hostPath mount" + } + }, + { + "controlID": "C-0046", + "patch": { + "name": "Insecure capabilities" + } + }, + { + "controlID": "C-0048", + "patch": { + "name": "HostPath mount" + } + }, + { + "controlID": "C-0211", + "patch": { + "name": "Apply Security Context to Your Pods and Containers" + } + }, + { + "controlID": "C-0262", + "patch": { + "name": "Anonymous access enabled" + } } ] -} \ No newline at end of file +} diff --git a/go.work.sum b/go.work.sum index 78a8bbb43..1bb71c85d 100644 --- a/go.work.sum +++ b/go.work.sum @@ -4,16 +4,19 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v66.0.0+incompatible h1:bmmC38SlE8/E81nNADlgmVGurPWMHDX2YNXVQMrBpEE= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= @@ -41,7 +44,9 @@ github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:m github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/assert/v2 v2.2.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA= @@ -310,6 +315,7 @@ github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDB github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= @@ -441,6 +447,7 @@ github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WT github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -627,9 +634,12 @@ github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -748,6 +758,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -832,7 +843,6 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -861,7 +871,6 @@ golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= @@ -899,12 +908,10 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= -k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= @@ -931,7 +938,6 @@ k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= @@ -942,10 +948,8 @@ k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2R k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= diff --git a/rules/RBAC-enabled/raw.rego b/rules/RBAC-enabled/raw.rego deleted file mode 100644 index f44a8d676..000000000 --- a/rules/RBAC-enabled/raw.rego +++ /dev/null @@ -1,74 +0,0 @@ -package armo_builtins - - -#Checks if RBAC is enabled -deny[msga] { - apigouplist := input[_] - groupVersions := [groupVersion | groupVersion = apigouplist.groups[_].versions[_].groupVersion] - - not list_contains(groupVersions, "rbac.authorization.k8s.io/v1") - - msga := { - "alertMessage": sprintf("%s", ["RBAC is not enabled for this cluster"]), - "alertScore": 9, - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [] - } - - } -} - - - -# Fails is rolebinding gives permsisiosn to anonymous user -deny[msga] { - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - rolebinding := rolebindings[_] - - isAnonymous(rolebinding) - - msga := { - "alertMessage": sprintf("the following rolebinding: %v gives permissions to anonymous users", [rolebinding.metadata.name]), - "alertScore": 9, - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [rolebinding] - } - - } -} - - -# Fails is clusterrolebinding gives permsisiosn to anonymous user -deny[msga] { - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - rolebinding := rolebindings[_] - - isAnonymous(rolebinding) - - msga := { - "alertMessage": sprintf("the following rolebinding: %v gives permissions to anonymous users", [rolebinding.metadata.name]), - "alertScore": 9, - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [rolebinding] - } - - } -} - -isAnonymous(binding) { - subject := binding.subjects[_] - subject.name == "system:anonymous" -} - -isAnonymous(binding) { - subject := binding.subjects[_] - subject.name == "system:unauthenticated" -} - -list_contains(list, element) { - some i - list[i] == element -} \ No newline at end of file diff --git a/rules/access-tiller-endpoint/filter.rego b/rules/access-tiller-endpoint/filter.rego deleted file mode 100644 index c407378cd..000000000 --- a/rules/access-tiller-endpoint/filter.rego +++ /dev/null @@ -1,20 +0,0 @@ -package armo_builtins - -# input: deployment -# fails if tiller exists in cluster - -deny[msga] { - deployment := input[_] - deployment.kind == "Deployment" - deployment.metadata.name == "tiller-deploy" - - msga := { - "alertMessage": sprintf("tiller exists in namespace: %v", [deployment.metadata.namespace]), - "packagename": "armo_builtins", - "alertScore": 7, - "failedPaths": ["metadata.name"], - "alertObject": { - "k8sApiObjects": [deployment] - } - } -} \ No newline at end of file diff --git a/rules/access-tiller-endpoint/raw.rego b/rules/access-tiller-endpoint/raw.rego deleted file mode 100644 index 26b309c41..000000000 --- a/rules/access-tiller-endpoint/raw.rego +++ /dev/null @@ -1,21 +0,0 @@ -package armo_builtins - -# input: deployment -# fails if tiller exists in cluster - -deny[msga] { - deployment := input[_] - deployment.kind == "Deployment" - deployment.metadata.name == "tiller-deploy" - - msga := { - "alertMessage": sprintf("tiller exists in namespace: %v", [deployment.metadata.namespace]), - "packagename": "armo_builtins", - "alertScore": 7, - "failedPaths": ["metadata.name"], - "fixPaths":[], - "alertObject": { - "k8sApiObjects": [deployment] - } - } -} \ No newline at end of file diff --git a/rules/access-tiller-endpoint/rule.metadata.json b/rules/access-tiller-endpoint/rule.metadata.json deleted file mode 100644 index 7b533ecc2..000000000 --- a/rules/access-tiller-endpoint/rule.metadata.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "access-tiller-endpoint", - "attributes": { - "microsoftK8sThreatMatrix": "Lateral movement::Access tiller endpoint", - "armoBuiltin": true - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Deployment" - ] - } - ], - "ruleDependencies": [], - "description": "fails if tiller exists in cluster", - "remediation": "", - "ruleQuery": "armo_builtins" -} \ No newline at end of file diff --git a/rules/access-tiller-endpoint/test/test/expected.json b/rules/access-tiller-endpoint/test/test/expected.json deleted file mode 100644 index ec1454b05..000000000 --- a/rules/access-tiller-endpoint/test/test/expected.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "alertMessage": "tiller exists in namespace: default", - "failedPaths": [ - "metadata.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "labels": { - "app": "audit-pod" - }, - "name": "tiller-deploy" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/access-tiller-endpoint/test/test/input/deployment.yaml b/rules/access-tiller-endpoint/test/test/input/deployment.yaml deleted file mode 100644 index c04d920bb..000000000 --- a/rules/access-tiller-endpoint/test/test/input/deployment.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: default - name: tiller-deploy - labels: - app: audit-pod -spec: - replicas: 3 - selector: - matchLabels: - app: audit-pod - template: - metadata: - labels: - app: audit-pod - spec : - securityContext : - runAsUser : 999 - containers : - - - name : tiller - image : hashicorp/http-echo:0.2.3 \ No newline at end of file diff --git a/rules/anonymous-access-enabled/raw.rego b/rules/anonymous-access-enabled/raw.rego new file mode 100644 index 000000000..235f25196 --- /dev/null +++ b/rules/anonymous-access-enabled/raw.rego @@ -0,0 +1,30 @@ +package armo_builtins + +# Fails is rolebinding/clusterrolebinding gives permissions to anonymous user +deny[msga] { + rolebindings := [rolebinding | rolebinding = input[_]; endswith(rolebinding.kind, "Binding")] + rolebinding := rolebindings[_] + + isAnonymous(rolebinding) + + msga := { + "alertMessage": sprintf("the following RoleBinding: %v gives permissions to anonymous users", [rolebinding.metadata.name]), + "alertScore": 9, + "packagename": "armo_builtins", + "alertObject": { + "k8sApiObjects": [rolebinding] + } + } +} + + +isAnonymous(binding) { + subject := binding.subjects[_] + subject.name == "system:anonymous" +} + + +isAnonymous(binding) { + subject := binding.subjects[_] + subject.name == "system:unauthenticated" +} diff --git a/rules/anonymous-access-enabled/rule.metadata.json b/rules/anonymous-access-enabled/rule.metadata.json new file mode 100644 index 000000000..eb6793735 --- /dev/null +++ b/rules/anonymous-access-enabled/rule.metadata.json @@ -0,0 +1,25 @@ +{ + "name": "anonymous-access-enabled", + "attributes": { + "armoBuiltin": true + }, + "ruleLanguage": "Rego", + "match": [ + { + "apiGroups": [ + "rbac.authorization.k8s.io" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "RoleBinding", + "ClusterRoleBinding" + ] + } + ], + "ruleDependencies": [], + "description": "Fails in case anonymous access is enabled on the cluster", + "remediation": "Disable anonymous access by passing the --anonymous-auth=false flag to the kube-apiserver component, or if it's a managed cluster, you can remove any RBAC rules which allow anonymous users to perform actions", + "ruleQuery": "armo_builtins" +} diff --git a/rules/anonymous-access-enabled/test/fail/expected.json b/rules/anonymous-access-enabled/test/fail/expected.json new file mode 100644 index 000000000..785972a18 --- /dev/null +++ b/rules/anonymous-access-enabled/test/fail/expected.json @@ -0,0 +1,24 @@ +[ + { + "alertMessage": "the following RoleBinding: system:public-info-viewer gives permissions to anonymous users", + "failedPaths": null, + "fixPaths": null, + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 9, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "rbac.authorization.k8s.io/v1", + "kind": "ClusterRoleBinding", + "metadata": { + "labels": { + "kubernetes.io/bootstrapping": "rbac-defaults" + }, + "name": "system:public-info-viewer" + } + } + ] + } + } +] \ No newline at end of file diff --git a/rules/anonymous-access-enabled/test/fail/input/clusterrolebinding.yaml b/rules/anonymous-access-enabled/test/fail/input/clusterrolebinding.yaml new file mode 100644 index 000000000..ea96c286d --- /dev/null +++ b/rules/anonymous-access-enabled/test/fail/input/clusterrolebinding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + labels: + kubernetes.io/bootstrapping: rbac-defaults + name: system:public-info-viewer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:public-info-viewer +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:unauthenticated diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/passed/expected.json b/rules/anonymous-access-enabled/test/success/expected.json similarity index 100% rename from rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/passed/expected.json rename to rules/anonymous-access-enabled/test/success/expected.json diff --git a/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/input/rolebinding.yaml b/rules/anonymous-access-enabled/test/success/input/rolebinding.yaml similarity index 77% rename from rules/rule-can-create-modify-pod-v1/test/role-rolebinding/input/rolebinding.yaml rename to rules/anonymous-access-enabled/test/success/input/rolebinding.yaml index 73ce62a17..ea48ffc51 100644 --- a/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/input/rolebinding.yaml +++ b/rules/anonymous-access-enabled/test/success/input/rolebinding.yaml @@ -9,5 +9,5 @@ subjects: apiGroup: rbac.authorization.k8s.io roleRef: kind: Role - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file + name: pod-reader + apiGroup: rbac.authorization.k8s.io diff --git a/rules/deny-RCE-vuln-image-pods/raw.rego b/rules/deny-RCE-vuln-image-pods/raw.rego deleted file mode 100644 index a2cc9b43d..000000000 --- a/rules/deny-RCE-vuln-image-pods/raw.rego +++ /dev/null @@ -1,346 +0,0 @@ -package armo_builtins - -import data.cautils - -# ========= RCE : no service score 5 ================ -deny[msga] { - pod := input[_] - container := pod.spec.containers[i] - path := sprintf("spec.containers[%v].image", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 5, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [pod], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -# workloads -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - path := sprintf("spec.template.spec.containers[%v].image", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 5, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -# cronjobs -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 5, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -# ======== RCE + service (not nodeport and not loadbalancer) 7 ===================== -deny[msga] { - pod := input[_] - container := pod.spec.containers[i] - path := sprintf("spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - service := input[_] - service.kind == "Service" - service.metadata.namespace == pod.metadata.namespace - labels := pod.metadata.labels - filtered_labels := json.remove(labels, ["pod-template-hash"]) - np_or_lb := {"NodePort", "LoadBalancer"} - not np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector, filtered_labels) - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 7, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [pod], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -# workloads -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - path := sprintf("spec.template.spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - service := input[_] - service.kind == "Service" - service.metadata.namespace == wl.metadata.namespace - labels := wl.spec.template.metadata.labels - np_or_lb := {"NodePort", "LoadBalancer"} - not np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector,labels) - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 7, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - - } -} -# cronjobs -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - service := input[_] - service.kind == "Service" - service.metadata.namespace == wl.metadata.namespace - labels := wl.spec.jobTemplate.spec.template.metadata.labels - np_or_lb := {"NodePort", "LoadBalancer"} - not np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector,labels) - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 7, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -# ======= RCE + service nodeport/loadbalancer 10 =========================== -deny[msga] { - pod := input[_] - container := pod.spec.containers[i] - path := sprintf("spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - service := input[_] - service.kind == "Service" - service.metadata.namespace == pod.metadata.namespace - labels := pod.metadata.labels - filtered_labels := json.remove(labels, ["pod-template-hash"]) - np_or_lb := {"NodePort", "LoadBalancer"} - np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector, filtered_labels) - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 10, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [pod], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -# workloads -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - path := sprintf("spec.template.spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - service := input[_] - service.kind == "Service" - service.metadata.namespace == wl.metadata.namespace - labels := wl.spec.template.metadata.labels - np_or_lb := {"NodePort", "LoadBalancer"} - np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector,labels) - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 10, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -# cronjobs -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - t := { "containersScanID": scan.containersScanID,"count":count(vulnerabilities),"vulnerabilities":vulnerabilities} - - service := input[_] - service.kind == "Service" - service.metadata.namespace == wl.metadata.namespace - labels := wl.spec.jobTemplate.spec.template.metadata.labels - np_or_lb := {"NodePort", "LoadBalancer"} - np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector,labels) - - msga := { - "alertMessage": sprintf("image %v has %v RCE vulnerabilities", [container.image,count(vulnerabilities)]), - "alertScore": 10, - "fixPaths":[], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - }, - } -} - -#treat as potentially critical -is_unsafe_image(scanresult) { - scanresult.numOfUnknownSeverity > 0 -} -is_unsafe_image(scanresult) { - scanresult.numOfNegligibleSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfLowSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfMeduiumSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfHighSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfCriticalSeverity > 0 -} \ No newline at end of file diff --git a/rules/deny-vuln-image-pods/raw.rego b/rules/deny-vuln-image-pods/raw.rego deleted file mode 100644 index a2bd06e9f..000000000 --- a/rules/deny-vuln-image-pods/raw.rego +++ /dev/null @@ -1,141 +0,0 @@ -package armo_builtins - -import data.cautils - -deny[msga] { - pod := input[_] - pod.kind == "Pod" - container := pod.spec.containers[i] - path := sprintf("spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - - labels := pod.metadata.labels - filtered_labels := json.remove(labels, ["pod-template-hash"]) - service := input[_] - service.kind == "Service" - service.metadata.namespace == pod.metadata.namespace - np_or_lb := {"NodePort", "LoadBalancer"} - np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector,filtered_labels) - - msga := { - "alertMessage": sprintf("pod %v/%v has vulnerabilities", [pod.metadata.namespace,pod.metadata.name]), - "alertScore": 2, - "failedPaths": [path], - "fixPaths":[], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [pod] - }, - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - } -} - -# covers most workloads -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - path := sprintf("spec.template.spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - - labels := wl.spec.template.metadata.labels - service := input[_] - service.kind == "Service" - service.metadata.namespace == wl.metadata.namespace - np_or_lb := {"NodePort", "LoadBalancer"} - np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector,labels) - - msga := { - "alertMessage": sprintf("%v: %v/%v has vulnerabilities", [wl.kind, wl.metadata.namespace, wl.metadata.name]), - "alertScore": 2, - "failedPaths": [path], - "fixPaths":[], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl] - }, - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - } -} - -# covers cronjobs -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v]", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - - is_unsafe_image(scan) - scan.containersScanID - vulnerabilities := armo.get_image_scan_details({"containersScanID":scan.containersScanID, "fieldCreteria":{"description":"RCE|like,Remote Code Execution|like,remote code execution|like,remote command execution|like,Remote Command Execution|like,arbitrary code|like,code execution|like,Arbitrary Code|like,Code Execution|like,code injection|like,Code Injection|like,execute code|like,Execute Code|like,arbitrary command|like,Arbitrary Command|like,arbitrary commands|like,Arbitrary Commands|like,command injection|like,Command Injection|like,command execution|like,Command Execution|like,inject arbitrary commands|like,Inject Arbitrary Commands|like"} }) - count(vulnerabilities) > 0 - - labels := wl.spec.jobTemplate.spec.template.metadata.labels - service := input[_] - service.kind == "Service" - service.metadata.namespace == wl.metadata.namespace - np_or_lb := {"NodePort", "LoadBalancer"} - np_or_lb[service.spec.type] - cautils.is_subobject(service.spec.selector,labels) - - - msga := { - "alertMessage": sprintf("%v: %v/%v has vulnerabilities", [wl.kind, wl.metadata.namespace, wl.metadata.name]), - "alertScore": 2, - "failedPaths": [path], - "fixPaths":[], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl] - }, - "externalObjects": { - "vulnerabilities" : [vulnerabilities] - } - } -} - - -#treat as potentially critical -is_unsafe_image(scanresult) { - scanresult.numOfUnknownSeverity > 0 -} -is_unsafe_image(scanresult) { - scanresult.numOfNegligibleSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfLowSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfMeduiumSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfHighSeverity > 0 -} - -is_unsafe_image(scanresult) { - scanresult.numOfCriticalSeverity > 0 -} diff --git a/rules/deny-vuln-image-pods/rule.metadata.json b/rules/deny-vuln-image-pods/rule.metadata.json deleted file mode 100644 index 5455dd760..000000000 --- a/rules/deny-vuln-image-pods/rule.metadata.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "deny-vuln-image-pods", - "attributes": { - "m$K8sThreatMatrix": "Initial Access::Application Vulnerability", - "mitre": "Exploit Public-Facing Application", - "mitreCode": "T1190", - "armoBuiltin": true, - "armoOpa": "true" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "Pod", - "Service" - ] - }, - { - "apiGroups": [ - "apps" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "Deployment", - "ReplicaSet", - "DaemonSet", - "StatefulSet" - ] - }, - { - "apiGroups": [ - "batch" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Job", - "CronJob" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "determines if pods/deployments has vulnerable image", - "remediation": "Isolate such deployments in sandboxes if possible. Otherwise, keep scanning frequently for in case a patch will be available - MAKE SURE it has least privileges as necessary!", - "ruleQuery": "armo_builtins" -} \ No newline at end of file diff --git a/rules/ensure-default-service-accounts-has-only-default-roles/test/passed_rolebinding_one_subject/input/rolebinding.yaml b/rules/ensure-default-service-accounts-has-only-default-roles/test/passed_rolebinding_one_subject/input/rolebinding.yaml index fc3b02ef1..eaeb7e332 100644 --- a/rules/ensure-default-service-accounts-has-only-default-roles/test/passed_rolebinding_one_subject/input/rolebinding.yaml +++ b/rules/ensure-default-service-accounts-has-only-default-roles/test/passed_rolebinding_one_subject/input/rolebinding.yaml @@ -8,4 +8,8 @@ metadata: subjects: - kind: ServiceAccount name: default - namespace: default \ No newline at end of file + namespace: default +roleRef: + kind: ClusterRole + name: test + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/raw.rego b/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/raw.rego deleted file mode 100644 index 915b6219d..000000000 --- a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/raw.rego +++ /dev/null @@ -1,37 +0,0 @@ -package armo_builtins - -import future.keywords.in - - -# Fail if etcd data dir not owned by etcd:etcd -deny[msg] { - obj = input[_] - obj.apiVersion == "hostdata.kubescape.cloud/v1beta0" - obj.kind == "ControlPlaneInfo" - - # Test - file := obj.data.etcdDataDir - not valid_ownership(file.ownership) - - # Add name to match the externalObject structure - output := json.patch(obj, [{"op": "add", "path": "name", "value": "ControlPlaneInfo"}]) - - msg := { - "alertMessage": sprintf("%s is not owned by `etcd:etcd`", [file.path]), - "alertScore": 2, - "failedPaths": [], - "fixPaths": [], - "fixCommand": sprintf("chown etcd:etcd %s", [file.path]), - "packagename": "armo_builtins", - "alertObject": {"externalObjects": output}, - } -} - - -valid_ownership(ownership) { - ownership.err != "" # Don't fail if host-sensor can't get ownership -} -valid_ownership(ownership) { - ownership.username == "etcd" - ownership.groupname == "etcd" -} \ No newline at end of file diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/rule.metadata.json b/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/rule.metadata.json deleted file mode 100644 index 634566ae1..000000000 --- a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/rule.metadata.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd", - "attributes": { - "armoBuiltin": true, - "hostSensorRule": "true" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [], - "apiVersions": [], - "resources": [] - } - ], - "dynamicMatch": [ - { - "apiGroups": [ - "hostdata.kubescape.cloud" - ], - "apiVersions": [ - "v1beta0" - ], - "resources": [ - "ControlPlaneInfo" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "Ensure that the etcd data directory ownership is set to `etcd:etcd`.", - "remediation": "On the etcd server node, get the etcd data directory, passed as an argument `--data-dir`, from the below command:\n\n \n```\nps -ef | grep etcd\n\n```\n Run the below command (based on the etcd data directory found above). For example,\n\n \n```\nchown etcd:etcd /var/lib/etcd\n\n```\n\n#### Impact Statement\nNone\n\n#### Default Value\nBy default, etcd data directory ownership is set to `etcd:etcd`.", - "ruleQuery": "" -} \ No newline at end of file diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/expected.json b/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/expected.json deleted file mode 100644 index 10c75af3c..000000000 --- a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/expected.json +++ /dev/null @@ -1,365 +0,0 @@ -[ - { - "fixCommand": "chown etcd:etcd /var/lib/minikube/etcd", - "alertMessage": "/var/lib/minikube/etcd is not owned by `etcd:etcd`", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "APIServerInfo": { - "cmdLine": "kube-apiserver --advertise-address=192.168.49.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --enable-bootstrap-token-auth=true --encryption-provider-config=/var/lib/minikube/certs/hack/encryptionConf.yaml --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-account-signing-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key ", - "encryptionProviderConfigFile": { - "content": "YXBpVmVyc2lvbjogYXBpc2VydmVyLmNvbmZpZy5rOHMuaW8vdjENCmtpbmQ6IEVuY3J5cHRpb25Db25maWd1cmF0aW9uDQpyZXNvdXJjZXM6DQogIC0gcmVzb3VyY2VzOg0KICAgICAgLSBzZWNyZXRzDQogICAgcHJvdmlkZXJzOg0KICAgICAgLSBhZXNjYmM6DQogICAgICAgICAga2V5czoNCiAgICAgICAgICAgIC0gbmFtZToga2V5MQ0KICAgICAgICAgICAgICBzZWNyZXQ6IDxCQVNFIDY0IEVOQ09ERUQgU0VDUkVUPg0KICAgICAgLSBpZGVudGl0eToge30=", - "ownership": { - "gid": 999, - "groupname": "", - "uid": 1000, - "username": "" - }, - "path": "/var/lib/minikube/certs/hack/encryptionConf.yaml", - "permissions": 436 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-apiserver.yaml", - "permissions": 384 - } - }, - "adminConfigFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/admin.conf", - "permissions": 384 - }, - "controllerManagerInfo": { - "cmdLine": "kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-cidr=10.244.0.0/16 --cluster-name=mk --cluster-signing-cert-file=/var/lib/minikube/certs/ca.crt --cluster-signing-key-file=/var/lib/minikube/certs/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=false --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --root-ca-file=/var/lib/minikube/certs/ca.crt --service-account-private-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --use-service-account-credentials=true ", - "configFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/controller-manager.conf", - "permissions": 384 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-controller-manager.yaml", - "permissions": 384 - } - }, - "etcdConfigFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/etcd.yaml", - "permissions": 384 - }, - "etcdDataDir": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/var/lib/minikube/etcd", - "permissions": 448 - }, - "schedulerInfo": { - "cmdLine": "kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false ", - "configFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/scheduler.conf", - "permissions": 384 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-scheduler.yaml", - "permissions": 384 - } - } - }, - "kind": "ControlPlaneInfo", - "metadata": { - "name": "minikube" - }, - "name": "ControlPlaneInfo" - } - } - }, - { - "fixCommand": "chown etcd:etcd /var/lib/minikube/etcd", - "alertMessage": "/var/lib/minikube/etcd is not owned by `etcd:etcd`", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "APIServerInfo": { - "cmdLine": "kube-apiserver --advertise-address=192.168.49.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --enable-bootstrap-token-auth=true --encryption-provider-config=/var/lib/minikube/certs/hack/encryptionConf.yaml --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-account-signing-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key ", - "encryptionProviderConfigFile": { - "content": "YXBpVmVyc2lvbjogYXBpc2VydmVyLmNvbmZpZy5rOHMuaW8vdjENCmtpbmQ6IEVuY3J5cHRpb25Db25maWd1cmF0aW9uDQpyZXNvdXJjZXM6DQogIC0gcmVzb3VyY2VzOg0KICAgICAgLSBzZWNyZXRzDQogICAgcHJvdmlkZXJzOg0KICAgICAgLSBhZXNjYmM6DQogICAgICAgICAga2V5czoNCiAgICAgICAgICAgIC0gbmFtZToga2V5MQ0KICAgICAgICAgICAgICBzZWNyZXQ6IDxCQVNFIDY0IEVOQ09ERUQgU0VDUkVUPg0KICAgICAgLSBpZGVudGl0eToge30=", - "ownership": { - "gid": 999, - "groupname": "", - "uid": 1000, - "username": "" - }, - "path": "/var/lib/minikube/certs/hack/encryptionConf.yaml", - "permissions": 436 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-apiserver.yaml", - "permissions": 384 - } - }, - "adminConfigFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/admin.conf", - "permissions": 384 - }, - "controllerManagerInfo": { - "cmdLine": "kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-cidr=10.244.0.0/16 --cluster-name=mk --cluster-signing-cert-file=/var/lib/minikube/certs/ca.crt --cluster-signing-key-file=/var/lib/minikube/certs/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=false --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --root-ca-file=/var/lib/minikube/certs/ca.crt --service-account-private-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --use-service-account-credentials=true ", - "configFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/controller-manager.conf", - "permissions": 384 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-controller-manager.yaml", - "permissions": 384 - } - }, - "etcdConfigFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/etcd.yaml", - "permissions": 384 - }, - "etcdDataDir": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "etcd" - }, - "path": "/var/lib/minikube/etcd", - "permissions": 448 - }, - "schedulerInfo": { - "cmdLine": "kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false ", - "configFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/scheduler.conf", - "permissions": 384 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-scheduler.yaml", - "permissions": 384 - } - } - }, - "kind": "ControlPlaneInfo", - "metadata": { - "name": "minikube" - }, - "name": "ControlPlaneInfo" - } - } - }, - { - "fixCommand": "chown etcd:etcd /var/lib/minikube/etcd", - "alertMessage": "/var/lib/minikube/etcd is not owned by `etcd:etcd`", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "APIServerInfo": { - "cmdLine": "kube-apiserver --advertise-address=192.168.49.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --enable-bootstrap-token-auth=true --encryption-provider-config=/var/lib/minikube/certs/hack/encryptionConf.yaml --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-account-signing-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key ", - "encryptionProviderConfigFile": { - "content": "YXBpVmVyc2lvbjogYXBpc2VydmVyLmNvbmZpZy5rOHMuaW8vdjENCmtpbmQ6IEVuY3J5cHRpb25Db25maWd1cmF0aW9uDQpyZXNvdXJjZXM6DQogIC0gcmVzb3VyY2VzOg0KICAgICAgLSBzZWNyZXRzDQogICAgcHJvdmlkZXJzOg0KICAgICAgLSBhZXNjYmM6DQogICAgICAgICAga2V5czoNCiAgICAgICAgICAgIC0gbmFtZToga2V5MQ0KICAgICAgICAgICAgICBzZWNyZXQ6IDxCQVNFIDY0IEVOQ09ERUQgU0VDUkVUPg0KICAgICAgLSBpZGVudGl0eToge30=", - "ownership": { - "gid": 999, - "groupname": "", - "uid": 1000, - "username": "" - }, - "path": "/var/lib/minikube/certs/hack/encryptionConf.yaml", - "permissions": 436 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-apiserver.yaml", - "permissions": 384 - } - }, - "adminConfigFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/admin.conf", - "permissions": 384 - }, - "controllerManagerInfo": { - "cmdLine": "kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-cidr=10.244.0.0/16 --cluster-name=mk --cluster-signing-cert-file=/var/lib/minikube/certs/ca.crt --cluster-signing-key-file=/var/lib/minikube/certs/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=false --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --root-ca-file=/var/lib/minikube/certs/ca.crt --service-account-private-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --use-service-account-credentials=true ", - "configFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/controller-manager.conf", - "permissions": 384 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-controller-manager.yaml", - "permissions": 384 - } - }, - "etcdConfigFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/etcd.yaml", - "permissions": 384 - }, - "etcdDataDir": { - "ownership": { - "gid": 0, - "groupname": "etcd", - "uid": 0, - "username": "root" - }, - "path": "/var/lib/minikube/etcd", - "permissions": 448 - }, - "schedulerInfo": { - "cmdLine": "kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false ", - "configFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/scheduler.conf", - "permissions": 384 - }, - "specsFile": { - "ownership": { - "gid": 0, - "groupname": "root", - "uid": 0, - "username": "root" - }, - "path": "/etc/kubernetes/manifests/kube-scheduler.yaml", - "permissions": 384 - } - } - }, - "kind": "ControlPlaneInfo", - "metadata": { - "name": "minikube" - }, - "name": "ControlPlaneInfo" - } - } - } -] \ No newline at end of file diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/1.json b/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/1.json deleted file mode 100644 index 2b9a4ac20..000000000 --- a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/1.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "ControlPlaneInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "APIServerInfo": { - "encryptionProviderConfigFile": { - "ownership": { - "uid": 1000, - "gid": 999, - "username": "", - "groupname": "" - }, - "path": "/var/lib/minikube/certs/hack/encryptionConf.yaml", - "content": "YXBpVmVyc2lvbjogYXBpc2VydmVyLmNvbmZpZy5rOHMuaW8vdjENCmtpbmQ6IEVuY3J5cHRpb25Db25maWd1cmF0aW9uDQpyZXNvdXJjZXM6DQogIC0gcmVzb3VyY2VzOg0KICAgICAgLSBzZWNyZXRzDQogICAgcHJvdmlkZXJzOg0KICAgICAgLSBhZXNjYmM6DQogICAgICAgICAga2V5czoNCiAgICAgICAgICAgIC0gbmFtZToga2V5MQ0KICAgICAgICAgICAgICBzZWNyZXQ6IDxCQVNFIDY0IEVOQ09ERUQgU0VDUkVUPg0KICAgICAgLSBpZGVudGl0eToge30=", - "permissions": 436 - }, - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-apiserver.yaml", - "permissions": 384 - }, - "cmdLine": "kube-apiserver --advertise-address=192.168.49.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --enable-bootstrap-token-auth=true --encryption-provider-config=/var/lib/minikube/certs/hack/encryptionConf.yaml --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-account-signing-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key " - }, - "controllerManagerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-controller-manager.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/controller-manager.conf", - "permissions": 384 - }, - "cmdLine": "kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-cidr=10.244.0.0/16 --cluster-name=mk --cluster-signing-cert-file=/var/lib/minikube/certs/ca.crt --cluster-signing-key-file=/var/lib/minikube/certs/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=false --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --root-ca-file=/var/lib/minikube/certs/ca.crt --service-account-private-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --use-service-account-credentials=true " - }, - "schedulerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-scheduler.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/scheduler.conf", - "permissions": 384 - }, - "cmdLine": "kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false " - }, - "etcdConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/etcd.yaml", - "permissions": 384 - }, - "etcdDataDir": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/var/lib/minikube/etcd", - "permissions": 448 - }, - "adminConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/admin.conf", - "permissions": 384 - } - } -} \ No newline at end of file diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/2.json b/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/2.json deleted file mode 100644 index fc2ccdbb6..000000000 --- a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/2.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "ControlPlaneInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "APIServerInfo": { - "encryptionProviderConfigFile": { - "ownership": { - "uid": 1000, - "gid": 999, - "username": "", - "groupname": "" - }, - "path": "/var/lib/minikube/certs/hack/encryptionConf.yaml", - "content": "YXBpVmVyc2lvbjogYXBpc2VydmVyLmNvbmZpZy5rOHMuaW8vdjENCmtpbmQ6IEVuY3J5cHRpb25Db25maWd1cmF0aW9uDQpyZXNvdXJjZXM6DQogIC0gcmVzb3VyY2VzOg0KICAgICAgLSBzZWNyZXRzDQogICAgcHJvdmlkZXJzOg0KICAgICAgLSBhZXNjYmM6DQogICAgICAgICAga2V5czoNCiAgICAgICAgICAgIC0gbmFtZToga2V5MQ0KICAgICAgICAgICAgICBzZWNyZXQ6IDxCQVNFIDY0IEVOQ09ERUQgU0VDUkVUPg0KICAgICAgLSBpZGVudGl0eToge30=", - "permissions": 436 - }, - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-apiserver.yaml", - "permissions": 384 - }, - "cmdLine": "kube-apiserver --advertise-address=192.168.49.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --enable-bootstrap-token-auth=true --encryption-provider-config=/var/lib/minikube/certs/hack/encryptionConf.yaml --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-account-signing-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key " - }, - "controllerManagerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-controller-manager.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/controller-manager.conf", - "permissions": 384 - }, - "cmdLine": "kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-cidr=10.244.0.0/16 --cluster-name=mk --cluster-signing-cert-file=/var/lib/minikube/certs/ca.crt --cluster-signing-key-file=/var/lib/minikube/certs/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=false --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --root-ca-file=/var/lib/minikube/certs/ca.crt --service-account-private-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --use-service-account-credentials=true " - }, - "schedulerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-scheduler.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/scheduler.conf", - "permissions": 384 - }, - "cmdLine": "kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false " - }, - "etcdConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/etcd.yaml", - "permissions": 384 - }, - "etcdDataDir": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "etcd", - "groupname": "root" - }, - "path": "/var/lib/minikube/etcd", - "permissions": 448 - }, - "adminConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/admin.conf", - "permissions": 384 - } - } -} \ No newline at end of file diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/3.json b/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/3.json deleted file mode 100644 index 00e41d934..000000000 --- a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/failed/input/3.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "ControlPlaneInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "APIServerInfo": { - "encryptionProviderConfigFile": { - "ownership": { - "uid": 1000, - "gid": 999, - "username": "", - "groupname": "" - }, - "path": "/var/lib/minikube/certs/hack/encryptionConf.yaml", - "content": "YXBpVmVyc2lvbjogYXBpc2VydmVyLmNvbmZpZy5rOHMuaW8vdjENCmtpbmQ6IEVuY3J5cHRpb25Db25maWd1cmF0aW9uDQpyZXNvdXJjZXM6DQogIC0gcmVzb3VyY2VzOg0KICAgICAgLSBzZWNyZXRzDQogICAgcHJvdmlkZXJzOg0KICAgICAgLSBhZXNjYmM6DQogICAgICAgICAga2V5czoNCiAgICAgICAgICAgIC0gbmFtZToga2V5MQ0KICAgICAgICAgICAgICBzZWNyZXQ6IDxCQVNFIDY0IEVOQ09ERUQgU0VDUkVUPg0KICAgICAgLSBpZGVudGl0eToge30=", - "permissions": 436 - }, - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-apiserver.yaml", - "permissions": 384 - }, - "cmdLine": "kube-apiserver --advertise-address=192.168.49.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --enable-bootstrap-token-auth=true --encryption-provider-config=/var/lib/minikube/certs/hack/encryptionConf.yaml --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-account-signing-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key " - }, - "controllerManagerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-controller-manager.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/controller-manager.conf", - "permissions": 384 - }, - "cmdLine": "kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-cidr=10.244.0.0/16 --cluster-name=mk --cluster-signing-cert-file=/var/lib/minikube/certs/ca.crt --cluster-signing-key-file=/var/lib/minikube/certs/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=false --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --root-ca-file=/var/lib/minikube/certs/ca.crt --service-account-private-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --use-service-account-credentials=true " - }, - "schedulerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-scheduler.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/scheduler.conf", - "permissions": 384 - }, - "cmdLine": "kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false " - }, - "etcdConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/etcd.yaml", - "permissions": 384 - }, - "etcdDataDir": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "etcd" - }, - "path": "/var/lib/minikube/etcd", - "permissions": 448 - }, - "adminConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/admin.conf", - "permissions": 384 - } - } -} \ No newline at end of file diff --git a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/passed/input/1.json b/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/passed/input/1.json deleted file mode 100644 index c43575c2c..000000000 --- a/rules/ensure-that-the-api-server-etcd-data-directory-ownership-is-set-to-etcd-etcd/test/passed/input/1.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "ControlPlaneInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-apiserver.yaml", - "permissions": 384 - }, - "cmdLine": "kube-apiserver --advertise-address=192.168.49.2 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/var/lib/minikube/certs/ca.crt --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota --enable-bootstrap-token-auth=true --etcd-cafile=/var/lib/minikube/certs/etcd/ca.crt --etcd-certfile=/var/lib/minikube/certs/apiserver-etcd-client.crt --etcd-keyfile=/var/lib/minikube/certs/apiserver-etcd-client.key --etcd-servers=https://127.0.0.1:2379 --kubelet-client-certificate=/var/lib/minikube/certs/apiserver-kubelet-client.crt --kubelet-client-key=/var/lib/minikube/certs/apiserver-kubelet-client.key --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --proxy-client-cert-file=/var/lib/minikube/certs/front-proxy-client.crt --proxy-client-key-file=/var/lib/minikube/certs/front-proxy-client.key --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --secure-port=8443 --service-account-issuer=https://kubernetes.default.svc.cluster.local --service-account-key-file=/var/lib/minikube/certs/sa.pub --service-account-signing-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --tls-cert-file=/var/lib/minikube/certs/apiserver.crt --tls-private-key-file=/var/lib/minikube/certs/apiserver.key " - }, - "controllerManagerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-controller-manager.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/controller-manager.conf", - "permissions": 384 - }, - "cmdLine": "kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-cidr=10.244.0.0/16 --cluster-name=mk --cluster-signing-cert-file=/var/lib/minikube/certs/ca.crt --cluster-signing-key-file=/var/lib/minikube/certs/ca.key --controllers=*,bootstrapsigner,tokencleaner --kubeconfig=/etc/kubernetes/controller-manager.conf --leader-elect=false --requestheader-client-ca-file=/var/lib/minikube/certs/front-proxy-ca.crt --root-ca-file=/var/lib/minikube/certs/ca.crt --service-account-private-key-file=/var/lib/minikube/certs/sa.key --service-cluster-ip-range=10.96.0.0/12 --use-service-account-credentials=true " - }, - "schedulerInfo": { - "specsFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/kube-scheduler.yaml", - "permissions": 384 - }, - "configFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/scheduler.conf", - "permissions": 384 - }, - "cmdLine": "kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false " - }, - "etcdConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/manifests/etcd.yaml", - "permissions": 384 - }, - "etcdDataDir": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "etcd", - "groupname": "etcd" - }, - "path": "/var/lib/minikube/etcd", - "permissions": 448 - }, - "adminConfigFile": { - "ownership": { - "uid": 0, - "gid": 0, - "username": "root", - "groupname": "root" - }, - "path": "/etc/kubernetes/admin.conf", - "permissions": 384 - } -} \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/raw.rego b/rules/ensure_network_policy_configured_in_labels/raw.rego new file mode 100644 index 000000000..10fc593d0 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/raw.rego @@ -0,0 +1,78 @@ +package armo_builtins + + +deny[msga] { + workload := input[_] + workload_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job", "Pod", "CronJob"} + workload_kinds[workload.kind] + + networkpolicies := [networkpolicy | networkpolicy = input[_]; networkpolicy.kind == "NetworkPolicy"] + not connected_to_any_network_policy(workload, networkpolicies) + + msga := { + "alertMessage": sprintf("%v: no networkpolicy configured in labels", [workload.metadata.name]), + "packagename": "armo_builtins", + "failedPaths": [], + "fixPaths":[], + "alertObject": { + "k8sApiObjects": [workload] + } + } +} + + +connected_to_any_network_policy(workload, networkpolicies){ + connected_to_network_policy(workload, networkpolicies[_]) +} + +# connected_to_network_policy returns true if the workload is connected to the networkpolicy +connected_to_network_policy(wl, networkpolicy){ + workload_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + workload_kinds[wl.kind] + is_same_namespace(networkpolicy.metadata, wl.metadata) + count(networkpolicy.spec.podSelector) > 0 + count({x | networkpolicy.spec.podSelector.matchLabels[x] == wl.spec.template.metadata.labels[x]}) == count(networkpolicy.spec.podSelector.matchLabels) +} + +# connected_to_network_policy returns true if the workload is connected to the networkpolicy +connected_to_network_policy(wl, networkpolicy){ + wl.kind == "Pod" + is_same_namespace(networkpolicy.metadata, wl.metadata) + count(networkpolicy.spec.podSelector) > 0 + count({x | networkpolicy.spec.podSelector.matchLabels[x] == wl.metadata.labels[x]}) == count(networkpolicy.spec.podSelector.matchLabels) +} + +# connected_to_network_policy returns true if the workload is connected to the networkpolicy +connected_to_network_policy(wl, networkpolicy){ + wl.kind == "CronJob" + is_same_namespace(networkpolicy.metadata, wl.metadata) + count(networkpolicy.spec.podSelector) > 0 + count({x | networkpolicy.spec.podSelector.matchLabels[x] == wl.spec.jobTemplate.spec.template.metadata.labels[x]}) == count(networkpolicy.spec.podSelector.matchLabels) +} + +# connected_to_network_policy returns true if the NetworkPolicy has no podSelector. +# if the NetworkPolicy has no podSelector, it is applied to all workloads in the namespace of the NetworkPolicy +connected_to_network_policy(wl, networkpolicy){ + is_same_namespace(networkpolicy.metadata, wl.metadata) + count(networkpolicy.spec.podSelector) == 0 +} + + +is_same_namespace(metadata1, metadata2) { + metadata1.namespace == metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + not metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata2.namespace + metadata1.namespace == "default" +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + metadata2.namespace == "default" +} \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/rule.metadata.json b/rules/ensure_network_policy_configured_in_labels/rule.metadata.json new file mode 100644 index 000000000..64711b69e --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/rule.metadata.json @@ -0,0 +1,61 @@ +{ + "name": "ensure_network_policy_configured_in_labels", + "attributes": { + "armoBuiltin": true + }, + "ruleLanguage": "Rego", + "match": [ + { + "apiGroups": [ + "" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Pod", + "ConfigMap" + ] + }, + { + "apiGroups": [ + "apps" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Deployment", + "ReplicaSet", + "DaemonSet", + "StatefulSet" + ] + }, + { + "apiGroups": [ + "batch" + ], + "apiVersions": [ + "*" + ], + "resources": [ + "Job", + "CronJob" + ] + }, + { + "apiGroups": [ + "networking.k8s.io" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "NetworkPolicy" + ] + } + ], + "description": "fails if no networkpolicy configured in workload labels", + "remediation": "", + "ruleQuery": "armo_builtins" +} \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/expected.json b/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/expected.json new file mode 100644 index 000000000..00ed39e97 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/expected.json @@ -0,0 +1,23 @@ +[ + { + "alertMessage": "my-cronjob: no networkpolicy configured in labels", + "failedPaths": [ + ], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 0, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "batch/v1beta1", + "kind": "CronJob", + "metadata": { + "name": "my-cronjob" + } + } + ] + + } + } +] \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/cronjob.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/cronjob.yaml new file mode 100644 index 000000000..0adbabc1d --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/cronjob.yaml @@ -0,0 +1,17 @@ +apiVersion: batch/v1beta1 +kind: CronJob +metadata: + name: my-cronjob +spec: + schedule: "*/1 * * * *" + jobTemplate: + spec: + template: + metadata: + labels: + job: my-cronjob + spec: + containers: + - name: my-cronjob-container + image: my-cronjob-image + restartPolicy: OnFailure \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/network_policy.yaml new file mode 100644 index 000000000..bccdea356 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_cronjob_no_matched_label/input/network_policy.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-pod-network-policy +spec: + podSelector: + matchLabels: + app: my-pod1 + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/expected.json b/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/expected.json new file mode 100644 index 000000000..10b4824f1 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/expected.json @@ -0,0 +1,26 @@ +[ + { + "alertMessage": "my-deployment: no networkpolicy configured in labels", + "failedPaths": [ + ], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 0, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "my-deployment", + "labels": { + "deployment": "my-deployment" + } + } + } + ] + + } + } +] \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/deployment.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/deployment.yaml new file mode 100644 index 000000000..c7b97b9c6 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deployment + labels: + deployment: my-deployment # label for the Deployment itself +spec: + replicas: 3 + selector: + matchLabels: + app: my-app # Used to select the Pods the Deployment should manage + template: + metadata: + labels: + app: my-app # Labels for the Pods created by the Deployment + spec: + containers: + - name: my-app + image: my-app:1.0.0 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/network_policy.yaml new file mode 100644 index 000000000..bccdea356 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_deployment_no_matched_label/input/network_policy.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-pod-network-policy +spec: + podSelector: + matchLabels: + app: my-pod1 + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/expected.json b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/expected.json new file mode 100644 index 000000000..b367f0e3a --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/expected.json @@ -0,0 +1,26 @@ +[ + { + "alertMessage": "my-pod: no networkpolicy configured in labels", + "failedPaths": [ + ], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 0, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "my-pod", + "labels": { + "app": "my-pod" + } + } + } + ] + + } + } +] \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy.yaml new file mode 100644 index 000000000..bccdea356 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-pod-network-policy +spec: + podSelector: + matchLabels: + app: my-pod1 + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy2.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy2.yaml new file mode 100644 index 000000000..5a62c5626 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/network_policy2.yaml @@ -0,0 +1,13 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-pod-network-policy2 + namespace: my-namespace +spec: + podSelector: + matchLabels: + app: my-pod + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/pod.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/pod.yaml new file mode 100644 index 000000000..f99f91caa --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_matched_label/input/pod.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: my-pod + labels: + app: my-pod +spec: + containers: + - name: my-app + image: my-app:1.0.0 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/expected.json b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/expected.json new file mode 100644 index 000000000..71a18183e --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/expected.json @@ -0,0 +1,23 @@ +[ + { + "alertMessage": "mypod: no networkpolicy configured in labels", + "failedPaths": [ + ], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 0, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "mypod" + } + } + ] + + } + } +] \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/input/pod.yaml b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/input/pod.yaml new file mode 100644 index 000000000..eb6ee4dd5 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/failed_pod_no_networkpolicy/input/pod.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: mynamespace +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + - name: configvolume + mountPath: "/etc/foo" + volumes: + - name: foo + secret: + secretName: mysecret + optional: true + - name: configvolume + configMap: + name: myconfigmap \ No newline at end of file diff --git a/rules/rule-access-kubelet-API/test/test/expected.json b/rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/expected.json similarity index 100% rename from rules/rule-access-kubelet-API/test/test/expected.json rename to rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/expected.json diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/cronjob.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/cronjob.yaml new file mode 100644 index 000000000..0adbabc1d --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/cronjob.yaml @@ -0,0 +1,17 @@ +apiVersion: batch/v1beta1 +kind: CronJob +metadata: + name: my-cronjob +spec: + schedule: "*/1 * * * *" + jobTemplate: + spec: + template: + metadata: + labels: + job: my-cronjob + spec: + containers: + - name: my-cronjob-container + image: my-cronjob-image + restartPolicy: OnFailure \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/network_policy.yaml new file mode 100644 index 000000000..2c2279434 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_cronjob_label_match/input/network_policy.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-app-network-policy +spec: + podSelector: + matchLabels: + job: my-cronjob + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/expected.json b/rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/expected.json similarity index 100% rename from rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/expected.json rename to rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/expected.json diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/deployment.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/deployment.yaml new file mode 100644 index 000000000..c7b97b9c6 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deployment + labels: + deployment: my-deployment # label for the Deployment itself +spec: + replicas: 3 + selector: + matchLabels: + app: my-app # Used to select the Pods the Deployment should manage + template: + metadata: + labels: + app: my-app # Labels for the Pods created by the Deployment + spec: + containers: + - name: my-app + image: my-app:1.0.0 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/network_policy.yaml new file mode 100644 index 000000000..29b71402d --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_deployment_label_match/input/network_policy.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-app-network-policy +spec: + podSelector: + matchLabels: + app: my-app + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/security-context-in-pod/test/cronjob/expected.json b/rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/expected.json similarity index 100% rename from rules/security-context-in-pod/test/cronjob/expected.json rename to rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/expected.json diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/network_policy.yaml new file mode 100644 index 000000000..a4f4d7b08 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/network_policy.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-pod-network-policy +spec: + podSelector: + matchLabels: + app: my-pod + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/pod.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/pod.yaml new file mode 100644 index 000000000..f99f91caa --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_pod_label_match/input/pod.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: my-pod + labels: + app: my-pod +spec: + containers: + - name: my-app + image: my-app:1.0.0 \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/valid/expected.json b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/expected.json similarity index 100% rename from rules/strict-file-owners-root/test/valid/expected.json rename to rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/expected.json diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/network_policy.yaml new file mode 100644 index 000000000..860ab46e5 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/network_policy.yaml @@ -0,0 +1,10 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-pod-network-policy +spec: + podSelector: {} + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/pod.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/pod.yaml new file mode 100644 index 000000000..f99f91caa --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector/input/pod.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: my-pod + labels: + app: my-pod +spec: + containers: + - name: my-app + image: my-app:1.0.0 \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/valid/expected.json b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/expected.json similarity index 100% rename from rules/strict-file-permissions-600/test/valid/expected.json rename to rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/expected.json diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/network_policy.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/network_policy.yaml new file mode 100644 index 000000000..f27c9fe47 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/network_policy.yaml @@ -0,0 +1,11 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: my-pod-network-policy + namespace: my-namespace +spec: + podSelector: {} + ingress: + - ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/pod.yaml b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/pod.yaml new file mode 100644 index 000000000..fc8293967 --- /dev/null +++ b/rules/ensure_network_policy_configured_in_labels/test/success_pod_no_pod_selector_ns/input/pod.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Pod +metadata: + name: my-pod + namespace: my-namespace + labels: + app: my-pod +spec: + containers: + - name: my-app + image: my-app:1.0.0 \ No newline at end of file diff --git a/rules/exposure-to-internet/raw.rego b/rules/exposure-to-internet/raw.rego new file mode 100644 index 000000000..4a6345c47 --- /dev/null +++ b/rules/exposure-to-internet/raw.rego @@ -0,0 +1,89 @@ +package armo_builtins + +# Checks if NodePort or LoadBalancer is connected to a workload to expose something +deny[msga] { + service := input[_] + service.kind == "Service" + is_exposed_service(service) + + wl := input[_] + spec_template_spec_patterns := {"Deployment", "ReplicaSet", "DaemonSet", "StatefulSet", "Pod", "Job", "CronJob"} + spec_template_spec_patterns[wl.kind] + wl_connected_to_service(wl, service) + failPath := ["spec.type"] + msga := { + "alertMessage": sprintf("workload '%v' is exposed through service '%v'", [wl.metadata.name, service.metadata.name]), + "packagename": "armo_builtins", + "alertScore": 7, + "fixPaths": [], + "failedPaths": [], + "alertObject": { + "k8sApiObjects": [wl] + }, + "relatedObjects": [{ + "object": service, + "failedPaths": failPath, + }] + } +} + +# Checks if Ingress is connected to a service and a workload to expose something +deny[msga] { + ingress := input[_] + ingress.kind == "Ingress" + + svc := input[_] + svc.kind == "Service" + # avoid duplicate alerts + # if service is already exposed through NodePort or LoadBalancer workload will fail on that + not is_exposed_service(svc) + + wl := input[_] + spec_template_spec_patterns := {"Deployment", "ReplicaSet", "DaemonSet", "StatefulSet", "Pod", "Job", "CronJob"} + spec_template_spec_patterns[wl.kind] + wl_connected_to_service(wl, svc) + + result := svc_connected_to_ingress(svc, ingress) + + msga := { + "alertMessage": sprintf("workload '%v' is exposed through ingress '%v'", [wl.metadata.name, ingress.metadata.name]), + "packagename": "armo_builtins", + "failedPaths": [], + "fixPaths": [], + "alertScore": 7, + "alertObject": { + "k8sApiObjects": [wl] + }, + "relatedObjects": [{ + "object": ingress, + "failedPaths": result, + }] + } +} + +# ==================================================================================== + +is_exposed_service(svc) { + svc.spec.type == "NodePort" +} + +is_exposed_service(svc) { + svc.spec.type == "LoadBalancer" +} + +wl_connected_to_service(wl, svc) { + count({x | svc.spec.selector[x] == wl.metadata.labels[x]}) == count(svc.spec.selector) +} + +wl_connected_to_service(wl, svc) { + wl.spec.selector.matchLabels == svc.spec.selector +} + +# check if service is connected to ingress +svc_connected_to_ingress(svc, ingress) = result { + rule := ingress.spec.rules[i] + paths := rule.http.paths[j] + svc.metadata.name == paths.backend.service.name + result := [sprintf("ingress.spec.rules[%d].http.paths[%d].backend.service.name", [i,j])] +} + diff --git a/rules/deny-RCE-vuln-image-pods/rule.metadata.json b/rules/exposure-to-internet/rule.metadata.json similarity index 60% rename from rules/deny-RCE-vuln-image-pods/rule.metadata.json rename to rules/exposure-to-internet/rule.metadata.json index 76c1d6490..46497eb24 100644 --- a/rules/deny-RCE-vuln-image-pods/rule.metadata.json +++ b/rules/exposure-to-internet/rule.metadata.json @@ -1,9 +1,7 @@ { - "name": "deny-RCE-vuln-image-pods", + "name": "exposure-to-internet", "attributes": { - "m$K8sThreatMatrix": "Execution::Application Exploit (RCE)", - "armoBuiltin": true, - "armoOpa": "true" + "armoBuiltin": true }, "ruleLanguage": "Rego", "match": [ @@ -44,14 +42,22 @@ "Job", "CronJob" ] - } - ], - "ruleDependencies": [ + }, { - "packageName": "cautils" + "apiGroups": [ + "extensions", + "networking.k8s.io" + ], + "apiVersions": [ + "v1beta1", + "v1" + ], + "resources": [ + "Ingress" + ] } ], - "description": "determines if pods has vulnerable image with remote code execution", + "description": "fails in case the running workload has binded Service or Ingress that are exposing it on Internet.", "remediation": "", - "ruleQuery": "package armo_builtins" -} \ No newline at end of file + "ruleQuery": "armo_builtins" +} diff --git a/rules/exposure-to-internet/test/failed_with_ingress/expected.json b/rules/exposure-to-internet/test/failed_with_ingress/expected.json new file mode 100644 index 000000000..5bd39611f --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_ingress/expected.json @@ -0,0 +1,56 @@ +[ + { + "alertMessage": "workload 'my-app' is exposed through ingress 'my-ingress'", + "failedPaths": [], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 7, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "my-app" + } + } + ] + }, + "relatedObjects": [ + { + "object": { + "apiVersion": "networking.k8s.io/v1beta1", + "kind": "Ingress", + "metadata": { + "name": "my-ingress" + }, + "spec": { + "ingressClassName": "nginx", + "rules": [ + { + "host": "myservicea.foo.org", + "http": { + "paths": [ + { + "backend": { + "service": { + "name": "my-service" + } + }, + "path": "/" + } + ] + } + } + ] + } + }, + "failedPaths": [ + "ingress.spec.rules[0].http.paths[0].backend.service.name" + ], + "fixPaths": null + } + ] + } +] \ No newline at end of file diff --git a/rules/exposure-to-internet/test/failed_with_ingress/input/deployment.yaml b/rules/exposure-to-internet/test/failed_with_ingress/input/deployment.yaml new file mode 100644 index 000000000..c886b6c46 --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_ingress/input/deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app + namespace: default +spec: + selector: + matchLabels: + app: my-app + template: + metadata: + labels: + app: my-app + spec: + containers: + - args: + - server + image: argoproj/argocli:latest + name: argo-server + diff --git a/rules/exposure-to-internet/test/failed_with_ingress/input/ingress.yaml b/rules/exposure-to-internet/test/failed_with_ingress/input/ingress.yaml new file mode 100644 index 000000000..096c24a22 --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_ingress/input/ingress.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: my-ingress +spec: + ingressClassName: nginx + rules: + - host: myservicea.foo.org + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: my-service + port: + number: 80 diff --git a/rules/exposure-to-internet/test/failed_with_ingress/input/service.yaml b/rules/exposure-to-internet/test/failed_with_ingress/input/service.yaml new file mode 100644 index 000000000..7ba441575 --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_ingress/input/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app: my-app + type: ClusterIP + ports: + - targetPort: 80 + port: 80 diff --git a/rules/exposure-to-internet/test/failed_with_service_loadbalancer/expected.json b/rules/exposure-to-internet/test/failed_with_service_loadbalancer/expected.json new file mode 100644 index 000000000..797e9c436 --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_service_loadbalancer/expected.json @@ -0,0 +1,59 @@ +[ + { + "alertMessage": "workload 'my-app' is exposed through service 'my-service'", + "failedPaths": [], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 7, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "my-app" + } + } + ] + }, + "relatedObjects": [ + { + "object": { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "name": "my-service" + }, + "spec": { + "clusterIP": "10.96.0.11", + "ports": [ + { + "port": 80, + "protocol": "TCP", + "targetPort": 9376 + } + ], + "selector": { + "app": "argo-server" + }, + "type": "LoadBalancer" + }, + "status": { + "loadBalancer": { + "ingress": [ + { + "ip": "192.0.2.127" + } + ] + } + } + }, + "failedPaths": [ + "spec.type" + ], + "fixPaths": null + } + ] + } +] \ No newline at end of file diff --git a/rules/exposure-to-internet/test/failed_with_service_loadbalancer/input/deployment.yaml b/rules/exposure-to-internet/test/failed_with_service_loadbalancer/input/deployment.yaml new file mode 100644 index 000000000..49a2f5106 --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_service_loadbalancer/input/deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app + namespace: default +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + image: argoproj/argocli:latest + name: argo-server + diff --git a/rules/rule-exposed-dashboard-v1/test/test/input/service.yaml b/rules/exposure-to-internet/test/failed_with_service_loadbalancer/input/service.yaml similarity index 71% rename from rules/rule-exposed-dashboard-v1/test/test/input/service.yaml rename to rules/exposure-to-internet/test/failed_with_service_loadbalancer/input/service.yaml index 297da4e39..410565d01 100644 --- a/rules/rule-exposed-dashboard-v1/test/test/input/service.yaml +++ b/rules/exposure-to-internet/test/failed_with_service_loadbalancer/input/service.yaml @@ -4,14 +4,14 @@ metadata: name: my-service spec: selector: - k8s-app: kubernetes-dashboard + app: argo-server ports: - protocol: TCP port: 80 targetPort: 9376 - clusterIP: 10.96.171.239 + clusterIP: 10.96.0.11 type: LoadBalancer status: loadBalancer: ingress: - - ip: 192.0.2.127 \ No newline at end of file + - ip: 192.0.2.127 diff --git a/rules/exposure-to-internet/test/failed_with_service_nodeport/expected.json b/rules/exposure-to-internet/test/failed_with_service_nodeport/expected.json new file mode 100644 index 000000000..53167dd6c --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_service_nodeport/expected.json @@ -0,0 +1,49 @@ +[ + { + "alertMessage": "workload 'my-app' is exposed through service 'my-service'", + "failedPaths": [], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 7, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "my-app" + } + } + ] + }, + "relatedObjects": [ + { + "object": { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "name": "my-service" + }, + "spec": { + "ports": [ + { + "nodePort": 30007, + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "app": "argo-server" + }, + "type": "NodePort" + } + }, + "failedPaths": [ + "spec.type" + ], + "fixPaths": null + } + ] + } +] \ No newline at end of file diff --git a/rules/exposure-to-internet/test/failed_with_service_nodeport/input/deployment.yaml b/rules/exposure-to-internet/test/failed_with_service_nodeport/input/deployment.yaml new file mode 100644 index 000000000..49a2f5106 --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_service_nodeport/input/deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app + namespace: default +spec: + selector: + matchLabels: + app: argo-server + template: + metadata: + labels: + app: argo-server + spec: + containers: + - args: + - server + image: argoproj/argocli:latest + name: argo-server + diff --git a/rules/exposure-to-internet/test/failed_with_service_nodeport/input/service.yaml b/rules/exposure-to-internet/test/failed_with_service_nodeport/input/service.yaml new file mode 100644 index 000000000..94654bcb9 --- /dev/null +++ b/rules/exposure-to-internet/test/failed_with_service_nodeport/input/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app: argo-server + type: NodePort + ports: + - port: 80 + targetPort: 80 + nodePort: 30007 diff --git a/rules/exposure-to-internet/test/success_with_ingress/expected.json b/rules/exposure-to-internet/test/success_with_ingress/expected.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/rules/exposure-to-internet/test/success_with_ingress/expected.json @@ -0,0 +1 @@ +[] diff --git a/rules/exposure-to-internet/test/success_with_ingress/input/deployment.yaml b/rules/exposure-to-internet/test/success_with_ingress/input/deployment.yaml new file mode 100644 index 000000000..c886b6c46 --- /dev/null +++ b/rules/exposure-to-internet/test/success_with_ingress/input/deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app + namespace: default +spec: + selector: + matchLabels: + app: my-app + template: + metadata: + labels: + app: my-app + spec: + containers: + - args: + - server + image: argoproj/argocli:latest + name: argo-server + diff --git a/rules/exposure-to-internet/test/success_with_ingress/input/ingress.yaml b/rules/exposure-to-internet/test/success_with_ingress/input/ingress.yaml new file mode 100644 index 000000000..1d707c51f --- /dev/null +++ b/rules/exposure-to-internet/test/success_with_ingress/input/ingress.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: my-ingress +spec: + ingressClassName: nginx + rules: + - host: myservicea.foo.org + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: my-service-b + port: + number: 80 diff --git a/rules/exposure-to-internet/test/success_with_ingress/input/service.yaml b/rules/exposure-to-internet/test/success_with_ingress/input/service.yaml new file mode 100644 index 000000000..7ba441575 --- /dev/null +++ b/rules/exposure-to-internet/test/success_with_ingress/input/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-service +spec: + selector: + app: my-app + type: ClusterIP + ports: + - targetPort: 80 + port: 80 diff --git a/rules/has-critical-vulnerability/filter.rego b/rules/has-critical-vulnerability/filter.rego deleted file mode 100644 index b13c01a90..000000000 --- a/rules/has-critical-vulnerability/filter.rego +++ /dev/null @@ -1,121 +0,0 @@ -package armo_builtins - -import data.cautils - -deny[msga] { - - # get pod and imageVulnerabilities - pods := [pod | pod= input[_]; pod.kind == "Pod"] - vulns := [vuln | vuln = input[_]; vuln.kind == "ImageVulnerabilities"] - pod := pods[_] - vuln := vulns[_] - - # get container image name - container := pod.spec.containers[i] - - # image has vulnerabilities - container.image == vuln.metadata.name - - path := sprintf("spec.containers[%v].image", [format_int(i, 10)]) - - metadata = { - "name": pod.metadata.name, - "namespace": pod.metadata.namespace - } - attackvector = { - "apiVersion": "result.vulnscan.com/v1", - "kind": pod.kind, - "metadata": metadata, - "relatedObjects": [pod, vuln] - } - - msga := { - "alertMessage": sprintf("image %v has critical vulnerabilities", [container.image]), - "alertScore": 5, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "externalObjects": attackvector - } - } -} - - -#handles majority of workload resources -deny[msga] { - - # get pod and imageVulnerabilities - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - - wls := [wl | wl= input[_]; spec_template_spec_patterns[wl.kind]] - vulns := [vuln | vuln = input[_]; vuln.kind == "ImageVulnerabilities"] - wl := wls[_] - vuln := vulns[_] - - # get container image name - container := wl.spec.template.spec.containers[i] - - # image has vulnerabilities - container.image == vuln.metadata.name - - path := sprintf("spec.template.spec.containers[%v].image", [format_int(i, 10)]) - - metadata = { - "name": wl.metadata.name, - "namespace": wl.metadata.namespace - } - attackvector = { - "apiVersion": "result.vulnscan.com/v1", - "kind": wl.kind, - "metadata": metadata, - "relatedObjects": [wl, vuln] - } - - msga := { - "alertMessage": sprintf("image %v has critical vulnerabilities", [container.image]), - "alertScore": 5, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "externalObjects": attackvector - } - } -} - -# handles cronjob -deny[msga] { - - wls := [wl | wl= input[_]; wl.kind == "CronJob"] - vulns := [vuln | vuln = input[_]; vuln.kind == "ImageVulnerabilities"] - wl := wls[_] - vuln := vulns[_] - - # get container image name - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - - # image has vulnerabilities - container.image == vuln.metadata.name - - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v].image", [format_int(i, 10)]) - - metadata = { - "name": wl.metadata.name, - "namespace": wl.metadata.namespace - } - attackvector = { - "apiVersion": "result.vulnscan.com/v1", - "kind": wl.kind, - "metadata": metadata, - "relatedObjects": [wl, vuln] - } - - msga := { - "alertMessage": sprintf("image %v has critical vulnerabilities", [container.image]), - "alertScore": 5, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "externalObjects": attackvector - } - } -} \ No newline at end of file diff --git a/rules/has-critical-vulnerability/raw.rego b/rules/has-critical-vulnerability/raw.rego deleted file mode 100644 index 52718931d..000000000 --- a/rules/has-critical-vulnerability/raw.rego +++ /dev/null @@ -1,141 +0,0 @@ -package armo_builtins - -import data.cautils - -deny[msga] { - - # get pod and imageVulnerabilities - pods := [pod | pod= input[_]; pod.kind == "Pod"] - vulns := [vuln | vuln = input[_]; vuln.kind == "ImageVulnerabilities"] - pod := pods[_] - vuln := vulns[_] - - # get container image name - container := pod.spec.containers[i] - - # image has vulnerabilities - container.image == vuln.metadata.name - - # has a "crirtical" vulnerability - has_crirtical_vulnerability(vuln) - - path := sprintf("spec.containers[%v].image", [format_int(i, 10)]) - - metadata = { - "name": pod.metadata.name, - "namespace": pod.metadata.namespace - } - attackvector = { - "apiVersion": "result.vulnscan.com/v1", - "kind": pod.kind, - "metadata": metadata, - "relatedObjects": [pod, vuln] - } - - msga := { - "alertMessage": sprintf("image %v has critical vulnerabilities", [container.image]), - "alertScore": 5, - "failedPaths": [path], - "fixPaths":[], - "packagename": "armo_builtins", - "alertObject": { - "externalObjects": attackvector - } - } -} - - -#handles majority of workload resources -deny[msga] { - - # get pod and imageVulnerabilities - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - - wls := [wl | wl= input[_]; spec_template_spec_patterns[wl.kind]] - vulns := [vuln | vuln = input[_]; vuln.kind == "ImageVulnerabilities"] - wl := wls[_] - vuln := vulns[_] - - # get container image name - container := wl.spec.template.spec.containers[i] - - # image has vulnerabilities - container.image == vuln.metadata.name - - # has a "crirtical" vulnerability - has_crirtical_vulnerability(vuln) - - path := sprintf("spec.template.spec.containers[%v].image", [format_int(i, 10)]) - - metadata = { - "name": wl.metadata.name, - "namespace": wl.metadata.namespace - } - attackvector = { - "apiVersion": "result.vulnscan.com/v1", - "kind": wl.kind, - "metadata": metadata, - "relatedObjects": [wl, vuln] - } - - msga := { - "alertMessage": sprintf("image %v has critical vulnerabilities", [container.image]), - "alertScore": 5, - "failedPaths": [path], - "fixPaths":[], - "packagename": "armo_builtins", - "alertObject": { - "externalObjects": attackvector - } - } -} - - -# handles cronjob -deny[msga] { - - wls := [wl | wl= input[_]; wl.kind == "CronJob"] - vulns := [vuln | vuln = input[_]; vuln.kind == "ImageVulnerabilities"] - wl := wls[_] - vuln := vulns[_] - - # get container image name - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - - # image has vulnerabilities - container.image == vuln.metadata.name - - # has a "crirtical" vulnerability - has_crirtical_vulnerability(vuln) - - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v].image", [format_int(i, 10)]) - - metadata = { - "name": wl.metadata.name, - "namespace": wl.metadata.namespace - } - attackvector = { - "apiVersion": "result.vulnscan.com/v1", - "kind": wl.kind, - "metadata": metadata, - "relatedObjects": [wl, vuln] - } - - msga := { - "alertMessage": sprintf("image %v has critical vulnerabilities", [container.image]), - "alertScore": 5, - "failedPaths": [path], - "fixPaths":[], - "packagename": "armo_builtins", - "alertObject": { - "externalObjects": attackvector - } - } -} - - -has_crirtical_vulnerability(vuln){ - count(vuln.data) > 0 - data := vuln.data[_] - data.severity == "Critical" -} \ No newline at end of file diff --git a/rules/has-critical-vulnerability/rule.metadata.json b/rules/has-critical-vulnerability/rule.metadata.json deleted file mode 100644 index 750396b49..000000000 --- a/rules/has-critical-vulnerability/rule.metadata.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "name": "has-critical-vulnerability", - "attributes": { - "m$K8sThreatMatrix": "has-critical-vulnerability", - "armoBuiltin": true, - "imageScanRelated": true - - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "Pod" - ] - }, - { - "apiGroups": [ - "apps" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "Deployment", - "ReplicaSet", - "DaemonSet", - "StatefulSet" - ] - }, - { - "apiGroups": [ - "batch" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Job", - "CronJob" - ] - } - ], - "dynamicMatch": [ - { - "apiGroups": [ - "armo.vuln.images", - "image.vulnscan.com" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "ImageVulnerabilities" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "image has-critical-vulnerability", - "remediation": "", - "ruleQuery": "package armo_builtins" -} \ No newline at end of file diff --git a/rules/has-critical-vulnerability/test/test-fail/expected.json b/rules/has-critical-vulnerability/test/test-fail/expected.json deleted file mode 100644 index 7f07aaa2d..000000000 --- a/rules/has-critical-vulnerability/test/test-fail/expected.json +++ /dev/null @@ -1,136 +0,0 @@ -[{ - "alertMessage": "image images.my-company.example/app:v4 has critical vulnerabilities", - "failedPaths": ["spec.containers[0].image"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 5, - "alertObject": { - "externalObjects": { - "apiVersion": "result.vulnscan.com/v1", - "kind": "Pod", - "metadata": { - "name": "name", - "namespace": "default" - }, - "relatedObjects": [{ - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "name": "name", - "namespace": "default" - }, - "spec": { - "containers": [{ - "image": "images.my-company.example/app:v4", - "name": "app", - "resources": { - "limits": { - "cpu": "500m", - "memory": "128Mi" - }, - "requests": { - "cpu": "250m", - "memory": "64Mi" - } - } - }, { - "image": "name", - "name": "log-aggregator", - "resources": { - "limits": { - "memory": "128Mi" - } - } - }] - } - }, { - "apiVersion": "armo.vuln.images/v1", - "data": [{ - "categories": { - "isRce": true - }, - "description": "zlib before 1.2.12 allows memory corruption when deflating (i.e., when compressing) if the input has many distant matches.", - "fixedIn": [{ - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "name": "fixed", - "version": "1:1.2.11.dfsg-2+deb11u1" - }], - "healthStatus": "", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2018-25032", - "name": "CVE-2018-25032", - "neglected": 0, - "packageName": "zlib1g", - "packageVersion": "1:1.2.11.dfsg-2", - "relevant": "No signature profile to compare", - "severity": "Critical", - "urgent": 0 - }, { - "categories": { - "isRce": false - }, - "description": "CPAN 2.28 allows Signature Verification Bypass.", - "fixedIn": [{ - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "name": "wont-fix", - "version": "" - }], - "healthStatus": "", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2020-16156", - "metadata": null, - "name": "CVE-2020-16156", - "neglected": 0, - "packageName": "perl-base", - "packageVersion": "5.32.1-4+deb11u1", - "relevant": "No signature profile to compare", - "severity": "High", - "urgent": 0 - }, { - "categories": { - "isRce": false - }, - "description": "Libgcrypt before 1.8.8 and 1.9.x before 1.9.3 mishandles ElGamal encryption because it lacks exponent blinding to address a side-channel attack against mpi_powm, and the window size is not chosen appropriately. This, for example, affects use of ElGamal in OpenPGP.", - "fixedIn": [{ - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "name": "wont-fix", - "version": "" - }], - "healthStatus": "", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2021-33560", - "metadata": null, - "name": "CVE-2021-33560", - "neglected": 0, - "packageName": "libgcrypt20", - "packageVersion": "1.8.7-6", - "relevant": "No signature profile to compare", - "severity": "High", - "urgent": 0 - }, { - "categories": { - "isRce": false - }, - "description": "ASN.1 strings are represented internally within OpenSSL as an ASN1_STRING structure which contains a buffer holding the string data and a field holding the buffer length. This contrasts with normal C strings which are repesented as a buffer for the string data which is terminated with a NUL (0) byte. Although not a strict requirement, ASN.1 strings that are parsed using OpenSSL's own \"d2i\" functions (and other similar parsing functions) as well as any string whose value has been set with the ASN1_STRING_set() function will additionally NUL terminate the byte array in the ASN1_STRING structure. However, it is possible for applications to directly construct valid ASN1_STRING structures which do not NUL terminate the byte array by directly setting the \"data\" and \"length\" fields in the ASN1_STRING array. This can also happen by using the ASN1_STRING_set0() function. Numerous OpenSSL functions that print ASN.1 data have been found to assume that the ASN1_STRING byte array will be NUL terminated, even though this is not guaranteed for strings that have been directly constructed. Where an application requests an ASN.1 structure to be printed, and where that ASN.1 structure contains ASN1_STRINGs that have been directly constructed by the application without NUL terminating the \"data\" field, then a read buffer overrun can occur. The same thing can also occur during name constraints processing of certificates (for example if a certificate has been directly constructed by the application instead of loading it via the OpenSSL parsing functions, and the certificate contains non NUL terminated ASN1_STRING structures). It can also occur in the X509_get1_email(), X509_REQ_get1_email() and X509_get1_ocsp() functions. If a malicious actor can cause an application to directly construct an ASN1_STRING and then process it through one of the affected OpenSSL functions then this issue could be hit. This might result in a crash (causing a Denial of Service attack). It could also result in the disclosure of private memory contents (such as private keys, or sensitive plaintext). Fixed in OpenSSL 1.1.1l (Affected 1.1.1-1.1.1k). Fixed in OpenSSL 1.0.2za (Affected 1.0.2-1.0.2y).", - "fixedIn": [{ - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "name": "fixed", - "version": "1.1.1k-1+deb11u1" - }], - "healthStatus": "", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2021-3712", - "metadata": null, - "name": "CVE-2021-3712", - "neglected": 0, - "packageName": "libssl1.1", - "packageVersion": "1.1.1k-1", - "relevant": "No signature profile to compare", - "severity": "High", - "urgent": 0 - }], - "kind": "ImageVulnerabilities", - "metadata": { - "name": "images.my-company.example/app:v4" - } - }] - } - } -}] \ No newline at end of file diff --git a/rules/has-critical-vulnerability/test/test-fail/input/pod.yaml b/rules/has-critical-vulnerability/test/test-fail/input/pod.yaml deleted file mode 100644 index c9769fa17..000000000 --- a/rules/has-critical-vulnerability/test/test-fail/input/pod.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: name - namespace: default -spec: - containers: - - name: app - image: images.my-company.example/app:v4 - resources: - requests: - memory: "64Mi" - cpu: "250m" - limits: - memory: "128Mi" - cpu: "500m" - - name: log-aggregator - image: name - resources: - limits: - memory: "128Mi" \ No newline at end of file diff --git a/rules/has-critical-vulnerability/test/test-fail/input/resource.json b/rules/has-critical-vulnerability/test/test-fail/input/resource.json deleted file mode 100644 index 71968fe09..000000000 --- a/rules/has-critical-vulnerability/test/test-fail/input/resource.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "apiVersion": "armo.vuln.images/v1", - "kind": "ImageVulnerabilities", - "metadata": { - "name":"images.my-company.example/app:v4" - }, - "data": [{ - "name": "CVE-2018-25032", - "packageName": "zlib1g", - "packageVersion": "1:1.2.11.dfsg-2", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2018-25032", - "description": "zlib before 1.2.12 allows memory corruption when deflating (i.e., when compressing) if the input has many distant matches.", - "severity": "Critical", - "fixedIn": [{ - "name": "fixed", - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "version": "1:1.2.11.dfsg-2+deb11u1" - }], - "relevant": "No signature profile to compare", - "urgent": 0, - "neglected": 0, - "healthStatus": "", - "categories": { - "isRce": true - } - }, { - "name": "CVE-2020-16156", - "packageName": "perl-base", - "packageVersion": "5.32.1-4+deb11u1", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2020-16156", - "description": "CPAN 2.28 allows Signature Verification Bypass.", - "severity": "High", - "metadata": null, - "fixedIn": [{ - "name": "wont-fix", - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "version": "" - }], - "relevant": "No signature profile to compare", - "urgent": 0, - "neglected": 0, - "healthStatus": "", - "categories": { - "isRce": false - } - }, { - "name": "CVE-2021-33560", - "packageName": "libgcrypt20", - "packageVersion": "1.8.7-6", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2021-33560", - "description": "Libgcrypt before 1.8.8 and 1.9.x before 1.9.3 mishandles ElGamal encryption because it lacks exponent blinding to address a side-channel attack against mpi_powm, and the window size is not chosen appropriately. This, for example, affects use of ElGamal in OpenPGP.", - "severity": "High", - "metadata": null, - "fixedIn": [{ - "name": "wont-fix", - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "version": "" - }], - "relevant": "No signature profile to compare", - "urgent": 0, - "neglected": 0, - "healthStatus": "", - "categories": { - "isRce": false - } - }, { - "name": "CVE-2021-3712", - "packageName": "libssl1.1", - "packageVersion": "1.1.1k-1", - "link": "https://nvd.nist.gov/vuln/detail/CVE-2021-3712", - "description": "ASN.1 strings are represented internally within OpenSSL as an ASN1_STRING structure which contains a buffer holding the string data and a field holding the buffer length. This contrasts with normal C strings which are repesented as a buffer for the string data which is terminated with a NUL (0) byte. Although not a strict requirement, ASN.1 strings that are parsed using OpenSSL's own \"d2i\" functions (and other similar parsing functions) as well as any string whose value has been set with the ASN1_STRING_set() function will additionally NUL terminate the byte array in the ASN1_STRING structure. However, it is possible for applications to directly construct valid ASN1_STRING structures which do not NUL terminate the byte array by directly setting the \"data\" and \"length\" fields in the ASN1_STRING array. This can also happen by using the ASN1_STRING_set0() function. Numerous OpenSSL functions that print ASN.1 data have been found to assume that the ASN1_STRING byte array will be NUL terminated, even though this is not guaranteed for strings that have been directly constructed. Where an application requests an ASN.1 structure to be printed, and where that ASN.1 structure contains ASN1_STRINGs that have been directly constructed by the application without NUL terminating the \"data\" field, then a read buffer overrun can occur. The same thing can also occur during name constraints processing of certificates (for example if a certificate has been directly constructed by the application instead of loading it via the OpenSSL parsing functions, and the certificate contains non NUL terminated ASN1_STRING structures). It can also occur in the X509_get1_email(), X509_REQ_get1_email() and X509_get1_ocsp() functions. If a malicious actor can cause an application to directly construct an ASN1_STRING and then process it through one of the affected OpenSSL functions then this issue could be hit. This might result in a crash (causing a Denial of Service attack). It could also result in the disclosure of private memory contents (such as private keys, or sensitive plaintext). Fixed in OpenSSL 1.1.1l (Affected 1.1.1-1.1.1k). Fixed in OpenSSL 1.0.2za (Affected 1.0.2-1.0.2y).", - "severity": "High", - "metadata": null, - "fixedIn": [{ - "name": "fixed", - "imageTag": "k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8", - "version": "1.1.1k-1+deb11u1" - }], - "relevant": "No signature profile to compare", - "urgent": 0, - "neglected": 0, - "healthStatus": "", - "categories": { - "isRce": false - } - }] -} \ No newline at end of file diff --git a/rules/image-pull-secrets/raw.rego b/rules/image-pull-secrets/raw.rego deleted file mode 100644 index 9e07b1e74..000000000 --- a/rules/image-pull-secrets/raw.rego +++ /dev/null @@ -1,22 +0,0 @@ -package armo_builtins - -# input: service accounts -# apiversion: v1 -# returns ImagePullSecrets that more than one service account have access to - -deny[msga] { - - image = input[i].imagePullSecrets[k] == input[j].imagePullSecrets[_] - path := sprintf("imagePullSecrets[%v]", [format_int(k, 10)]) - i > j - - msga := { - "alertMessage": sprintf("the following ImagePullSecret: %v, is exposed to more than one serviceaccount", [image]), - "alertScore": 9, - "failedPaths": [path], - "fixPaths":[], - "packagename": "armo_builtins", - "alertObject": { - } - } -} \ No newline at end of file diff --git a/rules/image-pull-secrets/rule.metadata.json b/rules/image-pull-secrets/rule.metadata.json deleted file mode 100644 index e4feb560c..000000000 --- a/rules/image-pull-secrets/rule.metadata.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "image-pull-secrets", - "attributes": { - "m$K8sThreatMatrix": "Collection::Images from private registry", - "armoBuiltin": true - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "ServiceAccount" - ] - } - ], - "ruleDependencies": [], - "description": "Checks if more than on service account have access to an ImagePullSecrets", - "remediation": "", - "ruleQuery": "armo_builtins" -} diff --git a/rules/image-pull-secrets/test/test/expected.json b/rules/image-pull-secrets/test/test/expected.json deleted file mode 100644 index f67f41999..000000000 --- a/rules/image-pull-secrets/test/test/expected.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "alertMessage": "the following ImagePullSecret: true, is exposed to more than one serviceaccount", - "failedPaths": [ - "imagePullSecrets[0]" - ], - "fixPaths":[], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 9, - "alertObject": {} - } -] \ No newline at end of file diff --git a/rules/image-pull-secrets/test/test/input/serviceaccount1.yaml b/rules/image-pull-secrets/test/test/input/serviceaccount1.yaml deleted file mode 100644 index 32be5c532..000000000 --- a/rules/image-pull-secrets/test/test/input/serviceaccount1.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: test1 - namespace: default -secrets: -- name: default-token-uudge -imagePullSecrets: -- name: myregistrykey \ No newline at end of file diff --git a/rules/image-pull-secrets/test/test/input/serviceaccount2.yaml b/rules/image-pull-secrets/test/test/input/serviceaccount2.yaml deleted file mode 100644 index abbfa8a4b..000000000 --- a/rules/image-pull-secrets/test/test/input/serviceaccount2.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: test2 - namespace: default -secrets: -- name: default-token-uudge -imagePullSecrets: -- name: myregistrykey \ No newline at end of file diff --git a/rules/label-usage-for-resources/rule.metadata.json b/rules/label-usage-for-resources/rule.metadata.json index a7ff7dddc..83817a665 100644 --- a/rules/label-usage-for-resources/rule.metadata.json +++ b/rules/label-usage-for-resources/rule.metadata.json @@ -7,19 +7,39 @@ "match": [ { "apiGroups": [ - "*" + "" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Pod" + ] + }, + { + "apiGroups": [ + "apps" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Deployment", + "ReplicaSet", + "DaemonSet", + "StatefulSet" + ] + }, + { + "apiGroups": [ + "batch" ], "apiVersions": [ "*" ], "resources": [ - "Pod", - "Deployment", - "ReplicaSet", - "DaemonSet", - "StatefulSet", - "Job", - "CronJob" + "Job", + "CronJob" ] } ], diff --git a/rules/more-than-one-replicas/raw.rego b/rules/more-than-one-replicas/raw.rego deleted file mode 100644 index b7d82d2b0..000000000 --- a/rules/more-than-one-replicas/raw.rego +++ /dev/null @@ -1,47 +0,0 @@ -package armo_builtins - - -# Fails if workload has only one replica -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","StatefulSet"} - spec_template_spec_patterns[wl.kind] - spec := wl.spec - result := replicas_one_or_less(spec) - failed_path := get_failed_path(result) - fixed_path := get_fixed_path(result) - - msga := { - "alertMessage": sprintf("Workload: %v: %v has only one replica", [ wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "failedPaths": failed_path, - "fixPaths": fixed_path, - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -replicas_one_or_less(spec) = [failed_path, fixPath] { - not spec.replicas - failed_path = "" - fixPath = {"path": "spec.replicas", "value": "YOUR_VALUE"} -} - -replicas_one_or_less(spec) = [failed_path, fixPath] { - spec.replicas == 1 - failed_path = "spec.replicas" - fixPath = "" -} - - get_failed_path(paths) = [paths[0]] { - paths[0] != "" -} else = [] - - -get_fixed_path(paths) = [paths[1]] { - paths[1] != "" -} else = [] - diff --git a/rules/more-than-one-replicas/rule.metadata.json b/rules/more-than-one-replicas/rule.metadata.json deleted file mode 100644 index ab880170d..000000000 --- a/rules/more-than-one-replicas/rule.metadata.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "more-than-one-replicas", - "attributes": { - "armoBuiltin": true - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Deployment", - "ReplicaSet", - "StatefulSet" - ] - } - ], - "ruleDependencies": [ - ], - "description": "Replicas are set to one.", - "remediation": "Ensure replicas field is set and value is bigger than one.", - "ruleQuery": "armo_builtins" -} \ No newline at end of file diff --git a/rules/more-than-one-replicas/test/deployment/expected.json b/rules/more-than-one-replicas/test/deployment/expected.json deleted file mode 100644 index f6e62738c..000000000 --- a/rules/more-than-one-replicas/test/deployment/expected.json +++ /dev/null @@ -1,23 +0,0 @@ -[{ - "alertMessage": "Workload: Deployment: test has only one replica", - "failedPaths": [], - "fixPaths": [{ - "path": "spec.replicas", - "value": "YOUR_VALUE" - }], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [{ - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "labels": { - "purpose": "demonstrate-command" - }, - "name": "test" - } - }] - } -}] \ No newline at end of file diff --git a/rules/more-than-one-replicas/test/deployment/input/wl.yaml b/rules/more-than-one-replicas/test/deployment/input/wl.yaml deleted file mode 100644 index aa3114445..000000000 --- a/rules/more-than-one-replicas/test/deployment/input/wl.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: default - name: test2 - labels: - purpose: demonstrate-command -spec: - replicas: 3 - selector: - matchLabels: - purpose: demonstrate-command - template: - metadata: - labels: - purpose: demonstrate-command - spec: - containers: - - name: nginx - image: nginx:1.14.2 - ports: - - containerPort: 80 \ No newline at end of file diff --git a/rules/more-than-one-replicas/test/deployment/input/wl2.yaml b/rules/more-than-one-replicas/test/deployment/input/wl2.yaml deleted file mode 100644 index 9be5f4d12..000000000 --- a/rules/more-than-one-replicas/test/deployment/input/wl2.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: default - name: test - labels: - purpose: demonstrate-command -spec: - selector: - matchLabels: - purpose: demonstrate-command - template: - metadata: - labels: - purpose: demonstrate-command - spec: - containers: - - name: nginx - image: nginx:1.14.2 - ports: - - containerPort: 80 \ No newline at end of file diff --git a/rules/more-than-one-replicas/test/statefulset/expected.json b/rules/more-than-one-replicas/test/statefulset/expected.json deleted file mode 100644 index 7cfadd63f..000000000 --- a/rules/more-than-one-replicas/test/statefulset/expected.json +++ /dev/null @@ -1,17 +0,0 @@ -[{ - "alertMessage": "Workload: StatefulSet: web has only one replica", - "failedPaths": ["spec.replicas"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [{ - "apiVersion": "apps/v1", - "kind": "StatefulSet", - "metadata": { - "name": "web" - } - }] - } -}] \ No newline at end of file diff --git a/rules/more-than-one-replicas/test/statefulset/input/statefulset.yaml b/rules/more-than-one-replicas/test/statefulset/input/statefulset.yaml deleted file mode 100644 index 79b340694..000000000 --- a/rules/more-than-one-replicas/test/statefulset/input/statefulset.yaml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: web -spec: - selector: - matchLabels: - app: nginx - serviceName: "nginx" - replicas: 1 - minReadySeconds: 10 - template: - metadata: - labels: - app: nginx - spec: - terminationGracePeriodSeconds: 10 - containers: - - name: nginx - image: k8s.gcr.io/nginx-slim:0.8 - ports: - - containerPort: 80 - name: web - volumeMounts: - - name: www - mountPath: /usr/share/nginx/html - volumeClaimTemplates: - - metadata: - name: www - spec: - accessModes: [ "ReadWriteOnce" ] - storageClassName: "my-storage-class" - resources: - requests: - storage: 1Gi \ No newline at end of file diff --git a/rules/pod-specific-version-tag/raw.rego b/rules/pod-specific-version-tag/raw.rego deleted file mode 100644 index 0a28039cb..000000000 --- a/rules/pod-specific-version-tag/raw.rego +++ /dev/null @@ -1,63 +0,0 @@ -package armo_builtins - - -deny[msga] { - pod := input[_] - pod.kind == "Pod" - container := pod.spec.containers[i] - is_latest_image_tag(container) - path := sprintf("spec.containers[%v].image", [format_int(i, 10)]) - msga := { - "alertMessage": sprintf("Container: %v in pod: %v has latest image tag.", [container.name, pod.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "failedPaths": [path], - "fixPaths": [], - "alertObject": { - "k8sApiObjects": [pod] - } - } -} - -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - path := sprintf("spec.template.spec.containers[%v].image", [format_int(i, 10)]) - is_latest_image_tag(container) - msga := { - "alertMessage": sprintf("Container: %v in %v: %v has latest image tag.", [ container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "failedPaths": [path], - "fixPaths": [], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container = wl.spec.jobTemplate.spec.template.spec.containers[i] - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v].image", [format_int(i, 10)]) - is_latest_image_tag(container) - msga := { - "alertMessage": sprintf("Container: %v in %v: %v has latest image tag.", [ container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "failedPaths": [path], - "fixPaths": [], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -is_latest_image_tag(container) { - endswith(container.image, ":latest") -} \ No newline at end of file diff --git a/rules/pod-specific-version-tag/test/cronjob/expected.json b/rules/pod-specific-version-tag/test/cronjob/expected.json deleted file mode 100644 index 751a989fe..000000000 --- a/rules/pod-specific-version-tag/test/cronjob/expected.json +++ /dev/null @@ -1,44 +0,0 @@ -[ - { - "alertMessage": "Container: hello in CronJob: hello has latest image tag.", - "failedPaths": [ - "spec.jobTemplate.spec.template.spec.containers[0].image" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "batch/v1beta1", - "kind": "CronJob", - "metadata": { - "name": "hello" - } - } - ] - } -}, -{ - "alertMessage": "Container: hello3 in CronJob: hello has latest image tag.", - "failedPaths": [ - "spec.jobTemplate.spec.template.spec.containers[2].image" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "batch/v1beta1", - "kind": "CronJob", - "metadata": { - "name": "hello" - } - } - ] - } -} -] \ No newline at end of file diff --git a/rules/pod-specific-version-tag/test/cronjob/input/cronjob.yaml b/rules/pod-specific-version-tag/test/cronjob/input/cronjob.yaml deleted file mode 100644 index ea4bd681f..000000000 --- a/rules/pod-specific-version-tag/test/cronjob/input/cronjob.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: batch/v1beta1 -kind: CronJob -metadata: - name: hello -spec: - schedule: "*/1 * * * *" - jobTemplate: - spec: - template: - spec: - restartPolicy: OnFailure - containers: - - name: hello - image: busybox:latest - imagePullPolicy: IfNotPresent - command: - - /bin/sh - - -c - - date; echo Hello from the Kubernetes cluster - - name: hello2 - image: busybox:1.2 - imagePullPolicy: IfNotPresent - command: - - /bin/sh - - -c - - date; echo Hello from the Kubernetes cluster - - name: hello3 - image: busybox2:latest - imagePullPolicy: IfNotPresent - command: - - /bin/sh - - -c - - date; echo Hello from the Kubernetes cluster diff --git a/rules/pod-specific-version-tag/test/pod/expected.json b/rules/pod-specific-version-tag/test/pod/expected.json deleted file mode 100644 index 38404acfc..000000000 --- a/rules/pod-specific-version-tag/test/pod/expected.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "alertMessage": "Container: envar-demo-container in pod: envar-demo has latest image tag.", - "failedPaths": [ - "spec.containers[0].image" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "labels": { - "purpose": "demonstrate-envars" - }, - "name": "envar-demo" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/pod-specific-version-tag/test/pod/input/pod.yaml b/rules/pod-specific-version-tag/test/pod/input/pod.yaml deleted file mode 100644 index 9b5774345..000000000 --- a/rules/pod-specific-version-tag/test/pod/input/pod.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: envar-demo - labels: - purpose: demonstrate-envars -spec: - containers: - - name: envar-demo-container - image: gcr.io/google-samples/node-hello:latest - securityContext: - runAsUser: 0 - - name: envar-demo-container2 - image: gcr.io/google-samples/node-hello:11.2 - securityContext: - runAsUser: 0 diff --git a/rules/pod-specific-version-tag/test/workload/expected.json b/rules/pod-specific-version-tag/test/workload/expected.json deleted file mode 100644 index 8e769614a..000000000 --- a/rules/pod-specific-version-tag/test/workload/expected.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "alertMessage": "Container: nginx2 in Deployment: test2 has latest image tag.", - "failedPaths": [ - "spec.template.spec.containers[1].image" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "labels": { - "purpose": "demonstrate-command" - }, - "name": "test2" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/pod-specific-version-tag/test/workload/input/workload.yaml b/rules/pod-specific-version-tag/test/workload/input/workload.yaml deleted file mode 100644 index f1fb292e9..000000000 --- a/rules/pod-specific-version-tag/test/workload/input/workload.yaml +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: default - name: test2 - labels: - purpose: demonstrate-command -spec: - replicas: 3 - selector: - matchLabels: - purpose: demonstrate-command - template: - metadata: - labels: - purpose: demonstrate-command - spec: - containers: - - name: nginx - image: nginx:1.14.2 - ports: - - containerPort: 80 - - name : nginx2 - image : nginx:latest - ports: - - containerPort : 80 \ No newline at end of file diff --git a/rules/resources-memory-limit-and-request/rule.metadata.json b/rules/resources-memory-limit-and-request/rule.metadata.json index e1eecfebb..9c3c3aff1 100644 --- a/rules/resources-memory-limit-and-request/rule.metadata.json +++ b/rules/resources-memory-limit-and-request/rule.metadata.json @@ -7,18 +7,38 @@ "match": [ { "apiGroups": [ - "*" + "" ], "apiVersions": [ - "*" + "v1" + ], + "resources": [ + "Pod" + ] + }, + { + "apiGroups": [ + "apps" + ], + "apiVersions": [ + "v1" ], "resources": [ "Deployment", "ReplicaSet", "DaemonSet", - "StatefulSet", + "StatefulSet" + ] + }, + { + "apiGroups": [ + "batch" + ], + "apiVersions": [ + "*" + ], + "resources": [ "Job", - "Pod", "CronJob" ] } diff --git a/rules/rule-access-dashboard-subject-v1/rule.metadata.json b/rules/rule-access-dashboard-subject-v1/rule.metadata.json index c57e955d9..9201de9a8 100644 --- a/rules/rule-access-dashboard-subject-v1/rule.metadata.json +++ b/rules/rule-access-dashboard-subject-v1/rule.metadata.json @@ -10,10 +10,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-access-kubelet-API/raw.rego b/rules/rule-access-kubelet-API/raw.rego deleted file mode 100644 index de79d311a..000000000 --- a/rules/rule-access-kubelet-API/raw.rego +++ /dev/null @@ -1,21 +0,0 @@ -package armo_builtins - -# input: network policies -# apiversion: networking.k8s.io/v1 -# fails if no network policies are defined - -deny[msga] { - networkpolicies := input - count(networkpolicies) == 0 - - msga := { - "alertMessage": "no network policy is defined", - "alertScore": 9, - "failedPaths": [], - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - - } - } -} \ No newline at end of file diff --git a/rules/rule-access-kubelet-API/rule.metadata.json b/rules/rule-access-kubelet-API/rule.metadata.json deleted file mode 100644 index d25b2a31f..000000000 --- a/rules/rule-access-kubelet-API/rule.metadata.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "rule-access-kubelet-API", - "attributes": { - "m$K8sThreatMatrix": "Discovery::Access Kubelet API", - "armoBuiltin": true - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "networkpolicies" - ] - } - ], - "ruleDependencies": [], - "description": "fails if no network policy exists", - "remediation": "", - "ruleQuery": "armo_builtins" - } \ No newline at end of file diff --git a/rules/rule-access-kubelet-API/test/test/input/wl.yaml b/rules/rule-access-kubelet-API/test/test/input/wl.yaml deleted file mode 100644 index 049b26402..000000000 --- a/rules/rule-access-kubelet-API/test/test/input/wl.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: batch/v1beta1 -kind: CronJob -metadata: - name: hello -spec: - schedule: "*/1 * * * *" - jobTemplate: - spec: - template: - spec: - serviceAccountName: kubernetes-dashboard - restartPolicy: OnFailure - containers: - - name: hello - image: busybox:latest - imagePullPolicy: IfNotPresent - command: - - /bin/sh - - -c - - date; echo Hello from the Kubernetes cluster diff --git a/rules/rule-can-bash-cmd-inside-container/raw.rego b/rules/rule-can-bash-cmd-inside-container/raw.rego deleted file mode 100644 index 40fceb1a2..000000000 --- a/rules/rule-can-bash-cmd-inside-container/raw.rego +++ /dev/null @@ -1,89 +0,0 @@ -package armo_builtins - -import data.cautils - -# Fails if container has bash/cmd inside it -# Pods -deny [msga] { - pod := input[_] - container := pod.spec.containers[i] - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - is_bash_container(scan) - path := sprintf("spec.containers[%v].image", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("the following container: %v has bash/cmd inside it.", [container.name]), - "alertScore": 6, - "failedPaths": [path], - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [pod], - "externalObjects": { - "container" : [{container.name}] - } - }, - } -} - - -# Workloads -deny [msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - path := sprintf("spec.template.spec.containers[%v].image", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - is_bash_container(scan) - - - msga := { - "alertMessage": sprintf("the following container: %v has bash/cmd inside it.", [container.name]), - "alertScore": 6, - "failedPaths": [path], - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "container" : [{container.name}] - } - }, - } -} - -# Cronjobs -deny [msga] { - wl := input[_] - wl.kind == "CronJob" - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v].image", [format_int(i, 10)]) - res := armo.get_image_scan_summary({"type":"imageTag","value":container.image,"size":1}) - scan := res[_] - is_bash_container(scan) - - msga := { - "alertMessage": sprintf("the following container: %v has bash/cmd inside it.", [container.name]), - "alertScore": 6, - "failedPaths": [path], - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [wl], - "externalObjects": { - "container" : [{container.name}] - } - }, - } -} - - -is_bash_container(scan) { - # see default-config-inputs.json for list values - shells := data.postureControlInputs.listOfDangerousArtifacts - shell := shells[_] - cautils.list_contains(scan.listOfDangerousArtifacts, shell) -} diff --git a/rules/rule-can-bash-cmd-inside-container/rule.metadata.json b/rules/rule-can-bash-cmd-inside-container/rule.metadata.json deleted file mode 100644 index edc1cf12a..000000000 --- a/rules/rule-can-bash-cmd-inside-container/rule.metadata.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "rule-can-bash-cmd-inside-container", - "attributes": { - "microsoftK8sThreatMatrix": "Execution::Bash/cmd inside container", - "armoBuiltin": true, - "armoOpa": "true" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "Pod" - ] - }, - { - "apiGroups": [ - "apps" - ], - "apiVersions": [ - "v1" - ], - "resources": [ - "Deployment", - "ReplicaSet", - "DaemonSet", - "StatefulSet" - ] - }, - { - "apiGroups": [ - "batch" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Job", - "CronJob" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "configInputs": [ - "settings.postureControlInputs.listOfDangerousArtifacts" - ], - "controlConfigInputs": [ - { - "path": "settings.postureControlInputs.listOfDangerousArtifacts", - "name": "Shell executable in container", - "description": "Kubescape checks if container images have the any of the these shell executables." - } - ], - "description": "determines which containers have dangerous artifacts (based on the list of dangerous artifacts)", - "remediation": "", - "ruleQuery": "armo_builtins" -} \ No newline at end of file diff --git a/rules/rule-can-bind-escalate/rule.metadata.json b/rules/rule-can-bind-escalate/rule.metadata.json index 30afe5018..dcbc9e19f 100644 --- a/rules/rule-can-bind-escalate/rule.metadata.json +++ b/rules/rule-can-bind-escalate/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-create-bind-escalate-role-v1/raw.rego b/rules/rule-can-create-bind-escalate-role-v1/raw.rego deleted file mode 100644 index 748f8a65f..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/raw.rego +++ /dev/null @@ -1,163 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# ================= create/update =============================== - -# fails if user has access to create/update rolebindings/clusterrolebindings -deny[msga] { - subjectVector := input[_] - role := subjectVector.relatedObjects[i] - rolebinding := subjectVector.relatedObjects[j] - endswith(role.kind, "Role") - endswith(rolebinding.kind, "Binding") - - rule := role.rules[p] - - subject := rolebinding.subjects[k] - is_same_subjects(subjectVector, subject) - - rule_path := sprintf("relatedObjects[%d].rules[%d]", [i, p]) - - verbs := ["create", "update", "patch", "*"] - verb_path := [sprintf("%s.verbs[%d]", [rule_path, l]) | verb = rule.verbs[l]; verb in verbs] - count(verb_path) > 0 - - api_groups := ["rbac.authorization.k8s.io", "*"] - api_groups_path := [sprintf("%s.apiGroups[%d]", [rule_path, a]) | apiGroup = rule.apiGroups[a]; apiGroup in api_groups] - count(api_groups_path) > 0 - - resources := ["rolebindings", "clusterrolebindings", "*"] - resources_path := [sprintf("%s.resources[%d]", [rule_path, l]) | resource = rule.resources[l]; resource in resources] - count(resources_path) > 0 - - path := array.concat(resources_path, verb_path) - path2 := array.concat(path, api_groups_path) - finalpath := array.concat(path2, [ - sprintf("relatedObjects[%d].subjects[%d]", [j, k]), - sprintf("relatedObjects[%d].roleRef.name", [j]), - ]) - - msga := { - "alertMessage": sprintf("Subject: %s-%s can create/update rolebinding/clusterrolebinding", [subjectVector.kind, subjectVector.name]), - "alertScore": 3, - "failedPaths": finalpath, - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": subjectVector, - }, - } -} - -# ================= bind =============================== - -# fails if user has access to bind clusterroles/roles -deny[msga] { - subjectVector := input[_] - role := subjectVector.relatedObjects[i] - rolebinding := subjectVector.relatedObjects[j] - endswith(role.kind, "Role") - endswith(rolebinding.kind, "Binding") - rule := role.rules[p] - - subject := rolebinding.subjects[k] - is_same_subjects(subjectVector, subject) - - rule_path := sprintf("relatedObjects[%d].rules[%d]", [i, p]) - - verbs := ["bind", "*"] - verb_path := [sprintf("%s.verbs[%d]", [rule_path, l]) | verb = rule.verbs[l]; verb in verbs] - count(verb_path) > 0 - - api_groups := ["rbac.authorization.k8s.io", "*"] - api_groups_path := [sprintf("%s.apiGroups[%d]", [rule_path, a]) | apiGroup = rule.apiGroups[a]; apiGroup in api_groups] - count(api_groups_path) > 0 - - resources := ["clusterroles", "roles", "*"] - resources_path := [sprintf("%s.resources[%d]", [rule_path, l]) | resource = rule.resources[l]; resource in resources] - count(resources_path) > 0 - - path := array.concat(resources_path, verb_path) - path2 := array.concat(path, api_groups_path) - finalpath := array.concat(path2, [ - sprintf("relatedObjects[%d].subjects[%d]", [j, k]), - sprintf("relatedObjects[%d].roleRef.name", [j]), - ]) - - msga := { - "alertMessage": sprintf("Subject: %s-%s can bind roles/clusterroles", [subjectVector.kind, subjectVector.name]), - "alertScore": 3, - "failedPaths": finalpath, - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": subjectVector, - }, - } -} - -# ================= escalate =============================== - -# fails if user has access to escalate rolebindings/clusterrolebindings -deny[msga] { - subjectVector := input[_] - role := subjectVector.relatedObjects[i] - rolebinding := subjectVector.relatedObjects[j] - endswith(role.kind, "Role") - endswith(rolebinding.kind, "Binding") - - rule := role.rules[p] - - subject := rolebinding.subjects[k] - is_same_subjects(subjectVector, subject) - - rule_path := sprintf("relatedObjects[%d].rules[%d]", [i, p]) - - verbs := ["escalate", "*"] - verb_path := [sprintf("%s.verbs[%d]", [rule_path, l]) | verb = rule.verbs[l]; verb in verbs] - count(verb_path) > 0 - - api_groups := ["rbac.authorization.k8s.io", "*"] - api_groups_path := [sprintf("%s.apiGroups[%d]", [rule_path, a]) | apiGroup = rule.apiGroups[a]; apiGroup in api_groups] - count(api_groups_path) > 0 - - resources := ["rolebindings", "clusterrolebindings", "*"] - resources_path := [sprintf("%s.resources[%d]", [rule_path, l]) | resource = rule.resources[l]; resource in resources] - count(resources_path) > 0 - - path := array.concat(resources_path, verb_path) - path2 := array.concat(path, api_groups_path) - finalpath := array.concat(path2, [ - sprintf("relatedObjects[%d].subjects[%d]", [j, k]), - sprintf("relatedObjects[%d].roleRef.name", [j]), - ]) - - msga := { - "alertMessage": sprintf("Subject: %s-%s can escalate rolebinding/clusterrolebinding", [subjectVector.kind, subjectVector.name]), - "alertScore": 3, - "failedPaths": finalpath, - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": subjectVector, - }, - } -} - -# for service accounts -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.namespace == subject.namespace -} - -# for users/ groups -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.apiGroup == subject.apiGroup -} diff --git a/rules/rule-can-create-bind-escalate-role-v1/rule.metadata.json b/rules/rule-can-create-bind-escalate-role-v1/rule.metadata.json deleted file mode 100644 index 301d06b26..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/rule.metadata.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "rule-can-create-bind-escalate-role-v1", - "attributes": { - "microsoftK8sThreatMatrix": "Discovery::Access the K8s API server", - "armoBuiltin": true, - "resourcesAggregator": "subject-role-rolebinding", - "useFromKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [], - "description": "determines which users can create/update rolebindings/clusterrolebindings or bind roles/clusterroles", - "remediation": "", - "ruleQuery": "armo_builtins" -} \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/expected.json b/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/expected.json deleted file mode 100644 index 6acf6feac..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/expected.json +++ /dev/null @@ -1,144 +0,0 @@ -[ - { - "alertMessage": "Subject: Group-manager can create/update rolebinding/clusterrolebinding", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[1]", - "relatedObjects[1].rules[0].verbs[0]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[0]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test", - "namespace": "default" - }, - "rules": [ - { - "apiGroups": [ - "rbac.authorization.k8s.io" - ], - "resources": [ - "pods", - "rolebindings" - ], - "verbs": [ - "create", - "watch", - "list" - ] - } - ] - } - ] - } - } - }, - { - "alertMessage": "Subject: Group-dev can create/update rolebinding/clusterrolebinding", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[1]", - "relatedObjects[1].rules[0].verbs[0]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[1]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test", - "namespace": "default" - }, - "rules": [ - { - "apiGroups": [ - "rbac.authorization.k8s.io" - ], - "resources": [ - "pods", - "rolebindings" - ], - "verbs": [ - "create", - "watch", - "list" - ] - } - ] - } - ] - } - } - } -] \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml b/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml deleted file mode 100644 index bab824f0e..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test - namespace: default -rules: -- apiGroups: ["rbac.authorization.k8s.io"] - resources: ["pods", "rolebindings"] - verbs: ["create", "watch", "list"] \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml b/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml deleted file mode 100644 index e1426bc28..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: read-secrets-global -subjects: -- kind: Group - name: manager - apiGroup: rbac.authorization.k8s.io -- kind: Group - name: dev - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/expected.json b/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/expected.json deleted file mode 100644 index 8e551dfca..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/expected.json +++ /dev/null @@ -1,89 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can create/update rolebinding/clusterrolebinding", - "failedPaths": ["relatedObjects[1].rules[0].resources[0]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].verbs[2]", "relatedObjects[1].rules[0].verbs[3]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "default" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Role", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "Role", - "metadata": { - "name": "test", - "namespace": "default" - }, - "rules": [{ - "apiGroups": ["*"], - "resources": ["rolebindings"], - "verbs": ["*", "watch", "create", "update"] - }] - }] - } - } -}, { - "alertMessage": "Subject: User-jane can escalate rolebinding/clusterrolebinding", - "failedPaths": ["relatedObjects[1].rules[0].resources[0]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "default" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Role", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "Role", - "metadata": { - "name": "test", - "namespace": "default" - }, - "rules": [{ - "apiGroups": ["*"], - "resources": ["rolebindings"], - "verbs": ["*", "watch", "create", "update"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/role.yaml b/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/role.yaml deleted file mode 100644 index 74e3fd719..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/role.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: test - namespace: default -rules: -- apiGroups: ["*"] - resources: ["rolebindings"] - verbs: ["*", "watch", "create", "update"] \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/rolebinding.yaml b/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/rolebinding.yaml deleted file mode 100644 index 73ce62a17..000000000 --- a/rules/rule-can-create-bind-escalate-role-v1/test/role-rolebinding/input/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: pod - namespace: default -subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role/raw.rego b/rules/rule-can-create-bind-escalate-role/raw.rego deleted file mode 100644 index bae908b69..000000000 --- a/rules/rule-can-create-bind-escalate-role/raw.rego +++ /dev/null @@ -1,389 +0,0 @@ - -package armo_builtins - -import data.cautils - -# ================= create/update =============================== - -# fails if user has access to create/update rolebindings/clusterrolebindings -# RoleBinding to Role -deny[msga] { - roles := [role | role= input[_]; role.kind == "Role"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_create_update_to_role_resource(rule) - can_create_update_to_role_verb(rule) - - rolebinding.roleRef.kind == "Role" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can create/update rolebinding/clusterrolebinding", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role, rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user has access to create/update rolebindings/clusterrolebindings -# RoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_create_update_to_role_resource(rule) - can_create_update_to_role_verb(rule) - - rolebinding.roleRef.kind == "ClusterRole" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can create/update rolebinding/clusterrolebinding", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user has access to create/update rolebindings/clusterrolebindings -# ClusterRoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - clusterrolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - role:= roles[_] - clusterrolebinding := clusterrolebindings[_] - - rule:= role.rules[_] - can_create_update_to_role_resource(rule) - can_create_update_to_role_verb(rule) - - clusterrolebinding.roleRef.kind == "ClusterRole" - clusterrolebinding.roleRef.name == role.metadata.name - subject := clusterrolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can create/update rolebinding/clusterrolebinding", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,clusterrolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# ================= bind =============================== - -# fails if user has access to bind clusterroles/roles -# RoleBinding to Role -deny [msga] { - roles := [role | role= input[_]; role.kind == "Role"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - - can_bind_to_role_resource(rule) - can_bind_to_role_verb(rule) - - rolebinding.roleRef.kind == "Role" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can bind roles/clusterroles", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - -# fails if user has access to bind clusterroles/roles -# RoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - - can_bind_to_role_resource(rule) - can_bind_to_role_verb(rule) - - rolebinding.roleRef.kind == "ClusterRole" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can bind roles/clusterroles", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - -# fails if user has access to bind clusterroles/roles -# ClusterRoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - clusterrolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - role:= roles[_] - clusterrolebinding := clusterrolebindings[_] - - rule:= role.rules[_] -can_bind_to_role_resource(rule) - can_bind_to_role_verb(rule) - - clusterrolebinding.roleRef.kind == "ClusterRole" - clusterrolebinding.roleRef.name == role.metadata.name - subject := clusterrolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can bind roles/clusterroles", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,clusterrolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - -# ================= escalate =============================== - - -# fails if user has access to escalate rolebindings/clusterrolebindings -# RoleBinding to Role -deny[msga] { - roles := [role | role= input[_]; role.kind == "Role"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_escalate_to_role_resource(rule) - can_escalate_to_role_verb(rule) - - rolebinding.roleRef.kind == "Role" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can escalate rolebinding/clusterrolebinding", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user has access to escalate rolebindings/clusterrolebindings -# RoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_escalate_to_role_resource(rule) - can_escalate_to_role_verb(rule) - - rolebinding.roleRef.kind == "ClusterRole" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can escalate rolebinding/clusterrolebinding", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user has access to escalate rolebindings/clusterrolebindings -# ClusterRoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - clusterrolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - role:= roles[_] - clusterrolebinding := clusterrolebindings[_] - - rule:= role.rules[_] - can_escalate_to_role_resource(rule) - can_escalate_to_role_verb(rule) - - clusterrolebinding.roleRef.kind == "ClusterRole" - clusterrolebinding.roleRef.name == role.metadata.name - subject := clusterrolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v, can escalate rolebinding/clusterrolebinding", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,clusterrolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - -# ============== escalate ===================== - -can_escalate_to_role_resource(rule){ - cautils.list_contains(rule.resources,"clusterroles") -} - -can_escalate_to_role_resource(rule){ - cautils.list_contains(rule.resources,"roles") -} - -can_escalate_to_role_resource(rule){ - is_api_group(rule) - cautils.list_contains(rule.resources,"*") -} - -can_escalate_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "escalate") -} - -can_escalate_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "*") -} - - -# ============== bind ===================== - -can_bind_to_role_resource(rule){ - cautils.list_contains(rule.resources,"clusterroles") -} - -can_bind_to_role_resource(rule){ - cautils.list_contains(rule.resources,"roles") -} - -can_bind_to_role_resource(rule){ - is_api_group(rule) - cautils.list_contains(rule.resources,"*") -} - - -can_bind_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "bind") -} - -can_bind_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "*") -} - -# ============== create/update ===================== - -can_create_update_to_role_resource(rule) { - cautils.list_contains(rule.resources,"rolebindings") -} - -can_create_update_to_role_resource(rule) { - cautils.list_contains(rule.resources,"clusterrolebindings") -} - -can_create_update_to_role_resource(rule) { - is_api_group(rule) - cautils.list_contains(rule.resources,"*") -} - - -can_create_update_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "create") -} - -can_create_update_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "update") -} - -can_create_update_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "patch") -} - -can_create_update_to_role_verb(rule) { - cautils.list_contains(rule.verbs, "*") -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "*" -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "rbac.authorization.k8s.io" -} \ No newline at end of file diff --git a/rules/rule-can-create-bind-escalate-role/rule.metadata.json b/rules/rule-can-create-bind-escalate-role/rule.metadata.json deleted file mode 100644 index 43f9ec2d3..000000000 --- a/rules/rule-can-create-bind-escalate-role/rule.metadata.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "rule-can-create-bind-escalate-role", - "attributes": { - "microsoftK8sThreatMatrix": "Discovery::Access the K8s API server", - "armoBuiltin": true, - "useUntilKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "determines which users can create/update rolebindings/clusterrolebindings or bind roles/clusterroles", - "remediation": "", - "ruleQuery": "armo_builtins", - "resourceCount": "subjects" - } \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/raw.rego b/rules/rule-can-create-modify-pod-v1/raw.rego deleted file mode 100644 index 8569b8e39..000000000 --- a/rules/rule-can-create-modify-pod-v1/raw.rego +++ /dev/null @@ -1,64 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# fails if subject has create/modify access to pods -deny[msga] { - subjectVector := input[_] - role := subjectVector.relatedObjects[i] - rolebinding := subjectVector.relatedObjects[j] - endswith(role.kind, "Role") - endswith(rolebinding.kind, "Binding") - - rule := role.rules[p] - - subject := rolebinding.subjects[k] - is_same_subjects(subjectVector, subject) - -rule_path := sprintf("relatedObjects[%d].rules[%d]", [i, p]) - - verbs := ["create", "patch", "update", "*"] - verb_path := [sprintf("%s.verbs[%d]", [rule_path, l]) | verb = rule.verbs[l]; verb in verbs] - count(verb_path) > 0 - - api_groups := ["", "*"] - api_groups_path := [sprintf("%s.apiGroups[%d]", [rule_path, a]) | apiGroup = rule.apiGroups[a]; apiGroup in api_groups] - count(api_groups_path) > 0 - - resources := ["pods", "deployments", "daemonsets", "replicasets", "statefulsets", "jobs", "cronjobs", "*"] - resources_path := [sprintf("%s.resources[%d]", [rule_path, l]) | resource = rule.resources[l]; resource in resources] - count(resources_path) > 0 - - path := array.concat(resources_path, verb_path) - path2 := array.concat(path, api_groups_path) - finalpath := array.concat(path2, [ - sprintf("relatedObjects[%d].subjects[%d]", [j, k]), - sprintf("relatedObjects[%d].roleRef.name", [j]), - ]) - - msga := { - "alertMessage": sprintf("Subject: %s-%s can create/modify workloads", [subjectVector.kind, subjectVector.name]), - "alertScore": 3, - "failedPaths": finalpath, - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": subjectVector, - }, - } -} - -# for service accounts -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.namespace == subject.namespace -} - -# for users/ groups -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.apiGroup == subject.apiGroup -} diff --git a/rules/rule-can-create-modify-pod-v1/rule.metadata.json b/rules/rule-can-create-modify-pod-v1/rule.metadata.json deleted file mode 100644 index e64083011..000000000 --- a/rules/rule-can-create-modify-pod-v1/rule.metadata.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "rule-can-create-modify-pod-v1", - "attributes": { - "m$K8sThreatMatrix": "Execution::New container, Persistence::Backdoor container", - "armoBuiltin": true, - "resourcesAggregator": "subject-role-rolebinding", - "useFromKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [], - "description": "determines which users have create/modify permissions on pods", - "remediation": "", - "ruleQuery": "armo_builtins" - } \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml b/rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml deleted file mode 100644 index 55543b027..000000000 --- a/rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: ["rbac.authorization.k8s.io"] - resources: ["pods", "rolebindings"] - verbs: ["create", "watch", "list"] \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml b/rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml deleted file mode 100644 index e1426bc28..000000000 --- a/rules/rule-can-create-modify-pod-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: read-secrets-global -subjects: -- kind: Group - name: manager - apiGroup: rbac.authorization.k8s.io -- kind: Group - name: dev - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/expected.json b/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/expected.json deleted file mode 100644 index 9a4afb5ee..000000000 --- a/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/expected.json +++ /dev/null @@ -1,44 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can create/modify workloads", - "failedPaths": ["relatedObjects[1].rules[0].resources[0]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "default" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [{ - "apiGroups": [""], - "resources": ["pods", "services"], - "verbs": ["*", "watch", "list"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/input/cluterrole.yaml b/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/input/cluterrole.yaml deleted file mode 100644 index 5d502afa9..000000000 --- a/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/input/cluterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: [""] - resources: ["pods", "services"] - verbs: ["*", "watch", "list"] \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/expected.json b/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/expected.json deleted file mode 100644 index 44e12adbb..000000000 --- a/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/expected.json +++ /dev/null @@ -1,45 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can create/modify workloads", - "failedPaths": ["relatedObjects[1].rules[0].resources[1]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].verbs[2]", "relatedObjects[1].rules[0].verbs[3]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "default" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Role", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "Role", - "metadata": { - "name": "test", - "namespace": "default" - }, - "rules": [{ - "apiGroups": ["*"], - "resources": ["rolebindings", "deployments"], - "verbs": ["*", "watch", "create", "update"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/input/role.yaml b/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/input/role.yaml deleted file mode 100644 index 013712760..000000000 --- a/rules/rule-can-create-modify-pod-v1/test/role-rolebinding/input/role.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: test - namespace: default -rules: -- apiGroups: ["*"] - resources: ["rolebindings", "deployments"] - verbs: ["*", "watch", "create", "update"] \ No newline at end of file diff --git a/rules/rule-can-create-modify-pod/raw.rego b/rules/rule-can-create-modify-pod/raw.rego deleted file mode 100644 index 0dcfd056f..000000000 --- a/rules/rule-can-create-modify-pod/raw.rego +++ /dev/null @@ -1,156 +0,0 @@ -package armo_builtins - -import data.cautils - -# fails if user has create/modify access to pods -# RoleBinding to Role -deny [msga] { - roles := [role | role= input[_]; role.kind == "Role"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_create_modify_to_pod_resource(rule) - can_create_modify_to_pod_verb(rule) - - rolebinding.roleRef.kind == "Role" - rolebinding.roleRef.name == role.metadata.name - - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create/modify workloads", [subject.kind, subject.name]), - "alertScore": 9, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user has create/modify access to pods -# RoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_create_modify_to_pod_resource(rule) - can_create_modify_to_pod_verb(rule) - - rolebinding.roleRef.kind == "ClusterRole" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create/modify workloads", [subject.kind, subject.name]), - "alertScore": 9, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user has create/modify access to pods -# ClusterRoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - clusterrolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - role:= roles[_] - clusterrolebinding := clusterrolebindings[_] - - rule:= role.rules[_] - can_create_modify_to_pod_resource(rule) - can_create_modify_to_pod_verb(rule) - - clusterrolebinding.roleRef.kind == "ClusterRole" - clusterrolebinding.roleRef.name == role.metadata.name - - subject := clusterrolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create/modify workloads", [subject.kind, subject.name]), - "alertScore": 9, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,clusterrolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - - - -can_create_modify_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"pods") -} - -can_create_modify_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"deployments") -} - -can_create_modify_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"daemonsets") -} - -can_create_modify_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"replicasets") -} -can_create_modify_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"statefulsets") -} -can_create_modify_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"jobs") -} -can_create_modify_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"cronjobs") -} -can_create_modify_to_pod_resource(rule){ - is_api_group(rule) - cautils.list_contains(rule.resources,"*") -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "*" -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "" -} - -can_create_modify_to_pod_verb(rule) { - cautils.list_contains(rule.verbs, "create") -} - -can_create_modify_to_pod_verb(rule) { - cautils.list_contains(rule.verbs, "patch") -} - -can_create_modify_to_pod_verb(rule) { - cautils.list_contains(rule.verbs, "update") -} - -can_create_modify_to_pod_verb(rule) { - cautils.list_contains(rule.verbs, "*") -} diff --git a/rules/rule-can-create-modify-pod/rule.metadata.json b/rules/rule-can-create-modify-pod/rule.metadata.json deleted file mode 100644 index 0781a221e..000000000 --- a/rules/rule-can-create-modify-pod/rule.metadata.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "rule-can-create-modify-pod", - "attributes": { - "m$K8sThreatMatrix": "Execution::New container, Persistence::Backdoor container", - "armoBuiltin": true, - "useUntilKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "determines which users have create/modify permissions on pods", - "remediation": "", - "ruleQuery": "armo_builtins", - "resourceCount": "subjects" - } \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/raw.rego b/rules/rule-can-create-pod-kube-system-v1/raw.rego deleted file mode 100644 index 34c1d9c21..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/raw.rego +++ /dev/null @@ -1,77 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# fails if user has create access to pods within kube-system namespace -deny[msga] { - subjectVector := input[_] - role := subjectVector.relatedObjects[i] - rolebinding := subjectVector.relatedObjects[j] - endswith(role.kind, "Role") - endswith(rolebinding.kind, "Binding") - - can_create_to_pod_namespace(rolebinding) - rule := role.rules[p] - - subject := rolebinding.subjects[k] - is_same_subjects(subjectVector, subject) - -is_same_subjects(subjectVector, subject) - rule_path := sprintf("relatedObjects[%d].rules[%d]", [i, p]) - - verbs := ["create", "*"] - verb_path := [sprintf("%s.verbs[%d]", [rule_path, l]) | verb = rule.verbs[l]; verb in verbs] - count(verb_path) > 0 - - api_groups := ["", "*"] - api_groups_path := [sprintf("%s.apiGroups[%d]", [rule_path, a]) | apiGroup = rule.apiGroups[a]; apiGroup in api_groups] - count(api_groups_path) > 0 - - resources := ["pods", "*"] - resources_path := [sprintf("%s.resources[%d]", [rule_path, l]) | resource = rule.resources[l]; resource in resources] - count(resources_path) > 0 - - path := array.concat(resources_path, verb_path) - path2 := array.concat(path, api_groups_path) - finalpath := array.concat(path2, [ - sprintf("relatedObjects[%d].subjects[%d]", [j, k]), - sprintf("relatedObjects[%d].roleRef.name", [j]), - ]) - - msga := { - "alertMessage": sprintf("Subject: %s-%s can create pods in kube-system", [subjectVector.kind, subjectVector.name]), - "alertScore": 3, - "failedPaths": finalpath, - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": subjectVector, - }, - } -} - -# 1. rolebinding in kubesystem ns + role in kubesystem ns -# 2. rolebinding in kubesystem ns + clusterrole -can_create_to_pod_namespace(rolebinding) { - rolebinding.metadata.namespace == "kube-system" -} - -# 3. clusterrolebinding + clusterrole -can_create_to_pod_namespace(rolebinding) { - rolebinding.kind == "ClusterRoleBinding" -} - -# for service accounts -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.namespace == subject.namespace -} - -# for users/ groups -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.apiGroup == subject.apiGroup -} diff --git a/rules/rule-can-create-pod-kube-system-v1/rule.metadata.json b/rules/rule-can-create-pod-kube-system-v1/rule.metadata.json deleted file mode 100644 index 9056aa225..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/rule.metadata.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "rule-can-create-pod-kube-system-v1", - "attributes": { - "microsoftK8sThreatMatrix": "Discovery::Access the K8s API server", - "armoBuiltin": true, - "resourcesAggregator": "subject-role-rolebinding", - "useFromKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [], - "description": "determines which users can create pods in kube-system namespace", - "remediation": "", - "ruleQuery": "armo_builtins" - } \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/expected.json b/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/expected.json deleted file mode 100644 index dd2369f31..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/expected.json +++ /dev/null @@ -1,142 +0,0 @@ -[ - { - "alertMessage": "Subject: Group-dev can create pods in kube-system", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[0]", - "relatedObjects[1].rules[0].verbs[0]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[1]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [ - { - "apiGroups": [ - "" - ], - "resources": [ - "pods", - "rolebindings" - ], - "verbs": [ - "create", - "watch", - "list" - ] - } - ] - } - ] - } - } - }, - { - "alertMessage": "Subject: Group-manager can create pods in kube-system", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[0]", - "relatedObjects[1].rules[0].verbs[0]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[0]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [ - { - "apiGroups": [ - "" - ], - "resources": [ - "pods", - "rolebindings" - ], - "verbs": [ - "create", - "watch", - "list" - ] - } - ] - } - ] - } - } - } -] \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml b/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml deleted file mode 100644 index d690308c6..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: [""] - resources: ["pods", "rolebindings"] - verbs: ["create", "watch", "list"] \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml b/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml deleted file mode 100644 index e1426bc28..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: read-secrets-global -subjects: -- kind: Group - name: manager - apiGroup: rbac.authorization.k8s.io -- kind: Group - name: dev - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/expected.json b/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/expected.json deleted file mode 100644 index b2c7e6630..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/expected.json +++ /dev/null @@ -1,68 +0,0 @@ -[ - { - "alertMessage": "Subject: User-jane can create pods in kube-system", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[0]", - "relatedObjects[1].rules[0].verbs[0]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[0]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "kube-system" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [ - { - "apiGroups": [ - "" - ], - "resources": [ - "pods", - "services" - ], - "verbs": [ - "*", - "watch", - "list" - ] - } - ] - } - ] - } - } - } -] \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/cluterrole.yaml b/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/cluterrole.yaml deleted file mode 100644 index 5d502afa9..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/cluterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: [""] - resources: ["pods", "services"] - verbs: ["*", "watch", "list"] \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/rolebinding.yaml b/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/rolebinding.yaml deleted file mode 100644 index 4448be426..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/clusterrole-rolebinding/input/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: pod - namespace: kube-system -subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/expected.json b/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/expected.json deleted file mode 100644 index fd7ff1ec9..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/expected.json +++ /dev/null @@ -1,45 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can create pods in kube-system", - "failedPaths": ["relatedObjects[1].rules[0].resources[2]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].verbs[2]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "kube-system" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Role", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "Role", - "metadata": { - "name": "test", - "namespace": "kube-system" - }, - "rules": [{ - "apiGroups": ["*"], - "resources": ["rolebindings", "deployments", "pods"], - "verbs": ["*", "watch", "create", "update"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/role.yaml b/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/role.yaml deleted file mode 100644 index 7a6cd8438..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/role.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: test - namespace: kube-system -rules: -- apiGroups: ["*"] - resources: ["rolebindings", "deployments","pods"] - verbs: ["*", "watch", "create", "update"] \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/rolebinding.yaml b/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/rolebinding.yaml deleted file mode 100644 index a4a5798dd..000000000 --- a/rules/rule-can-create-pod-kube-system-v1/test/role-rolebinding/input/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: pod - namespace: kube-system -subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-create-pod-kube-system/raw.rego b/rules/rule-can-create-pod-kube-system/raw.rego deleted file mode 100644 index 9d4b23961..000000000 --- a/rules/rule-can-create-pod-kube-system/raw.rego +++ /dev/null @@ -1,141 +0,0 @@ -package armo_builtins - -import data.cautils - -# fails if user has create access to pods within kube-system namespace -# RoleBinding to Role -deny[msga] { - roles := [role | role= input[_]; role.kind == "Role"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_create_to_pod_namespace(role) - can_create_to_pod_resource(rule) - can_create_to_pod_verb(rule) - - rolebinding.roleRef.kind == "Role" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create pods in kube-system", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - - - -# fails if user has create access to pods within kube-system namespace -# RoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - can_create_to_pod_namespace(rolebinding) - can_create_to_pod_resource(rule) - can_create_to_pod_verb(rule) - - - - rolebinding.roleRef.kind == "ClusterRole" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create pods in kube-system", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - - - -# fails if user has create access to pods within kube-system namespace -# ClusterRoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - clusterrolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - role:= roles[_] - clusterrolebinding := clusterrolebindings[_] - - rule:= role.rules[_] - can_create_to_pod_resource(rule) - can_create_to_pod_verb(rule) - - clusterrolebinding.roleRef.kind == "ClusterRole" - clusterrolebinding.roleRef.name == role.metadata.name - - subject := clusterrolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create pods in kube-system", [subject.kind, subject.name]), - "alertScore": 3, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,clusterrolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - -can_create_to_pod_resource(rule){ - cautils.list_contains(rule.resources,"pods") -} - -can_create_to_pod_resource(rule){ - is_api_group(rule) - cautils.list_contains(rule.resources,"*") -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "*" -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "" -} - -can_create_to_pod_verb(rule) { - cautils.list_contains(rule.verbs, "create") -} - - -can_create_to_pod_verb(rule) { - cautils.list_contains(rule.verbs, "*") -} - -can_create_to_pod_namespace(role) { - role.metadata.namespace == "kube-system" -} diff --git a/rules/rule-can-create-pod-kube-system/rule.metadata.json b/rules/rule-can-create-pod-kube-system/rule.metadata.json deleted file mode 100644 index 8192d0ab7..000000000 --- a/rules/rule-can-create-pod-kube-system/rule.metadata.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "rule-can-create-pod-kube-system", - "attributes": { - "microsoftK8sThreatMatrix": "Discovery::Access the K8s API server", - "armoBuiltin": true, - "useUntilKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "determines which users can create pods in kube-system namespace", - "remediation": "", - "ruleQuery": "armo_builtins", - "resourceCount": "subjects" - } \ No newline at end of file diff --git a/rules/rule-can-create-pod/rule.metadata.json b/rules/rule-can-create-pod/rule.metadata.json index a719987b8..9527c346e 100644 --- a/rules/rule-can-create-pod/rule.metadata.json +++ b/rules/rule-can-create-pod/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-delete-create-service-v1/raw.rego b/rules/rule-can-delete-create-service-v1/raw.rego deleted file mode 100644 index ac29609e3..000000000 --- a/rules/rule-can-delete-create-service-v1/raw.rego +++ /dev/null @@ -1,64 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# fails if user has create/delete access to services -deny[msga] { - subjectVector := input[_] - role := subjectVector.relatedObjects[i] - rolebinding := subjectVector.relatedObjects[j] - endswith(role.kind, "Role") - endswith(rolebinding.kind, "Binding") - - rule := role.rules[p] - - subject := rolebinding.subjects[k] - is_same_subjects(subjectVector, subject) - - rule_path := sprintf("relatedObjects[%d].rules[%d]", [i, p]) - - verbs := ["create", "delete", "deletecollection", "*"] - verb_path := [sprintf("%s.verbs[%d]", [rule_path, l]) | verb = rule.verbs[l]; verb in verbs] - count(verb_path) > 0 - - api_groups := ["", "*"] - api_groups_path := [sprintf("%s.apiGroups[%d]", [rule_path, a]) | apiGroup = rule.apiGroups[a]; apiGroup in api_groups] - count(api_groups_path) > 0 - - resources := ["services", "*"] - resources_path := [sprintf("%s.resources[%d]", [rule_path, l]) | resource = rule.resources[l]; resource in resources] - count(resources_path) > 0 - - path := array.concat(resources_path, verb_path) - path2 := array.concat(path, api_groups_path) - finalpath := array.concat(path2, [ - sprintf("relatedObjects[%d].subjects[%d]", [j, k]), - sprintf("relatedObjects[%d].roleRef.name", [j]), - ]) - - msga := { - "alertMessage": sprintf("Subject: %s-%s can create/delete services", [subjectVector.kind, subjectVector.name]), - "alertScore": 3, - "failedPaths": finalpath, - "fixPaths": [], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": subjectVector, - }, - } -} - -# for service accounts -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.namespace == subject.namespace -} - -# for users/ groups -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.apiGroup == subject.apiGroup -} diff --git a/rules/rule-can-delete-create-service-v1/rule.metadata.json b/rules/rule-can-delete-create-service-v1/rule.metadata.json deleted file mode 100644 index 059047c07..000000000 --- a/rules/rule-can-delete-create-service-v1/rule.metadata.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "rule-can-delete-create-service-v1", - "attributes": { - "m$K8sThreatMatrix": "Discovery::Access the K8s API server", - "armoBuiltin": true, - "resourcesAggregator": "subject-role-rolebinding", - "useFromKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [], - "description": "determines which users have create/delete permissions on services", - "remediation": "", - "ruleQuery": "armo_builtins" - } \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/expected.json b/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/expected.json deleted file mode 100644 index 13c5118d7..000000000 --- a/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/expected.json +++ /dev/null @@ -1,142 +0,0 @@ -[ - { - "alertMessage": "Subject: Group-manager can create/delete services", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[2]", - "relatedObjects[1].rules[0].verbs[1]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[0]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [ - { - "apiGroups": [ - "" - ], - "resources": [ - "pods", - "rolebindings", - "services" - ], - "verbs": [ - "watch", - "delete" - ] - } - ] - } - ] - } - } - }, - { - "alertMessage": "Subject: Group-dev can create/delete services", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[2]", - "relatedObjects[1].rules[0].verbs[1]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[1]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [ - { - "apiGroups": [ - "" - ], - "resources": [ - "pods", - "rolebindings", - "services" - ], - "verbs": [ - "watch", - "delete" - ] - } - ] - } - ] - } - } - } -] \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml b/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml deleted file mode 100644 index 9f42b1de6..000000000 --- a/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: [""] - resources: ["pods", "rolebindings", "services"] - verbs: ["watch", "delete"] \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml b/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml deleted file mode 100644 index e1426bc28..000000000 --- a/rules/rule-can-delete-create-service-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: read-secrets-global -subjects: -- kind: Group - name: manager - apiGroup: rbac.authorization.k8s.io -- kind: Group - name: dev - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/expected.json b/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/expected.json deleted file mode 100644 index 79e0c018f..000000000 --- a/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/expected.json +++ /dev/null @@ -1,44 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can create/delete services", - "failedPaths": ["relatedObjects[1].rules[0].resources[0]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "kube-system" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [{ - "apiGroups": [""], - "resources": ["*"], - "verbs": ["*"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/cluterrole.yaml b/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/cluterrole.yaml deleted file mode 100644 index fd8e287be..000000000 --- a/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/cluterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: [""] - resources: ["*"] - verbs: ["*"] \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/rolebinding.yaml b/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/rolebinding.yaml deleted file mode 100644 index 4448be426..000000000 --- a/rules/rule-can-delete-create-service-v1/test/clusterrole-rolebinding/input/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: pod - namespace: kube-system -subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/role-rolebinding/expected.json b/rules/rule-can-delete-create-service-v1/test/role-rolebinding/expected.json deleted file mode 100644 index 1ea4932ff..000000000 --- a/rules/rule-can-delete-create-service-v1/test/role-rolebinding/expected.json +++ /dev/null @@ -1,45 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can create/delete services", - "failedPaths": ["relatedObjects[1].rules[0].resources[3]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].verbs[2]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "kube-system" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Role", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "Role", - "metadata": { - "name": "test", - "namespace": "kube-system" - }, - "rules": [{ - "apiGroups": ["*"], - "resources": ["rolebindings", "deployments", "pods", "services"], - "verbs": ["*", "watch", "create", "update"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/role.yaml b/rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/role.yaml deleted file mode 100644 index f10fcb329..000000000 --- a/rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/role.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: test - namespace: kube-system -rules: -- apiGroups: ["*"] - resources: ["rolebindings", "deployments","pods", "services"] - verbs: ["*", "watch", "create", "update"] \ No newline at end of file diff --git a/rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/rolebinding.yaml b/rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/rolebinding.yaml deleted file mode 100644 index a4a5798dd..000000000 --- a/rules/rule-can-delete-create-service-v1/test/role-rolebinding/input/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: pod - namespace: kube-system -subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-delete-create-service/raw.rego b/rules/rule-can-delete-create-service/raw.rego deleted file mode 100644 index 5102753f6..000000000 --- a/rules/rule-can-delete-create-service/raw.rego +++ /dev/null @@ -1,137 +0,0 @@ -package armo_builtins - -import data.cautils - -# fails if user has create/delete access to services -# RoleBinding to Role -deny[msga] { - roles := [role | role= input[_]; role.kind == "Role"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - canCreateDeleteToServiceResource(rule) - canCreateDeleteToServiceVerb(rule) - - rolebinding.roleRef.kind == "Role" - rolebinding.roleRef.name == role.metadata.name - - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create/delete services", [subject.kind, subject.name]), - "alertScore": 9, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user has create/delete access to services -# RoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - - canCreateDeleteToServiceResource(rule) - canCreateDeleteToServiceVerb(rule) - - rolebinding.roleRef.kind == "ClusterRole" - rolebinding.roleRef.name == role.metadata.name - - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create/delete services", [subject.kind, subject.name]), - "alertScore": 9, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } - -} - -# fails if user has create/delete access to services -# ClusterRoleBinding to ClusterRole -deny [msga]{ - roles := [role | role= input[_]; role.kind == "ClusterRole"] - clusterrolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - role:= roles[_] - clusterrolebinding := clusterrolebindings[_] - - rule:= role.rules[_] - - canCreateDeleteToServiceResource(rule) - canCreateDeleteToServiceVerb(rule) - - clusterrolebinding.roleRef.kind == "ClusterRole" - clusterrolebinding.roleRef.name == role.metadata.name - subject := clusterrolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can create/delete services", [subject.kind, subject.name]), - "alertScore": 9, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,clusterrolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - -canCreateDeleteToServiceResource(rule) { - cautils.list_contains(rule.resources, "services") -} - -canCreateDeleteToServiceResource(rule) { - is_api_group(rule) - cautils.list_contains(rule.resources, "*") -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "*" -} - -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "" -} - -canCreateDeleteToServiceVerb(rule) { - cautils.list_contains(rule.verbs, "create") -} - -canCreateDeleteToServiceVerb(rule) { - cautils.list_contains(rule.verbs, "delete") -} - -canCreateDeleteToServiceVerb(rule) { - cautils.list_contains(rule.verbs, "deletecollection") -} - -canCreateDeleteToServiceVerb(rule) { - cautils.list_contains(rule.verbs, "*") -} \ No newline at end of file diff --git a/rules/rule-can-delete-create-service/rule.metadata.json b/rules/rule-can-delete-create-service/rule.metadata.json deleted file mode 100644 index 94089f478..000000000 --- a/rules/rule-can-delete-create-service/rule.metadata.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "rule-can-delete-create-service", - "attributes": { - "m$K8sThreatMatrix": "Discovery::Access the K8s API server", - "armoBuiltin": true, - "useUntilKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "determines which users have create/delete permissions on services", - "remediation": "", - "ruleQuery": "armo_builtins", - "resourceCount": "subjects" - } \ No newline at end of file diff --git a/rules/rule-can-delete-k8s-events-v1/rule.metadata.json b/rules/rule-can-delete-k8s-events-v1/rule.metadata.json index 270a5af8b..533373171 100644 --- a/rules/rule-can-delete-k8s-events-v1/rule.metadata.json +++ b/rules/rule-can-delete-k8s-events-v1/rule.metadata.json @@ -10,10 +10,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-delete-k8s-events/rule.metadata.json b/rules/rule-can-delete-k8s-events/rule.metadata.json index 5d4478e3c..4f3cf14b0 100644 --- a/rules/rule-can-delete-k8s-events/rule.metadata.json +++ b/rules/rule-can-delete-k8s-events/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-delete-logs-v1/raw.rego b/rules/rule-can-delete-logs-v1/raw.rego deleted file mode 100644 index 17bbc3625..000000000 --- a/rules/rule-can-delete-logs-v1/raw.rego +++ /dev/null @@ -1,64 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# fails if user can delete logs of pod -deny[msga] { - subjectVector := input[_] - role := subjectVector.relatedObjects[i] - rolebinding := subjectVector.relatedObjects[j] - endswith(role.kind, "Role") - endswith(rolebinding.kind, "Binding") - - rule := role.rules[p] - - subject := rolebinding.subjects[k] - is_same_subjects(subjectVector, subject) - -rule_path := sprintf("relatedObjects[%d].rules[%d]", [i, p]) - - verbs := ["delete", "deletecollection", "*"] - verb_path := [sprintf("%s.verbs[%d]", [rule_path, l]) | verb = rule.verbs[l]; verb in verbs] - count(verb_path) > 0 - - api_groups := ["", "*"] - api_groups_path := [sprintf("%s.apiGroups[%d]", [rule_path, a]) | apiGroup = rule.apiGroups[a]; apiGroup in api_groups] - count(api_groups_path) > 0 - - resources := ["pods/log", "pods/*", "*"] - resources_path := [sprintf("%s.resources[%d]", [rule_path, l]) | resource = rule.resources[l]; resource in resources] - count(resources_path) > 0 - - path := array.concat(resources_path, verb_path) - path2 := array.concat(path, api_groups_path) - finalpath := array.concat(path2, [ - sprintf("relatedObjects[%d].subjects[%d]", [j, k]), - sprintf("relatedObjects[%d].roleRef.name", [j]), - ]) - - msga := { - "alertMessage": sprintf("Subject: %s-%s can delete logs", [subjectVector.kind, subjectVector.name]), - "alertScore": 3, - "packagename": "armo_builtins", - "failedPaths": finalpath, - "fixPaths": [], - "alertObject": { - "k8sApiObjects": [], - "externalObjects": subjectVector, - }, - } -} - -# for service accounts -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.namespace == subject.namespace -} - -# for users/ groups -is_same_subjects(subjectVector, subject) { - subjectVector.kind == subject.kind - subjectVector.name == subject.name - subjectVector.apiGroup == subject.apiGroup -} diff --git a/rules/rule-can-delete-logs-v1/rule.metadata.json b/rules/rule-can-delete-logs-v1/rule.metadata.json deleted file mode 100644 index 7318f3732..000000000 --- a/rules/rule-can-delete-logs-v1/rule.metadata.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "rule-can-delete-logs-v1", - "attributes": { - "microsoftK8sThreatMatrix": "Defense Evasion::Clear container logs", - "armoBuiltin": true, - "resourcesAggregator": "subject-role-rolebinding", - "useFromKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [], - "description": "determines which users can delete logs inside a container", - "remediation": "", - "ruleQuery": "armo_builtins" - } \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/expected.json b/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/expected.json deleted file mode 100644 index 9c638a327..000000000 --- a/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/expected.json +++ /dev/null @@ -1,142 +0,0 @@ -[ - { - "alertMessage": "Subject: Group-manager can delete logs", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[0]", - "relatedObjects[1].rules[0].verbs[1]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[0]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [ - { - "apiGroups": [ - "" - ], - "resources": [ - "pods/log", - "events", - "services" - ], - "verbs": [ - "watch", - "delete" - ] - } - ] - } - ] - } - } - }, - { - "alertMessage": "Subject: Group-dev can delete logs", - "failedPaths": [ - "relatedObjects[1].rules[0].resources[0]", - "relatedObjects[1].rules[0].verbs[1]", - "relatedObjects[1].rules[0].apiGroups[0]", - "relatedObjects[0].subjects[1]", - "relatedObjects[0].roleRef.name" - ], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev", - "relatedObjects": [ - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRoleBinding", - "metadata": { - "name": "read-secrets-global" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [ - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "manager" - }, - { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Group", - "name": "dev" - } - ] - }, - { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [ - { - "apiGroups": [ - "" - ], - "resources": [ - "pods/log", - "events", - "services" - ], - "verbs": [ - "watch", - "delete" - ] - } - ] - } - ] - } - } - } -] \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml b/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml deleted file mode 100644 index 7cb95500b..000000000 --- a/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: [""] - resources: ["pods/log", "events", "services"] - verbs: ["watch", "delete"] \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml b/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml deleted file mode 100644 index e1426bc28..000000000 --- a/rules/rule-can-delete-logs-v1/test/clusterrole-clusterrolebinding/input/clusterrolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: read-secrets-global -subjects: -- kind: Group - name: manager - apiGroup: rbac.authorization.k8s.io -- kind: Group - name: dev - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/expected.json b/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/expected.json deleted file mode 100644 index 4e4b4b3ca..000000000 --- a/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/expected.json +++ /dev/null @@ -1,44 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can delete logs", - "failedPaths": ["relatedObjects[1].rules[0].resources[0]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "kube-system" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "ClusterRole", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "ClusterRole", - "metadata": { - "name": "test" - }, - "rules": [{ - "apiGroups": [""], - "resources": ["*"], - "verbs": ["*"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/cluterrole.yaml b/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/cluterrole.yaml deleted file mode 100644 index fd8e287be..000000000 --- a/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/cluterrole.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: test -rules: -- apiGroups: [""] - resources: ["*"] - verbs: ["*"] \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/rolebinding.yaml b/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/rolebinding.yaml deleted file mode 100644 index 4448be426..000000000 --- a/rules/rule-can-delete-logs-v1/test/clusterrole-rolebinding/input/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: pod - namespace: kube-system -subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/role-rolebinding/expected.json b/rules/rule-can-delete-logs-v1/test/role-rolebinding/expected.json deleted file mode 100644 index 0214515dc..000000000 --- a/rules/rule-can-delete-logs-v1/test/role-rolebinding/expected.json +++ /dev/null @@ -1,45 +0,0 @@ -[{ - "alertMessage": "Subject: User-jane can delete logs", - "failedPaths": ["relatedObjects[1].rules[0].resources[2]", "relatedObjects[1].rules[0].resources[4]", "relatedObjects[1].rules[0].verbs[0]", "relatedObjects[1].rules[0].apiGroups[0]", "relatedObjects[0].subjects[0]", "relatedObjects[0].roleRef.name"], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 3, - "alertObject": { - "externalObjects": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane", - "relatedObjects": [{ - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "RoleBinding", - "metadata": { - "name": "pod", - "namespace": "kube-system" - }, - "roleRef": { - "apiGroup": "rbac.authorization.k8s.io", - "kind": "Role", - "name": "test" - }, - "subjects": [{ - "apiGroup": "rbac.authorization.k8s.io", - "kind": "User", - "name": "jane" - }] - }, { - "apiVersion": "rbac.authorization.k8s.io/v1", - "kind": "Role", - "metadata": { - "name": "test", - "namespace": "kube-system" - }, - "rules": [{ - "apiGroups": ["*"], - "resources": ["rolebindings", "deployments", "pods/*", "services", "*"], - "verbs": ["*", "watch", "create", "update"] - }] - }] - } - } -}] \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/role-rolebinding/input/role.yaml b/rules/rule-can-delete-logs-v1/test/role-rolebinding/input/role.yaml deleted file mode 100644 index 3c7c0d875..000000000 --- a/rules/rule-can-delete-logs-v1/test/role-rolebinding/input/role.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: test - namespace: kube-system -rules: -- apiGroups: ["*"] - resources: ["rolebindings", "deployments","pods/*", "services", "*"] - verbs: ["*", "watch", "create", "update"] \ No newline at end of file diff --git a/rules/rule-can-delete-logs-v1/test/role-rolebinding/input/rolebinding.yaml b/rules/rule-can-delete-logs-v1/test/role-rolebinding/input/rolebinding.yaml deleted file mode 100644 index a4a5798dd..000000000 --- a/rules/rule-can-delete-logs-v1/test/role-rolebinding/input/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: pod - namespace: kube-system -subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io -roleRef: - kind: Role - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/rules/rule-can-delete-logs/raw.rego b/rules/rule-can-delete-logs/raw.rego deleted file mode 100644 index 7b1da37ef..000000000 --- a/rules/rule-can-delete-logs/raw.rego +++ /dev/null @@ -1,146 +0,0 @@ -package armo_builtins - -import data.cautils - -# fails if user can delete logs of pod -#RoleBinding to Role -deny [msga] { - roles := [role | role= input[_]; role.kind == "Role"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - canDeleteLogs(rule) - - rolebinding.roleRef.kind == "Role" - rolebinding.roleRef.name == role.metadata.name - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can delete logs", [subject.kind, subject.name]), - "alertScore": 6, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } - -} - - -# fails if user can delete logs of pod -# RoleBinding to ClusterRole -deny[msga] { - roles := [role | role= input[_]; role.kind == "ClusterRole"] - rolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "RoleBinding"] - role:= roles[_] - rolebinding := rolebindings[_] - - rule:= role.rules[_] - canDeleteLogs(rule) - - rolebinding.roleRef.kind == "ClusterRole" - rolebinding.roleRef.name == role.metadata.name - - - subject := rolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can delete logs", [subject.kind, subject.name]), - "alertScore": 6, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,rolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - -# fails if user can delete logs of pod -# ClusterRoleBinding to ClusterRole -deny[msga] { - roles := [role | role= input[_]; role.kind == "ClusterRole"] - clusterrolebindings := [rolebinding | rolebinding = input[_]; rolebinding.kind == "ClusterRoleBinding"] - role:= roles[_] - clusterrolebinding := clusterrolebindings[_] - - rule:= role.rules[_] - canDeleteLogs(rule) - - clusterrolebinding.roleRef.kind == "ClusterRole" - clusterrolebinding.roleRef.name == role.metadata.name - - - subject := clusterrolebinding.subjects[i] - path := sprintf("subjects[%v]", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The following %v: %v can delete logs", [subject.kind, subject.name]), - "alertScore": 6, - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [role,clusterrolebinding], - "externalObjects": { - "subject" : [subject] - } - } - } -} - - - - -canDeleteLogs(rule) { - cautils.list_contains(rule.resources,"*") - is_api_group(rule) - cautils.list_contains(rule.verbs,"*") -} - -canDeleteLogs(rule) { - cautils.list_contains(rule.resources,"pods/log") - cautils.list_contains(rule.verbs,"delete") -} -canDeleteLogs(rule) { - cautils.list_contains(rule.resources,"pods/log") - cautils.list_contains(rule.verbs,"*") -} - -canDeleteLogs(rule) { - cautils.list_contains(rule.resources,"*") - is_api_group(rule) - cautils.list_contains(rule.verbs,"delete") -} - -canDeleteLogs(rule) { - cautils.list_contains(rule.resources,"pods/*") - cautils.list_contains(rule.verbs,"delete") -} -canDeleteLogs(rule) { - cautils.list_contains(rule.resources,"pods/*") - cautils.list_contains(rule.verbs,"*") -} - -canDeleteLogs(rule) { - cautils.list_contains(rule.resources,"*") - is_api_group(rule) - cautils.list_contains(rule.verbs,"deletecollection") -} -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "*" -} -is_api_group(rule) { - apiGroup := rule.apiGroups[_] - apiGroup == "" -} \ No newline at end of file diff --git a/rules/rule-can-delete-logs/rule.metadata.json b/rules/rule-can-delete-logs/rule.metadata.json deleted file mode 100644 index 5e34d80e2..000000000 --- a/rules/rule-can-delete-logs/rule.metadata.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "rule-can-delete-logs", - "attributes": { - "microsoftK8sThreatMatrix": "Defense Evasion::Clear container logs", - "armoBuiltin": true, - "useUntilKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Role", - "ClusterRole", - "ClusterRoleBinding", - "RoleBinding" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "determines which users can delete logs inside a container", - "remediation": "", - "ruleQuery": "armo_builtins", - "resourceCount": "subjects" - } \ No newline at end of file diff --git a/rules/rule-can-impersonate-users-groups-v1/rule.metadata.json b/rules/rule-can-impersonate-users-groups-v1/rule.metadata.json index 044e8738b..2e7483c5e 100644 --- a/rules/rule-can-impersonate-users-groups-v1/rule.metadata.json +++ b/rules/rule-can-impersonate-users-groups-v1/rule.metadata.json @@ -10,10 +10,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-impersonate-users-groups/rule.metadata.json b/rules/rule-can-impersonate-users-groups/rule.metadata.json index 5692ca072..67dfa8481 100644 --- a/rules/rule-can-impersonate-users-groups/rule.metadata.json +++ b/rules/rule-can-impersonate-users-groups/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-list-get-secrets-v1/rule.metadata.json b/rules/rule-can-list-get-secrets-v1/rule.metadata.json index 97a672524..c0fd2011c 100644 --- a/rules/rule-can-list-get-secrets-v1/rule.metadata.json +++ b/rules/rule-can-list-get-secrets-v1/rule.metadata.json @@ -10,10 +10,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-list-get-secrets/rule.metadata.json b/rules/rule-can-list-get-secrets/rule.metadata.json index bb3fe2599..bc30fbc08 100644 --- a/rules/rule-can-list-get-secrets/rule.metadata.json +++ b/rules/rule-can-list-get-secrets/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-portforward-v1/rule.metadata.json b/rules/rule-can-portforward-v1/rule.metadata.json index b9a1483ee..68e075d5e 100644 --- a/rules/rule-can-portforward-v1/rule.metadata.json +++ b/rules/rule-can-portforward-v1/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-portforward/rule.metadata.json b/rules/rule-can-portforward/rule.metadata.json index 01d34c75f..03b928883 100644 --- a/rules/rule-can-portforward/rule.metadata.json +++ b/rules/rule-can-portforward/rule.metadata.json @@ -8,10 +8,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-can-update-configmap-v1/rule.metadata.json b/rules/rule-can-update-configmap-v1/rule.metadata.json index 49613054a..083f78b7c 100644 --- a/rules/rule-can-update-configmap-v1/rule.metadata.json +++ b/rules/rule-can-update-configmap-v1/rule.metadata.json @@ -10,10 +10,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-excessive-delete-rights-v1/rule.metadata.json b/rules/rule-excessive-delete-rights-v1/rule.metadata.json index c6430c948..6f86e94b0 100644 --- a/rules/rule-excessive-delete-rights-v1/rule.metadata.json +++ b/rules/rule-excessive-delete-rights-v1/rule.metadata.json @@ -10,10 +10,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-excessive-delete-rights/rule.metadata.json b/rules/rule-excessive-delete-rights/rule.metadata.json index 4f157841d..937e53927 100644 --- a/rules/rule-excessive-delete-rights/rule.metadata.json +++ b/rules/rule-excessive-delete-rights/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-exposed-dashboard-v1/filter.rego b/rules/rule-exposed-dashboard-v1/filter.rego deleted file mode 100644 index 310e8d755..000000000 --- a/rules/rule-exposed-dashboard-v1/filter.rego +++ /dev/null @@ -1,45 +0,0 @@ -package armo_builtins - -# input: deployment, service -# apiversion: v1 -# fails if dashboard exists and is exposed - -deny[msga] { - deployment := input[_] - startswith(deployment.metadata.name, "kubernetes-dashboard") - container := deployment.spec.template.spec.containers[j] - version := trim_prefix(container.image, "kubernetesui/dashboard:v") - to_number(replace(version, ".", "")) < 201 - - service := input[_] - service.kind == "Service" - count({x | service.spec.selector[x]; deployment.metadata.labels[x]}) == count(service.spec.selector) - path := sprintf("spec.template.spec.containers[%v]", [format_int(j, 10)]) - - deploymentvector = {"name": deployment.metadata.name, - "namespace": deployment.metadata.namespace, - "kind": deployment.kind, - "relatedObjects": [service]} - - msga := { - "alertMessage": sprintf("dashboard exists and is exposed %s", [container.image]), - "alertScore": 9, - "fixPaths": [], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": deploymentvector - } - } -} - - - -isNodePortLbService(service) { - service.spec.type == "NodePort" -} - -isNodePortLbService(service) { - service.spec.type == "LoadBalancer" -} \ No newline at end of file diff --git a/rules/rule-exposed-dashboard-v1/raw.rego b/rules/rule-exposed-dashboard-v1/raw.rego deleted file mode 100644 index 9947142f2..000000000 --- a/rules/rule-exposed-dashboard-v1/raw.rego +++ /dev/null @@ -1,46 +0,0 @@ -package armo_builtins - -# input: deployment, service -# apiversion: v1 -# fails if dashboard exists and is exposed - -deny[msga] { - deployment := input[_] - startswith(deployment.metadata.name, "kubernetes-dashboard") - container := deployment.spec.template.spec.containers[j] - version := trim_prefix(container.image, "kubernetesui/dashboard:v") - to_number(replace(version, ".", "")) < 201 - - service := input[_] - service.kind == "Service" - isNodePortLbService(service) - count({x | service.spec.selector[x]; deployment.metadata.labels[x]}) == count(service.spec.selector) - path := sprintf("spec.template.spec.containers[%v]", [format_int(j, 10)]) - - deploymentvector = {"name": deployment.metadata.name, - "namespace": deployment.metadata.namespace, - "kind": deployment.kind, - "relatedObjects": [service]} - - msga := { - "alertMessage": sprintf("dashboard exists and is exposed %s", [container.image]), - "alertScore": 9, - "fixPaths": [], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [], - "externalObjects": deploymentvector - } - } -} - - - -isNodePortLbService(service) { - service.spec.type == "NodePort" -} - -isNodePortLbService(service) { - service.spec.type == "LoadBalancer" -} \ No newline at end of file diff --git a/rules/rule-exposed-dashboard-v1/rule.metadata.json b/rules/rule-exposed-dashboard-v1/rule.metadata.json deleted file mode 100644 index 5127a64b5..000000000 --- a/rules/rule-exposed-dashboard-v1/rule.metadata.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "rule-exposed-dashboard-v1", - "attributes": { - "m$K8sThreatMatrix": "Initial Access::Exposed Dashboard", - "armoBuiltin": true, - "useFromKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Deployment", - "Service" - ] - } - ], - "ruleDependencies": [], - "description": "fails if dashboard exists and is exposed", - "remediation": "", - "ruleQuery": "armo_builtins" - } \ No newline at end of file diff --git a/rules/rule-exposed-dashboard-v1/test/test/expected.json b/rules/rule-exposed-dashboard-v1/test/test/expected.json deleted file mode 100644 index 188be07f4..000000000 --- a/rules/rule-exposed-dashboard-v1/test/test/expected.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "alertMessage": "dashboard exists and is exposed kubernetesui/dashboard:v1.4.0", - "fixPaths": [], - "failedPaths": [ - "spec.template.spec.containers[0]" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 9, - "alertObject": { - "externalObjects": { - "kind": "Deployment", - "name": "kubernetes-dashboard", - "namespace": "kubernetes-dashboard", - "relatedObjects": [ - { - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "name": "my-service" - }, - "spec": { - "clusterIP": "10.96.171.239", - "ports": [ - { - "port": 80, - "protocol": "TCP", - "targetPort": 9376 - } - ], - "selector": { - "k8s-app": "kubernetes-dashboard" - }, - "type": "LoadBalancer" - }, - "status": { - "loadBalancer": { - "ingress": [ - { - "ip": "192.0.2.127" - } - ] - } - } - } - ] - } - } - } -] \ No newline at end of file diff --git a/rules/rule-exposed-dashboard-v1/test/test/input/deployment.yaml b/rules/rule-exposed-dashboard-v1/test/test/input/deployment.yaml deleted file mode 100644 index 633867ef6..000000000 --- a/rules/rule-exposed-dashboard-v1/test/test/input/deployment.yaml +++ /dev/null @@ -1,63 +0,0 @@ -kind: Deployment -apiVersion: apps/v1 -metadata: - labels: - k8s-app: kubernetes-dashboard - name: kubernetes-dashboard - namespace: kubernetes-dashboard -spec: - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - k8s-app: kubernetes-dashboard - template: - metadata: - labels: - k8s-app: kubernetes-dashboard - spec: - containers: - - name: kubernetes-dashboard - image: kubernetesui/dashboard:v1.4.0 - imagePullPolicy: Always - ports: - - containerPort: 8443 - protocol: TCP - args: - - --auto-generate-certificates - - --namespace=kubernetes-dashboard - # Uncomment the following line to manually specify Kubernetes API server Host - # If not specified, Dashboard will attempt to auto discover the API server and connect - # to it. Uncomment only if the default does not work. - # - --apiserver-host=http://my-address:port - volumeMounts: - - name: kubernetes-dashboard-certs - mountPath: /certs - # Create on-disk volume to store exec logs - - mountPath: /tmp - name: tmp-volume - livenessProbe: - httpGet: - scheme: HTTPS - path: / - port: 8443 - initialDelaySeconds: 30 - timeoutSeconds: 30 - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - runAsUser: 1001 - runAsGroup: 2001 - volumes: - - name: kubernetes-dashboard-certs - secret: - secretName: kubernetes-dashboard-certs - - name: tmp-volume - emptyDir: {} - serviceAccountName: kubernetes-dashboard - nodeSelector: - "kubernetes.io/os": linux - # Comment the following tolerations if Dashboard must not be deployed on master - tolerations: - - key: node-role.kubernetes.io/master - effect: NoSchedule diff --git a/rules/rule-exposed-dashboard/raw.rego b/rules/rule-exposed-dashboard/raw.rego deleted file mode 100644 index 5787b8f2b..000000000 --- a/rules/rule-exposed-dashboard/raw.rego +++ /dev/null @@ -1,40 +0,0 @@ - package armo_builtins - - # input: pods - # apiversion: v1 - # fails if dashboard exists and is exposed - - deny[msga] { - deployment := input[_] - startswith(deployment.metadata.name, "kubernetes-dashboard") - container := deployment.spec.template.spec.containers[j] - version := trim_prefix(container.image, "kubernetesui/dashboard:v") - to_number(replace(version, ".", "")) < 201 - - service := input[_] - service.kind == "Service" - isNodePortLbService(service) - count({x | service.spec.selector[x]; deployment.metadata.labels[x]}) == count(service.spec.selector) - path := sprintf("spec.template.spec.containers[%v]", [format_int(j, 10)]) - - msga := { - "alertMessage": sprintf("dashboard exists and is exposed %s", [container.image]), - "alertScore": 9, - "fixPaths": [], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [deployment] - } - } - } - - - -isNodePortLbService(service) { - service.spec.type == "NodePort" -} - -isNodePortLbService(service) { - service.spec.type == "LoadBalancer" -} \ No newline at end of file diff --git a/rules/rule-exposed-dashboard/rule.metadata.json b/rules/rule-exposed-dashboard/rule.metadata.json deleted file mode 100644 index 76c664781..000000000 --- a/rules/rule-exposed-dashboard/rule.metadata.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "rule-exposed-dashboard", - "attributes": { - "m$K8sThreatMatrix": "Initial Access::Exposed Dashboard", - "armoBuiltin": true, - "useUntilKubescapeVersion": "v1.0.133" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Deployment", - "Service" - ] - } - ], - "ruleDependencies": [], - "description": "fails if dashboard exists and is exposed", - "remediation": "", - "ruleQuery": "armo_builtins" - } \ No newline at end of file diff --git a/rules/rule-identify-blocklisted-image-registries/rule.metadata.json b/rules/rule-identify-blocklisted-image-registries/rule.metadata.json index b33949795..d173b460b 100644 --- a/rules/rule-identify-blocklisted-image-registries/rule.metadata.json +++ b/rules/rule-identify-blocklisted-image-registries/rule.metadata.json @@ -8,19 +8,39 @@ "match": [ { "apiGroups": [ - "*" + "" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Pod" + ] + }, + { + "apiGroups": [ + "apps" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Deployment", + "ReplicaSet", + "DaemonSet", + "StatefulSet" + ] + }, + { + "apiGroups": [ + "batch" ], "apiVersions": [ "*" ], "resources": [ - "Pod", - "Deployment", - "ReplicaSet", - "DaemonSet", - "StatefulSet", - "Job", - "CronJob" + "Job", + "CronJob" ] } ], diff --git a/rules/rule-identify-old-k8s-registry/rule.metadata.json b/rules/rule-identify-old-k8s-registry/rule.metadata.json index b5bedcbf1..985f67387 100644 --- a/rules/rule-identify-old-k8s-registry/rule.metadata.json +++ b/rules/rule-identify-old-k8s-registry/rule.metadata.json @@ -8,19 +8,39 @@ "match": [ { "apiGroups": [ - "*" + "" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Pod" + ] + }, + { + "apiGroups": [ + "apps" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Deployment", + "ReplicaSet", + "DaemonSet", + "StatefulSet" + ] + }, + { + "apiGroups": [ + "batch" ], "apiVersions": [ "*" ], "resources": [ - "Pod", - "Deployment", - "ReplicaSet", - "DaemonSet", - "StatefulSet", - "Job", - "CronJob" + "Job", + "CronJob" ] } ], diff --git a/rules/rule-list-all-cluster-admins-v1/rule.metadata.json b/rules/rule-list-all-cluster-admins-v1/rule.metadata.json index cc51a2cc5..1bd7d2fb7 100644 --- a/rules/rule-list-all-cluster-admins-v1/rule.metadata.json +++ b/rules/rule-list-all-cluster-admins-v1/rule.metadata.json @@ -10,10 +10,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-list-all-cluster-admins/rule.metadata.json b/rules/rule-list-all-cluster-admins/rule.metadata.json index 9b6c68654..54777a54f 100644 --- a/rules/rule-list-all-cluster-admins/rule.metadata.json +++ b/rules/rule-list-all-cluster-admins/rule.metadata.json @@ -9,10 +9,10 @@ "match": [ { "apiGroups": [ - "*" + "rbac.authorization.k8s.io" ], "apiVersions": [ - "*" + "v1" ], "resources": [ "Role", diff --git a/rules/rule-name-similarity/raw.rego b/rules/rule-name-similarity/raw.rego deleted file mode 100644 index 46ed24f44..000000000 --- a/rules/rule-name-similarity/raw.rego +++ /dev/null @@ -1,28 +0,0 @@ -package armo_builtins - -# input: pods -# apiversion: v1 -# fails if object has similar name to known workload (but is not from that workload) - -deny[msga] { - object := input[_] - wanted_kinds := {"Pod", "ReplicaSet", "Job"} - wanted_kinds[object.kind] - - # see default-config-inputs.json for list values - wl_known_names := data.postureControlInputs.wlKnownNames - wl_name := wl_known_names[_] - contains(object.metadata.name, wl_name) - path := "metadata.name" - - msga := { - "alertMessage": sprintf("this %v has a similar name to %v", [object.kind, wl_name]), - "alertScore": 9, - "fixPaths": [], - "failedPaths": [path], - "packagename": "armo_builtins", - "alertObject": { - "k8sApiObjects": [object] - } - } -} \ No newline at end of file diff --git a/rules/rule-name-similarity/rule.metadata.json b/rules/rule-name-similarity/rule.metadata.json deleted file mode 100644 index 9b591ab7b..000000000 --- a/rules/rule-name-similarity/rule.metadata.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "rule-name-similarity", - "attributes": { - "m$K8sThreatMatrix": "Defense evasion::Pod / container name similarity", - "armoBuiltin": true - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Pod", - "ReplicaSet", - "Job" - ] - } - ], - "ruleDependencies": [], - "configInputs": [ - "settings.postureControlInputs.wlKnownNames" - ], - "controlConfigInputs": [ - { - "path": "settings.postureControlInputs.wlKnownNames", - "name": "Kubescape will look for the following deployment names in your cluster, it will make sure that no one is trying to create similar pod names to hide their attack. ", - "description": "Deployment names" - } - ], - "description": "fails if there are objects with names similar to system pods, or other known deployments", - "remediation": "", - "ruleQuery": "armo_builtins" -} \ No newline at end of file diff --git a/rules/rule-name-similarity/test/job/expected.json b/rules/rule-name-similarity/test/job/expected.json deleted file mode 100644 index e257e60f7..000000000 --- a/rules/rule-name-similarity/test/job/expected.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "alertMessage": "this Job has a similar name to coredns", - "fixPaths": [], - "failedPaths": [ - "metadata.name" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 9, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "batch/v1", - "kind": "Job", - "metadata": { - "name": "coredns" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/rule-name-similarity/test/job/input/job.yaml b/rules/rule-name-similarity/test/job/input/job.yaml deleted file mode 100644 index 32ca2295e..000000000 --- a/rules/rule-name-similarity/test/job/input/job.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: coredns -spec: - template: - spec: - containers: - - name: pi - image: perl - command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] - restartPolicy: Never - backoffLimit: 4 diff --git a/rules/rule-name-similarity/test/pod/expected.json b/rules/rule-name-similarity/test/pod/expected.json deleted file mode 100644 index 338bd8359..000000000 --- a/rules/rule-name-similarity/test/pod/expected.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "alertMessage": "this Pod has a similar name to coredns", - "fixPaths": [], - "failedPaths": [ - "metadata.name" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 9, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "labels": { - "purpose": "demonstrate-envars" - }, - "name": "coredns" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/rule-name-similarity/test/pod/input/pod.yaml b/rules/rule-name-similarity/test/pod/input/pod.yaml deleted file mode 100644 index 0f0d4642d..000000000 --- a/rules/rule-name-similarity/test/pod/input/pod.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: coredns - labels: - purpose: demonstrate-envars -spec: - containers: - - name: envar-demo-container - image: gcr.io/google-samples/node-hello:1.0 diff --git a/rules/rule-name-similarity/test/replicaset/expected.json b/rules/rule-name-similarity/test/replicaset/expected.json deleted file mode 100644 index 45f0d66c7..000000000 --- a/rules/rule-name-similarity/test/replicaset/expected.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "alertMessage": "this ReplicaSet has a similar name to kube-proxy", - "fixPaths": [], - "failedPaths": [ - "metadata.name" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 9, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "apps/v1", - "kind": "ReplicaSet", - "metadata": { - "labels": { - "app": "guestbook", - "tier": "frontend" - }, - "name": "kube-proxy" - } - } - ] - } -} -] \ No newline at end of file diff --git a/rules/rule-name-similarity/test/replicaset/input/replicaset.yaml b/rules/rule-name-similarity/test/replicaset/input/replicaset.yaml deleted file mode 100644 index 94f70d7f2..000000000 --- a/rules/rule-name-similarity/test/replicaset/input/replicaset.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: apps/v1 -kind: ReplicaSet -metadata: - name: kube-proxy - labels: - app: guestbook - tier: frontend -spec: - replicas: 3 - selector: - matchLabels: - tier: frontend - template: - metadata: - labels: - tier: frontend - spec: - containers: - - name: kube-proxy - image: gcr.io/google_samples/gb-frontend:v3 - - name : frontend - image : gcr.io/google_samples/gb-frontend:v3 \ No newline at end of file diff --git a/rules/security-context-in-pod/raw.rego b/rules/security-context-in-pod/raw.rego deleted file mode 100644 index 46b96c7a3..000000000 --- a/rules/security-context-in-pod/raw.rego +++ /dev/null @@ -1,87 +0,0 @@ -package armo_builtins - - -deny[msga] { - pod := input[_] - pod.kind == "Pod" - container := pod.spec.containers[i] - is_not_security_context(pod, container) - fixPaths := [{"path": sprintf("spec.containers[%v].securityContext", [format_int(i, 10)]), "value": "YOUR_VALUE"}] - - msga := { - "alertMessage": sprintf("Container: %v in pod: %v does not define a securityContext.", [container.name, pod.metadata.name]), - "packagename": "armo_builtins", - "failedPaths": [], - "fixPaths": fixPaths, - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [pod] - } - } -} - - - -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - is_not_security_context(wl.spec.template, container) - fixPaths := [{"path": sprintf("spec.template.spec.containers[%v].securityContext", [format_int(i, 10)]), "value": "YOUR_VALUE"}] - - msga := { - "alertMessage": sprintf("Container: %v in %v: %v does not define a securityContext.", [ container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "failedPaths": [], - "fixPaths": fixPaths, - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container = wl.spec.jobTemplate.spec.template.spec.containers[i] - is_not_security_context(wl.spec.jobTemplate.spec.template, container) - fixPaths := [{"path": sprintf("spec.jobTemplate.spec.template.spec.containers[%v].securityContext", [format_int(i, 10)]), "value": "YOUR_VALUE"}] - - msga := { - "alertMessage": sprintf("Container: %v in %v: %v does not define a securityContext.", [ container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "failedPaths": [], - "fixPaths": fixPaths, - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -is_not_security_context(pod, container) { - not pod.spec.securityContext - not container.securityContext -} - -is_not_security_context(pod, container) { - count(pod.spec.securityContext) == 0 - not container.securityContext -} - - -is_not_security_context(pod, container) { - not pod.spec.securityContext - container.securityContext - count(container.securityContext) == 0 -} - -is_not_security_context(pod, container) { - count(pod.spec.securityContext) == 0 - container.securityContext - count(container.securityContext) == 0 -} \ No newline at end of file diff --git a/rules/security-context-in-pod/test/cronjob/input/cronjob.yaml b/rules/security-context-in-pod/test/cronjob/input/cronjob.yaml deleted file mode 100644 index 5c8e07298..000000000 --- a/rules/security-context-in-pod/test/cronjob/input/cronjob.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: batch/v1beta1 -kind: CronJob -metadata: - name: hello -spec: - schedule: "*/1 * * * *" - jobTemplate: - spec: - template: - spec: - serviceAccountName: kubernetes-dashboard - restartPolicy: OnFailure - containers: - - name: hello - image: busybox:latest - securityContext : - capabilities : - add : [ "NET_ADMIN", "SYS_TIME", "SYS_ADMIN"] - env : - - - name : pwd - value : "Hpwd" - imagePullPolicy: IfNotPresent - command: - - /bin/sh - - -c - - date; echo Hello from the Kubernetes cluster diff --git a/rules/security-context-in-pod/test/pod/expected.json b/rules/security-context-in-pod/test/pod/expected.json deleted file mode 100644 index 6c48480af..000000000 --- a/rules/security-context-in-pod/test/pod/expected.json +++ /dev/null @@ -1,29 +0,0 @@ -[ - { - "alertMessage": "Container: test-container2 in pod: audit-pod does not define a securityContext.", - "failedPaths": [], - "fixPaths": [ - { - "path": "spec.containers[1].securityContext", - "value": "YOUR_VALUE" - } - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "labels": { - "app": "audit-pod" - }, - "name": "audit-pod" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/security-context-in-pod/test/pod/input/pod.yaml b/rules/security-context-in-pod/test/pod/input/pod.yaml deleted file mode 100644 index b2c04cc48..000000000 --- a/rules/security-context-in-pod/test/pod/input/pod.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: audit-pod - labels: - app: audit-pod -spec: - containers: - - name: test-container - env : - - name : azure_batch_key - value : "Hello from the environment" - image: hashicorp/http-echo:0.2.3 - securityContext: - capabilities: - add: ["NET_ADMIN", "SYS_ADMIN"] - allowPrivilegeEscalation: true - - name : test-container2 - env : - - name : random - value : "Hello from the environment" - image : hashicorp/http-echo:0.2.3 diff --git a/rules/security-context-in-pod/test/workloads/expected.json b/rules/security-context-in-pod/test/workloads/expected.json deleted file mode 100644 index eef87bfb8..000000000 --- a/rules/security-context-in-pod/test/workloads/expected.json +++ /dev/null @@ -1,56 +0,0 @@ -[ - { - "alertMessage": "Container: test-container in Deployment: test2 does not define a securityContext.", - "failedPaths": [], - "fixPaths": [ - { - "path": "spec.template.spec.containers[0].securityContext", - "value": "YOUR_VALUE" - } - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "labels": { - "app": "audit-pod" - }, - "name": "test2" - } - } - ] - } - }, - { - "alertMessage": "Container: test-container2 in Deployment: test2 does not define a securityContext.", - "failedPaths": [], - "fixPaths": [ - { - "path": "spec.template.spec.containers[1].securityContext", - "value": "YOUR_VALUE" - } - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "labels": { - "app": "audit-pod" - }, - "name": "test2" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/security-context-in-pod/test/workloads/input/deployment.yaml b/rules/security-context-in-pod/test/workloads/input/deployment.yaml deleted file mode 100644 index 0ca424055..000000000 --- a/rules/security-context-in-pod/test/workloads/input/deployment.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: default - name: test2 - labels: - app: audit-pod -spec: - replicas: 3 - selector: - matchLabels: - app: audit-pod - template: - metadata: - labels: - app: audit-pod - spec : - containers : - - - name : test-container - env : - - - name : random - value : "Hello from the environment" - image : hashicorp/http-echo:0.2.3 - - - name : test-container2 - env : - - - name : azure_batch_key - value : "Hello from the environment" - image : hashicorp/http-echo:0.2.3 \ No newline at end of file diff --git a/rules/serviceaccount-token-mount/raw.rego b/rules/serviceaccount-token-mount/raw.rego new file mode 100644 index 000000000..f11e8ea29 --- /dev/null +++ b/rules/serviceaccount-token-mount/raw.rego @@ -0,0 +1,131 @@ +package armo_builtins + +deny[msga] { + wl := input[_] + beggining_of_path := get_beginning_of_path(wl) + spec := object.get(wl, beggining_of_path, []) + + wl_namespace := wl.metadata.namespace + result := is_sa_auto_mounted(spec, beggining_of_path, wl_namespace) + + sa := input[_] + is_same_sa(spec, sa.metadata.name) + is_same_namespace(sa.metadata.namespace , wl_namespace) + has_service_account_binding(sa) + + failed_path := get_failed_path(result) + fixed_path := get_fixed_path(result) + + msga := { + "alertMessage": sprintf("%v: %v in the following namespace: %v mounts service account tokens by default", [wl.kind, wl.metadata.name, wl.metadata.namespace]), + "packagename": "armo_builtins", + "alertScore": 9, + "fixPaths": fixed_path, + "failedPaths": failed_path, + "alertObject": { + "k8sApiObjects": [wl] + }, + "relatedObjects": [{ + "object": sa + }] + } +} + + +get_beginning_of_path(workload) = beggining_of_path { + spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + spec_template_spec_patterns[workload.kind] + beggining_of_path := ["spec", "template", "spec"] +} + +get_beginning_of_path(workload) = beggining_of_path { + workload.kind == "Pod" + beggining_of_path := ["spec"] +} + +get_beginning_of_path(workload) = beggining_of_path { + workload.kind == "CronJob" + beggining_of_path := ["spec", "jobTemplate", "spec", "template", "spec"] +} + + + # -- ---- For workloads -- ---- +is_sa_auto_mounted(spec, beggining_of_path, wl_namespace) = [failed_path, fix_path] { + # automountServiceAccountToken not in pod spec + not spec.automountServiceAccountToken == false + not spec.automountServiceAccountToken == true + + fix_path = { "path": sprintf("%v.automountServiceAccountToken", [concat(".", beggining_of_path)]), "value": "false"} + failed_path = "" +} + +is_sa_auto_mounted(spec, beggining_of_path, wl_namespace) = [failed_path, fix_path] { + # automountServiceAccountToken set to true in pod spec + spec.automountServiceAccountToken == true + + failed_path = sprintf("%v.automountServiceAccountToken", [concat(".", beggining_of_path)]) + fix_path = "" +} + +get_failed_path(paths) = [paths[0]] { + paths[0] != "" +} else = [] + + +get_fixed_path(paths) = [paths[1]] { + paths[1] != "" +} else = [] + + +is_same_sa(spec, serviceAccountName) { + spec.serviceAccountName == serviceAccountName +} + +is_same_sa(spec, serviceAccountName) { + not spec.serviceAccountName + serviceAccountName == "default" +} + +is_same_namespace(metadata1, metadata2) { + metadata1.namespace == metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + not metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata2.namespace + metadata1.namespace == "default" +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + metadata2.namespace == "default" +} + +# checks if RoleBinding/ClusterRoleBinding has a bind with the given ServiceAccount +has_service_account_binding(service_account) { + role_bindings := [role_binding | role_binding = input[_]; endswith(role_binding.kind, "Binding")] + role_binding := role_bindings[_] + role_binding.subjects[_].name == service_account.metadata.name + role_binding.subjects[_].namespace == service_account.metadata.namespace + role_binding.subjects[_].kind == "ServiceAccount" +} + +# checks if RoleBinding/ClusterRoleBinding has a bind with the system:authenticated group +# which gives access to all authenticated users, including service accounts +has_service_account_binding(service_account) { + role_bindings := [role_binding | role_binding = input[_]; endswith(role_binding.kind, "Binding")] + role_binding := role_bindings[_] + role_binding.subjects[_].name == "system:authenticated" +} + +# checks if RoleBinding/ClusterRoleBinding has a bind with the "system:serviceaccounts" group +# which gives access to all service accounts +has_service_account_binding(service_account) { + role_bindings := [role_binding | role_binding = input[_]; endswith(role_binding.kind, "Binding")] + role_binding := role_bindings[_] + role_binding.subjects[_].name == "system:serviceaccounts" +} diff --git a/rules/serviceaccount-token-mount/rule.metadata.json b/rules/serviceaccount-token-mount/rule.metadata.json new file mode 100644 index 000000000..c10e5c9f2 --- /dev/null +++ b/rules/serviceaccount-token-mount/rule.metadata.json @@ -0,0 +1,64 @@ +{ + "name": "serviceaccount-token-mount", + "attributes": { + "armoBuiltin": true + }, + "ruleLanguage": "Rego", + "match": [ + { + "apiGroups": [ + "" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Pod", + "ServiceAccount" + ] + }, + { + "apiGroups": [ + "rbac.authorization.k8s.io" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "RoleBinding", + "ClusterRoleBinding" + ] + }, + { + "apiGroups": [ + "apps" + ], + "apiVersions": [ + "v1" + ], + "resources": [ + "Deployment", + "ReplicaSet", + "DaemonSet", + "StatefulSet" + ] + }, + { + "apiGroups": [ + "batch" + ], + "apiVersions": [ + "*" + ], + "resources": [ + "Job", + "CronJob" + ] + } + ], + "ruleDependencies": [ + ], + "description": "fails if service account and workloads mount service account token by default", + "remediation": "Make sure that the automountServiceAccountToken field on the service account spec if set to false", + "ruleQuery": "armo_builtins" +} diff --git a/rules/serviceaccount-token-mount/test/both-mount-default/expected.json b/rules/serviceaccount-token-mount/test/both-mount-default/expected.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/both-mount-default/expected.json @@ -0,0 +1 @@ +[] diff --git a/rules/serviceaccount-token-mount/test/both-mount-default/input/file.yaml b/rules/serviceaccount-token-mount/test/both-mount-default/input/file.yaml new file mode 100644 index 000000000..d9bad8b02 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/both-mount-default/input/file.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-pd +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + hostPath: + path: /var diff --git a/rules/serviceaccount-token-mount/test/both-mount-default/input/serviceaccount.json b/rules/serviceaccount-token-mount/test/both-mount-default/input/serviceaccount.json new file mode 100644 index 000000000..365b25c6d --- /dev/null +++ b/rules/serviceaccount-token-mount/test/both-mount-default/input/serviceaccount.json @@ -0,0 +1,16 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "metadata": { + "creationTimestamp": "2022-02-07T11:21:55Z", + "name": "default", + "namespace": "default", + "resourceVersion": "410", + "uid": "5195ed3a-fa3c-46ce-8c66-32d1a83ea41f" + }, + "secrets": [ + { + "name": "default-token-sn9f8" + } + ] +} diff --git a/rules/serviceaccount-token-mount/test/both-mount/expected.json b/rules/serviceaccount-token-mount/test/both-mount/expected.json new file mode 100644 index 000000000..0d4f101c7 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/both-mount/expected.json @@ -0,0 +1,2 @@ +[ +] diff --git a/rules/serviceaccount-token-mount/test/both-mount/input/file.yaml b/rules/serviceaccount-token-mount/test/both-mount/input/file.yaml new file mode 100644 index 000000000..495720efa --- /dev/null +++ b/rules/serviceaccount-token-mount/test/both-mount/input/file.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-pd + namespace: default +spec: + automountServiceAccountToken: true + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + hostPath: + path: /var diff --git a/rules/serviceaccount-token-mount/test/both-mount/input/sa.json b/rules/serviceaccount-token-mount/test/both-mount/input/sa.json new file mode 100644 index 000000000..ab36c3bb1 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/both-mount/input/sa.json @@ -0,0 +1,17 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "automountServiceAccountToken": true, + "metadata": { + "creationTimestamp": "2022-02-07T11:21:55Z", + "name": "default", + "namespace": "default", + "resourceVersion": "410", + "uid": "5195ed3a-fa3c-46ce-8c66-32d1a83ea41f" + }, + "secrets": [ + { + "name": "default-token-sn9f8" + } + ] +} diff --git a/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/expected.json b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/expected.json new file mode 100644 index 000000000..60d95519a --- /dev/null +++ b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/expected.json @@ -0,0 +1,20 @@ +[ + { + "alertMessage": "Pod: test-pd in the following namespace: default mounts service account tokens by default", + "alertScore": 9, + "packagename": "armo_builtins", + "fixPaths": [], + "failedPaths": ["spec.automountServiceAccountToken"], + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion":"v1", + "kind":"Pod", + "metadata":{ + "name":"test-pd" + } + } + ] + } + } +] diff --git a/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/file.yaml b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/file.yaml new file mode 100644 index 000000000..495720efa --- /dev/null +++ b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/file.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-pd + namespace: default +spec: + automountServiceAccountToken: true + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + hostPath: + path: /var diff --git a/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/input/rolebinding.yaml b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/rolebinding.yaml similarity index 56% rename from rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/input/rolebinding.yaml rename to rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/rolebinding.yaml index 6ea8afd13..5eebb29f3 100644 --- a/rules/rule-can-create-modify-pod-v1/test/clusterrole-rolebinding/input/rolebinding.yaml +++ b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/rolebinding.yaml @@ -1,13 +1,13 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: pod + name: my-role-binding namespace: default subjects: -- kind: User - name: jane - apiGroup: rbac.authorization.k8s.io +- kind: ServiceAccount + name: default + namespace: default roleRef: - kind: ClusterRole - name: test - apiGroup: rbac.authorization.k8s.io \ No newline at end of file + kind: Role + name: my-role + apiGroup: rbac.authorization.k8s.io diff --git a/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/serviceaccount.json b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/serviceaccount.json new file mode 100644 index 000000000..dd44d7488 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/pod-mount-and-rb-bind/input/serviceaccount.json @@ -0,0 +1,17 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "automountServiceAccountToken": false, + "metadata": { + "creationTimestamp": "2022-02-07T11:21:55Z", + "name": "default", + "namespace": "default", + "resourceVersion": "410", + "uid": "5195ed3a-fa3c-46ce-8c66-32d1a83ea41f" + }, + "secrets": [ + { + "name": "default-token-sn9f8" + } + ] +} diff --git a/rules/strict-file-permissions-700/test/valid/expected.json b/rules/serviceaccount-token-mount/test/pod-mount/expected.json similarity index 100% rename from rules/strict-file-permissions-700/test/valid/expected.json rename to rules/serviceaccount-token-mount/test/pod-mount/expected.json diff --git a/rules/serviceaccount-token-mount/test/pod-mount/input/file.yaml b/rules/serviceaccount-token-mount/test/pod-mount/input/file.yaml new file mode 100644 index 000000000..2710c772a --- /dev/null +++ b/rules/serviceaccount-token-mount/test/pod-mount/input/file.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-pd +spec: + automountServiceAccountToken: true + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + hostPath: + path: /var diff --git a/rules/serviceaccount-token-mount/test/pod-mount/input/serviceaccount.json b/rules/serviceaccount-token-mount/test/pod-mount/input/serviceaccount.json new file mode 100644 index 000000000..dd44d7488 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/pod-mount/input/serviceaccount.json @@ -0,0 +1,17 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "automountServiceAccountToken": false, + "metadata": { + "creationTimestamp": "2022-02-07T11:21:55Z", + "name": "default", + "namespace": "default", + "resourceVersion": "410", + "uid": "5195ed3a-fa3c-46ce-8c66-32d1a83ea41f" + }, + "secrets": [ + { + "name": "default-token-sn9f8" + } + ] +} diff --git a/rules/serviceaccount-token-mount/test/sa-mount/expected.json b/rules/serviceaccount-token-mount/test/sa-mount/expected.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/sa-mount/expected.json @@ -0,0 +1 @@ +[] diff --git a/rules/serviceaccount-token-mount/test/sa-mount/input/file.yaml b/rules/serviceaccount-token-mount/test/sa-mount/input/file.yaml new file mode 100644 index 000000000..cbeb4dbeb --- /dev/null +++ b/rules/serviceaccount-token-mount/test/sa-mount/input/file.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-pd +spec: + automountServiceAccountToken: false + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + hostPath: + path: /var diff --git a/rules/serviceaccount-token-mount/test/sa-mount/input/serviceaccount.json b/rules/serviceaccount-token-mount/test/sa-mount/input/serviceaccount.json new file mode 100644 index 000000000..ab36c3bb1 --- /dev/null +++ b/rules/serviceaccount-token-mount/test/sa-mount/input/serviceaccount.json @@ -0,0 +1,17 @@ +{ + "apiVersion": "v1", + "kind": "ServiceAccount", + "automountServiceAccountToken": true, + "metadata": { + "creationTimestamp": "2022-02-07T11:21:55Z", + "name": "default", + "namespace": "default", + "resourceVersion": "410", + "uid": "5195ed3a-fa3c-46ce-8c66-32d1a83ea41f" + }, + "secrets": [ + { + "name": "default-token-sn9f8" + } + ] +} diff --git a/rules/sidecar-injection/raw.rego b/rules/sidecar-injection/raw.rego deleted file mode 100644 index 13ea71a4a..000000000 --- a/rules/sidecar-injection/raw.rego +++ /dev/null @@ -1,122 +0,0 @@ -package armo_builtins - -# =========== looks for containers with lifecycle.type "Sidecar" =========== -#pods -deny[msga] { - pod := input[_] - pod.kind == "Pod" - container := pod.spec.containers[i] - container.lifecycle.type == "Sidecar" - path := sprintf("spec.containers[%v].lifecycle.type", [format_int(i, 10)]) - msga := { - "alertMessage": sprintf("The pod: %v has a sidecar: %v", [pod.metadata.name, container.name]), - "packagename": "armo_builtins", - "alertScore": 3, - "fixPaths": [], - "failedPaths": [path], - "alertObject": { - "k8sApiObjects": [pod] - } - } -} - -#handles majority of workload resources -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - container.lifecycle.type == "Sidecar" - path := sprintf("spec.template.spec.containers[%v].lifecycle.type", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("%v: %v has a sidecar: %v", [wl.kind, wl.metadata.name, container.name]), - "packagename": "armo_builtins", - "alertScore": 3, - "fixPaths": [], - "failedPaths": [path], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - -#handles cronjob -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - container.lifecycle.type == "Sidecar" - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v].lifecycle.type", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("Cronjob: %v has a sidecar: %v", [wl.metadata.name, container.name]), - "packagename": "armo_builtins", - "alertScore": 3, - "fixPaths": [], - "failedPaths": [path], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -# =========== looks for containers "sidecar" in name =========== -#pods -deny[msga] { - pod := input[_] - pod.kind == "Pod" - container := pod.spec.containers[i] - contains(lower(container.name), "sidecar") - path := sprintf("spec.containers[%v].name", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("The pod: %v has a sidecar: %v", [pod.metadata.name, container.name]), - "packagename": "armo_builtins", - "alertScore": 3, - "failedPaths": [path], - "alertObject": { - "k8sApiObjects": [pod] - } - } -} - -#handles majority of workload resources -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - contains(lower(container.name), "sidecar") - path := sprintf("spec.template.spec.containers[%v].name", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("%v: %v has a sidecar: %v", [wl.kind, wl.metadata.name, container.name]), - "packagename": "armo_builtins", - "alertScore": 3, - "failedPaths": [path], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - -#handles cronjob -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container := wl.spec.jobTemplate.spec.template.spec.containers[i] - contains(lower(container.name), "sidecar") - path := sprintf("spec.jobTemplate.spec.template.spec.containers[%v].name", [format_int(i, 10)]) - - msga := { - "alertMessage": sprintf("Cronjob: %v has a sidecar: %v", [wl.metadata.name, container.name]), - "packagename": "armo_builtins", - "alertScore": 3, - "failedPaths": [path], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} \ No newline at end of file diff --git a/rules/sidecar-injection/rule.metadata.json b/rules/sidecar-injection/rule.metadata.json deleted file mode 100644 index b80776eae..000000000 --- a/rules/sidecar-injection/rule.metadata.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "sidecar-injection", - "attributes": { - "m$K8sThreatMatrix": "Execution::Sidecar injection", - "armoBuiltin": true - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [ - "*" - ], - "apiVersions": [ - "*" - ], - "resources": [ - "Pod", - "Deployment", - "ReplicaSet", - "DaemonSet", - "StatefulSet", - "Job", - "CronJob" - ] - } - ], - "ruleDependencies": [], - "description": "fails if container lifecycle field is set to sidecar, or if container name includes 'sidecar'.", - "remediation": "", - "ruleQuery": "" - } \ No newline at end of file diff --git a/rules/strict-file-owners-root/filter.rego b/rules/strict-file-owners-root/filter.rego deleted file mode 100644 index 83f5ea3cb..000000000 --- a/rules/strict-file-owners-root/filter.rego +++ /dev/null @@ -1,23 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# Filter out non-host-sensor as well. -# If no kindFilter - match every kind -deny[msg] { - obj = input[_] - obj.apiVersion == "hostdata.kubescape.cloud/v1beta0" - filter_kind(obj.kind) - msg := {"alertObject": {"externalObjects": obj}} -} - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# If no kindFilter - match everything -filter_kind(kind) { - kind in data.postureControlInputs.kindFilter -} - -filter_kind(kind) { - not data.postureControlInputs.kindFilter -} diff --git a/rules/strict-file-owners-root/raw.rego b/rules/strict-file-owners-root/raw.rego deleted file mode 100644 index b25d085b8..000000000 --- a/rules/strict-file-owners-root/raw.rego +++ /dev/null @@ -1,91 +0,0 @@ -package armo_builtins - -import future.keywords.in - -import data.cautils - -# Fail for every file in data.postureControlInputs.fileObjPath -# if the owners of the file are not `root:root`. -# Expect (supposed to be fixed per control, not user configurable): -# (required) data.postureControlInputs.fileObjPath - list of paths strings. The item delimiter is `.`. -# (optional) data.postureControlInputs.kindFilter -# (optional) data.postureControlInputs.pathGlob -deny[msg] { - # Filter out irrelevent resources - obj = input[_] - obj.apiVersion == "hostdata.kubescape.cloud/v1beta0" - filter_kind(obj.kind) - - # Get the file info using the input object-paths - rawObjPath = data.postureControlInputs.fileObjPath[_] - objPath := split(rawObjPath, "/") - subject := object.get(obj, objPath, false) - subject != false - - # Run the test for every file - files := get_files(subject) - file = files[file_index] - file_path_glob(file.path) - - # Actual ownership test - cautils.is_not_strict_conf_ownership(file.ownership) - - # Filter out irrelevant data from the alert object - file_filtered := filter_file(obj, objPath, file_index) - obj_filtered := json.filter(obj, ["apiVersion", "kind", "metadata"]) - output := object.union(file_filtered, obj_filtered) - - msg := { - "alertMessage": sprintf("%s is not owned by `root:root`", [file.path]), - "alertScore": 2, - "failedPaths": [], - "fixPaths": [], - "fixCommand": sprintf("chown root:root %s", [file.path]), - "packagename": "armo_builtins", - "alertObject": {"externalObjects": output}, - } -} - -# Always return a list -get_files(obj) = files { - is_array(obj) - files = obj -} - -get_files(obj) = files { - not is_array(obj) - files = [obj] -} - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# If no kindFilter - match everything -filter_kind(kind) { - kind in data.postureControlInputs.kindFilter -} - -filter_kind(kind) { - not data.postureControlInputs.kindFilter -} - -# Filter file path globs from data.postureControlInputs.pathGlob -file_path_glob(path) { - patterns = data.postureControlInputs.pathGlob - count({true | patterns[i]; glob.match(patterns[i], null, path)}) > 0 -} - -file_path_glob(path) { - not data.postureControlInputs.pathGlob -} - -# Filter only the current file -filter_file(obj, objPath, file_index) = ret { - is_array(object.get(obj, objPath, false)) - full_path := array.concat(objPath, [format_int(file_index, 10)]) - final_path := concat("/", full_path) - ret := json.filter(obj, [final_path]) -} - -filter_file(obj, objPath, file_index) = ret { - not is_array(object.get(obj, objPath, false)) - ret = object.filter(obj, objPath) -} diff --git a/rules/strict-file-owners-root/rule.metadata.json b/rules/strict-file-owners-root/rule.metadata.json deleted file mode 100644 index 5e000b3ae..000000000 --- a/rules/strict-file-owners-root/rule.metadata.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "strict-file-owners-root", - "attributes": { - "armoBuiltin": true, - "hostSensorRule": "true", - "useFromKubescapeVersion": "v2.0.170" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [], - "apiVersions": [], - "resources": [] - } - ], - "dynamicMatch": [ - { - "apiGroups": [ - "hostdata.kubescape.cloud" - ], - "apiVersions": [ - "v1beta0" - ], - "resources": [ - "KubeletInfo", - "KubeProxyInfo", - "ControlPlaneInfo" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "Ensure that file owners are `root:root`", - "remediation": "Set the owners of the failed file to `root:root`", - "ruleQuery": "" - } \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/invalid-group/data.json b/rules/strict-file-owners-root/test/invalid-group/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-owners-root/test/invalid-group/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/invalid-group/expected.json b/rules/strict-file-owners-root/test/invalid-group/expected.json deleted file mode 100644 index 29b2602e2..000000000 --- a/rules/strict-file-owners-root/test/invalid-group/expected.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "fixCommand": "chown root:root /var/lib/minikube/certs/ca.crt", - "alertMessage": "/var/lib/minikube/certs/ca.crt is not owned by `root:root`", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "ownership": { - "gid": 1, - "uid": 0 - }, - "path": "/var/lib/minikube/certs/ca.crt", - "permissions": 432 - } - }, - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - } - } - } - } - ] \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/invalid-group/input/kubelet-info.json b/rules/strict-file-owners-root/test/invalid-group/input/kubelet-info.json deleted file mode 100644 index 055a44a44..000000000 --- a/rules/strict-file-owners-root/test/invalid-group/input/kubelet-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 0, - "gid": 1 - }, - "permissions": 432 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/invalid-user/data.json b/rules/strict-file-owners-root/test/invalid-user/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-owners-root/test/invalid-user/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/invalid-user/expected.json b/rules/strict-file-owners-root/test/invalid-user/expected.json deleted file mode 100644 index 4345377f7..000000000 --- a/rules/strict-file-owners-root/test/invalid-user/expected.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "fixCommand": "chown root:root /var/lib/minikube/certs/ca.crt", - "alertMessage": "/var/lib/minikube/certs/ca.crt is not owned by `root:root`", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "ownership": { - "gid": 0, - "uid": 1 - }, - "path": "/var/lib/minikube/certs/ca.crt", - "permissions": 257 - } - }, - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - } - } - } - } - ] \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/invalid-user/input/kubelet-info.json b/rules/strict-file-owners-root/test/invalid-user/input/kubelet-info.json deleted file mode 100644 index 733d77734..000000000 --- a/rules/strict-file-owners-root/test/invalid-user/input/kubelet-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 1, - "gid": 0 - }, - "permissions": 257 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/valid/data.json b/rules/strict-file-owners-root/test/valid/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-owners-root/test/valid/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-owners-root/test/valid/input/kubelet-info.json b/rules/strict-file-owners-root/test/valid/input/kubelet-info.json deleted file mode 100644 index ba9f1d5d7..000000000 --- a/rules/strict-file-owners-root/test/valid/input/kubelet-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 0, - "gid": 0 - }, - "permissions": 384 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-600/filter.rego b/rules/strict-file-permissions-600/filter.rego deleted file mode 100644 index 83f5ea3cb..000000000 --- a/rules/strict-file-permissions-600/filter.rego +++ /dev/null @@ -1,23 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# Filter out non-host-sensor as well. -# If no kindFilter - match every kind -deny[msg] { - obj = input[_] - obj.apiVersion == "hostdata.kubescape.cloud/v1beta0" - filter_kind(obj.kind) - msg := {"alertObject": {"externalObjects": obj}} -} - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# If no kindFilter - match everything -filter_kind(kind) { - kind in data.postureControlInputs.kindFilter -} - -filter_kind(kind) { - not data.postureControlInputs.kindFilter -} diff --git a/rules/strict-file-permissions-600/raw.rego b/rules/strict-file-permissions-600/raw.rego deleted file mode 100644 index 7dc6c87fe..000000000 --- a/rules/strict-file-permissions-600/raw.rego +++ /dev/null @@ -1,93 +0,0 @@ -package armo_builtins - -import future.keywords.in - -import data.cautils - -# Fail for every file in data.postureControlInputs.fileObjPath -# if the permissions of the file are more permissive that 600. -# Expect (supposed to be fixed per control, not user configurable): -# (required) data.postureControlInputs.fileObjPath - list of paths strings. The item delimiter is `.`. -# (optional) data.postureControlInputs.kindFilter -# (optional) data.postureControlInputs.pathGlob -deny[msg] { - # Filter out irrelevent resources - obj = input[_] - obj.apiVersion == "hostdata.kubescape.cloud/v1beta0" - filter_kind(obj.kind) - - # Get the file info using the input object-paths - rawObjPath = data.postureControlInputs.fileObjPath[_] - objPath := split(rawObjPath, "/") - subject := object.get(obj, objPath, false) - subject != false - - # Run the test for every file - files := get_files(subject) - file = files[file_index] - file_path_glob(file.path) - - # Actual permissions test - allowed_perms := 384 # 0o600 == 384 - not cautils.unix_permissions_allow(allowed_perms, file.permissions) - - # Filter out irrelevant data from the alert object - file_filtered := filter_file(obj, objPath, file_index) - obj_filtered := json.filter(obj, ["apiVersion", "kind", "metadata"]) - output := object.union(file_filtered, obj_filtered) - - alert := sprintf("the permissions of %s are too permissive. maximum allowed: %o. actual: %o", [file.path, allowed_perms, file.permissions]) - msg := { - "alertMessage": alert, - "alertScore": 2, - "failedPaths": [], - "fixPaths": [], - "fixCommand": sprintf("chmod %o %s", [allowed_perms, file.path]), - "packagename": "armo_builtins", - "alertObject": {"externalObjects": output}, - } -} - -# Return always a list -get_files(obj) = files { - is_array(obj) - files = obj -} - -get_files(obj) = files { - not is_array(obj) - files = [obj] -} - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# If no kindFilter - match everything -filter_kind(kind) { - kind in data.postureControlInputs.kindFilter -} - -filter_kind(kind) { - not data.postureControlInputs.kindFilter -} - -# Filter file path globs from data.postureControlInputs.pathGlob -file_path_glob(path) { - patterns = data.postureControlInputs.pathGlob - count({true | patterns[i]; glob.match(patterns[i], null, path)}) > 0 -} - -file_path_glob(path) { - not data.postureControlInputs.pathGlob -} - -# Filter only the current file -filter_file(obj, objPath, file_index) = ret { - is_array(object.get(obj, objPath, false)) - full_path := array.concat(objPath, [format_int(file_index, 10)]) - final_path := concat("/", full_path) - ret := json.filter(obj, [final_path]) -} - -filter_file(obj, objPath, file_index) = ret { - not is_array(object.get(obj, objPath, false)) - ret = object.filter(obj, objPath) -} \ No newline at end of file diff --git a/rules/strict-file-permissions-600/rule.metadata.json b/rules/strict-file-permissions-600/rule.metadata.json deleted file mode 100644 index a6466e0cc..000000000 --- a/rules/strict-file-permissions-600/rule.metadata.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "strict-file-permissions-600", - "attributes": { - "armoBuiltin": true, - "hostSensorRule": "true", - "useFromKubescapeVersion": "v2.0.159" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [], - "apiVersions": [], - "resources": [] - } - ], - "dynamicMatch": [ - { - "apiGroups": [ - "hostdata.kubescape.cloud" - ], - "apiVersions": [ - "v1beta0" - ], - "resources": [ - "KubeletInfo", - "KubeProxyInfo", - "ControlPlaneInfo" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "Ensure that file has permissions of 600 or more restrictive", - "remediation": "Set the permission of the failed file file to 600 or more restrictive", - "ruleQuery": "" - } \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/invalid-everyone/data.json b/rules/strict-file-permissions-600/test/invalid-everyone/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-permissions-600/test/invalid-everyone/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/invalid-everyone/expected.json b/rules/strict-file-permissions-600/test/invalid-everyone/expected.json deleted file mode 100644 index 9609bda80..000000000 --- a/rules/strict-file-permissions-600/test/invalid-everyone/expected.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "fixCommand": "chmod 600 /var/lib/minikube/certs/ca.crt", - "alertMessage": "the permissions of /var/lib/minikube/certs/ca.crt are too permissive. maximum allowed: 600. actual: 401", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "ownership": { - "gid": 0, - "uid": 1 - }, - "path": "/var/lib/minikube/certs/ca.crt", - "permissions": 257 - } - }, - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - } - } - } - } -] \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/invalid-everyone/input/kube-proxy-info.json b/rules/strict-file-permissions-600/test/invalid-everyone/input/kube-proxy-info.json deleted file mode 100644 index 733d77734..000000000 --- a/rules/strict-file-permissions-600/test/invalid-everyone/input/kube-proxy-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 1, - "gid": 0 - }, - "permissions": 257 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/invalid-group/data.json b/rules/strict-file-permissions-600/test/invalid-group/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-permissions-600/test/invalid-group/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/invalid-group/expected.json b/rules/strict-file-permissions-600/test/invalid-group/expected.json deleted file mode 100644 index 13e8e0925..000000000 --- a/rules/strict-file-permissions-600/test/invalid-group/expected.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "fixCommand": "chmod 600 /var/lib/minikube/certs/ca.crt", - "alertMessage": "the permissions of /var/lib/minikube/certs/ca.crt are too permissive. maximum allowed: 600. actual: 660", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "ownership": { - "gid": 1, - "uid": 0 - }, - "path": "/var/lib/minikube/certs/ca.crt", - "permissions": 432 - } - }, - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - } - } - } - } -] \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/invalid-group/input/kubelet-info.json b/rules/strict-file-permissions-600/test/invalid-group/input/kubelet-info.json deleted file mode 100644 index 055a44a44..000000000 --- a/rules/strict-file-permissions-600/test/invalid-group/input/kubelet-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 0, - "gid": 1 - }, - "permissions": 432 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/valid/data.json b/rules/strict-file-permissions-600/test/valid/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-permissions-600/test/valid/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-600/test/valid/input/kubelet-info.json b/rules/strict-file-permissions-600/test/valid/input/kubelet-info.json deleted file mode 100644 index ba9f1d5d7..000000000 --- a/rules/strict-file-permissions-600/test/valid/input/kubelet-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 0, - "gid": 0 - }, - "permissions": 384 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-700/filter.rego b/rules/strict-file-permissions-700/filter.rego deleted file mode 100644 index 83f5ea3cb..000000000 --- a/rules/strict-file-permissions-700/filter.rego +++ /dev/null @@ -1,23 +0,0 @@ -package armo_builtins - -import future.keywords.in - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# Filter out non-host-sensor as well. -# If no kindFilter - match every kind -deny[msg] { - obj = input[_] - obj.apiVersion == "hostdata.kubescape.cloud/v1beta0" - filter_kind(obj.kind) - msg := {"alertObject": {"externalObjects": obj}} -} - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# If no kindFilter - match everything -filter_kind(kind) { - kind in data.postureControlInputs.kindFilter -} - -filter_kind(kind) { - not data.postureControlInputs.kindFilter -} diff --git a/rules/strict-file-permissions-700/raw.rego b/rules/strict-file-permissions-700/raw.rego deleted file mode 100644 index 41ca8df3c..000000000 --- a/rules/strict-file-permissions-700/raw.rego +++ /dev/null @@ -1,93 +0,0 @@ -package armo_builtins - -import future.keywords.in - -import data.cautils - -# Fail for every file in data.postureControlInputs.fileObjPath -# if the permissions of the file are more permissive that 600. -# Expect (supposed to be fixed per control, not user configurable): -# (required) data.postureControlInputs.fileObjPath - list of paths strings. The item delimiter is `.`. -# (optional) data.postureControlInputs.kindFilter -# (optional) data.postureControlInputs.pathGlob -deny[msg] { - # Filter out irrelevent resources - obj = input[_] - obj.apiVersion == "hostdata.kubescape.cloud/v1beta0" - filter_kind(obj.kind) - - # Get the file info using the input object-paths - rawObjPath = data.postureControlInputs.fileObjPath[_] - objPath := split(rawObjPath, "/") - subject := object.get(obj, objPath, false) - subject != false - - # Run the test for every file - files := get_files(subject) - file = files[file_index] - file_path_glob(file.path) - - # Actual permissions test - allowed_perms := 448 # 0o700 == 448 - not cautils.unix_permissions_allow(allowed_perms, file.permissions) - - # Filter out irrelevant data from the alert object - file_filtered := filter_file(obj, objPath, file_index) - obj_filtered := json.filter(obj, ["apiVersion", "kind", "metadata"]) - output := object.union(file_filtered, obj_filtered) - - alert := sprintf("the permissions of %s are too permissive. maximum allowed: %o. actual: %o", [file.path, allowed_perms, file.permissions]) - msg := { - "alertMessage": alert, - "alertScore": 2, - "failedPaths": [], - "fixPaths": [], - "fixCommand": sprintf("chmod %o %s", [allowed_perms, file.path]), - "packagename": "armo_builtins", - "alertObject": {"externalObjects": output}, - } -} - -# Return always a list -get_files(obj) = files { - is_array(obj) - files = obj -} - -get_files(obj) = files { - not is_array(obj) - files = [obj] -} - -# Filter only kinds that are in data.postureControlInputs.kindFilter. -# If no kindFilter - match everything -filter_kind(kind) { - kind in data.postureControlInputs.kindFilter -} - -filter_kind(kind) { - not data.postureControlInputs.kindFilter -} - -# Filter file path globs from data.postureControlInputs.pathGlob -file_path_glob(path) { - patterns = data.postureControlInputs.pathGlob - count({true | patterns[i]; glob.match(patterns[i], null, path)}) > 0 -} - -file_path_glob(path) { - not data.postureControlInputs.pathGlob -} - -# Filter only the current file -filter_file(obj, objPath, file_index) = ret { - is_array(object.get(obj, objPath, false)) - full_path := array.concat(objPath, [format_int(file_index, 10)]) - final_path := concat("/", full_path) - ret := json.filter(obj, [final_path]) -} - -filter_file(obj, objPath, file_index) = ret { - not is_array(object.get(obj, objPath, false)) - ret = object.filter(obj, objPath) -} \ No newline at end of file diff --git a/rules/strict-file-permissions-700/rule.metadata.json b/rules/strict-file-permissions-700/rule.metadata.json deleted file mode 100644 index 4e2d3330d..000000000 --- a/rules/strict-file-permissions-700/rule.metadata.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "strict-file-permissions-700", - "attributes": { - "armoBuiltin": true, - "hostSensorRule": "true", - "useFromKubescapeVersion": "v2.0.159" - }, - "ruleLanguage": "Rego", - "match": [ - { - "apiGroups": [], - "apiVersions": [], - "resources": [] - } - ], - "dynamicMatch": [ - { - "apiGroups": [ - "hostdata.kubescape.cloud" - ], - "apiVersions": [ - "v1beta0" - ], - "resources": [ - "KubeletInfo", - "KubeProxyInfo", - "ControlPlaneInfo" - ] - } - ], - "ruleDependencies": [ - { - "packageName": "cautils" - } - ], - "description": "Ensure that file has permissions of 700 or more restrictive", - "remediation": "Set the permission of the failed file file to 700 or more restrictive", - "ruleQuery": "" - } \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/invalid-everyone/data.json b/rules/strict-file-permissions-700/test/invalid-everyone/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-permissions-700/test/invalid-everyone/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/invalid-everyone/expected.json b/rules/strict-file-permissions-700/test/invalid-everyone/expected.json deleted file mode 100644 index 8aa11931c..000000000 --- a/rules/strict-file-permissions-700/test/invalid-everyone/expected.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "fixCommand": "chmod 700 /var/lib/minikube/certs/ca.crt", - "alertMessage": "the permissions of /var/lib/minikube/certs/ca.crt are too permissive. maximum allowed: 700. actual: 401", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "ownership": { - "gid": 0, - "uid": 1 - }, - "path": "/var/lib/minikube/certs/ca.crt", - "permissions": 257 - } - }, - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - } - } - } - } -] \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/invalid-everyone/input/kube-proxy-info.json b/rules/strict-file-permissions-700/test/invalid-everyone/input/kube-proxy-info.json deleted file mode 100644 index 733d77734..000000000 --- a/rules/strict-file-permissions-700/test/invalid-everyone/input/kube-proxy-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 1, - "gid": 0 - }, - "permissions": 257 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/invalid-group/data.json b/rules/strict-file-permissions-700/test/invalid-group/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-permissions-700/test/invalid-group/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/invalid-group/expected.json b/rules/strict-file-permissions-700/test/invalid-group/expected.json deleted file mode 100644 index 5e42bae5b..000000000 --- a/rules/strict-file-permissions-700/test/invalid-group/expected.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "fixCommand": "chmod 700 /var/lib/minikube/certs/ca.crt", - "alertMessage": "the permissions of /var/lib/minikube/certs/ca.crt are too permissive. maximum allowed: 700. actual: 660", - "failedPaths": [], - "fixPaths": [], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 2, - "alertObject": { - "externalObjects": { - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "ownership": { - "gid": 1, - "uid": 0 - }, - "path": "/var/lib/minikube/certs/ca.crt", - "permissions": 432 - } - }, - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - } - } - } - } -] \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/invalid-group/input/kubelet-info.json b/rules/strict-file-permissions-700/test/invalid-group/input/kubelet-info.json deleted file mode 100644 index 055a44a44..000000000 --- a/rules/strict-file-permissions-700/test/invalid-group/input/kubelet-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 0, - "gid": 1 - }, - "permissions": 432 - } - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/valid/data.json b/rules/strict-file-permissions-700/test/valid/data.json deleted file mode 100644 index c7327c654..000000000 --- a/rules/strict-file-permissions-700/test/valid/data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "postureControlInputs": { - "fileObjPath": [ - "data/configFile" - ] - } -} \ No newline at end of file diff --git a/rules/strict-file-permissions-700/test/valid/input/kubelet-info.json b/rules/strict-file-permissions-700/test/valid/input/kubelet-info.json deleted file mode 100644 index ba9f1d5d7..000000000 --- a/rules/strict-file-permissions-700/test/valid/input/kubelet-info.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "apiVersion": "hostdata.kubescape.cloud/v1beta0", - "kind": "KubeletInfo", - "metadata": { - "name": "minikube" - }, - "data": { - "cmdLine": "/var/lib/minikube/binaries/v1.23.1/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=minikube --housekeeping-interval=5m --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.49.2 ", - "configFile": { - "path": "/var/lib/minikube/certs/ca.crt", - "ownership": { - "uid": 0, - "gid": 0 - }, - "permissions": 384 - } - } -} \ No newline at end of file diff --git a/rules/user-id-less-than-thousands/raw.rego b/rules/user-id-less-than-thousands/raw.rego deleted file mode 100644 index 9103299ad..000000000 --- a/rules/user-id-less-than-thousands/raw.rego +++ /dev/null @@ -1,172 +0,0 @@ -package armo_builtins - -# TODO - FIX FAILED PATHS IF THE CONTROL WILL BE ACTIVE AGAIN - -# Fails if pod has container configured to run with id less than 1000 -deny[msga] { - pod := input[_] - pod.kind == "Pod" - container := pod.spec.containers[i] - beggining_of_path := "spec." - result := is_root_container(container, beggining_of_path, i) - msga := { - "alertMessage": sprintf("container: %v in pod: %v runs with id less than 1000", [container.name, pod.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "fixPaths": [], - "failedPaths": [result], - "alertObject": { - "k8sApiObjects": [pod] - } - } -} - -# Fails if pod has container configured to run with id less than 1000 -deny[msga] { - pod := input[_] - pod.kind == "Pod" - container := pod.spec.containers[i] - beggining_of_path := "" - result := is_root_pod(pod, container, beggining_of_path) - msga := { - "alertMessage": sprintf("container: %v in pod: %v runs with id less than 1000", [container.name, pod.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "fixPaths": [], - "failedPaths": [result], - "alertObject": { - "k8sApiObjects": [pod] - } - } -} - - - -# Fails if workload has container configured to run with id less than 1000 -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - beggining_of_path := "spec.template.spec." - result := is_root_container(container, beggining_of_path, i) - msga := { - "alertMessage": sprintf("container :%v in %v: %v runs with id less than 1000", [container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "fixPaths": [], - "failedPaths": [result], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - -# Fails if workload has container configured to run with id less than 1000 -deny[msga] { - wl := input[_] - spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} - spec_template_spec_patterns[wl.kind] - container := wl.spec.template.spec.containers[i] - beggining_of_path := "spec.template." - result := is_root_pod(wl.spec.template, container, beggining_of_path) - msga := { - "alertMessage": sprintf("container :%v in %v: %v runs with id less than 1000", [container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "fixPaths": [], - "failedPaths": [result], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -# Fails if cronjob has a container configured to run with id less than 1000 -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container = wl.spec.jobTemplate.spec.template.spec.containers[i] - beggining_of_path := "spec.jobTemplate.spec.template.spec." - result := is_root_container(container, beggining_of_path, i) - msga := { - "alertMessage": sprintf("container :%v in %v: %v runs with id less than 1000", [container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "fixPaths": [], - "failedPaths": [result], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - - -# Fails if workload has container configured to run with id less than 1000 -deny[msga] { - wl := input[_] - wl.kind == "CronJob" - container = wl.spec.jobTemplate.spec.template.spec.containers[i] - beggining_of_path := "spec.jobTemplate.spec.template." - result := is_root_pod(wl.spec.jobTemplate.spec.template, container, beggining_of_path) - msga := { - "alertMessage": sprintf("container :%v in %v: %v runs with id less than 1000", [container.name, wl.kind, wl.metadata.name]), - "packagename": "armo_builtins", - "alertScore": 7, - "fixPaths": [], - "failedPaths": [result], - "alertObject": { - "k8sApiObjects": [wl] - } - } -} - - -is_root_pod(pod, container, beggining_of_path) = path { - not container.securityContext.runAsGroup - not container.securityContext.runAsUser - pod.spec.securityContext.runAsUser < 1000 - not pod.spec.securityContext.runAsGroup - path = sprintf("%vspec.securityContext.runAsUser", [beggining_of_path]) -} - -is_root_pod(pod, container, beggining_of_path) = path { - not container.securityContext.runAsUser - not container.securityContext.runAsGroup - pod.spec.securityContext.runAsGroup < 1000 - not pod.spec.securityContext.runAsUser - path = sprintf("%vspec.securityContext.runAsGroup", [beggining_of_path]) -} - -is_root_pod(pod, container, beggining_of_path) = path { - pod.spec.securityContext.runAsGroup > 1000 - pod.spec.securityContext.runAsUser < 1000 - path = sprintf("%vspec.securityContext.runAsUser", [beggining_of_path]) -} - -is_root_pod(pod, container, beggining_of_path) = path { - pod.spec.securityContext.runAsGroup < 1000 - pod.spec.securityContext.runAsUser > 1000 - path = sprintf("%vspec.securityContext.runAsGroup", [beggining_of_path]) -} - -is_root_pod(pod, container, beggining_of_path) = path { - pod.spec.securityContext.runAsGroup < 1000 - pod.spec.securityContext.runAsUser < 1000 - path = sprintf("%vspec.securityContext", [beggining_of_path]) -} - - -is_root_container(container, beggining_of_path, i) = path { - container.securityContext.runAsUser < 1000 - not container.securityContext.runAsGroup - path = sprintf("%vcontainers[%v].securityContext.runAsUser", [beggining_of_path, format_int(i, 10)]) -} - -is_root_container(container, beggining_of_path, i) = path { - container.securityContext.runAsGroup < 1000 - not container.securityContext.runAsUser - path = sprintf("%vcontainers[%v].securityContext.runAsGroup", [beggining_of_path, format_int(i, 10)]) -} \ No newline at end of file diff --git a/rules/user-id-less-than-thousands/test/cronjob/expected.json b/rules/user-id-less-than-thousands/test/cronjob/expected.json deleted file mode 100644 index 618c01e43..000000000 --- a/rules/user-id-less-than-thousands/test/cronjob/expected.json +++ /dev/null @@ -1,23 +0,0 @@ -[ - { - "alertMessage": "container :hello in CronJob: hello runs with id less than 1000", - "fixPaths": [], - "failedPaths": [ - "spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsUser" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "batch/v1beta1", - "kind": "CronJob", - "metadata": { - "name": "hello" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/user-id-less-than-thousands/test/cronjob/input/cronjob.yaml b/rules/user-id-less-than-thousands/test/cronjob/input/cronjob.yaml deleted file mode 100644 index e9a0fc5d6..000000000 --- a/rules/user-id-less-than-thousands/test/cronjob/input/cronjob.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: batch/v1beta1 -kind: CronJob -metadata: - name: hello -spec: - schedule: "*/1 * * * *" - jobTemplate: - spec: - template: - spec: - spec : - securityContext : - runAsUser : 1000 - runAsGroup : 3000 - serviceAccountName: kubernetes-dashboard - restartPolicy: OnFailure - containers: - - name: hello - image: busybox:latest - securityContext : - runAsUser : 1 - capabilities : - add : [ "NET_ADMIN", "SYS_TIME", "SYS_ADMIN"] - env : - - - name : pwd - value : "Hpwd" - imagePullPolicy: IfNotPresent - command: - - /bin/sh - - -c - - date; echo Hello from the Kubernetes cluster diff --git a/rules/user-id-less-than-thousands/test/pod/expected.json b/rules/user-id-less-than-thousands/test/pod/expected.json deleted file mode 100644 index 5380cdf13..000000000 --- a/rules/user-id-less-than-thousands/test/pod/expected.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "alertMessage": "container: command-demo-container in pod: command-demo runs with id less than 1000", - "fixPaths": [], - "failedPaths": [ - "spec.securityContext.runAsUser" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "labels": { - "purpose": "demonstrate-command" - }, - "name": "command-demo" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/user-id-less-than-thousands/test/pod/input/pod.yaml b/rules/user-id-less-than-thousands/test/pod/input/pod.yaml deleted file mode 100644 index 29bb0eea7..000000000 --- a/rules/user-id-less-than-thousands/test/pod/input/pod.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: command-demo - labels: - purpose: demonstrate-command -spec: - securityContext : - runAsUser : 999 - runAsGroup: 3000 - containers: - - name: command-demo-container - image: debian - command: ["sudo printenv"] - args: ["HOSTNAME", "KUBERNETES_PORT"] - restartPolicy: OnFailure \ No newline at end of file diff --git a/rules/user-id-less-than-thousands/test/workloads/expected.json b/rules/user-id-less-than-thousands/test/workloads/expected.json deleted file mode 100644 index 88d957a0d..000000000 --- a/rules/user-id-less-than-thousands/test/workloads/expected.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "alertMessage": "container :test-container in Deployment: test2 runs with id less than 1000", - "fixPaths": [], - "failedPaths": [ - "spec.template.spec.securityContext.runAsUser" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "labels": { - "app": "audit-pod" - }, - "name": "test2" - } - } - ] - } - }, - { - "alertMessage": "container :test-container2 in Deployment: test2 runs with id less than 1000", - "fixPaths": [], - "failedPaths": [ - "spec.template.spec.securityContext.runAsUser" - ], - "ruleStatus": "", - "packagename": "armo_builtins", - "alertScore": 7, - "alertObject": { - "k8sApiObjects": [ - { - "apiVersion": "apps/v1", - "kind": "Deployment", - "metadata": { - "labels": { - "app": "audit-pod" - }, - "name": "test2" - } - } - ] - } - } -] \ No newline at end of file diff --git a/rules/user-id-less-than-thousands/test/workloads/input/deployment.yaml b/rules/user-id-less-than-thousands/test/workloads/input/deployment.yaml deleted file mode 100644 index f104fba15..000000000 --- a/rules/user-id-less-than-thousands/test/workloads/input/deployment.yaml +++ /dev/null @@ -1,39 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: default - name: test2 - labels: - app: audit-pod -spec: - replicas: 3 - selector: - matchLabels: - app: audit-pod - template: - metadata: - labels: - app: audit-pod - spec : - securityContext : - runAsUser : 999 - containers : - - - name : test-container - env : - - - name : random - value : "Hello from the environment" - image : hashicorp/http-echo:0.2.3 - securityContext : - allowPrivilegeEscalation : true - privileged: true - - - name : test-container2 - env : - - - name : azure_batch_key - value : "Hello from the environment" - image : hashicorp/http-echo:0.2.3 - command : [ "sudo cat" ] - args : [ "HOSTNAME", "KUBERNETES_PORT" ] \ No newline at end of file diff --git a/rules/workload-mounted-configmap/raw.rego b/rules/workload-mounted-configmap/raw.rego new file mode 100644 index 000000000..ad01ec974 --- /dev/null +++ b/rules/workload-mounted-configmap/raw.rego @@ -0,0 +1,99 @@ +package armo_builtins + +deny[msga] { + resource := input[_] + volumes_path := get_volumes_path(resource) + volumes := object.get(resource, volumes_path, []) + volume := volumes[i] + volume.configMap + + configMap := input[_] + configMap.kind == "ConfigMap" + configMap.metadata.name == volume.configMap.name + is_same_namespace(configMap.metadata, resource.metadata) + + containers_path := get_containers_path(resource) + containers := object.get(resource, containers_path, []) + container := containers[j] + container.volumeMounts + + # check if volume is mounted + container.volumeMounts[_].name == volume.name + + failedPaths := sprintf("%s[%d].volumeMounts", [concat(".", containers_path), j]) + + + msga := { + "alertMessage": sprintf("%v: %v has mounted configMap", [resource.kind, resource.metadata.name]), + "packagename": "armo_builtins", + "failedPaths": [failedPaths], + "fixPaths":[], + "alertObject": { + "k8sApiObjects": [resource] + }, + "relatedObjects": [{ + "object": configMap + }] + } +} + + + +# get_containers_path - get resource containers paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} +get_containers_path(resource) := result { + resource_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + resource_kinds[resource.kind] + result = ["spec", "template", "spec", "containers"] +} + +# get_containers_path - get resource containers paths for "Pod" +get_containers_path(resource) := result { + resource.kind == "Pod" + result = ["spec", "containers"] +} + +# get_containers_path - get resource containers paths for "CronJob" +get_containers_path(resource) := result { + resource.kind == "CronJob" + result = ["spec", "jobTemplate", "spec", "template", "spec", "containers"] +} + +# get_volume_path - get resource volumes paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} +get_volumes_path(resource) := result { + resource_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + resource_kinds[resource.kind] + result = ["spec", "template", "spec", "volumes"] +} + +# get_volumes_path - get resource volumes paths for "Pod" +get_volumes_path(resource) := result { + resource.kind == "Pod" + result = ["spec", "volumes"] +} + +# get_volumes_path - get resource volumes paths for "CronJob" +get_volumes_path(resource) := result { + resource.kind == "CronJob" + result = ["spec", "jobTemplate", "spec", "template", "spec", "volumes"] +} + + + +is_same_namespace(metadata1, metadata2) { + metadata1.namespace == metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + not metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata2.namespace + metadata1.namespace == "default" +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + metadata2.namespace == "default" +} \ No newline at end of file diff --git a/rules/pod-specific-version-tag/rule.metadata.json b/rules/workload-mounted-configmap/rule.metadata.json similarity index 74% rename from rules/pod-specific-version-tag/rule.metadata.json rename to rules/workload-mounted-configmap/rule.metadata.json index d80b93dfc..acef14c9c 100644 --- a/rules/pod-specific-version-tag/rule.metadata.json +++ b/rules/workload-mounted-configmap/rule.metadata.json @@ -1,5 +1,5 @@ { - "name": "pod-specific-version-tag", + "name": "workload-mounted-configmap", "attributes": { "armoBuiltin": true }, @@ -13,7 +13,8 @@ "v1" ], "resources": [ - "Pod" + "Pod", + "ConfigMap" ] }, { @@ -43,9 +44,7 @@ ] } ], - "ruleDependencies": [ - ], - "description": "Fails if container has image tag set to latest", - "remediation": "Make sure you define a specific image tag for container and not 'latest'.", + "description": "fails if workload mounts ConfigMaps", + "remediation": "", "ruleQuery": "armo_builtins" } \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/failed_pod/expected.json b/rules/workload-mounted-configmap/test/failed_pod/expected.json new file mode 100644 index 000000000..fc1d607bc --- /dev/null +++ b/rules/workload-mounted-configmap/test/failed_pod/expected.json @@ -0,0 +1,24 @@ +[ + { + "alertMessage": "Pod: mypod has mounted configMap", + "failedPaths": [ + "spec.containers[0].volumeMounts" + ], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 0, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "mypod" + } + } + ] + + } + } +] \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/failed_pod/input/configmap.yaml b/rules/workload-mounted-configmap/test/failed_pod/input/configmap.yaml new file mode 100644 index 000000000..c5fd26646 --- /dev/null +++ b/rules/workload-mounted-configmap/test/failed_pod/input/configmap.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: myconfigmap + namespace: mynamespace +data: + key1: value1 + key2: value2 \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/failed_pod/input/pod.yaml b/rules/workload-mounted-configmap/test/failed_pod/input/pod.yaml new file mode 100644 index 000000000..eb6ee4dd5 --- /dev/null +++ b/rules/workload-mounted-configmap/test/failed_pod/input/pod.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: mynamespace +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + - name: configvolume + mountPath: "/etc/foo" + volumes: + - name: foo + secret: + secretName: mysecret + optional: true + - name: configvolume + configMap: + name: myconfigmap \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/success_different_namespaces/expected.json b/rules/workload-mounted-configmap/test/success_different_namespaces/expected.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/rules/workload-mounted-configmap/test/success_different_namespaces/expected.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/success_different_namespaces/input/configmap.yaml b/rules/workload-mounted-configmap/test/success_different_namespaces/input/configmap.yaml new file mode 100644 index 000000000..a25762322 --- /dev/null +++ b/rules/workload-mounted-configmap/test/success_different_namespaces/input/configmap.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: myconfigmap + namespace: mynamespace1 +data: + key1: value1 + key2: value2 \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/success_different_namespaces/input/pod.yaml b/rules/workload-mounted-configmap/test/success_different_namespaces/input/pod.yaml new file mode 100644 index 000000000..eb6ee4dd5 --- /dev/null +++ b/rules/workload-mounted-configmap/test/success_different_namespaces/input/pod.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: mynamespace +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + - name: configvolume + mountPath: "/etc/foo" + volumes: + - name: foo + secret: + secretName: mysecret + optional: true + - name: configvolume + configMap: + name: myconfigmap \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/success_no_configmap/expected.json b/rules/workload-mounted-configmap/test/success_no_configmap/expected.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/rules/workload-mounted-configmap/test/success_no_configmap/expected.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/rules/workload-mounted-configmap/test/success_no_configmap/input/pod.yaml b/rules/workload-mounted-configmap/test/success_no_configmap/input/pod.yaml new file mode 100644 index 000000000..ec5b3ddf3 --- /dev/null +++ b/rules/workload-mounted-configmap/test/success_no_configmap/input/pod.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: default +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + optional: true \ No newline at end of file diff --git a/rules/workload-mounted-pvc/raw.rego b/rules/workload-mounted-pvc/raw.rego new file mode 100644 index 000000000..1e9a535c3 --- /dev/null +++ b/rules/workload-mounted-pvc/raw.rego @@ -0,0 +1,97 @@ +package armo_builtins + +deny[msga] { + resource := input[_] + volumes_path := get_volumes_path(resource) + volumes := object.get(resource, volumes_path, []) + volume := volumes[i] + volume.persistentVolumeClaim + + PVC := input[_] + PVC.kind == "PersistentVolumeClaim" + PVC.metadata.name == volume.persistentVolumeClaim.claimName + is_same_namespace(PVC.metadata, resource.metadata) + + containers_path := get_containers_path(resource) + containers := object.get(resource, containers_path, []) + container := containers[j] + container.volumeMounts + + # check if volume is mounted + container.volumeMounts[_].name == volume.name + + failedPaths := sprintf("%s[%d].volumeMounts", [concat(".", containers_path), j]) + + msga := { + "alertMessage": sprintf("%v: %v has mounted PVC", [resource.kind, resource.metadata.name]), + "packagename": "armo_builtins", + "failedPaths": [failedPaths], + "fixPaths":[], + "alertObject": { + "k8sApiObjects": [resource] + }, + "relatedObjects": [{ + "object": PVC + }] + } +} + + +# get_containers_path - get resource containers paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} +get_containers_path(resource) := result { + resource_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + resource_kinds[resource.kind] + result = ["spec", "template", "spec", "containers"] +} + +# get_containers_path - get resource containers paths for "Pod" +get_containers_path(resource) := result { + resource.kind == "Pod" + result = ["spec", "containers"] +} + +# get_containers_path - get resource containers paths for "CronJob" +get_containers_path(resource) := result { + resource.kind == "CronJob" + result = ["spec", "jobTemplate", "spec", "template", "spec", "containers"] +} + +# get_volume_path - get resource volumes paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} +get_volumes_path(resource) := result { + resource_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + resource_kinds[resource.kind] + result = ["spec", "template", "spec", "volumes"] +} + +# get_volumes_path - get resource volumes paths for "Pod" +get_volumes_path(resource) := result { + resource.kind == "Pod" + result = ["spec", "volumes"] +} + +# get_volumes_path - get resource volumes paths for "CronJob" +get_volumes_path(resource) := result { + resource.kind == "CronJob" + result = ["spec", "jobTemplate", "spec", "template", "spec", "volumes"] +} + + + +is_same_namespace(metadata1, metadata2) { + metadata1.namespace == metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + not metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata2.namespace + metadata1.namespace == "default" +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + metadata2.namespace == "default" +} \ No newline at end of file diff --git a/rules/security-context-in-pod/rule.metadata.json b/rules/workload-mounted-pvc/rule.metadata.json similarity index 73% rename from rules/security-context-in-pod/rule.metadata.json rename to rules/workload-mounted-pvc/rule.metadata.json index fc808fe0f..dc22b0543 100644 --- a/rules/security-context-in-pod/rule.metadata.json +++ b/rules/workload-mounted-pvc/rule.metadata.json @@ -1,5 +1,5 @@ { - "name": "security-context-in-pod", + "name": "workload-mounted-pvc", "attributes": { "armoBuiltin": true }, @@ -13,7 +13,8 @@ "v1" ], "resources": [ - "Pod" + "Pod", + "ConfigMap" ] }, { @@ -43,9 +44,7 @@ ] } ], - "ruleDependencies": [ - ], - "description": "fails if pod/container does not define a security context.", - "remediation": "Make sure that the securityContext field is defined for pod/container.", + "description": "fails if workload mounts PVC", + "remediation": "", "ruleQuery": "armo_builtins" } \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/failed_pod_mounted/expected.json b/rules/workload-mounted-pvc/test/failed_pod_mounted/expected.json new file mode 100644 index 000000000..eefbd7016 --- /dev/null +++ b/rules/workload-mounted-pvc/test/failed_pod_mounted/expected.json @@ -0,0 +1,24 @@ +[ + { + "alertMessage": "Pod: mypod has mounted PVC", + "failedPaths": [ + "spec.containers[0].volumeMounts" + ], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 0, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "mypod" + } + } + ] + + } + } +] \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/failed_pod_mounted/input/PVC.yaml b/rules/workload-mounted-pvc/test/failed_pod_mounted/input/PVC.yaml new file mode 100644 index 000000000..6993c5d8e --- /dev/null +++ b/rules/workload-mounted-pvc/test/failed_pod_mounted/input/PVC.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: myclaim +spec: + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + resources: + requests: + storage: 8Gi + storageClassName: slow + selector: + matchLabels: + release: "stable" + matchExpressions: + - {key: environment, operator: In, values: [dev]} \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/failed_pod_mounted/input/pod.yaml b/rules/workload-mounted-pvc/test/failed_pod_mounted/input/pod.yaml new file mode 100644 index 000000000..6a6bada6a --- /dev/null +++ b/rules/workload-mounted-pvc/test/failed_pod_mounted/input/pod.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: myfrontend + image: nginx + volumeMounts: + - mountPath: "/var/www/html" + name: mypd + volumes: + - name: mypd + persistentVolumeClaim: + claimName: myclaim \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_different_namespaces/expected.json b/rules/workload-mounted-pvc/test/success_different_namespaces/expected.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_different_namespaces/expected.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_different_namespaces/input/PVC.yaml b/rules/workload-mounted-pvc/test/success_different_namespaces/input/PVC.yaml new file mode 100644 index 000000000..6993c5d8e --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_different_namespaces/input/PVC.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: myclaim +spec: + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + resources: + requests: + storage: 8Gi + storageClassName: slow + selector: + matchLabels: + release: "stable" + matchExpressions: + - {key: environment, operator: In, values: [dev]} \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_different_namespaces/input/pod.yaml b/rules/workload-mounted-pvc/test/success_different_namespaces/input/pod.yaml new file mode 100644 index 000000000..eaabde538 --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_different_namespaces/input/pod.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: namespace1 +spec: + containers: + - name: myfrontend + image: nginx + volumeMounts: + - mountPath: "/var/www/html" + name: mypd + volumes: + - name: mypd + persistentVolumeClaim: + claimName: myclaim \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_no_PVC/expected.json b/rules/workload-mounted-pvc/test/success_no_PVC/expected.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_no_PVC/expected.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_no_PVC/input/pod.yaml b/rules/workload-mounted-pvc/test/success_no_PVC/input/pod.yaml new file mode 100644 index 000000000..ec5b3ddf3 --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_no_PVC/input/pod.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: default +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + optional: true \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/expected.json b/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/expected.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/expected.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/PVC.yaml b/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/PVC.yaml new file mode 100644 index 000000000..6993c5d8e --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/PVC.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: myclaim +spec: + accessModes: + - ReadWriteOnce + volumeMode: Filesystem + resources: + requests: + storage: 8Gi + storageClassName: slow + selector: + matchLabels: + release: "stable" + matchExpressions: + - {key: environment, operator: In, values: [dev]} \ No newline at end of file diff --git a/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/pod.yaml b/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/pod.yaml new file mode 100644 index 000000000..42a1ebb24 --- /dev/null +++ b/rules/workload-mounted-pvc/test/success_with_PVC_not_mounted/input/pod.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + containers: + - name: myfrontend + image: nginx + volumeMounts: + - mountPath: "/var/www/html" + name: mypd1 + volumes: + - name: mypd + persistentVolumeClaim: + claimName: myclaim \ No newline at end of file diff --git a/rules/workload-mounted-secrets/raw.rego b/rules/workload-mounted-secrets/raw.rego new file mode 100644 index 000000000..fa6076cd7 --- /dev/null +++ b/rules/workload-mounted-secrets/raw.rego @@ -0,0 +1,96 @@ +package armo_builtins + +deny[msga] { + resource := input[_] + volumes_path := get_volumes_path(resource) + volumes := object.get(resource, volumes_path, []) + volume := volumes[i] + volume.secret + + secret := input[_] + secret.kind == "Secret" + secret.metadata.name == volume.secret.secretName + is_same_namespace(secret.metadata, resource.metadata) + + containers_path := get_containers_path(resource) + containers := object.get(resource, containers_path, []) + container := containers[j] + container.volumeMounts + + # check if volume is mounted + container.volumeMounts[_].name == volume.name + + failedPaths := sprintf("%s[%d].volumeMounts", [concat(".", containers_path), j]) + + msga := { + "alertMessage": sprintf("%v: %v has mounted secret", [resource.kind, resource.metadata.name]), + "packagename": "armo_builtins", + "failedPaths": [failedPaths], + "fixPaths":[], + "alertObject": { + "k8sApiObjects": [resource] + }, + "relatedObjects": [{ + "object": secret + }] + } +} + +# get_volume_path - get resource volumes paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} +get_volumes_path(resource) := result { + resource_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + resource_kinds[resource.kind] + result = ["spec", "template", "spec", "volumes"] +} + +# get_containers_path - get resource containers paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} +get_containers_path(resource) := result { + resource_kinds := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"} + resource_kinds[resource.kind] + result = ["spec", "template", "spec", "containers"] +} + +# get_containers_path - get resource containers paths for "Pod" +get_containers_path(resource) := result { + resource.kind == "Pod" + result = ["spec", "containers"] +} + +# get_containers_path - get resource containers paths for "CronJob" +get_containers_path(resource) := result { + resource.kind == "CronJob" + result = ["spec", "jobTemplate", "spec", "template", "spec", "containers"] +} + +# get_volumes_path - get resource volumes paths for "Pod" +get_volumes_path(resource) := result { + resource.kind == "Pod" + result = ["spec", "volumes"] +} + +# get_volumes_path - get resource volumes paths for "CronJob" +get_volumes_path(resource) := result { + resource.kind == "CronJob" + result = ["spec", "jobTemplate", "spec", "template", "spec", "volumes"] +} + + + +is_same_namespace(metadata1, metadata2) { + metadata1.namespace == metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + not metadata2.namespace +} + +is_same_namespace(metadata1, metadata2) { + not metadata2.namespace + metadata1.namespace == "default" +} + +is_same_namespace(metadata1, metadata2) { + not metadata1.namespace + metadata2.namespace == "default" +} \ No newline at end of file diff --git a/rules/user-id-less-than-thousands/rule.metadata.json b/rules/workload-mounted-secrets/rule.metadata.json similarity index 67% rename from rules/user-id-less-than-thousands/rule.metadata.json rename to rules/workload-mounted-secrets/rule.metadata.json index ac8d0a624..8f561c805 100644 --- a/rules/user-id-less-than-thousands/rule.metadata.json +++ b/rules/workload-mounted-secrets/rule.metadata.json @@ -1,5 +1,5 @@ { - "name": "user-id-less-than-thousands", + "name": "workload-mounted-secrets", "attributes": { "armoBuiltin": true }, @@ -13,7 +13,8 @@ "v1" ], "resources": [ - "Pod" + "Pod", + "Secret" ] }, { @@ -38,14 +39,12 @@ "*" ], "resources": [ - "Job", - "CronJob" + "Job", + "CronJob" ] } ], - "ruleDependencies": [ - ], - "description": "fails if container can run as high user (id less than 1000)", - "remediation": "Make sure that the user/group in the securityContext of pod/container is set to an id less than 1000.", + "description": "fails if workload mounts secrets", + "remediation": "", "ruleQuery": "armo_builtins" -} \ No newline at end of file +} diff --git a/rules/workload-mounted-secrets/test/failed/expected.json b/rules/workload-mounted-secrets/test/failed/expected.json new file mode 100644 index 000000000..177f27a7e --- /dev/null +++ b/rules/workload-mounted-secrets/test/failed/expected.json @@ -0,0 +1,23 @@ +[ + { + "alertMessage": "Pod: mypod has mounted secret", + "failedPaths": [ + "spec.containers[0].volumeMounts" + ], + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 0, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "mypod" + } + } + ] + } + } +] \ No newline at end of file diff --git a/rules/workload-mounted-secrets/test/failed/input/pod.yaml b/rules/workload-mounted-secrets/test/failed/input/pod.yaml new file mode 100644 index 000000000..ec5b3ddf3 --- /dev/null +++ b/rules/workload-mounted-secrets/test/failed/input/pod.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: mypod + namespace: default +spec: + containers: + - name: mypod + image: redis + volumeMounts: + - name: foo + mountPath: "/etc/foo" + readOnly: true + volumes: + - name: foo + secret: + secretName: mysecret + optional: true \ No newline at end of file diff --git a/rules/workload-mounted-secrets/test/failed/input/secret.yaml b/rules/workload-mounted-secrets/test/failed/input/secret.yaml new file mode 100644 index 000000000..721bffd05 --- /dev/null +++ b/rules/workload-mounted-secrets/test/failed/input/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: mysecret +type: Opaque +data: + username: YWRtaW4= + password: MWYyZDFlMmU2N2Rm \ No newline at end of file diff --git a/rules/workload-mounted-secrets/test/success/expected.json b/rules/workload-mounted-secrets/test/success/expected.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/rules/workload-mounted-secrets/test/success/expected.json @@ -0,0 +1 @@ +[] diff --git a/rules/workload-mounted-secrets/test/success/input/pod.yaml b/rules/workload-mounted-secrets/test/success/input/pod.yaml new file mode 100644 index 000000000..9b20af164 --- /dev/null +++ b/rules/workload-mounted-secrets/test/success/input/pod.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: test-pd +spec: + containers: + - image: k8s.gcr.io/test-webserver + name: test-container + volumeMounts: + - mountPath: /test-pd + name: test-volume + volumes: + - name: test-volume + hostPath: + path: /data + \ No newline at end of file diff --git a/scripts/init-rule.py b/scripts/init-rule.py index 9800f0050..86a0d9480 100644 --- a/scripts/init-rule.py +++ b/scripts/init-rule.py @@ -259,7 +259,7 @@ def define_args(): parser.add_argument('--test-list', type=str, default=test_list_default, - help='comma separated list of tests you want to provide on the rule. example: succes,failed') + help='comma separated list of tests you want to provide on the rule. example: success,failed') args = parser.parse_args() return args diff --git a/scripts/validations.py b/scripts/validations.py index 738c07450..c660409eb 100644 --- a/scripts/validations.py +++ b/scripts/validations.py @@ -5,7 +5,7 @@ FRAMEWORK_DIR = "frameworks" CONTROLS_DIR = "controls" RULES_DIR = "rules" -RULES_CHECKED = [] +RULES_CHECKED = set() CONTROLID_TO_FILENAME = {} RULENAME_TO_RULE_DIR = {} @@ -51,7 +51,7 @@ def validate_controls(): # If there is another rule with same name as this rule with "-v1" at the end - don't validate it if not os.path.exists(os.path.join(RULES_DIR, rule_dir + "-v1")): validate_tests_dir_for_rule(rule_dir) - RULES_CHECKED.append(rule_name) + RULES_CHECKED.add(rule_name) # Test that each rule directory in the "rules" directory has a non-empty "tests" subdirectory @@ -81,6 +81,17 @@ def fill_rulename_to_rule_dir(): rule = json.load(f1) RULENAME_TO_RULE_DIR[rule['name']] = rule_dir +def validate_rules(): + for rule_dir_name in os.listdir(RULES_DIR): + rule_dir = os.path.join(RULES_DIR, rule_dir_name) + if not os.path.isdir(rule_dir) or rule_dir_name.startswith("."): + continue + + rule_file_path = os.path.join(RULES_DIR, rule_dir_name, "rule.metadata.json") + assert os.path.exists(rule_file_path), f"No rule.metadata.json file in {rule_dir_name}" + with open(rule_file_path) as rule_file: + data = json.load(rule_file) + assert data["name"] in RULES_CHECKED, f"rule {data['name']} is not used by any control" if __name__ == "__main__": @@ -88,3 +99,4 @@ def fill_rulename_to_rule_dir(): fill_controlID_to_filename_map() validate_controls_in_framework() validate_controls() + validate_rules() diff --git a/testrunner/go.mod b/testrunner/go.mod index 7aa706fd3..7fb8d8fef 100644 --- a/testrunner/go.mod +++ b/testrunner/go.mod @@ -12,6 +12,8 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) +require github.com/santhosh-tekuri/jsonschema/v5 v5.1.1 // indirect + require ( cloud.google.com/go v0.102.1 // indirect cloud.google.com/go/compute v1.7.0 // indirect @@ -95,6 +97,7 @@ require ( github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/yannh/kubeconform v0.6.2 github.com/yashtewari/glob-intersection v0.1.0 // indirect go.opencensus.io v0.23.0 // indirect go.uber.org/atomic v1.7.0 // indirect diff --git a/testrunner/go.sum b/testrunner/go.sum index ef2223980..60d22354e 100644 --- a/testrunner/go.sum +++ b/testrunner/go.sum @@ -438,6 +438,8 @@ github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqn github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/santhosh-tekuri/jsonschema/v5 v5.1.1 h1:lEOLY2vyGIqKWUI9nzsOJRV3mb3WC9dXYORsLEUcoeY= +github.com/santhosh-tekuri/jsonschema/v5 v5.1.1/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -489,6 +491,8 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMc github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/yannh/kubeconform v0.6.2 h1:xjUxiCcqTBofTsM3UT6fNb/tKRfqjakNfWvHRa3sGOo= +github.com/yannh/kubeconform v0.6.2/go.mod h1:4E6oaL+lh7KgCG2SaOabeeAFBkyKu5D9ab0OEekGcbs= github.com/yashtewari/glob-intersection v0.1.0 h1:6gJvMYQlTDOL3dMsPF6J0+26vwX9MB8/1q3uAdhmTrg= github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/testrunner/opaprocessor/processorutils.go b/testrunner/opaprocessor/processorutils.go index 11f830325..7a63b0f4d 100644 --- a/testrunner/opaprocessor/processorutils.go +++ b/testrunner/opaprocessor/processorutils.go @@ -16,6 +16,8 @@ import ( "github.com/kubescape/opa-utils/resources" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/yannh/kubeconform/pkg/resource" + "github.com/yannh/kubeconform/pkg/validator" "gopkg.in/yaml.v3" ) @@ -42,6 +44,37 @@ func convertYamlToJson(i interface{}) interface{} { return i } +// validateInputResource return an error in case the provided k8s resource is not considered valid. +// It uses packages from kubeconform project in order to validate resources. +func validateInputResource(res []byte) error { + k8sResource := resource.Resource{ + Bytes: res, + } + schemaLocation := []string{} + var val validator.Validator + val, err := validator.New(schemaLocation, + validator.Opts{ + Cache: "", + Debug: false, + SkipTLS: false, + SkipKinds: map[string]struct{}{}, + RejectKinds: map[string]struct{}{}, + KubernetesVersion: "master", + Strict: false, + IgnoreMissingSchemas: true, + }, + ) + if err != nil { + return err + } + + result := val.ValidateResource(k8sResource) + if result.Err != nil { + return result.Err + } + return nil +} + func GetInputRawResources(dir string, policyRule *reporthandling.PolicyRule) ([]map[string]interface{}, error) { var IMetadataResources []workloadinterface.IMetadata @@ -53,6 +86,7 @@ func GetInputRawResources(dir string, policyRule *reporthandling.PolicyRule) ([] if resp == nil { return nil, fmt.Errorf("resource is nil") } + metadataResource := objectsenvelopes.NewObject(resp) // if metadataResource.GetNamespace() == "" { // metadataResource.SetNamespace("default") @@ -86,6 +120,12 @@ func GetMockContentFromFile(filename string) (string, error) { if err != nil { return "", err } + + // validate input resource using kubeconform packages + if err = validateInputResource(mockContent); err != nil { + return "", err + } + var body interface{} if err := yaml.Unmarshal([]byte(mockContent), &body); err != nil { return "", err @@ -246,7 +286,7 @@ func RunSingleTest(t *testing.T, dir string, policyRule *reporthandling.PolicyRu expectedResponses, err := GetExpectedResults(dir) if err != nil { - return err + return fmt.Errorf("expected.json doesn't match: %v", err) } err = AssertResponses(t, responses, expectedResponses) From d117c1f6a92e9a8e939186d5ba144ff9b83ee74d Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Thu, 20 Jul 2023 09:20:00 +0300 Subject: [PATCH 05/11] new fws Signed-off-by: Daniel Grunberger --- README.md | 2 +- categories/mapCategoryNameToID.json | 11 ++ .../C-0001-forbiddencontainerregistries.json | 6 +- controls/C-0002-execintocontainer.json | 6 +- ...C-0004-resourcesmemorylimitandrequest.json | 9 +- ...C-0005-apiserverinsecureportisenabled.json | 6 +- controls/C-0007-datadestruction.json | 6 +- controls/C-0009-resourcelimits.json | 6 +- ...ationscredentialsinconfigurationfiles.json | 6 +- controls/C-0013-nonrootcontainers.json | 9 +- .../C-0014-accesskubernetesdashboard.json | 6 +- controls/C-0015-listkubernetessecrets.json | 6 +- controls/C-0016-allowprivilegeescalation.json | 9 +- .../C-0017-immutablecontainerfilesystem.json | 9 +- controls/C-0018-configuredreadinessprobe.json | 6 +- controls/C-0020-mountserviceprincipal.json | 6 +- .../C-0021-exposedsensitiveinterfaces.json | 6 +- controls/C-0026-kubernetescronjob.json | 6 +- controls/C-0030-ingressandegressblocked.json | 6 +- controls/C-0031-deletekubernetesevents.json | 6 +- ...0034-automaticmappingofserviceaccount.json | 6 +- controls/C-0035-clusteradminbinding.json | 6 +- ...aliciousadmissioncontrollervalidating.json | 6 +- controls/C-0037-corednspoisoning.json | 6 +- controls/C-0038-hostpidipcprivileges.json | 9 +- ...-maliciousadmissioncontrollermutating.json | 6 +- controls/C-0041-hostnetworkaccess.json | 6 +- ...-0042-sshserverrunninginsidecontainer.json | 6 +- controls/C-0044-containerhostport.json | 6 +- controls/C-0045-writablehostpathmount.json | 9 +- controls/C-0046-insecurecapabilities.json | 9 +- controls/C-0048-hostpathmount.json | 9 +- controls/C-0049-networkmapping.json | 6 +- .../C-0050-resourcescpulimitandrequest.json | 9 +- controls/C-0052-instancemetadataapi.json | 6 +- .../C-0053-accesscontainerserviceaccount.json | 6 +- .../C-0054-clusterinternalnetworking.json | 6 +- controls/C-0055-linuxhardening.json | 9 +- controls/C-0056-configuredlivenessprobe.json | 6 +- controls/C-0057-privilegedcontainer.json | 9 +- ...mlinkforarbitraryhostfilesystemaccess.json | 6 +- ...ingresssnippetannotationvulnerability.json | 6 +- controls/C-0061-podsindefaultnamespace.json | 6 +- .../C-0062-sudoincontainerentrypoint.json | 6 +- controls/C-0063-portforwardingprivileges.json | 6 +- controls/C-0065-noimpersonation.json | 6 +- .../C-0066-secretetcdencryptionenabled.json | 6 +- controls/C-0067-auditlogsenabled.json | 6 +- controls/C-0068-pspenabled.json | 6 +- ...isableanonymousaccesstokubeletservice.json | 6 +- ...enforcekubeletclienttlsauthentication.json | 6 +- controls/C-0073-nakedpods.json | 6 +- .../C-0075-imagepullpolicyonlatesttag.json | 6 +- controls/C-0076-labelusageforresources.json | 6 +- controls/C-0077-k8scommonlabelsusage.json | 6 +- .../C-0078-imagesfromallowedregistry.json | 9 +- ...cve20220185linuxkernelcontainerescape.json | 6 +- ...C-0081-cve202224348argocddirtraversal.json | 6 +- ...lnerabilitiesexposedtoexternaltraffic.json | 6 +- ...lnerabilitiesexposedtoexternaltraffic.json | 6 +- ...swithexcessiveamountofvulnerabilities.json | 6 +- ...086-cve20220492cgroupscontainerescape.json | 6 +- ...C-0087-cve202223648containerdfsescape.json | 6 +- controls/C-0088-rbacenabled.json | 6 +- ...ve20223172aggregatedapiserverredirect.json | 6 +- .../C-0090-cve202239328grafanaauthbypass.json | 6 +- ...91-cve202247633kyvernosignaturebypass.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...ificationfileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...ificationfileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...ificationfileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...ificationfileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...interfacefileownershipissettorootroot.json | 6 +- ...rmissionsaresetto700ormorerestrictive.json | 6 +- ...datadirectoryownershipissettoetcdetcd.json | 6 +- ...headminconffilepermissionsaresetto600.json | 6 +- ...adminconffileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...dulerconffileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...nagerconffileownershipissettorootroot.json | 6 +- ...ectoryandfileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...netespkikeyfilepermissionsaresetto600.json | 6 +- ...rveranonymousauthargumentissettofalse.json | 6 +- ...iservertokenauthfileparameterisnotset.json | 6 +- ...iserverdenyserviceexternalipsisnotset.json | 6 +- ...clientkeyargumentsaresetasappropriate.json | 6 +- ...teauthorityargumentissetasappropriate.json | 6 +- ...tionmodeargumentisnotsettoalwaysallow.json | 6 +- ...authorizationmodeargumentincludesnode.json | 6 +- ...authorizationmodeargumentincludesrbac.json | 6 +- ...ssioncontrolplugineventratelimitisset.json | 6 +- ...ssioncontrolpluginalwaysadmitisnotset.json | 6 +- ...ioncontrolpluginalwayspullimagesisset.json | 6 +- ...denyissetifpodsecuritypolicyisnotused.json | 6 +- ...ssioncontrolpluginserviceaccountisset.json | 6 +- ...ncontrolpluginnamespacelifecycleisset.json | 6 +- ...sioncontrolpluginnoderestrictionisset.json | 6 +- ...piserversecureportargumentisnotsetto0.json | 6 +- ...piserverprofilingargumentissettofalse.json | 6 +- ...theapiserverauditlogpathargumentisset.json | 6 +- ...axageargumentissetto30orasappropriate.json | 6 +- ...ackupargumentissetto10orasappropriate.json | 6 +- ...sizeargumentissetto100orasappropriate.json | 6 +- ...uesttimeoutargumentissetasappropriate.json | 6 +- ...rviceaccountlookupargumentissettotrue.json | 6 +- ...ountkeyfileargumentissetasappropriate.json | 6 +- ...cdkeyfileargumentsaresetasappropriate.json | 6 +- ...tekeyfileargumentsaresetasappropriate.json | 6 +- ...lientcafileargumentissetasappropriate.json | 6 +- ...retcdcafileargumentissetasappropriate.json | 6 +- ...viderconfigargumentissetasappropriate.json | 6 +- ...onprovidersareappropriatelyconfigured.json | 6 +- ...ymakesuseofstrongcryptographicciphers.json | 6 +- ...gcthresholdargumentissetasappropriate.json | 6 +- ...rmanagerprofilingargumentissettofalse.json | 6 +- ...accountcredentialsargumentissettotrue.json | 6 +- ...vatekeyfileargumentissetasappropriate.json | 6 +- ...rrootcafileargumentissetasappropriate.json | 6 +- ...tservercertificateargumentissettotrue.json | 6 +- ...nagerbindaddressargumentissetto127001.json | 6 +- ...chedulerprofilingargumentissettofalse.json | 6 +- ...dulerbindaddressargumentissetto127001.json | 6 +- ...ndkeyfileargumentsaresetasappropriate.json | 6 +- ...ttheclientcertauthargumentissettotrue.json | 6 +- ...ethattheautotlsargumentisnotsettotrue.json | 6 +- ...erkeyfileargumentsaresetasappropriate.json | 6 +- ...peerclientcertauthargumentissettotrue.json | 6 +- ...tthepeerautotlsargumentisnotsettotrue.json | 6 +- ...iquecertificateauthorityisusedforetcd.json | 6 +- ...nsurethataminimalauditpolicyiscreated.json | 6 +- ...eauditpolicycoverskeysecurityconcerns.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...etservicefileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...eexistsensureownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...beletconffileownershipissettorootroot.json | 6 +- ...rmissionsaresetto600ormorerestrictive.json | 6 +- ...thoritiesfileownershipissettorootroot.json | 6 +- ...epermissionssetto600ormorerestrictive.json | 6 +- ...dvalidatefileownershipissettorootroot.json | 6 +- ...ttheanonymousauthargumentissettofalse.json | 6 +- ...tionmodeargumentisnotsettoalwaysallow.json | 6 +- ...lientcafileargumentissetasappropriate.json | 6 +- ...fythatthereadonlyportargumentissetto0.json | 6 +- ...nectionidletimeoutargumentisnotsetto0.json | 6 +- ...tectkerneldefaultsargumentissettotrue.json | 6 +- ...iptablesutilchainsargumentissettotrue.json | 6 +- ...atthehostnameoverrideargumentisnotset.json | 6 +- ...elwhichensuresappropriateeventcapture.json | 6 +- ...tekeyfileargumentsaresetasappropriate.json | 6 +- ...tecertificatesargumentisnotsettofalse.json | 6 +- ...tservercertificateargumentissettotrue.json | 6 +- ...ymakesuseofstrongcryptographicciphers.json | 6 +- ...usteradminroleisonlyusedwhererequired.json | 6 +- controls/C-0186-minimizeaccesstosecrets.json | 6 +- ...mizewildcarduseinrolesandclusterroles.json | 6 +- .../C-0188-minimizeaccesstocreatepods.json | 6 +- ...aultserviceaccountsarenotactivelyused.json | 6 +- ...unttokensareonlymountedwherenecessary.json | 6 +- ...latepermissionsinthekubernetescluster.json | 6 +- ...neactivepolicycontrolmechanisminplace.json | 6 +- ...izetheadmissionofprivilegedcontainers.json | 6 +- ...shingtosharethehostprocessidnamespace.json | 6 +- ...nerswishingtosharethehostipcnamespace.json | 6 +- ...wishingtosharethehostnetworknamespace.json | 6 +- ...ontainerswithallowprivilegeescalation.json | 6 +- ...-minimizetheadmissionofrootcontainers.json | 6 +- ...nofcontainerswiththenet_rawcapability.json | 6 +- ...sionofcontainerswithaddedcapabilities.json | 6 +- ...nofcontainerswithcapabilitiesassigned.json | 6 +- ...missionofwindowshostprocesscontainers.json | 6 +- ...minimizetheadmissionofhostpathvolumes.json | 6 +- ...dmissionofcontainerswhichusehostports.json | 6 +- ...hatthecniinusesupportsnetworkpolicies.json | 6 +- ...lnamespaceshavenetworkpoliciesdefined.json | 6 +- ...ilesoversecretsasenvironmentvariables.json | 9 +- .../C-0208-considerexternalsecretstorage.json | 6 +- ...dariesbetweenresourcesusingnamespaces.json | 6 +- ...ettodockerdefaultinyourpoddefinitions.json | 6 +- ...ecuritycontexttoyourpodsandcontainers.json | 6 +- ...12-thedefaultnamespaceshouldnotbeused.json | 6 +- controls/C-0236-verifyimagesignature.json | 9 +- controls/C-0237-hasimagesignature.json | 9 +- controls/C-0260-missingnetworkpolicy.json | 5 +- controls/C-0262-anonymousaccessisenabled.json | 8 +- frameworks/clusterscan.json | 144 ++++++++++++++++++ frameworks/workloadscan.json | 139 +++++++++++++++++ scripts/export.py | 23 +++ 195 files changed, 938 insertions(+), 567 deletions(-) create mode 100644 categories/mapCategoryNameToID.json create mode 100644 frameworks/clusterscan.json create mode 100644 frameworks/workloadscan.json diff --git a/README.md b/README.md index 5eb8cd968..ab1b3da26 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Example of a framework: }, "controlsNames": [ "Naked PODs", - "Containers mounting Docker socket", + "Container runtime socket mounted", "Image pull policy on latest tag", "Label usage for resources", "K8s common labels usage", diff --git a/categories/mapCategoryNameToID.json b/categories/mapCategoryNameToID.json new file mode 100644 index 000000000..e3e4f4f44 --- /dev/null +++ b/categories/mapCategoryNameToID.json @@ -0,0 +1,11 @@ +{ + "Control plane": "Cat-1", + "Access control": "Cat-2", + "Secrets": "Cat-3", + "Network": "Cat-4", + "Workload": "Cat-5", + "Supply chain": "Cat-6", + "Resource management": "Cat-7", + "Storage": "Cat-8", + "Node escape": "Cat-9" +} \ No newline at end of file diff --git a/controls/C-0001-forbiddencontainerregistries.json b/controls/C-0001-forbiddencontainerregistries.json index e72ae4e4d..4d888e487 100644 --- a/controls/C-0001-forbiddencontainerregistries.json +++ b/controls/C-0001-forbiddencontainerregistries.json @@ -29,7 +29,7 @@ "controlID": "C-0001", "baseScore": 7.0, "example": "@controls/examples/c001.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0002-execintocontainer.json b/controls/C-0002-execintocontainer.json index 60278b9de..872323e65 100644 --- a/controls/C-0002-execintocontainer.json +++ b/controls/C-0002-execintocontainer.json @@ -22,7 +22,7 @@ "controlID": "C-0002", "baseScore": 5.0, "example": "@controls/examples/c002.yaml", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0004-resourcesmemorylimitandrequest.json b/controls/C-0004-resourcesmemorylimitandrequest.json index b9f78ee69..2151a24bc 100644 --- a/controls/C-0004-resourcesmemorylimitandrequest.json +++ b/controls/C-0004-resourcesmemorylimitandrequest.json @@ -24,7 +24,10 @@ "controlID": "C-0004", "example": "@controls/examples/c004.yaml", "baseScore": 8.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload", + "subCategory": { + "name": "Resource management" + } + } } \ No newline at end of file diff --git a/controls/C-0005-apiserverinsecureportisenabled.json b/controls/C-0005-apiserverinsecureportisenabled.json index 24e2f72f1..1bd0085e4 100644 --- a/controls/C-0005-apiserverinsecureportisenabled.json +++ b/controls/C-0005-apiserverinsecureportisenabled.json @@ -24,7 +24,7 @@ "test": "Check if the insecure-port flag is set (in case of cloud vendor hosted Kubernetes service this verification will not be effective).", "controlID": "C-0005", "baseScore": 9.0, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0007-datadestruction.json b/controls/C-0007-datadestruction.json index b158aabfb..d106abf8c 100644 --- a/controls/C-0007-datadestruction.json +++ b/controls/C-0007-datadestruction.json @@ -21,7 +21,7 @@ "controlID": "C-0007", "baseScore": 5.0, "example": "@controls/examples/c007.yaml", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0009-resourcelimits.json b/controls/C-0009-resourcelimits.json index 0cf064514..4074cf404 100644 --- a/controls/C-0009-resourcelimits.json +++ b/controls/C-0009-resourcelimits.json @@ -24,7 +24,7 @@ "controlID": "C-0009", "baseScore": 7.0, "example": "@controls/examples/c009.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0012-applicationscredentialsinconfigurationfiles.json b/controls/C-0012-applicationscredentialsinconfigurationfiles.json index 5bd205e92..e6c730c43 100644 --- a/controls/C-0012-applicationscredentialsinconfigurationfiles.json +++ b/controls/C-0012-applicationscredentialsinconfigurationfiles.json @@ -37,7 +37,7 @@ "test": "Check if the pod has sensitive information in environment variables, by using list of known sensitive key names. Check if there are configmaps with sensitive information.", "controlID": "C-0012", "baseScore": 8.0, - "categories": [ - "Secrets" - ] + "category": { + "name" : "Secrets" + } } \ No newline at end of file diff --git a/controls/C-0013-nonrootcontainers.json b/controls/C-0013-nonrootcontainers.json index ab6b2dad8..1d98aefe4 100644 --- a/controls/C-0013-nonrootcontainers.json +++ b/controls/C-0013-nonrootcontainers.json @@ -25,7 +25,10 @@ "controlID": "C-0013", "baseScore": 6.0, "example": "@controls/examples/c013.yaml", - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Node escape" + } + } } \ No newline at end of file diff --git a/controls/C-0014-accesskubernetesdashboard.json b/controls/C-0014-accesskubernetesdashboard.json index a71e0d732..9baf1390a 100644 --- a/controls/C-0014-accesskubernetesdashboard.json +++ b/controls/C-0014-accesskubernetesdashboard.json @@ -22,7 +22,7 @@ "test": "Check who is associated with the dashboard service account or bound to dashboard role/clusterrole.", "controlID": "C-0014", "baseScore": 2.0, - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0015-listkubernetessecrets.json b/controls/C-0015-listkubernetessecrets.json index 584c5ff01..c8cce205f 100644 --- a/controls/C-0015-listkubernetessecrets.json +++ b/controls/C-0015-listkubernetessecrets.json @@ -30,7 +30,7 @@ "controlID": "C-0015", "baseScore": 7.0, "example": "@controls/examples/c015.yaml", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0016-allowprivilegeescalation.json b/controls/C-0016-allowprivilegeescalation.json index 6b90cf0e9..6d7ad7f5c 100644 --- a/controls/C-0016-allowprivilegeescalation.json +++ b/controls/C-0016-allowprivilegeescalation.json @@ -24,7 +24,10 @@ "controlID": "C-0016", "baseScore": 6.0, "example": "@controls/examples/allowprivilegeescalation.yaml", - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Node escape" + } + } } \ No newline at end of file diff --git a/controls/C-0017-immutablecontainerfilesystem.json b/controls/C-0017-immutablecontainerfilesystem.json index 003110e34..45a4f4a68 100644 --- a/controls/C-0017-immutablecontainerfilesystem.json +++ b/controls/C-0017-immutablecontainerfilesystem.json @@ -26,7 +26,10 @@ "controlID": "C-0017", "baseScore": 3.0, "example": "@controls/examples/c017.yaml", - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Node escape" + } + } } \ No newline at end of file diff --git a/controls/C-0018-configuredreadinessprobe.json b/controls/C-0018-configuredreadinessprobe.json index 432430134..cb7d73e13 100644 --- a/controls/C-0018-configuredreadinessprobe.json +++ b/controls/C-0018-configuredreadinessprobe.json @@ -15,7 +15,7 @@ "controlID": "C-0018", "example": "@controls/examples/c018.yaml", "baseScore": 3, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0020-mountserviceprincipal.json b/controls/C-0020-mountserviceprincipal.json index ffd895390..a24a2cb02 100644 --- a/controls/C-0020-mountserviceprincipal.json +++ b/controls/C-0020-mountserviceprincipal.json @@ -19,7 +19,7 @@ "test": "Check which workloads have volumes with potential access to known cloud credentials folders or files in node, like \u201c/etc/kubernetes/azure.json\u201d for Azure.", "controlID": "C-0020", "baseScore": 4.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0021-exposedsensitiveinterfaces.json b/controls/C-0021-exposedsensitiveinterfaces.json index 5e2f0cc23..a6271eb91 100644 --- a/controls/C-0021-exposedsensitiveinterfaces.json +++ b/controls/C-0021-exposedsensitiveinterfaces.json @@ -20,7 +20,7 @@ "test": "Checking if a service of type nodeport/loadbalancer to one of the known exploited interfaces (Apache NiFi, Kubeflow, Argo Workflows, Weave Scope Kubernetes dashboard) exists. Needs to add user config", "controlID": "C-0021", "baseScore": 6.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0026-kubernetescronjob.json b/controls/C-0026-kubernetescronjob.json index 1774e4c72..3e06589bd 100644 --- a/controls/C-0026-kubernetescronjob.json +++ b/controls/C-0026-kubernetescronjob.json @@ -18,7 +18,7 @@ "test": "We list all CronJobs that exist in cluster for the user to approve.", "controlID": "C-0026", "baseScore": 1.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0030-ingressandegressblocked.json b/controls/C-0030-ingressandegressblocked.json index 5952d72e6..1cda23b46 100644 --- a/controls/C-0030-ingressandegressblocked.json +++ b/controls/C-0030-ingressandegressblocked.json @@ -16,7 +16,7 @@ "controlID": "C-0030", "baseScore": 6.0, "example": "@controls/examples/c030.yaml", - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0031-deletekubernetesevents.json b/controls/C-0031-deletekubernetesevents.json index 8f916970e..e83816443 100644 --- a/controls/C-0031-deletekubernetesevents.json +++ b/controls/C-0031-deletekubernetesevents.json @@ -30,7 +30,7 @@ "controlID": "C-0031", "baseScore": 4.0, "example": "@controls/examples/c031.yaml", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0034-automaticmappingofserviceaccount.json b/controls/C-0034-automaticmappingofserviceaccount.json index d28fc9ff8..d4745f421 100644 --- a/controls/C-0034-automaticmappingofserviceaccount.json +++ b/controls/C-0034-automaticmappingofserviceaccount.json @@ -26,7 +26,7 @@ "controlID": "C-0034", "baseScore": 6.0, "example": "@controls/examples/c034.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Secrets" + } } \ No newline at end of file diff --git a/controls/C-0035-clusteradminbinding.json b/controls/C-0035-clusteradminbinding.json index 617d9569c..ca66ebef9 100644 --- a/controls/C-0035-clusteradminbinding.json +++ b/controls/C-0035-clusteradminbinding.json @@ -30,7 +30,7 @@ "test": "Check which subjects have cluster-admin RBAC permissions \u2013 either by being bound to the cluster-admin clusterrole, or by having equivalent high privileges. ", "controlID": "C-0035", "baseScore": 6.0, - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0036-maliciousadmissioncontrollervalidating.json b/controls/C-0036-maliciousadmissioncontrollervalidating.json index b3e1c1a8b..421aef524 100644 --- a/controls/C-0036-maliciousadmissioncontrollervalidating.json +++ b/controls/C-0036-maliciousadmissioncontrollervalidating.json @@ -26,7 +26,7 @@ ], "controlID": "C-0036", "baseScore": 3.0, - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0037-corednspoisoning.json b/controls/C-0037-corednspoisoning.json index 274d61263..a8ab0babc 100644 --- a/controls/C-0037-corednspoisoning.json +++ b/controls/C-0037-corednspoisoning.json @@ -27,7 +27,7 @@ "test": "Check who has update/patch RBAC permissions on \u2018coredns\u2019 configmaps, or to all configmaps.", "controlID": "C-0037", "baseScore": 4.0, - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0038-hostpidipcprivileges.json b/controls/C-0038-hostpidipcprivileges.json index f143c0649..2403cb671 100644 --- a/controls/C-0038-hostpidipcprivileges.json +++ b/controls/C-0038-hostpidipcprivileges.json @@ -24,7 +24,10 @@ "controlID": "C-0038", "baseScore": 7.0, "example": "@controls/examples/c038.yaml", - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Node escape" + } + } } \ No newline at end of file diff --git a/controls/C-0039-maliciousadmissioncontrollermutating.json b/controls/C-0039-maliciousadmissioncontrollermutating.json index c93655e94..e1681ea0f 100644 --- a/controls/C-0039-maliciousadmissioncontrollermutating.json +++ b/controls/C-0039-maliciousadmissioncontrollermutating.json @@ -25,7 +25,7 @@ ], "controlID": "C-0039", "baseScore": 4.0, - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0041-hostnetworkaccess.json b/controls/C-0041-hostnetworkaccess.json index 7f6d5374d..dd6c87b89 100644 --- a/controls/C-0041-hostnetworkaccess.json +++ b/controls/C-0041-hostnetworkaccess.json @@ -27,7 +27,7 @@ "controlID": "C-0041", "baseScore": 7.0, "example": "@controls/examples/c041.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0042-sshserverrunninginsidecontainer.json b/controls/C-0042-sshserverrunninginsidecontainer.json index 1d3e4a820..9423027f1 100644 --- a/controls/C-0042-sshserverrunninginsidecontainer.json +++ b/controls/C-0042-sshserverrunninginsidecontainer.json @@ -19,7 +19,7 @@ "test": "Check if service connected to some workload has an SSH port (22/2222). If so we raise an alert. ", "controlID": "C-0042", "baseScore": 3.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0044-containerhostport.json b/controls/C-0044-containerhostport.json index d6d065ec2..c86d1aeb7 100644 --- a/controls/C-0044-containerhostport.json +++ b/controls/C-0044-containerhostport.json @@ -26,7 +26,7 @@ "controlID": "C-0044", "baseScore": 4.0, "example": "@controls/examples/c044.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0045-writablehostpathmount.json b/controls/C-0045-writablehostpathmount.json index dca6b4bf5..4289e5fc1 100644 --- a/controls/C-0045-writablehostpathmount.json +++ b/controls/C-0045-writablehostpathmount.json @@ -32,7 +32,10 @@ "controlID": "C-0045", "baseScore": 8.0, "example": "@controls/examples/c045.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload", + "subCategory": { + "name": "Storage" + } + } } \ No newline at end of file diff --git a/controls/C-0046-insecurecapabilities.json b/controls/C-0046-insecurecapabilities.json index d885935ed..2ef879291 100644 --- a/controls/C-0046-insecurecapabilities.json +++ b/controls/C-0046-insecurecapabilities.json @@ -26,7 +26,10 @@ "controlID": "C-0046", "baseScore": 7.0, "example": "@controls/examples/c046.yaml", - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Node escape" + } + } } \ No newline at end of file diff --git a/controls/C-0048-hostpathmount.json b/controls/C-0048-hostpathmount.json index 40dfd33e3..9b023485c 100644 --- a/controls/C-0048-hostpathmount.json +++ b/controls/C-0048-hostpathmount.json @@ -26,7 +26,10 @@ ], "controlID": "C-0048", "baseScore": 7.0, - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Storage" + } + } } \ No newline at end of file diff --git a/controls/C-0049-networkmapping.json b/controls/C-0049-networkmapping.json index 49bb25faf..0b9e21fa8 100644 --- a/controls/C-0049-networkmapping.json +++ b/controls/C-0049-networkmapping.json @@ -28,7 +28,7 @@ "controlID": "C-0049", "baseScore": 3.0, "example": "@controls/examples/c049.yaml", - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0050-resourcescpulimitandrequest.json b/controls/C-0050-resourcescpulimitandrequest.json index 7e422ba75..5b049b46f 100644 --- a/controls/C-0050-resourcescpulimitandrequest.json +++ b/controls/C-0050-resourcescpulimitandrequest.json @@ -15,7 +15,10 @@ ], "controlID": "C-0050", "baseScore": 8.0, - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Resource management" + } + } } \ No newline at end of file diff --git a/controls/C-0052-instancemetadataapi.json b/controls/C-0052-instancemetadataapi.json index 635f10c40..82061926c 100644 --- a/controls/C-0052-instancemetadataapi.json +++ b/controls/C-0052-instancemetadataapi.json @@ -29,7 +29,7 @@ "test": "Check which nodes have access to instance metadata services. The check is for AWS, GCP and Azure.", "controlID": "C-0052", "baseScore": 7.0, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0053-accesscontainerserviceaccount.json b/controls/C-0053-accesscontainerserviceaccount.json index edde0d810..140952ae7 100644 --- a/controls/C-0053-accesscontainerserviceaccount.json +++ b/controls/C-0053-accesscontainerserviceaccount.json @@ -30,7 +30,7 @@ "test": "Control checks if RBAC is enabled. If it's not, the SA has unlimited permissions. If RBAC is enabled, it lists all permissions for each SA.", "controlID": "C-0053", "baseScore": 6.0, - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0054-clusterinternalnetworking.json b/controls/C-0054-clusterinternalnetworking.json index 27c68445a..db0bec8e8 100644 --- a/controls/C-0054-clusterinternalnetworking.json +++ b/controls/C-0054-clusterinternalnetworking.json @@ -28,7 +28,7 @@ "test": "Check for each namespace if there is a network policy defined.", "controlID": "C-0054", "baseScore": 4.0, - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0055-linuxhardening.json b/controls/C-0055-linuxhardening.json index abafc315b..6aa4469ba 100644 --- a/controls/C-0055-linuxhardening.json +++ b/controls/C-0055-linuxhardening.json @@ -24,7 +24,10 @@ "test": "Check if there is AppArmor or Seccomp or SELinux or Capabilities are defined in the securityContext of container and pod. If none of these fields are defined for both the container and pod, alert.", "controlID": "C-0055", "baseScore": 4.0, - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Node escape" + } + } } \ No newline at end of file diff --git a/controls/C-0056-configuredlivenessprobe.json b/controls/C-0056-configuredlivenessprobe.json index f4566cd7f..586dc4f8a 100644 --- a/controls/C-0056-configuredlivenessprobe.json +++ b/controls/C-0056-configuredlivenessprobe.json @@ -14,7 +14,7 @@ "long_description": "Liveness probe is intended to ensure that workload remains healthy during its entire execution lifecycle, or otherwise restrat the container. It is highly recommended to define liveness probe for every worker container. This control finds all the PODs where the Liveness probe is not configured.", "controlID": "C-0056", "baseScore": 4, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0057-privilegedcontainer.json b/controls/C-0057-privilegedcontainer.json index ecf009dac..a591263fe 100644 --- a/controls/C-0057-privilegedcontainer.json +++ b/controls/C-0057-privilegedcontainer.json @@ -27,7 +27,10 @@ "test": "Check in POD spec if securityContext.privileged == true, if so raise an alert.", "controlID": "C-0057", "baseScore": 8.0, - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Node escape" + } + } } \ No newline at end of file diff --git a/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json b/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json index e27c6e8c6..13d91edc9 100644 --- a/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json +++ b/controls/C-0058-cve202125741usingsymlinkforarbitraryhostfilesystemaccess.json @@ -23,7 +23,7 @@ ], "controlID": "C-0058", "baseScore": 6.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json b/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json index 9e827915c..841b24085 100644 --- a/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json +++ b/controls/C-0059-cve202125742nginxingresssnippetannotationvulnerability.json @@ -24,7 +24,7 @@ ], "controlID": "C-0059", "baseScore": 8.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0061-podsindefaultnamespace.json b/controls/C-0061-podsindefaultnamespace.json index e2bd0b938..5238f4209 100644 --- a/controls/C-0061-podsindefaultnamespace.json +++ b/controls/C-0061-podsindefaultnamespace.json @@ -16,7 +16,7 @@ "test": "Check that there are no pods in the 'default' namespace", "controlID": "C-0061", "baseScore": 3, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0062-sudoincontainerentrypoint.json b/controls/C-0062-sudoincontainerentrypoint.json index 7a524b576..b8abe000d 100644 --- a/controls/C-0062-sudoincontainerentrypoint.json +++ b/controls/C-0062-sudoincontainerentrypoint.json @@ -24,7 +24,7 @@ "controlID": "C-0062", "baseScore": 5.0, "example": "@controls/examples/c062.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0063-portforwardingprivileges.json b/controls/C-0063-portforwardingprivileges.json index 7e9eabe57..c15f9a05d 100644 --- a/controls/C-0063-portforwardingprivileges.json +++ b/controls/C-0063-portforwardingprivileges.json @@ -29,7 +29,7 @@ "controlID": "C-0063", "baseScore": 5.0, "example": "@controls/examples/c063.yaml", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0065-noimpersonation.json b/controls/C-0065-noimpersonation.json index f49f2c5c9..0cc3b951b 100644 --- a/controls/C-0065-noimpersonation.json +++ b/controls/C-0065-noimpersonation.json @@ -27,7 +27,7 @@ "controlID": "C-0065", "baseScore": 6.0, "example": "@controls/examples/c065.yaml", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0066-secretetcdencryptionenabled.json b/controls/C-0066-secretetcdencryptionenabled.json index 2bfface12..f41c06582 100644 --- a/controls/C-0066-secretetcdencryptionenabled.json +++ b/controls/C-0066-secretetcdencryptionenabled.json @@ -25,7 +25,7 @@ "test": "Reading the cluster description from the managed cloud API (EKS, GKE), or the API server pod configuration for native K8s and checking if etcd encryption is enabled", "controlID": "C-0066", "baseScore": 6.0, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0067-auditlogsenabled.json b/controls/C-0067-auditlogsenabled.json index c39b272c2..e75cb88e1 100644 --- a/controls/C-0067-auditlogsenabled.json +++ b/controls/C-0067-auditlogsenabled.json @@ -25,7 +25,7 @@ "test": "Reading the cluster description from the managed cloud API (EKS, GKE), or the API server pod configuration for native K8s and checking if audit logging is enabled", "controlID": "C-0067", "baseScore": 5.0, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0068-pspenabled.json b/controls/C-0068-pspenabled.json index 23607b524..94c48fb53 100644 --- a/controls/C-0068-pspenabled.json +++ b/controls/C-0068-pspenabled.json @@ -25,7 +25,7 @@ "test": "Reading the cluster description from the managed cloud API (EKS, GKE), or the API server pod configuration for native K8s and checking if PSP is enabled", "controlID": "C-0068", "baseScore": 1.0, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0069-disableanonymousaccesstokubeletservice.json b/controls/C-0069-disableanonymousaccesstokubeletservice.json index adfc2f79f..82fc7cbe7 100644 --- a/controls/C-0069-disableanonymousaccesstokubeletservice.json +++ b/controls/C-0069-disableanonymousaccesstokubeletservice.json @@ -24,7 +24,7 @@ "test": "Reading the kubelet command lines and configuration file looking for anonymous-auth configuration. If this configuration is set on both, the command line values take precedence over it.", "controlID": "C-0069", "baseScore": 10, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0070-enforcekubeletclienttlsauthentication.json b/controls/C-0070-enforcekubeletclienttlsauthentication.json index 43d2a5971..5238c7d7f 100644 --- a/controls/C-0070-enforcekubeletclienttlsauthentication.json +++ b/controls/C-0070-enforcekubeletclienttlsauthentication.json @@ -24,7 +24,7 @@ "test": "Reading the kubelet command lines and configuration file looking for client TLS configuration.", "controlID": "C-0070", "baseScore": 9.0, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0073-nakedpods.json b/controls/C-0073-nakedpods.json index 804aa50db..a9ad67967 100644 --- a/controls/C-0073-nakedpods.json +++ b/controls/C-0073-nakedpods.json @@ -15,7 +15,7 @@ "test": "Test if PODs are not associated with Deployment, ReplicaSet etc. If not, fail.", "controlID": "C-0073", "baseScore": 3, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0075-imagepullpolicyonlatesttag.json b/controls/C-0075-imagepullpolicyonlatesttag.json index 3b95877fc..6c18a4706 100644 --- a/controls/C-0075-imagepullpolicyonlatesttag.json +++ b/controls/C-0075-imagepullpolicyonlatesttag.json @@ -15,7 +15,7 @@ "test": "If imagePullPolicy = always pass, else fail.", "controlID": "C-0075", "baseScore": 2, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0076-labelusageforresources.json b/controls/C-0076-labelusageforresources.json index d8c86a165..61480dc7f 100644 --- a/controls/C-0076-labelusageforresources.json +++ b/controls/C-0076-labelusageforresources.json @@ -16,7 +16,7 @@ "test": "Test will check if a certain set of labels is defined, this is a configurable control. Initial list: app, tier, phase, version, owner, env.", "controlID": "C-0076", "baseScore": 2, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0077-k8scommonlabelsusage.json b/controls/C-0077-k8scommonlabelsusage.json index e9487d57e..100719999 100644 --- a/controls/C-0077-k8scommonlabelsusage.json +++ b/controls/C-0077-k8scommonlabelsusage.json @@ -16,7 +16,7 @@ "test": "Test will check if the list of label that start with app.kubernetes.io/ are defined.", "controlID": "C-0077", "baseScore": 2.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0078-imagesfromallowedregistry.json b/controls/C-0078-imagesfromallowedregistry.json index e44588dc5..c81342d34 100644 --- a/controls/C-0078-imagesfromallowedregistry.json +++ b/controls/C-0078-imagesfromallowedregistry.json @@ -29,7 +29,10 @@ "test": "Checks if image is from allowed listed registry.", "controlID": "C-0078", "baseScore": 5.0, - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload", + "subCategory": { + "name": "Supply chain" + } + } } \ No newline at end of file diff --git a/controls/C-0079-cve20220185linuxkernelcontainerescape.json b/controls/C-0079-cve20220185linuxkernelcontainerescape.json index 227f97a11..c190f8a66 100644 --- a/controls/C-0079-cve20220185linuxkernelcontainerescape.json +++ b/controls/C-0079-cve20220185linuxkernelcontainerescape.json @@ -25,7 +25,7 @@ "controlID": "C-0079", "baseScore": 4.0, "example": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0081-cve202224348argocddirtraversal.json b/controls/C-0081-cve202224348argocddirtraversal.json index cccb508be..bcbe5e737 100644 --- a/controls/C-0081-cve202224348argocddirtraversal.json +++ b/controls/C-0081-cve202224348argocddirtraversal.json @@ -24,7 +24,7 @@ "controlID": "C-0081", "baseScore": 4.0, "example": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json b/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json index b72394f5c..e232f7bfb 100644 --- a/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json +++ b/controls/C-0083-workloadswithcriticalvulnerabilitiesexposedtoexternaltraffic.json @@ -25,7 +25,7 @@ "controlID": "C-0083", "baseScore": 8.0, "example": "@controls/examples/c83.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json b/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json index 436569c68..e78f94d33 100644 --- a/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json +++ b/controls/C-0084-workloadswithrcevulnerabilitiesexposedtoexternaltraffic.json @@ -26,7 +26,7 @@ "controlID": "C-0084", "baseScore": 8.0, "example": "@controls/examples/c84.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json b/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json index de0af548d..031edc574 100644 --- a/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json +++ b/controls/C-0085-workloadswithexcessiveamountofvulnerabilities.json @@ -27,7 +27,7 @@ "controlID": "C-0085", "baseScore": 6.0, "example": "@controls/examples/c85.yaml", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0086-cve20220492cgroupscontainerescape.json b/controls/C-0086-cve20220492cgroupscontainerescape.json index 313b1be64..42c6b605c 100644 --- a/controls/C-0086-cve20220492cgroupscontainerescape.json +++ b/controls/C-0086-cve20220492cgroupscontainerescape.json @@ -25,7 +25,7 @@ "controlID": "C-0086", "baseScore": 4.0, "example": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0087-cve202223648containerdfsescape.json b/controls/C-0087-cve202223648containerdfsescape.json index 23f6353a5..5e5c061ae 100644 --- a/controls/C-0087-cve202223648containerdfsescape.json +++ b/controls/C-0087-cve202223648containerdfsescape.json @@ -25,7 +25,7 @@ "controlID": "C-0087", "baseScore": 7.0, "example": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0088-rbacenabled.json b/controls/C-0088-rbacenabled.json index b2ef0737a..6dedc7c9f 100644 --- a/controls/C-0088-rbacenabled.json +++ b/controls/C-0088-rbacenabled.json @@ -26,7 +26,7 @@ "test": "Testing API server or managed Kubernetes vendor API to determine if RBAC is enabled", "controlID": "C-0088", "baseScore": 7.0, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0089-cve20223172aggregatedapiserverredirect.json b/controls/C-0089-cve20223172aggregatedapiserverredirect.json index 682833537..50fc6d04b 100644 --- a/controls/C-0089-cve20223172aggregatedapiserverredirect.json +++ b/controls/C-0089-cve20223172aggregatedapiserverredirect.json @@ -17,7 +17,7 @@ "controlID": "C-0089", "baseScore": 3.0, "example": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0090-cve202239328grafanaauthbypass.json b/controls/C-0090-cve202239328grafanaauthbypass.json index 7c0172342..a8e16df0a 100644 --- a/controls/C-0090-cve202239328grafanaauthbypass.json +++ b/controls/C-0090-cve202239328grafanaauthbypass.json @@ -25,7 +25,7 @@ "controlID": "C-0090", "baseScore": 9.0, "example": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0091-cve202247633kyvernosignaturebypass.json b/controls/C-0091-cve202247633kyvernosignaturebypass.json index 8d1a21803..75abae624 100644 --- a/controls/C-0091-cve202247633kyvernosignaturebypass.json +++ b/controls/C-0091-cve202247633kyvernosignaturebypass.json @@ -25,7 +25,7 @@ "controlID": "C-0091", "baseScore": 8.0, "example": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json index ce1442467..38ac270d2 100644 --- a/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0092-ensurethattheapiserverpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, the `kube-apiserver.yaml` file has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json b/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json index add86fd06..c45791b21 100644 --- a/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0093-ensurethattheapiserverpodspecificationfileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, the `kube-apiserver.yaml` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json index 70b048b65..5b5ea4341 100644 --- a/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0094-ensurethatthecontrollermanagerpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, the `kube-controller-manager.yaml` file has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json b/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json index 111723c60..5b17e8377 100644 --- a/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0095-ensurethatthecontrollermanagerpodspecificationfileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `kube-controller-manager.yaml` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json index fae7bab0b..207b8391d 100644 --- a/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0096-ensurethattheschedulerpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `kube-scheduler.yaml` file has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json b/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json index fe04c769d..70be0e296 100644 --- a/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0097-ensurethattheschedulerpodspecificationfileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `kube-scheduler.yaml` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json index 4061abf66..39b48f99f 100644 --- a/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0098-ensurethattheetcdpodspecificationfilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `/etc/kubernetes/manifests/etcd.yaml` file has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json b/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json index 88575d203..8ac652a6c 100644 --- a/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json +++ b/controls/C-0099-ensurethattheetcdpodspecificationfileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `/etc/kubernetes/manifests/etcd.yaml` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json b/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json index 1d3fb4be3..ec2e54ac0 100644 --- a/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0100-ensurethatthecontainernetworkinterfacefilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "NA", - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json b/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json index 7c9d6fdd2..7f33e1f9a 100644 --- a/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json +++ b/controls/C-0101-ensurethatthecontainernetworkinterfacefileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "NA", - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json b/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json index 88172e390..e25f4194c 100644 --- a/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json +++ b/controls/C-0102-ensurethattheetcddatadirectorypermissionsaresetto700ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default, etcd data directory has permissions of `755`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json b/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json index f7d3e174a..63d6e8029 100644 --- a/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json +++ b/controls/C-0103-ensurethattheetcddatadirectoryownershipissettoetcdetcd.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default, etcd data directory ownership is set to `etcd:etcd`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json b/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json index 4ae419af9..22bbd3120 100644 --- a/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json +++ b/controls/C-0104-ensurethattheadminconffilepermissionsaresetto600.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None.", "default_value": "By default, admin.conf has permissions of `600`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json b/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json index c5388b21d..c6217e1e4 100644 --- a/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json +++ b/controls/C-0105-ensurethattheadminconffileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None.", "default_value": "By default, `admin.conf` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json b/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json index 796dc02fb..78dd55631 100644 --- a/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0106-ensurethattheschedulerconffilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `scheduler.conf` has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json b/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json index 91f870624..7ec6b9413 100644 --- a/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json +++ b/controls/C-0107-ensurethattheschedulerconffileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `scheduler.conf` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json b/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json index 0c037d0e0..fe58034a7 100644 --- a/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0108-ensurethatthecontrollermanagerconffilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `controller-manager.conf` has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json b/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json index 9534b5637..2c220ccd7 100644 --- a/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json +++ b/controls/C-0109-ensurethatthecontrollermanagerconffileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `controller-manager.conf` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json b/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json index 0a567c477..250aa2632 100644 --- a/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json +++ b/controls/C-0110-ensurethatthekubernetespkidirectoryandfileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "None", "default_value": "By default, the /etc/kubernetes/pki/ directory and all of the files and directories contained within it, are set to be owned by the root user.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json b/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json index 9bf26e508..78eebb953 100644 --- a/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0111-ensurethatthekubernetespkicertificatefilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "None", "default_value": "By default, the certificates used by Kubernetes are set to have permissions of `644`", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json b/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json index dba32ba7d..026eb47f3 100644 --- a/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json +++ b/controls/C-0112-ensurethatthekubernetespkikeyfilepermissionsaresetto600.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "None", "default_value": "By default, the keys used by Kubernetes are set to have permissions of `600`", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json b/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json index d9e8d2536..993718b5c 100644 --- a/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json +++ b/controls/C-0113-ensurethattheapiserveranonymousauthargumentissettofalse.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "Anonymous requests will be rejected.", "default_value": "By default, anonymous access is enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json b/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json index 3d238d057..b6c014d25 100644 --- a/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json +++ b/controls/C-0114-ensurethattheapiservertokenauthfileparameterisnotset.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "You will have to configure and use alternate authentication mechanisms such as certificates. Static token based authentication could not be used.", "default_value": "By default, `--token-auth-file` argument is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json b/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json index 365b9da22..d2f73fa2c 100644 --- a/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json +++ b/controls/C-0115-ensurethattheapiserverdenyserviceexternalipsisnotset.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "When enabled, users of the cluster may not create new Services which use externalIPs and may not add new values to externalIPs on existing Service objects.", "default_value": "By default, `--token-auth-file` argument is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json b/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json index 4047956d7..84fd6f4f9 100644 --- a/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json +++ b/controls/C-0116-ensurethattheapiserverkubeletclientcertificateandkubeletclientkeyargumentsaresetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "You require TLS to be configured on apiserver as well as kubelets.", "default_value": "By default, certificate-based kubelet authentication is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json b/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json index e859ef701..c3e751b71 100644 --- a/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json +++ b/controls/C-0117-ensurethattheapiserverkubeletcertificateauthorityargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "You require TLS to be configured on apiserver as well as kubelets.", "default_value": "By default, `--kubelet-certificate-authority` argument is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json b/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json index 4278d7cca..bb75d6a8c 100644 --- a/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json +++ b/controls/C-0118-ensurethattheapiserverauthorizationmodeargumentisnotsettoalwaysallow.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "Only authorized requests will be served.", "default_value": "By default, `AlwaysAllow` is not enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json b/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json index 6d05724ad..78fd41126 100644 --- a/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json +++ b/controls/C-0119-ensurethattheapiserverauthorizationmodeargumentincludesnode.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "None", "default_value": "By default, `Node` authorization is not enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json b/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json index 9b1b55b5f..382955977 100644 --- a/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json +++ b/controls/C-0120-ensurethattheapiserverauthorizationmodeargumentincludesrbac.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "When RBAC is enabled you will need to ensure that appropriate RBAC settings (including Roles, RoleBindings and ClusterRoleBindings) are configured to allow appropriate access.", "default_value": "By default, `RBAC` authorization is not enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json b/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json index b7a0817b1..decb83290 100644 --- a/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json +++ b/controls/C-0121-ensurethattheadmissioncontrolplugineventratelimitisset.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "You need to carefully tune in limits as per your environment.", "default_value": "By default, `EventRateLimit` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json b/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json index 8995f799d..c19a77eb1 100644 --- a/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json +++ b/controls/C-0122-ensurethattheadmissioncontrolpluginalwaysadmitisnotset.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "Only requests explicitly allowed by the admissions control plugins would be served.", "default_value": "`AlwaysAdmit` is not in the list of default admission plugins.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json b/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json index ccf0cf7c0..1fe168074 100644 --- a/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json +++ b/controls/C-0123-ensurethattheadmissioncontrolpluginalwayspullimagesisset.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "Credentials would be required to pull the private images every time. Also, in trusted environments, this might increases load on network, registry, and decreases speed.\n\n This setting could impact offline or isolated clusters, which have images pre-loaded and do not have access to a registry to pull in-use images. This setting is not appropriate for clusters which use this configuration.", "default_value": "By default, `AlwaysPullImages` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json b/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json index b81933a67..cdcaeb750 100644 --- a/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json +++ b/controls/C-0124-ensurethattheadmissioncontrolpluginsecuritycontextdenyissetifpodsecuritypolicyisnotused.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "This admission controller should only be used where Pod Security Policies cannot be used on the cluster, as it can interact poorly with certain Pod Security Policies", "default_value": "By default, `SecurityContextDeny` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json b/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json index e0c125597..f5abc0384 100644 --- a/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json +++ b/controls/C-0125-ensurethattheadmissioncontrolpluginserviceaccountisset.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "None.", "default_value": "By default, `ServiceAccount` is set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json b/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json index 62dd3c8f5..3ef25d741 100644 --- a/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json +++ b/controls/C-0126-ensurethattheadmissioncontrolpluginnamespacelifecycleisset.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "None", "default_value": "By default, `NamespaceLifecycle` is set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json b/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json index f7b5d375f..2b18e9857 100644 --- a/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json +++ b/controls/C-0127-ensurethattheadmissioncontrolpluginnoderestrictionisset.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "By default, `NodeRestriction` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json b/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json index 1d191cd3f..cc6dbfd35 100644 --- a/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json +++ b/controls/C-0128-ensurethattheapiserversecureportargumentisnotsetto0.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "You need to set the API Server up with the right TLS certificates.", "default_value": "By default, port 6443 is used as the secure port.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json b/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json index 838e314f1..ce06281d8 100644 --- a/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json +++ b/controls/C-0129-ensurethattheapiserverprofilingargumentissettofalse.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "Profiling information would not be available.", "default_value": "By default, profiling is enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json b/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json index 2ce31766d..1ba6bf484 100644 --- a/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json +++ b/controls/C-0130-ensurethattheapiserverauditlogpathargumentisset.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default, auditing is not enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json b/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json index d9ee2d6d5..3438fcca1 100644 --- a/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json +++ b/controls/C-0131-ensurethattheapiserverauditlogmaxageargumentissetto30orasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "By default, auditing is not enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json b/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json index 3a01de52b..8cfe8bd6a 100644 --- a/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json +++ b/controls/C-0132-ensurethattheapiserverauditlogmaxbackupargumentissetto10orasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "By default, auditing is not enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json b/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json index db6ed3f2a..efe116ec1 100644 --- a/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json +++ b/controls/C-0133-ensurethattheapiserverauditlogmaxsizeargumentissetto100orasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "By default, auditing is not enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json b/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json index ff32dfc25..2b060961a 100644 --- a/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json +++ b/controls/C-0134-ensurethattheapiserverrequesttimeoutargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "By default, `--request-timeout` is set to 60 seconds.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json b/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json index 0614fea1f..c25392f90 100644 --- a/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json +++ b/controls/C-0135-ensurethattheapiserverserviceaccountlookupargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `--service-account-lookup` argument is set to `true`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json b/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json index f61aa6eed..9841db83f 100644 --- a/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json +++ b/controls/C-0136-ensurethattheapiserverserviceaccountkeyfileargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "The corresponding private key must be provided to the controller manager. You would need to securely maintain the key file and rotate the keys based on your organization's key rotation policy.", "default_value": "By default, `--service-account-key-file` argument is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json b/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json index f50c4fe8d..4764f1c76 100644 --- a/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json +++ b/controls/C-0137-ensurethattheapiserveretcdcertfileandetcdkeyfileargumentsaresetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for etcd.", "default_value": "By default, `--etcd-certfile` and `--etcd-keyfile` arguments are not set", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json b/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json index 0dc320fd6..262d1bb13 100644 --- a/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json +++ b/controls/C-0138-ensurethattheapiservertlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for your Kubernetes cluster deployment.", "default_value": "By default, `--tls-cert-file` and `--tls-private-key-file` arguments are not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json b/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json index 3b6ac688f..7c6a8c739 100644 --- a/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json +++ b/controls/C-0139-ensurethattheapiserverclientcafileargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for your Kubernetes cluster deployment.", "default_value": "By default, `--client-ca-file` argument is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json b/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json index 89ced3789..f84a4cf63 100644 --- a/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json +++ b/controls/C-0140-ensurethattheapiserveretcdcafileargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "TLS and client certificate authentication must be configured for etcd.", "default_value": "By default, `--etcd-cafile` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json b/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json index 5ded1cc7a..820b2fa45 100644 --- a/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json +++ b/controls/C-0141-ensurethattheapiserverencryptionproviderconfigargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default, `--encryption-provider-config` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json b/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json index 5eccc3d4d..663ac8971 100755 --- a/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json +++ b/controls/C-0142-ensurethatencryptionprovidersareappropriatelyconfigured.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default, no encryption provider is set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json b/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json index 528f47a68..3a2e84a0d 100644 --- a/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json +++ b/controls/C-0143-ensurethattheapiserveronlymakesuseofstrongcryptographicciphers.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "API server clients that cannot support modern cryptographic ciphers will not be able to make connections to the API server.", "default_value": "By default the Kubernetes API server supports a wide range of TLS ciphers", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json b/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json index 67d03a9a1..844151faa 100644 --- a/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json +++ b/controls/C-0144-ensurethatthecontrollermanagerterminatedpodgcthresholdargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "By default, `--terminated-pod-gc-threshold` is set to `12500`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json b/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json index 982c033b8..fcab582fc 100644 --- a/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json +++ b/controls/C-0145-ensurethatthecontrollermanagerprofilingargumentissettofalse.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "Profiling information would not be available.", "default_value": "By default, profiling is enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json b/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json index 123bc36e9..4da2fa6d2 100644 --- a/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json +++ b/controls/C-0146-ensurethatthecontrollermanageruseserviceaccountcredentialsargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "Whatever authorizer is configured for the cluster, it must grant sufficient permissions to the service accounts to perform their intended tasks. When using the RBAC authorizer, those roles are created and bound to the appropriate service accounts in the `kube-system` namespace automatically with default roles and rolebindings that are auto-reconciled on startup.\n\n If using other authorization methods (ABAC, Webhook, etc), the cluster deployer is responsible for granting appropriate permissions to the service accounts (the required permissions can be seen by inspecting the `controller-roles.yaml` and `controller-role-bindings.yaml` files for the RBAC roles.", "default_value": "By default, `--use-service-account-credentials` is set to false.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json b/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json index ccc12a7a0..88e2b5d83 100644 --- a/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json +++ b/controls/C-0147-ensurethatthecontrollermanagerserviceaccountprivatekeyfileargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "You would need to securely maintain the key file and rotate the keys based on your organization's key rotation policy.", "default_value": "By default, `--service-account-private-key-file` it not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json b/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json index 7829302a9..811907a43 100644 --- a/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json +++ b/controls/C-0148-ensurethatthecontrollermanagerrootcafileargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "You need to setup and maintain root certificate authority file.", "default_value": "By default, `--root-ca-file` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json b/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json index 0c8ad21c7..79a2d9590 100644 --- a/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json +++ b/controls/C-0149-ensurethatthecontrollermanagerrotatekubeletservercertificateargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `RotateKubeletServerCertificate` is set to \"true\" this recommendation verifies that it has not been disabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json b/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json index f9fdc8a60..54b27fedf 100644 --- a/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json +++ b/controls/C-0150-ensurethatthecontrollermanagerbindaddressargumentissetto127001.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "None", "default_value": "By default, the `--bind-address` parameter is set to 0.0.0.0", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json b/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json index ed1be2be4..a1c077c26 100644 --- a/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json +++ b/controls/C-0151-ensurethattheschedulerprofilingargumentissettofalse.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "Profiling information would not be available.", "default_value": "By default, profiling is enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json b/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json index 6f99be38a..95e833d5f 100644 --- a/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json +++ b/controls/C-0152-ensurethattheschedulerbindaddressargumentissetto127001.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "None", "default_value": "By default, the `--bind-address` parameter is set to 0.0.0.0", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json b/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json index 73030037e..ddd045671 100644 --- a/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json +++ b/controls/C-0153-ensurethatthecertfileandkeyfileargumentsaresetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "Client connections only over TLS would be served.", "default_value": "By default, TLS encryption is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json b/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json index 7c88271a2..c37d3fc9b 100644 --- a/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json +++ b/controls/C-0154-ensurethattheclientcertauthargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "All clients attempting to access the etcd server will require a valid client certificate.", "default_value": "By default, the etcd service can be queried by unauthenticated clients.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json b/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json index aa69f1817..d068a8fad 100644 --- a/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json +++ b/controls/C-0155-ensurethattheautotlsargumentisnotsettotrue.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "Clients will not be able to use self-signed certificates for TLS.", "default_value": "By default, `--auto-tls` is set to `false`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json b/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json index 7d1b1f004..b64627e39 100644 --- a/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json +++ b/controls/C-0156-ensurethatthepeercertfileandpeerkeyfileargumentsaresetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "etcd cluster peers would need to set up TLS for their communication.", "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, peer communication over TLS is not configured.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json b/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json index aaf75a8ff..eda801ff2 100644 --- a/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json +++ b/controls/C-0157-ensurethatthepeerclientcertauthargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "All peers attempting to communicate with the etcd server will require a valid client certificate for authentication.", "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, `--peer-client-cert-auth` argument is set to `false`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json b/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json index 865c467ec..09fc066a6 100644 --- a/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json +++ b/controls/C-0158-ensurethatthepeerautotlsargumentisnotsettotrue.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "All peers attempting to communicate with the etcd server will require a valid client certificate for authentication.", "default_value": "**Note:** This recommendation is applicable only for etcd clusters. If you are using only one etcd server in your environment then this recommendation is not applicable.\n\n By default, `--peer-auto-tls` argument is set to `false`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json b/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json index 8503a619d..33db048d0 100644 --- a/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json +++ b/controls/C-0159-ensurethatauniquecertificateauthorityisusedforetcd.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "Additional management of the certificates and keys for the dedicated certificate authority will be required.", "default_value": "By default, no etcd certificate is created and used.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0160-ensurethataminimalauditpolicyiscreated.json b/controls/C-0160-ensurethataminimalauditpolicyiscreated.json index fd1dc95fe..92626fd52 100644 --- a/controls/C-0160-ensurethataminimalauditpolicyiscreated.json +++ b/controls/C-0160-ensurethataminimalauditpolicyiscreated.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Audit logs will be created on the master nodes, which will consume disk space. Care should be taken to avoid generating too large volumes of log information as this could impact the available of the cluster nodes.", "default_value": "Unless the `--audit-policy-file` flag is specified, no auditing will be carried out.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json b/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json index 345f50a97..e33561372 100644 --- a/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json +++ b/controls/C-0161-ensurethattheauditpolicycoverskeysecurityconcerns.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Increasing audit logging will consume resources on the nodes or other log destination.", "default_value": "By default Kubernetes clusters do not log audit information.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json b/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json index 1a28677c3..d4219564e 100644 --- a/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0162-ensurethatthekubeletservicefilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, the `kubelet` service file has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json b/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json index d7afcb3d7..f07b3b874 100644 --- a/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json +++ b/controls/C-0163-ensurethatthekubeletservicefileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `kubelet` service file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json b/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json index 865e5d7f6..179bdb620 100644 --- a/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0164-ifproxykubeconfigfileexistsensurepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, proxy file has permissions of `640`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json b/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json index dd0221f6a..d2b02106e 100644 --- a/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json +++ b/controls/C-0165-ifproxykubeconfigfileexistsensureownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `proxy` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json b/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json index 67f3fc339..f0387868d 100644 --- a/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0166-ensurethatthekubeconfigkubeletconffilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `kubelet.conf` file has permissions of `600`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json b/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json index 3683fd9c4..594658092 100644 --- a/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json +++ b/controls/C-0167-ensurethatthekubeconfigkubeletconffileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, `kubelet.conf` file ownership is set to `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json b/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json index 38d1712c4..589370503 100644 --- a/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json +++ b/controls/C-0168-ensurethatthecertificateauthoritiesfilepermissionsaresetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default no `--client-ca-file` is specified.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json b/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json index bf3ade848..c14e3f9b3 100644 --- a/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json +++ b/controls/C-0169-ensurethattheclientcertificateauthoritiesfileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default no `--client-ca-file` is specified.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json b/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json index 82a58698b..f274df7c2 100644 --- a/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json +++ b/controls/C-0170-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatepermissionssetto600ormorerestrictive.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default, the /var/lib/kubelet/config.yaml file as set up by `kubeadm` has permissions of 600.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json b/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json index 66b7a52b3..8c8234961 100644 --- a/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json +++ b/controls/C-0171-ifthekubeletconfigyamlconfigurationfileisbeingusedvalidatefileownershipissettorootroot.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "None", "default_value": "By default, `/var/lib/kubelet/config.yaml` file as set up by `kubeadm` is owned by `root:root`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json b/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json index 49ac206f3..6d479c4a7 100644 --- a/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json +++ b/controls/C-0172-ensurethattheanonymousauthargumentissettofalse.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "Anonymous requests will be rejected.", "default_value": "By default, anonymous access is enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json b/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json index 403867f8b..5f6c5f2d9 100644 --- a/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json +++ b/controls/C-0173-ensurethattheauthorizationmodeargumentisnotsettoalwaysallow.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "Unauthorized requests will be denied.", "default_value": "By default, `--authorization-mode` argument is set to `AlwaysAllow`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json b/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json index 52abb5eb6..ddfb96d72 100644 --- a/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json +++ b/controls/C-0174-ensurethattheclientcafileargumentissetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "You require TLS to be configured on apiserver as well as kubelets.", "default_value": "By default, `--client-ca-file` argument is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0175-verifythatthereadonlyportargumentissetto0.json b/controls/C-0175-verifythatthereadonlyportargumentissetto0.json index 9f39a7492..ed7500618 100644 --- a/controls/C-0175-verifythatthereadonlyportargumentissetto0.json +++ b/controls/C-0175-verifythatthereadonlyportargumentissetto0.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "Removal of the read-only port will require that any service which made use of it will need to be re-configured to use the main Kubelet API.", "default_value": "By default, `--read-only-port` is set to `10255/TCP`. However, if a config file is specified by `--config` the default value for `readOnlyPort` is 0.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json b/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json index 6b8a66569..a6e674bfa 100644 --- a/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json +++ b/controls/C-0176-ensurethatthestreamingconnectionidletimeoutargumentisnotsetto0.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "Long-lived connections could be interrupted.", "default_value": "By default, `--streaming-connection-idle-timeout` is set to 4 hours.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json b/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json index b3b389730..53d03692b 100644 --- a/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json +++ b/controls/C-0177-ensurethattheprotectkerneldefaultsargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 2, "impact_statement": "You would have to re-tune kernel parameters to match kubelet parameters.", "default_value": "By default, `--protect-kernel-defaults` is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json b/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json index 21dbbf367..7d1d52ad9 100644 --- a/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json +++ b/controls/C-0178-ensurethatthemakeiptablesutilchainsargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "Kubelet would manage the iptables on the system and keep it in sync. If you are using any other iptables management solution, then there might be some conflicts.", "default_value": "By default, `--make-iptables-util-chains` argument is set to `true`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json b/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json index 707a2163e..348ac3aed 100644 --- a/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json +++ b/controls/C-0179-ensurethatthehostnameoverrideargumentisnotset.json @@ -17,7 +17,7 @@ "baseScore": 3, "impact_statement": "Some cloud providers may require this flag to ensure that hostname matches names issued by the cloud provider. In these environments, this recommendation should not apply.", "default_value": "By default, `--hostname-override` argument is not set.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json b/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json index a86633725..8a7869072 100644 --- a/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json +++ b/controls/C-0180-ensurethattheeventqpsargumentissetto0oralevelwhichensuresappropriateeventcapture.json @@ -17,7 +17,7 @@ "baseScore": 2, "impact_statement": "Setting this parameter to `0` could result in a denial of service condition due to excessive events being created. The cluster's event processing and storage systems should be scaled to handle expected event loads.", "default_value": "By default, `--event-qps` argument is set to `5`.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json b/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json index 73902fd8e..fabadde3d 100644 --- a/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json +++ b/controls/C-0181-ensurethatthetlscertfileandtlsprivatekeyfileargumentsaresetasappropriate.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "", "default_value": "", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json b/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json index 9118523d6..2bc254e2a 100644 --- a/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json +++ b/controls/C-0182-ensurethattherotatecertificatesargumentisnotsettofalse.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, kubelet client certificate rotation is enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json b/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json index aa36f41b9..7140c2e10 100644 --- a/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json +++ b/controls/C-0183-verifythattherotatekubeletservercertificateargumentissettotrue.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "None", "default_value": "By default, kubelet server certificate rotation is enabled.", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json b/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json index ce1ce2abf..410612fae 100644 --- a/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json +++ b/controls/C-0184-ensurethatthekubeletonlymakesuseofstrongcryptographicciphers.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Kubelet clients that cannot support modern cryptographic ciphers will not be able to make connections to the Kubelet API.", "default_value": "By default the Kubernetes API server supports a wide range of TLS ciphers", - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json b/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json index 6a0ae554c..0e5c8cb0f 100644 --- a/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json +++ b/controls/C-0185-ensurethattheclusteradminroleisonlyusedwhererequired.json @@ -18,7 +18,7 @@ "baseScore": 8, "impact_statement": "Care should be taken before removing any `clusterrolebindings` from the environment to ensure they were not required for operation of the cluster. Specifically, modifications should not be made to `clusterrolebindings` with the `system:` prefix as they are required for the operation of system components.", "default_value": "By default a single `clusterrolebinding` called `cluster-admin` is provided with the `system:masters` group as its principal.", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0186-minimizeaccesstosecrets.json b/controls/C-0186-minimizeaccesstosecrets.json index 90b8197cf..221715b2b 100644 --- a/controls/C-0186-minimizeaccesstosecrets.json +++ b/controls/C-0186-minimizeaccesstosecrets.json @@ -18,7 +18,7 @@ "baseScore": 6, "impact_statement": "Care should be taken not to remove access to secrets to system components which require this for their operation", "default_value": "By default in a kubeadm cluster the following list of principals have `get` privileges on `secret` objects\n\n \n```\nCLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE\ncluster-admin system:masters Group \nsystem:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system\nsystem:controller:expand-controller expand-controller ServiceAccount kube-system\nsystem:controller:generic-garbage-collector generic-garbage-collector ServiceAccount kube-system\nsystem:controller:namespace-controller namespace-controller ServiceAccount kube-system\nsystem:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system\nsystem:kube-controller-manager system:kube-controller-manager User \n\n```", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json b/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json index b0820d0e4..47c44090e 100644 --- a/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json +++ b/controls/C-0187-minimizewildcarduseinrolesandclusterroles.json @@ -18,7 +18,7 @@ "baseScore": 7, "impact_statement": "", "default_value": "", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0188-minimizeaccesstocreatepods.json b/controls/C-0188-minimizeaccesstocreatepods.json index 7011f324c..20016d4f3 100644 --- a/controls/C-0188-minimizeaccesstocreatepods.json +++ b/controls/C-0188-minimizeaccesstocreatepods.json @@ -18,7 +18,7 @@ "baseScore": 5, "impact_statement": "Care should be taken not to remove access to pods to system components which require this for their operation", "default_value": "By default in a kubeadm cluster the following list of principals have `create` privileges on `pod` objects\n\n \n```\nCLUSTERROLEBINDING SUBJECT TYPE SA-NAMESPACE\ncluster-admin system:masters Group \nsystem:controller:clusterrole-aggregation-controller clusterrole-aggregation-controller ServiceAccount kube-system\nsystem:controller:daemon-set-controller daemon-set-controller ServiceAccount kube-system\nsystem:controller:job-controller job-controller ServiceAccount kube-system\nsystem:controller:persistent-volume-binder persistent-volume-binder ServiceAccount kube-system\nsystem:controller:replicaset-controller replicaset-controller ServiceAccount kube-system\nsystem:controller:replication-controller replication-controller ServiceAccount kube-system\nsystem:controller:statefulset-controller statefulset-controller ServiceAccount kube-system\n\n```", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json b/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json index 2278e03c6..bb36a7539 100644 --- a/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json +++ b/controls/C-0189-ensurethatdefaultserviceaccountsarenotactivelyused.json @@ -19,7 +19,7 @@ "baseScore": 5, "impact_statement": "All workloads which require access to the Kubernetes API will require an explicit service account to be created.", "default_value": "By default the `default` service account allows for its service account token to be mounted in pods in its namespace.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json b/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json index b985df847..63704b294 100644 --- a/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json +++ b/controls/C-0190-ensurethatserviceaccounttokensareonlymountedwherenecessary.json @@ -18,7 +18,7 @@ "baseScore": 5, "impact_statement": "Pods mounted without service account tokens will not be able to communicate with the API server, except where the resource is available to unauthenticated principals.", "default_value": "By default, all pods get a service account token mounted in them.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json b/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json index 1242fdc5e..879e2f500 100644 --- a/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json +++ b/controls/C-0191-limituseofthebindimpersonateandescalatepermissionsinthekubernetescluster.json @@ -18,7 +18,7 @@ "baseScore": 6, "impact_statement": "There are some cases where these permissions are required for cluster service operation, and care should be taken before removing these permissions from system service accounts.", "default_value": "In a default kubeadm cluster, the system:masters group and clusterrole-aggregation-controller service account have access to the escalate privilege. The system:masters group also has access to bind and impersonate.", - "categories": [ - "Access control" - ] + "category": { + "name" : "Access control" + } } \ No newline at end of file diff --git a/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json b/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json index 11457c7b7..e601f7f50 100644 --- a/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json +++ b/controls/C-0192-ensurethattheclusterhasatleastoneactivepolicycontrolmechanisminplace.json @@ -18,7 +18,7 @@ "baseScore": 4, "impact_statement": "Where policy control systems are in place, there is a risk that workloads required for the operation of the cluster may be stopped from running. Care is required when implementing admission control policies to ensure that this does not occur.", "default_value": "By default, Pod Security Admission is enabled but no policies are in place.", - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json b/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json index a3cc4a4cd..6be68c9df 100644 --- a/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json +++ b/controls/C-0193-minimizetheadmissionofprivilegedcontainers.json @@ -17,7 +17,7 @@ "baseScore": 8, "impact_statement": "Pods defined with `spec.containers[].securityContext.privileged: true`, `spec.initContainers[].securityContext.privileged: true` and `spec.ephemeralContainers[].securityContext.privileged: true` will not be permitted.", "default_value": "By default, there are no restrictions on the creation of privileged containers.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json b/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json index 23de1b4de..4c53d7420 100644 --- a/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json +++ b/controls/C-0194-minimizetheadmissionofcontainerswishingtosharethehostprocessidnamespace.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Pods defined with `spec.hostPID: true` will not be permitted unless they are run under a specific policy.", "default_value": "By default, there are no restrictions on the creation of `hostPID` containers.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json b/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json index bc60fdc3a..60ed3de0d 100644 --- a/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json +++ b/controls/C-0195-minimizetheadmissionofcontainerswishingtosharethehostipcnamespace.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Pods defined with `spec.hostIPC: true` will not be permitted unless they are run under a specific policy.", "default_value": "By default, there are no restrictions on the creation of `hostIPC` containers.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json b/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json index 9b44aba60..450a8a02e 100644 --- a/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json +++ b/controls/C-0196-minimizetheadmissionofcontainerswishingtosharethehostnetworknamespace.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Pods defined with `spec.hostNetwork: true` will not be permitted unless they are run under a specific policy.", "default_value": "By default, there are no restrictions on the creation of `hostNetwork` containers.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json b/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json index c08c00539..2b9a88dd6 100644 --- a/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json +++ b/controls/C-0197-minimizetheadmissionofcontainerswithallowprivilegeescalation.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "Pods defined with `spec.allowPrivilegeEscalation: true` will not be permitted unless they are run under a specific policy.", "default_value": "By default, there are no restrictions on contained process ability to escalate privileges, within the context of the container.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0198-minimizetheadmissionofrootcontainers.json b/controls/C-0198-minimizetheadmissionofrootcontainers.json index e4fe4aa73..35ddeadfc 100644 --- a/controls/C-0198-minimizetheadmissionofrootcontainers.json +++ b/controls/C-0198-minimizetheadmissionofrootcontainers.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "Pods with containers which run as the root user will not be permitted.", "default_value": "By default, there are no restrictions on the use of root containers and if a User is not specified in the image, the container will run as root.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json b/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json index deb58c43b..dcb527dc9 100644 --- a/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json +++ b/controls/C-0199-minimizetheadmissionofcontainerswiththenet_rawcapability.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "Pods with containers which run with the NET\\_RAW capability will not be permitted.", "default_value": "By default, there are no restrictions on the creation of containers with the `NET_RAW` capability.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json b/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json index 67a261fee..6a8006cff 100644 --- a/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json +++ b/controls/C-0200-minimizetheadmissionofcontainerswithaddedcapabilities.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Pods with containers which require capabilities outwith the default set will not be permitted.", "default_value": "By default, there are no restrictions on adding capabilities to containers.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json b/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json index 6fe20d6c5..d0d18c57f 100644 --- a/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json +++ b/controls/C-0201-minimizetheadmissionofcontainerswithcapabilitiesassigned.json @@ -17,7 +17,7 @@ "baseScore": 5, "impact_statement": "Pods with containers require capabilities to operate will not be permitted.", "default_value": "By default, there are no restrictions on the creation of containers with additional capabilities", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json b/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json index f92984c88..bee7f842d 100644 --- a/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json +++ b/controls/C-0202-minimizetheadmissionofwindowshostprocesscontainers.json @@ -17,7 +17,7 @@ "baseScore": 7, "impact_statement": "Pods defined with `securityContext.windowsOptions.hostProcess: true` will not be permitted unless they are run under a specific policy.", "default_value": "By default, there are no restrictions on the creation of `hostProcess` containers.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0203-minimizetheadmissionofhostpathvolumes.json b/controls/C-0203-minimizetheadmissionofhostpathvolumes.json index 5e1a09232..861a26835 100644 --- a/controls/C-0203-minimizetheadmissionofhostpathvolumes.json +++ b/controls/C-0203-minimizetheadmissionofhostpathvolumes.json @@ -17,7 +17,7 @@ "baseScore": 6, "impact_statement": "Pods defined which make use of `hostPath` volumes will not be permitted unless they are run under a spefific policy.", "default_value": "By default, there are no restrictions on the creation of `hostPath` volumes.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json b/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json index dbd28b742..d49b9cca4 100644 --- a/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json +++ b/controls/C-0204-minimizetheadmissionofcontainerswhichusehostports.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "Pods defined with `hostPort` settings in either the container, initContainer or ephemeralContainer sections will not be permitted unless they are run under a specific policy.", "default_value": "By default, there are no restrictions on the use of HostPorts.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json b/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json index e3d60c6be..1339f4340 100644 --- a/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json +++ b/controls/C-0205-ensurethatthecniinusesupportsnetworkpolicies.json @@ -17,7 +17,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "This will depend on the CNI plugin in use.", - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json b/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json index aff7af7e5..d59fbfaed 100644 --- a/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json +++ b/controls/C-0206-ensurethatallnamespaceshavenetworkpoliciesdefined.json @@ -18,7 +18,7 @@ "baseScore": 4, "impact_statement": "Once network policies are in use within a given namespace, traffic not explicitly allowed by a network policy will be denied. As such it is important to ensure that, when introducing network policies, legitimate traffic is not blocked.", "default_value": "By default, network policies are not created.", - "categories": [ - "Network" - ] + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json b/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json index 39cf71035..da044cf02 100644 --- a/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json +++ b/controls/C-0207-preferusingsecretsasfilesoversecretsasenvironmentvariables.json @@ -18,7 +18,10 @@ "baseScore": 4, "impact_statement": "Application code which expects to read secrets in the form of environment variables would need modification", "default_value": "By default, secrets are not defined", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload", + "subCategory": { + "name" : "Secrets" +} + } } \ No newline at end of file diff --git a/controls/C-0208-considerexternalsecretstorage.json b/controls/C-0208-considerexternalsecretstorage.json index 58f0032ed..6b4544611 100644 --- a/controls/C-0208-considerexternalsecretstorage.json +++ b/controls/C-0208-considerexternalsecretstorage.json @@ -18,7 +18,7 @@ "external-secret-storage" ], "baseScore": 5, - "categories": [ - "Control plane" - ] + "category": { + "name" : "Control plane" + } } \ No newline at end of file diff --git a/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json b/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json index 8ce3a126b..331db12f4 100644 --- a/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json +++ b/controls/C-0209-createadministrativeboundariesbetweenresourcesusingnamespaces.json @@ -18,7 +18,7 @@ "baseScore": 5, "impact_statement": "You need to switch between namespaces for administration.", "default_value": "By default, Kubernetes starts with two initial namespaces:\n\n 1. `default` - The default namespace for objects with no other namespace\n2. `kube-system` - The namespace for objects created by the Kubernetes system\n3. `kube-node-lease` - Namespace used for node heartbeats\n4. `kube-public` - Namespace used for public information in a cluster", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json b/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json index 7000e8999..b26d316f5 100644 --- a/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json +++ b/controls/C-0210-ensurethattheseccompprofileissettodockerdefaultinyourpoddefinitions.json @@ -18,7 +18,7 @@ "baseScore": 4, "impact_statement": "If the `docker/default` seccomp profile is too restrictive for you, you would have to create/manage your own seccomp profiles.", "default_value": "By default, seccomp profile is set to `unconfined` which means that no seccomp profiles are enabled.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json b/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json index defc6627d..71f7b8e3e 100644 --- a/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json +++ b/controls/C-0211-applysecuritycontexttoyourpodsandcontainers.json @@ -28,7 +28,7 @@ "baseScore": 8, "impact_statement": "If you incorrectly apply security contexts, you may have trouble running the pods.", "default_value": "By default, no security contexts are automatically applied to pods.", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0212-thedefaultnamespaceshouldnotbeused.json b/controls/C-0212-thedefaultnamespaceshouldnotbeused.json index 6020eef8b..69d287d04 100644 --- a/controls/C-0212-thedefaultnamespaceshouldnotbeused.json +++ b/controls/C-0212-thedefaultnamespaceshouldnotbeused.json @@ -25,7 +25,7 @@ "baseScore": 4, "impact_statement": "None", "default_value": "Unless a namespace is specific on object creation, the `default` namespace will be used", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload" + } } \ No newline at end of file diff --git a/controls/C-0236-verifyimagesignature.json b/controls/C-0236-verifyimagesignature.json index 266dd3755..5c79b269f 100644 --- a/controls/C-0236-verifyimagesignature.json +++ b/controls/C-0236-verifyimagesignature.json @@ -16,7 +16,10 @@ "baseScore": 7, "impact_statement": "", "default_value": "", - "categories": [ - "Workload" - ] + "category": { + "name": "Workload", + "subCategory": { + "name": "Supply chain" + } + } } \ No newline at end of file diff --git a/controls/C-0237-hasimagesignature.json b/controls/C-0237-hasimagesignature.json index e181b2074..623cf76c9 100644 --- a/controls/C-0237-hasimagesignature.json +++ b/controls/C-0237-hasimagesignature.json @@ -15,7 +15,10 @@ "baseScore": 7, "impact_statement": "", "default_value": "", - "categories": [ - "Workload" - ] + "category": { + "name" : "Workload", + "subCategory": { + "name": "Supply chain" +} + } } \ No newline at end of file diff --git a/controls/C-0260-missingnetworkpolicy.json b/controls/C-0260-missingnetworkpolicy.json index a2efffdbd..d3733c1f9 100644 --- a/controls/C-0260-missingnetworkpolicy.json +++ b/controls/C-0260-missingnetworkpolicy.json @@ -19,5 +19,8 @@ "rulesNames": ["ensure_network_policy_configured_in_labels"], "test": "Check that all workloads has a network policy configured in labels.", "controlID": "C-0260", - "baseScore": 5.0 + "baseScore": 5.0, + "category": { + "name" : "Network" + } } \ No newline at end of file diff --git a/controls/C-0262-anonymousaccessisenabled.json b/controls/C-0262-anonymousaccessisenabled.json index 4f6ed8aa0..13868b5fe 100644 --- a/controls/C-0262-anonymousaccessisenabled.json +++ b/controls/C-0262-anonymousaccessisenabled.json @@ -11,5 +11,11 @@ "ensure-that-the-api-server-anonymous-auth-argument-is-set-to-false", "anonymous-access-enabled" ], - "baseScore": 5 + "baseScore": 5, + "category": { + "name" : "Control plane", + "subCategory": { + "name": "Supply chain" +} + } } diff --git a/frameworks/clusterscan.json b/frameworks/clusterscan.json new file mode 100644 index 000000000..3cec6b089 --- /dev/null +++ b/frameworks/clusterscan.json @@ -0,0 +1,144 @@ +{ + "name": "ClusterScan", + "description": "Framework for scanning a cluster", + "attributes": { + "armoBuiltin": true + }, + "typeTags": [ + "security" + ], + "activeControls": [ + { + "controlID": "C-0066", + "patch": { + "name": "Secret/ETCD encryption enabled" + } + }, + { + "controlID": "C-0088", + "patch": { + "name": "RBAC enabled" + } + }, + { + "controlID": "C-0067", + "patch": { + "name": "Audit logs enabled" + } + }, + { + "controlID": "C-0005", + "patch": { + "name": "API server insecure port is enabled" + } + }, + { + "controlID": "C-0262", + "patch": { + "name": "Anonymous access enabled" + } + }, + { + "controlID": "C-0015", + "patch": { + "name": "List Kubernetes secrets" + } + }, + { + "controlID": "C-0002", + "patch": { + "name": "Exec into container" + } + }, + { + "controlID": "C-0007", + "patch": { + "name": "Data Destruction" + } + }, + { + "controlID": "C-0063", + "patch": { + "name": "Portforwarding privileges" + } + }, + { + "controlID": "C-0036", + "patch": { + "name": "Validate admission controller (validating)" + } + }, + { + "controlID": "C-0039", + "patch": { + "name": "Validate admission controller (mutating)" + } + }, + { + "controlID": "C-0035", + "patch": { + "name": "Cluster-admin binding" + } + }, + { + "controlID": "C-0188", + "patch": { + "name": "Minimize access to create pods" + } + }, + { + "controlID": "C-0187", + "patch": { + "name": "Minimize wildcard use in Roles and ClusterRoles" + } + }, + { + "controlID": "C-0012", + "patch": { + "name": "Applications credentials in configuration files" + } + }, + { + "controlID": "C-0260", + "patch": { + "name": "Missing network policy" + } + }, + { + "controlID": "C-0256", + "patch": { + "name": "Exposure to internet" + } + }, + { + "controlID": "C-0038", + "patch": { + "name": "Host PID/IPC privileges" + } + }, + { + "controlID": "C-0041", + "patch": { + "name": "HostNetwork access" + } + }, + { + "controlID": "C-0048", + "patch": { + "name": "HostPath mount" + } + }, + { + "controlID": "C-0057", + "patch": { + "name": "Privileged container" + } + }, + { + "controlID": "C-0013", + "patch": { + "name": "Non-root containers" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/workloadscan.json b/frameworks/workloadscan.json new file mode 100644 index 000000000..c92f72ea3 --- /dev/null +++ b/frameworks/workloadscan.json @@ -0,0 +1,139 @@ +{ + "name": "WorkloadScan", + "description": "Framework for scanning a workload", + "attributes": { + "armoBuiltin": true + }, + "typeTags": [ + "security" + ], + "activeControls": [ + { + "controlID": "C-0078", + "patch": { + "name": "Images from allowed registry" + } + }, + { + "controlID": "C-0236", + "patch": { + "name": "Verify image signature" + } + }, + { + "controlID": "C-0237", + "patch": { + "name": "Check if signature exists" + } + }, + { + "controlID": "C-0004", + "patch": { + "name": "Resources memory limit and request" + } + }, + { + "controlID": "C-0050", + "patch": { + "name": "Resources CPU limit and request" + } + }, + { + "controlID": "C-0045", + "patch": { + "name": "Writable hostPath mount" + } + }, + { + "controlID": "C-0048", + "patch": { + "name": "HostPath mount" + } + }, + { + "controlID": "C-0257", + "patch": { + "name": "Workload with PVC access" + } + }, + { + "controlID": "C-0207", + "patch": { + "name": "Prefer using secrets as files over secrets as environment variables" + } + }, + { + "controlID": "C-0034", + "patch": { + "name": "Automatic mapping of service account" + } + }, + { + "controlID": "C-0012", + "patch": { + "name": "Applications credentials in configuration files" + } + }, + + { + "controlID": "C-0041", + "patch": { + "name": "HostNetwork access" + } + }, + { + "controlID": "C-0260", + "patch": { + "name": "Missing network policy" + } + }, + { + "controlID": "C-0044", + "patch": { + "name": "Container hostPort" + } + }, + { + "controlID": "C-0038", + "patch": { + "name": "Host PID/IPC privileges" + } + }, + { + "controlID": "C-0046", + "patch": { + "name": "Insecure capabilities" + } + }, + { + "controlID": "C-0013", + "patch": { + "name": "Non-root containers" + } + }, + { + "controlID": "C-0016", + "patch": { + "name": "Allow privilege escalation" + } + }, + { + "controlID": "C-0017", + "patch": { + "name": "Immutable container filesystem" + } + }, + { + "controlID": "C-0055", + "patch": { + "name": "Linux hardening" + } + }, + { + "controlID": "C-0057", + "patch": { + "name": "Privileged container" + } + } + ] +} \ No newline at end of file diff --git a/scripts/export.py b/scripts/export.py index 865726fe8..47e39b0f1 100644 --- a/scripts/export.py +++ b/scripts/export.py @@ -100,6 +100,9 @@ def load_rules(): """ def load_controls(loaded_rules: dict): + with open(os.path.join(__CWD__, 'categories', 'mapCategoryNameToID.json'), "r") as f: + map_category_name_to_id = json.load(f) + p2 = os.path.join(__CWD__, 'controls') logging.info(f"Loading controls from folder '{p2}'") @@ -119,6 +122,26 @@ def load_controls(loaded_rules: dict): logging.error(f"failed to open control: '{path_in_str}'") raise TypeError(e) + categoryFieldName = "category" + subCategoryFieldName = "subCategory" + + # insert category ID into control obj + if categoryFieldName in new_control: + categoryName = new_control[categoryFieldName]['name'] + if categoryName in map_category_name_to_id: + new_control[categoryFieldName]['id'] = map_category_name_to_id[categoryName] + else: + raise TypeError(f"Failed to find category name '{categoryName}' in mapCategoryNameToID.json") + + if subCategoryFieldName in new_control[categoryFieldName]: + subCategoryName = new_control[categoryFieldName][subCategoryFieldName]['name'] + if subCategoryName in map_category_name_to_id: + new_control[categoryFieldName][subCategoryFieldName]['id'] = map_category_name_to_id[subCategoryName] + else: + if subCategoryName == "": + continue + raise TypeError(f"Failed to find subcategory name '{subCategoryName}' in mapCategoryNameToID.json") + new_control["rules"] = [] new_control_copy = copy.deepcopy(new_control) controls_list.append(new_control_copy) From ec3fb4acc5125bb8c9f324445d80c62aed53d329 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Thu, 20 Jul 2023 09:24:04 +0300 Subject: [PATCH 06/11] fix conflict --- controls/C-0262-anonymousaccessisenabled.json | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/controls/C-0262-anonymousaccessisenabled.json b/controls/C-0262-anonymousaccessisenabled.json index 45c3fb7da..6bd904649 100644 --- a/controls/C-0262-anonymousaccessisenabled.json +++ b/controls/C-0262-anonymousaccessisenabled.json @@ -11,15 +11,11 @@ "ensure-that-the-api-server-anonymous-auth-argument-is-set-to-false", "anonymous-access-enabled" ], -<<<<<<< HEAD "baseScore": 5, "category": { - "name" : "Control plane", + "name": "Control plane", "subCategory": { - "name": "Supply chain" -} - } -======= - "baseScore": 5 ->>>>>>> master -} + "name": "Supply chain" + } + } +} \ No newline at end of file From 3ac52cb04727823c2bc11a1f8214f074a7225fb3 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Thu, 20 Jul 2023 09:38:03 +0300 Subject: [PATCH 07/11] format doc Signed-off-by: Daniel Grunberger --- controls/C-0237-hasimagesignature.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controls/C-0237-hasimagesignature.json b/controls/C-0237-hasimagesignature.json index 623cf76c9..eb9b8ebc5 100644 --- a/controls/C-0237-hasimagesignature.json +++ b/controls/C-0237-hasimagesignature.json @@ -16,9 +16,9 @@ "impact_statement": "", "default_value": "", "category": { - "name" : "Workload", + "name": "Workload", "subCategory": { - "name": "Supply chain" -} - } + "name": "Supply chain" + } + } } \ No newline at end of file From 09b3bbc286bfd4e34ba6f4ab2ff81d8bf4f34f82 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Thu, 20 Jul 2023 15:26:10 +0300 Subject: [PATCH 08/11] changes --- scripts/export.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/scripts/export.py b/scripts/export.py index 47e39b0f1..0779fba7a 100644 --- a/scripts/export.py +++ b/scripts/export.py @@ -122,25 +122,26 @@ def load_controls(loaded_rules: dict): logging.error(f"failed to open control: '{path_in_str}'") raise TypeError(e) - categoryFieldName = "category" - subCategoryFieldName = "subCategory" + category_field_name = "category" + sub_category_field_name = "subCategory" + + name_field = "name" + id_field = "id" # insert category ID into control obj - if categoryFieldName in new_control: - categoryName = new_control[categoryFieldName]['name'] - if categoryName in map_category_name_to_id: - new_control[categoryFieldName]['id'] = map_category_name_to_id[categoryName] + if category_field_name in new_control: + category_name = new_control[category_field_name][name_field] + if category_name in map_category_name_to_id: + new_control[category_field_name][id_field] = map_category_name_to_id[category_name] else: - raise TypeError(f"Failed to find category name '{categoryName}' in mapCategoryNameToID.json") + raise TypeError(f"Failed to find category name '{category_name}' in mapCategoryNameToID.json") - if subCategoryFieldName in new_control[categoryFieldName]: - subCategoryName = new_control[categoryFieldName][subCategoryFieldName]['name'] - if subCategoryName in map_category_name_to_id: - new_control[categoryFieldName][subCategoryFieldName]['id'] = map_category_name_to_id[subCategoryName] + if sub_category_field_name in new_control[category_field_name]: + sub_category_name = new_control[category_field_name][sub_category_field_name][name_field] + if sub_category_name in map_category_name_to_id: + new_control[category_field_name][sub_category_field_name][id_field] = map_category_name_to_id[sub_category_name] else: - if subCategoryName == "": - continue - raise TypeError(f"Failed to find subcategory name '{subCategoryName}' in mapCategoryNameToID.json") + raise TypeError(f"Failed to find subcategory name '{sub_category_name}' in mapCategoryNameToID.json") new_control["rules"] = [] new_control_copy = copy.deepcopy(new_control) From 163298de5ef8c3f2517e88adeb6d189e05962bc8 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Mon, 24 Jul 2023 21:06:53 +0300 Subject: [PATCH 09/11] use const --- scripts/export.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/export.py b/scripts/export.py index 0779fba7a..d0b6cd737 100644 --- a/scripts/export.py +++ b/scripts/export.py @@ -100,7 +100,9 @@ def load_rules(): """ def load_controls(loaded_rules: dict): - with open(os.path.join(__CWD__, 'categories', 'mapCategoryNameToID.json'), "r") as f: + map_category_name_to_id_file = 'mapCategoryNameToID.json' + + with open(os.path.join(__CWD__, 'categories', map_category_name_to_id_file), "r") as f: map_category_name_to_id = json.load(f) p2 = os.path.join(__CWD__, 'controls') @@ -134,14 +136,14 @@ def load_controls(loaded_rules: dict): if category_name in map_category_name_to_id: new_control[category_field_name][id_field] = map_category_name_to_id[category_name] else: - raise TypeError(f"Failed to find category name '{category_name}' in mapCategoryNameToID.json") + raise TypeError(f"Failed to find category name '{category_name}' in {map_category_name_to_id_file}") if sub_category_field_name in new_control[category_field_name]: sub_category_name = new_control[category_field_name][sub_category_field_name][name_field] if sub_category_name in map_category_name_to_id: new_control[category_field_name][sub_category_field_name][id_field] = map_category_name_to_id[sub_category_name] else: - raise TypeError(f"Failed to find subcategory name '{sub_category_name}' in mapCategoryNameToID.json") + raise TypeError(f"Failed to find subcategory name '{sub_category_name}' in {map_category_name_to_id_file}") new_control["rules"] = [] new_control_copy = copy.deepcopy(new_control) From 0784933c8fb0ef195866614a230ba9fb56e8b576 Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Wed, 26 Jul 2023 11:33:40 +0300 Subject: [PATCH 10/11] docs Signed-off-by: Daniel Grunberger --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 54a9ab04f..7e6ade979 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,20 @@ Example of a control: "cluster", "file" ] - } + }, + "category": { + "name" : "Workload", + "subCategory": { + "name": "Resource management" + } + } } ``` * Attribute `"armoBuiltin": true` - mandatory for armo rules. Only ARMO team members are authorized to create builtin objects. * `rulesNames` - List of rules to run, must be exact name. Use copy-paste to be sure. * `scanningScope` - this control will run just if kubescape scan process match to the scope in the list.(for example the control above will run if the running kubescape scan is for scanning cluster or file) - list of allowed scanning scope ``` [["cluster", "file"], ["cluster"], ["cloud"], ["GKE"], ["EKS"], ["AKS"]] ``` +* `category` - The category the control belongs to. Some controls may also define a `subCategory`. The available categories/sub categories are listed under the `mapCategoryNameToID.json` file, mapped to their respective IDs +* `subCategory` - A sub category for a `category` (optional). Must be listed under the `mapCategoryNameToID.json` file * `long_description`, `test` and other control fields are used mainly in the [documentation](https://hub.armosec.io/docs) From 9b425203725cf018383c73643e6c7c65f620684e Mon Sep 17 00:00:00 2001 From: Daniel Grunberger Date: Sun, 30 Jul 2023 09:18:41 +0300 Subject: [PATCH 11/11] update categories --- controls/C-0041-hostnetworkaccess.json | 5 ++++- controls/C-0257-pvcaccess.json | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/controls/C-0041-hostnetworkaccess.json b/controls/C-0041-hostnetworkaccess.json index 16a9ab3a9..1be0a86aa 100644 --- a/controls/C-0041-hostnetworkaccess.json +++ b/controls/C-0041-hostnetworkaccess.json @@ -26,7 +26,10 @@ "baseScore": 7.0, "example": "@controls/examples/c041.yaml", "category": { - "name" : "Network" + "name" : "Workload", + "subCategory": { + "name": "Network" + } }, "scanningScope": { "matches": [ diff --git a/controls/C-0257-pvcaccess.json b/controls/C-0257-pvcaccess.json index 05a43cd02..de95b7d71 100644 --- a/controls/C-0257-pvcaccess.json +++ b/controls/C-0257-pvcaccess.json @@ -25,5 +25,11 @@ "cluster", "file" ] - } + }, + "category": { + "name" : "Workload", + "subCategory": { + "name": "Storage" + } + } } \ No newline at end of file