├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── stale.yml │ └── sync-labels.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── all_controls ├── all_controls.pp ├── cluster_role_binding.pp ├── config_map.pp ├── cronjob.pp ├── daemonset.pp ├── deployment.pp ├── docs │ └── all_controls_overview.md ├── endpoint.pp ├── ingress.pp ├── job.pp ├── namespace.pp ├── network_policy.pp ├── pod.pp ├── pod_security_policy.pp ├── pod_template.pp ├── replicaset.pp ├── replication_controller.pp ├── role.pp ├── role_binding.pp ├── secret.pp ├── service.pp ├── service_account.pp └── statefulset.pp ├── cis_kube_v120 ├── cis_kube_v120.pp ├── cis_kube_v120_v100.pp └── docs │ ├── cis_kube_v120_v100_5_1_6.md │ ├── cis_kube_v120_v100_5_2_1.md │ ├── cis_kube_v120_v100_5_2_2.md │ ├── cis_kube_v120_v100_5_2_3.md │ ├── cis_kube_v120_v100_5_2_4.md │ ├── cis_kube_v120_v100_5_2_5.md │ ├── cis_kube_v120_v100_5_2_6.md │ ├── cis_kube_v120_v100_5_3_2.md │ ├── cis_kube_v120_v100_5_7_2.md │ ├── cis_kube_v120_v100_5_7_4.md │ └── cis_kube_v120_v100_overview.md ├── cis_v170 ├── cis.pp ├── docs │ ├── cis_v170_5_1.md │ ├── cis_v170_5_1_3.md │ ├── cis_v170_5_1_6.md │ ├── cis_v170_5_3.md │ ├── cis_v170_5_3_2.md │ ├── cis_v170_5_7.md │ ├── cis_v170_5_7_2.md │ ├── cis_v170_5_7_4.md │ └── cis_v170_overview.md └── section_5.pp ├── controls ├── cluster_role_binding.pp ├── config_map.pp ├── cronjob.pp ├── daemonset.pp ├── deployment.pp ├── endpoint.pp ├── ingress.pp ├── job.pp ├── local.pp ├── namespace.pp ├── network_policy.pp ├── pod.pp ├── pod_security_policy.pp ├── pod_template.pp ├── replicaset.pp ├── replication_controller.pp ├── role.pp ├── role_binding.pp ├── secret.pp ├── service.pp ├── service_account.pp └── statefulset.pp ├── docs ├── index.md ├── kubernetes_cis_v120.png ├── kubernetes_compliance_dashboard.png ├── kubernetes_compliance_mod_console_output.png └── kubernetes_nsa_csa_v1.png ├── mod.pp ├── nsa_cisa_v1 ├── docs │ └── nsa_cisa_v1_overview.md ├── nsa_cisa_v1.pp ├── nsa_cisa_v1_network_hardening.pp └── nsa_cisa_v1_pod_security.pp ├── powerpipe.ppvars.example ├── query ├── cluster_role_binding.pp ├── config_map.pp ├── cronjob.pp ├── daemonset.pp ├── deployment.pp ├── endpoint.pp ├── ingress.pp ├── job.pp ├── namespace.pp ├── network_policy.pp ├── pod.pp ├── pod_security_policy.pp ├── pod_template.pp ├── replicaset.pp ├── replication_controller.pp ├── role.pp ├── role_binding.pp ├── secret.pp ├── service.pp ├── service_account.pp └── statefulset.pp └── variables.pp /.gitattributes: -------------------------------------------------------------------------------- 1 | **/*.sp linguist-language=HCL 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Powerpipe version (`powerpipe -v`)** 14 | Example: v0.3.0 15 | 16 | **Steampipe version (`steampipe -v`)** 17 | Example: v0.3.0 18 | 19 | **Plugin version (`steampipe plugin list`)** 20 | Example: v0.5.0 21 | 22 | **To reproduce** 23 | Steps to reproduce the behavior (please include relevant code and/or commands). 24 | 25 | **Expected behavior** 26 | A clear and concise description of what you expected to happen. 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Questions 4 | url: https://turbot.com/community/join 5 | about: GitHub issues in this repository are only intended for bug reports and feature requests. Other issues will be closed. Please ask and answer questions through the Steampipe Slack community. 6 | - name: Powerpipe CLI Bug Reports and Feature Requests 7 | url: https://github.com/turbot/powerpipe/issues/new/choose 8 | about: Powerpipe CLI has its own codebase. Bug reports and feature requests for those pieces of functionality should be directed to that repository. 9 | - name: Steampipe CLI Bug Reports and Feature Requests 10 | url: https://github.com/turbot/steampipe/issues/new/choose 11 | about: Steampipe CLI has its own codebase. Bug reports and feature requests for those pieces of functionality should be directed to that repository. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Checklist 2 | - [ ] Issue(s) linked 3 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Stale Issues and PRs 2 | on: 3 | schedule: 4 | - cron: "30 23 * * *" 5 | workflow_dispatch: 6 | inputs: 7 | dryRun: 8 | description: Set to true for a dry run 9 | required: false 10 | default: "false" 11 | type: string 12 | 13 | jobs: 14 | stale_workflow: 15 | uses: turbot/steampipe-workflows/.github/workflows/stale.yml@main 16 | with: 17 | dryRun: ${{ github.event.inputs.dryRun }} -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yml: -------------------------------------------------------------------------------- 1 | name: Sync Labels 2 | on: 3 | schedule: 4 | - cron: "30 22 * * 1" 5 | workflow_dispatch: 6 | 7 | jobs: 8 | sync_labels_workflow: 9 | uses: turbot/steampipe-workflows/.github/workflows/sync-labels.yml@main -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Swap files 9 | *.swp 10 | 11 | .DS_Store 12 | 13 | # Steampipe variable files 14 | *.spvars 15 | *.auto.spvars 16 | 17 | # Powerpipe variable files 18 | *.ppvars 19 | *.auto.ppvars -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v1.0.2 [2025-04-15] 2 | 3 | _Bug fixes_ 4 | 5 | - Fixed the `pod_host_network_access_disabled` query to include the `Kubernetes/Pod` service tag. ([#94](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/94)) 6 | 7 | ## v1.0.1 [2024-10-24] 8 | 9 | _Bug fixes_ 10 | 11 | - Renamed `steampipe.spvars.example` files to `powerpipe.ppvars.example` and updated documentation. ([#92](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/92)) 12 | 13 | ## v1.0.0 [2024-10-22] 14 | 15 | This mod now requires [Powerpipe](https://powerpipe.io). [Steampipe](https://steampipe.io) users should check the [migration guide](https://powerpipe.io/blog/migrating-from-steampipe). 16 | 17 | ## v0.18 [2024-03-06] 18 | 19 | _Powerpipe_ 20 | 21 | [Powerpipe](https://powerpipe.io) is now the preferred way to run this mod! [Migrating from Steampipe →](https://powerpipe.io/blog/migrating-from-steampipe) 22 | 23 | All v0.x versions of this mod will work in both Steampipe and Powerpipe, but v1.0.0 onwards will be in Powerpipe format only. 24 | 25 | _Enhancements_ 26 | 27 | - Focus documentation on Powerpipe commands. 28 | - Show how to combine Powerpipe mods with Steampipe plugins. 29 | 30 | ## v0.17 [2023-11-03] 31 | 32 | _Breaking changes_ 33 | 34 | - Updated the plugin dependency section of the mod to use `min_version` instead of `version`. ([#82](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/82)) 35 | 36 | _Bug fixes_ 37 | 38 | - Updated the docs to include the correct links for the `nsa_cisa_v1` benchmark. ([#80](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/80)) (Thanks [@aniketh-varma](https://github.com/aniketh-varma) for the contribution!) 39 | - Fixed the following queries to cast the data to boolean format. ([#79](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/79)) 40 | - `cronjob_container_privilege_disabled` 41 | - `cronjob_host_network_access_disabled` 42 | - `cronjob_hostpid_hostipc_sharing_disabled` 43 | - `cronjob_immutable_container_filesystem` 44 | - `cronjob_non_root_container` 45 | - `daemonset_container_privilege_disabled` 46 | - `daemonset_host_network_access_disabled` 47 | - `daemonset_hostpid_hostipc_sharing_disabled` 48 | - `daemonset_immutable_container_filesystem` 49 | - `daemonset_non_root_container` 50 | - `deployment_container_privilege_disabled` 51 | - `deployment_host_network_access_disabled` 52 | - `deployment_hostpid_hostipc_sharing_disabled` 53 | - `deployment_immutable_container_filesystem` 54 | - `deployment_non_root_container` 55 | - `job_container_privilege_disabled` 56 | - `job_host_network_access_disabled` 57 | - `job_hostpid_hostipc_sharing_disabled` 58 | - `job_immutable_container_filesystem` 59 | - `job_non_root_container` 60 | - `pod_container_privilege_disabled` 61 | - `pod_immutable_container_filesystem` 62 | - `pod_non_root_container` 63 | - `pod_service_account_token_enabled` 64 | - `pod_template_container_privilege_disabled` 65 | - `pod_template_immutable_container_filesystem` 66 | - `replicaset_container_privilege_disabled` 67 | - `replicaset_host_network_access_disabled` 68 | - `replicaset_hostpid_hostipc_sharing_disabled` 69 | - `replicaset_immutable_container_filesystem` 70 | - `replicaset_non_root_container` 71 | - `replication_controller_container_privilege_disabled` 72 | - `replication_controller_host_network_access_disabled` 73 | - `replication_controller_hostpid_hostipc_sharing_disabled` 74 | - `replication_controller_immutable_container_filesystem` 75 | - `replication_controller_non_root_container` 76 | - `statefulset_container_privilege_disabled` 77 | - `statefulset_host_network_access_disabled` 78 | - `statefulset_hostpid_hostipc_sharing_disabled` 79 | - `statefulset_immutable_container_filesystem` 80 | - `statefulset_non_root_container` 81 | 82 | ## v0.16 [2023-10-04] 83 | 84 | _Bug fixes_ 85 | 86 | - Fixed queries to correctly return data for `connection_name` and `tags` dimensions instead of an error. ([#73](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/73)) 87 | 88 | ## v0.15 [2023-10-03] 89 | 90 | _What's new?_ 91 | 92 | - Added 39 new controls for the `ClusterRoleBinding`, `CronJob`, `DaemonSet`, `Ingress`, `Job`, `Pod` resource types to the `all_controls` benchmark. ([#68](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/68)) 93 | 94 | ## v0.14 [2023-09-29] 95 | 96 | _What's new?_ 97 | 98 | - Added 350+ new controls across all resource types to the `all_controls` benchmark. ([#64](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/64)) 99 | 100 | _Enhancements_ 101 | 102 | - Added `path` to default set of `common_dimensions`, so now any file paths will appear by default in the additional dimensions in control results. ([#63](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/63)) 103 | - Added `iac` category to mod definition. 104 | 105 | _Dependencies_ 106 | 107 | - Kubernetes plugin `v0.23.0` or higher is now required. 108 | 109 | ## v0.13 [2023-09-25] 110 | 111 | _Enhancements_ 112 | 113 | - Added 112 new controls to the `All Controls` benchmark for the following services: ([#59](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/59)) 114 | - `CronJob` 115 | - `DaemonSet` 116 | - `Deployment` 117 | - `Job` 118 | - `Pod` 119 | - `ReplicaSet` 120 | - `ReplicationController` 121 | - `StatefulSet` 122 | 123 | ## v0.12 [2023-09-15] 124 | 125 | _Enhancements_ 126 | 127 | - Added 90 new controls to the `All Controls` benchmark for the following services: ([#56](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/56)) 128 | - `CronJob` 129 | - `DaemonSet` 130 | - `Deployment` 131 | - `Job` 132 | - `Pod` 133 | - `ReplicaSet` 134 | - `ReplicationController` 135 | - `StatefulSet` 136 | 137 | _Bug fixes_ 138 | 139 | - Fixed the `role_with_wildcards_used` control to correctly return data instead of an error. ([#54](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/54)) 140 | 141 | ## v0.11 [2023-09-05] 142 | 143 | _Breaking changes_ 144 | 145 | - The `Other Compliance Checks` benchmark (`steampipe check benchmark.other_checks`) has been removed and replaced by the new `All Controls` benchmark (`steampipe check benchmark.all_controls`). This new benchmark includes 154 service-specific controls. ([#47](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/47)) 146 | 147 | _Bug fixes_ 148 | 149 | - Fixed the `namespace_*` queries to use the correct common dimensions. ([#49](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/49)) 150 | 151 | ## v0.10 [2023-06-02] 152 | 153 | _Dependencies_ 154 | 155 | - Kubernetes plugin `v0.20.0` or higher is now required. ([#41](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/41)) 156 | 157 | _What's new?_ 158 | 159 | - Added `path` and `source_type` in the common dimensions to group and filter findings. (see [var.common_dimensions](https://hub.steampipe.io/mods/turbot/kubernetes_compliance/variables)) ([#41](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/41)) 160 | 161 | _Enhancements_ 162 | 163 | - Updated the `resource` column to use `path` and `start_line` for manifest resources. ([#41](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/41)) 164 | 165 | ## v0.9 [2023-05-18] 166 | 167 | _What's new?_ 168 | 169 | - Added CIS v1.7.0 for Kubernetes v1.25 benchmark (`steampipe check benchmark.cis_v170`). ([#35](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/35)) 170 | - Added `connection_name` in the common dimensions to group and filter findings. (see [var.common_dimensions](https://hub.steampipe.io/mods/turbot/kubernetes_compliance/variables)) ([#34](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/34)) 171 | - Added `tags` as dimensions to group and filter findings. (see [var.tag_dimensions](https://hub.steampipe.io/mods/turbot/kubernetes_compliance/variables)) ([#34](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/34)) 172 | 173 | _Bug fixes_ 174 | 175 | - Fixed dashboard localhost URLs in README and index doc. ([#37](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/37)) 176 | 177 | ## v0.8 [2023-04-13] 178 | 179 | _Bug fixes_ 180 | 181 | - Fixed the structure and the order of sub-benchmarks and controls of `cis_kube_v120_v100_5` benchmark based on the CIS documentation. ([#30](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/30)) 182 | 183 | ## v0.7 [2022-11-22] 184 | 185 | _Bug fixes_ 186 | 187 | - Fixed `pod_service_account_token_disabled`, `pod_security_policy_*` and `service_account_token_disabled` queries to include the name of the relevant resource in the `Reason` column of the compliance report. ([#23](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/23)) 188 | 189 | ## v0.6 [2022-05-09] 190 | 191 | _Enhancements_ 192 | 193 | - Added `category`, `service`, and `type` tags to benchmarks and controls. ([#18](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/18)) 194 | 195 | _Breaking changes_ 196 | 197 | - Updated all CIS Kubernetes v1.20 v1.0.0 filenames, benchmarks, and controls to include the Kubernetes version for future version compatibility. ([#18](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/18)) 198 | - Fixed all typos in control and query names namesapce->namespace. ([#18](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/18)) 199 | 200 | ## v0.5 [2022-01-19] 201 | 202 | _What's new?_ 203 | 204 | - Added a new benchmark (`cis_v100_5_7_2`) to the `CIS v1.0.0 for Kubernetes v1.20` benchmark ([#13](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/13)) 205 | - Added new controls for `CronJob`, `ConfigMap`, `Ingress`, `Role`, `RoleBinding`, `Secret` and `StatefulSet` resource types to `CIS v1.0.0 for Kubernetes v1.20`, `Extra Checks` and `NSA CISA Kubernetes Hardening Guidance v1` benchmarks ([#13](https://github.com/turbot/steampipe-mod-kubernetes-compliance/pull/13)) 206 | 207 | ## v0.4 [2021-11-12] 208 | 209 | _Enhancements_ 210 | 211 | - `docs/index.md` file now includes the console output image 212 | 213 | ## v0.3 [2021-11-10] 214 | 215 | _What's new?_ 216 | 217 | - Added: CIS v1.0.0 for Kubernetes v1.20 benchmark (`steampipe check kubernetes_compliance.benchmark.cis_kubernetes_v120`) 218 | - Added: Extra Checks benchmark (`steampipe check kubernetes_compliance.benchmark.extra_checks`) to provide additional information around other Kubernetes compliance best practices 219 | 220 | ## v0.2 [2021-09-22] 221 | 222 | _Bug fixes_ 223 | 224 | - Fixed: Broken links in docs/index.md to mod controls and queries 225 | 226 | ## v0.1 [2021-09-22] 227 | 228 | _What's new?_ 229 | 230 | - Added: NSA CISA Kubernetes Hardening Guidance v1 benchmark (`steampipe check benchmark.nsa_cisa_v1`) 231 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Compliance Mod for Powerpipe 2 | 3 | Multiple checks covering industry defined security best practices for Kubernetes. The mod supports parsing and analyzing Kubernetes manifest files, allowing you to assess compliance directly on your configuration files before deployment. Includes support for CIS, National Security Agency (NSA) and Cybersecurity and Infrastructure Security Agency (CISA) Cybersecurity technical report for Kubernetes hardening. 4 | 5 | Run checks in a dashboard: 6 | ![image](https://raw.githubusercontent.com/turbot/steampipe-mod-kubernetes-compliance/main/docs/kubernetes_nsa_csa_v1.png) 7 | 8 | Or in a terminal: 9 | ![image](https://raw.githubusercontent.com/turbot/steampipe-mod-kubernetes-compliance/main/docs/kubernetes_compliance_mod_console_output.png) 10 | 11 | ## Documentation 12 | 13 | - **[Benchmarks and controls →](https://hub.powerpipe.io/mods/turbot/kubernetes_compliance/controls)** 14 | - **[Named queries →](https://hub.powerpipe.io/mods/turbot/kubernetes_compliance/queries)** 15 | 16 | ## Getting Started 17 | 18 | ### Installation 19 | 20 | Install Powerpipe (https://powerpipe.io/downloads), or use Brew: 21 | 22 | ```sh 23 | brew install turbot/tap/powerpipe 24 | ``` 25 | 26 | This mod also requires [Steampipe](https://steampipe.io) with the [Kubernetes plugin](https://hub.steampipe.io/plugins/turbot/kubernetes) as the data source. Install Steampipe (https://steampipe.io/downloads), or use Brew: 27 | 28 | ```sh 29 | brew install turbot/tap/steampipe 30 | steampipe plugin install kubernetes 31 | ``` 32 | 33 | Steampipe will automatically use your default Kubernetes credentials. Optionally, you can [setup multiple context connections](https://hub.steampipe.io/plugins/turbot/kubernetes#multiple-context-connections) or [customize Kubernetes credentials](https://hub.steampipe.io/plugins/turbot/kubernetes#configuring-kubernetes-cluster-credentials). 34 | 35 | Finally, install the mod: 36 | 37 | ```sh 38 | mkdir dashboards 39 | cd dashboards 40 | powerpipe mod init 41 | powerpipe mod install github.com/turbot/steampipe-mod-kubernetes-compliance 42 | ``` 43 | 44 | ### Browsing Dashboards 45 | 46 | Start Steampipe as the data source: 47 | 48 | ```sh 49 | steampipe service start 50 | ``` 51 | 52 | Start the dashboard server: 53 | 54 | ```sh 55 | powerpipe server 56 | ``` 57 | 58 | Browse and view your dashboards at **http://localhost:9033**. 59 | 60 | ### Running Checks in Your Terminal 61 | 62 | Instead of running benchmarks in a dashboard, you can also run them within your 63 | terminal with the `powerpipe benchmark` command: 64 | 65 | List available benchmarks: 66 | 67 | ```sh 68 | powerpipe benchmark list 69 | ``` 70 | 71 | Run a benchmark: 72 | 73 | ```sh 74 | powerpipe benchmark run kubernetes_compliance.benchmark.cis_v170 75 | ``` 76 | 77 | Different output formats are also available, for more information please see 78 | [Output Formats](https://powerpipe.io/docs/reference/cli/benchmark#output-formats). 79 | 80 | ### Common and Tag Dimensions 81 | 82 | The benchmark queries use common properties (like `connection_name`, `context_name`, `namespace`, `path` and `source_type`) and tags that are defined in the form of a default list of strings in the `variables.sp` file. These properties can be overwritten in several ways: 83 | 84 | It's easiest to setup your vars file, starting with the sample: 85 | 86 | ```sh 87 | cp powerpipe.ppvars.example powerpipe.ppvars 88 | vi powerpipe.ppvars 89 | ``` 90 | 91 | Alternatively you can pass variables on the command line: 92 | 93 | ```sh 94 | powerpipe benchmark run kubernetes_compliance.benchmark.cis_v170 --var 'tag_dimensions=["Environment", "Owner"]' 95 | ``` 96 | 97 | Or through environment variables: 98 | 99 | ```sh 100 | export PP_VAR_common_dimensions='["connection_name", "context_name", "namespace", "path", "source_type"]' 101 | export PP_VAR_tag_dimensions='["Environment", "Owner"]' 102 | powerpipe benchmark run kubernetes_compliance.benchmark.cis_v170 103 | ``` 104 | 105 | ## Open Source & Contributing 106 | 107 | This repository is published under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0). Please see our [code of conduct](https://github.com/turbot/.github/blob/main/CODE_OF_CONDUCT.md). We look forward to collaborating with you! 108 | 109 | [Steampipe](https://steampipe.io) and [Powerpipe](https://powerpipe.io) are products produced from this open source software, exclusively by [Turbot HQ, Inc](https://turbot.com). They are distributed under our commercial terms. Others are allowed to make their own distribution of the software, but cannot use any of the Turbot trademarks, cloud services, etc. You can learn more in our [Open Source FAQ](https://turbot.com/open-source). 110 | 111 | ## Get Involved 112 | 113 | **[Join #powerpipe on Slack →](https://turbot.com/community/join)** 114 | 115 | Want to help but don't know where to start? Pick up one of the `help wanted` issues: 116 | 117 | - [Powerpipe](https://github.com/turbot/powerpipe/labels/help%20wanted) 118 | - [Kubernetes Compliance Mod](https://github.com/turbot/steampipe-mod-kubernetes-compliance/labels/help%20wanted) 119 | -------------------------------------------------------------------------------- /all_controls/all_controls.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | type = "Benchmark" 4 | }) 5 | } 6 | 7 | benchmark "all_controls" { 8 | title = "All Controls" 9 | description = "This benchmark contains all controls grouped by component to help you detect resource configurations that do not meet best practices." 10 | documentation = file("./all_controls/docs/all_controls_overview.md") 11 | children = [ 12 | benchmark.all_controls_cluster_role_binding, 13 | benchmark.all_controls_config_map, 14 | benchmark.all_controls_cronjob, 15 | benchmark.all_controls_daemonset, 16 | benchmark.all_controls_deployment, 17 | benchmark.all_controls_endpoint, 18 | benchmark.all_controls_ingress, 19 | benchmark.all_controls_job, 20 | benchmark.all_controls_namespace, 21 | benchmark.all_controls_network_policy, 22 | benchmark.all_controls_pod, 23 | benchmark.all_controls_pod_security_policy, 24 | benchmark.all_controls_pod_template, 25 | benchmark.all_controls_replicaset, 26 | benchmark.all_controls_replication_controller, 27 | benchmark.all_controls_role, 28 | benchmark.all_controls_role_binding, 29 | benchmark.all_controls_secret, 30 | benchmark.all_controls_service, 31 | benchmark.all_controls_service_account, 32 | benchmark.all_controls_statefulset 33 | ] 34 | 35 | tags = local.all_controls_common_tags 36 | } 37 | -------------------------------------------------------------------------------- /all_controls/cluster_role_binding.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_cluster_role_binding_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/ClusterRoleBinding" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_cluster_role_binding" { 8 | title = "Cluster Role Binding" 9 | description = "This section contains recommendations for configuring Cluster Role Binding resources." 10 | children = [ 11 | control.cluster_role_binding_default_service_account_binding_not_active 12 | ] 13 | 14 | tags = merge(local.all_controls_cluster_role_binding_common_tags, { 15 | type = "Benchmark" 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /all_controls/config_map.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_config_map_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/ConfigMap" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_config_map" { 8 | title = "ConfigMap" 9 | description = "This section contains recommendations for configuring ConfigMap resources." 10 | children = [ 11 | control.config_map_default_namespace_used 12 | ] 13 | 14 | tags = merge(local.all_controls_config_map_common_tags, { 15 | type = "Benchmark" 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /all_controls/cronjob.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_cronjob_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/CronJob" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_cronjob" { 8 | title = "CronJob" 9 | description = "This section contains recommendations for configuring CronJob resources." 10 | children = [ 11 | control.cronjob_container_admission_capability_restricted, 12 | control.cronjob_container_admission_control_plugin_always_pull_images, 13 | control.cronjob_container_admission_control_plugin_no_always_admit, 14 | control.cronjob_container_arg_peer_client_cert_auth_enabled, 15 | control.cronjob_container_argument_anonymous_auth_disabled, 16 | control.cronjob_container_argument_audit_log_maxage_greater_than_30, 17 | control.cronjob_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.cronjob_container_argument_audit_log_maxsize_greater_than_100, 19 | control.cronjob_container_argument_audit_log_path_configured, 20 | control.cronjob_container_argument_authorization_mode_no_always_allow, 21 | control.cronjob_container_argument_authorization_mode_node, 22 | control.cronjob_container_argument_authorization_mode_rbac, 23 | control.cronjob_container_argument_etcd_auto_tls_disabled, 24 | control.cronjob_container_argument_etcd_cafile_configured, 25 | control.cronjob_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.cronjob_container_argument_etcd_client_cert_auth_enabled, 27 | control.cronjob_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.cronjob_container_argument_event_qps_less_than_5, 29 | control.cronjob_container_argument_insecure_port_0, 30 | control.cronjob_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.cronjob_container_argument_kube_apiserver_profiling_disabled, 32 | control.cronjob_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.cronjob_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.cronjob_container_argument_kube_controller_manager_profiling_disabled, 35 | control.cronjob_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.cronjob_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.cronjob_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.cronjob_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.cronjob_container_argument_kube_scheduler_profiling_disabled, 40 | control.cronjob_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.cronjob_container_argument_kubelet_client_ca_file_configured, 42 | control.cronjob_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.cronjob_container_argument_kubelet_https_enabled, 44 | control.cronjob_container_argument_kubelet_read_only_port_0, 45 | control.cronjob_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.cronjob_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.cronjob_container_argument_make_iptables_util_chains_enabled, 48 | control.cronjob_container_argument_namespace_lifecycle_enabled, 49 | control.cronjob_container_argument_node_restriction_enabled, 50 | control.cronjob_container_argument_pod_security_policy_enabled, 51 | control.cronjob_container_argument_protect_kernel_defaults_enabled, 52 | control.cronjob_container_argument_request_timeout_appropriate, 53 | control.cronjob_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.cronjob_container_argument_secure_port_not_0, 55 | control.cronjob_container_argument_security_context_deny_enabled, 56 | control.cronjob_container_argument_service_account_enabled, 57 | control.cronjob_container_argument_service_account_key_file_appropriate, 58 | control.cronjob_container_argument_service_account_lookup_enabled, 59 | control.cronjob_container_capabilities_drop_all, 60 | control.cronjob_container_encryption_providers_configured, 61 | control.cronjob_container_host_port_not_specified, 62 | control.cronjob_container_image_pull_policy_always, 63 | control.cronjob_container_image_tag_specified, 64 | control.cronjob_container_kubelet_certificate_authority_configured, 65 | control.cronjob_container_kubernetes_dashboard_not_deployed, 66 | control.cronjob_container_liveness_probe, 67 | control.cronjob_container_no_argument_basic_auth_file, 68 | control.cronjob_container_no_argument_hostname_override_configured, 69 | control.cronjob_container_no_argument_insecure_bind_address, 70 | control.cronjob_container_privilege_disabled, 71 | control.cronjob_container_privilege_escalation_disabled, 72 | control.cronjob_container_privilege_port_mapped, 73 | control.cronjob_container_readiness_probe, 74 | control.cronjob_container_rotate_certificate_enabled, 75 | control.cronjob_container_secrets_defined_as_files, 76 | control.cronjob_container_security_context_exists, 77 | control.cronjob_container_streaming_connection_idle_timeout_not_zero, 78 | control.cronjob_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.cronjob_container_strong_kubelet_cryptographic_ciphers, 80 | control.cronjob_container_sys_admin_capability_disabled, 81 | control.cronjob_container_token_auth_file_not_configured, 82 | control.cronjob_container_with_added_capabilities, 83 | control.cronjob_cpu_limit, 84 | control.cronjob_cpu_request, 85 | control.cronjob_default_namespace_used, 86 | control.cronjob_default_seccomp_profile_enabled, 87 | control.cronjob_host_network_access_disabled, 88 | control.cronjob_hostpid_hostipc_sharing_disabled, 89 | control.cronjob_immutable_container_filesystem, 90 | control.cronjob_memory_limit, 91 | control.cronjob_memory_request, 92 | control.cronjob_non_root_container 93 | ] 94 | 95 | tags = merge(local.all_controls_cronjob_common_tags, { 96 | type = "Benchmark" 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /all_controls/daemonset.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_daemonset_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/DaemonSet" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_daemonset" { 8 | title = "DaemonSet" 9 | description = "This section contains recommendations for configuring DaemonSet resources." 10 | children = [ 11 | control.daemonset_container_admission_capability_restricted, 12 | control.daemonset_container_admission_control_plugin_always_pull_images, 13 | control.daemonset_container_admission_control_plugin_no_always_admit, 14 | control.daemonset_container_arg_peer_client_cert_auth_enabled, 15 | control.daemonset_container_argument_anonymous_auth_disabled, 16 | control.daemonset_container_argument_audit_log_maxage_greater_than_30, 17 | control.daemonset_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.daemonset_container_argument_audit_log_maxsize_greater_than_100, 19 | control.daemonset_container_argument_audit_log_path_configured, 20 | control.daemonset_container_argument_authorization_mode_no_always_allow, 21 | control.daemonset_container_argument_authorization_mode_node, 22 | control.daemonset_container_argument_authorization_mode_rbac, 23 | control.daemonset_container_argument_etcd_auto_tls_disabled, 24 | control.daemonset_container_argument_etcd_cafile_configured, 25 | control.daemonset_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.daemonset_container_argument_etcd_client_cert_auth_enabled, 27 | control.daemonset_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.daemonset_container_argument_event_qps_less_than_5, 29 | control.daemonset_container_argument_insecure_port_0, 30 | control.daemonset_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.daemonset_container_argument_kube_apiserver_profiling_disabled, 32 | control.daemonset_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.daemonset_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.daemonset_container_argument_kube_controller_manager_profiling_disabled, 35 | control.daemonset_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.daemonset_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.daemonset_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.daemonset_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.daemonset_container_argument_kube_scheduler_profiling_disabled, 40 | control.daemonset_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.daemonset_container_argument_kubelet_client_ca_file_configured, 42 | control.daemonset_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.daemonset_container_argument_kubelet_https_enabled, 44 | control.daemonset_container_argument_kubelet_read_only_port_0, 45 | control.daemonset_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.daemonset_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.daemonset_container_argument_make_iptables_util_chains_enabled, 48 | control.daemonset_container_argument_namespace_lifecycle_enabled, 49 | control.daemonset_container_argument_node_restriction_enabled, 50 | control.daemonset_container_argument_pod_security_policy_enabled, 51 | control.daemonset_container_argument_protect_kernel_defaults_enabled, 52 | control.daemonset_container_argument_request_timeout_appropriate, 53 | control.daemonset_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.daemonset_container_argument_secure_port_not_0, 55 | control.daemonset_container_argument_security_context_deny_enabled, 56 | control.daemonset_container_argument_service_account_enabled, 57 | control.daemonset_container_argument_service_account_key_file_appropriate, 58 | control.daemonset_container_argument_service_account_lookup_enabled, 59 | control.daemonset_container_capabilities_drop_all, 60 | control.daemonset_container_encryption_providers_configured, 61 | control.daemonset_container_host_port_not_specified, 62 | control.daemonset_container_image_pull_policy_always, 63 | control.daemonset_container_image_tag_specified, 64 | control.daemonset_container_kubelet_certificate_authority_configured, 65 | control.daemonset_container_kubernetes_dashboard_not_deployed, 66 | control.daemonset_container_liveness_probe, 67 | control.daemonset_container_no_argument_basic_auth_file, 68 | control.daemonset_container_no_argument_hostname_override_configured, 69 | control.daemonset_container_no_argument_insecure_bind_address, 70 | control.daemonset_container_privilege_disabled, 71 | control.daemonset_container_privilege_escalation_disabled, 72 | control.daemonset_container_privilege_port_mapped, 73 | control.daemonset_container_readiness_probe, 74 | control.daemonset_container_rotate_certificate_enabled, 75 | control.daemonset_container_secrets_defined_as_files, 76 | control.daemonset_container_security_context_exists, 77 | control.daemonset_container_streaming_connection_idle_timeout_not_zero, 78 | control.daemonset_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.daemonset_container_strong_kubelet_cryptographic_ciphers, 80 | control.daemonset_container_sys_admin_capability_disabled, 81 | control.daemonset_container_token_auth_file_not_configured, 82 | control.daemonset_container_with_added_capabilities, 83 | control.daemonset_cpu_limit, 84 | control.daemonset_cpu_request, 85 | control.daemonset_default_namespace_used, 86 | control.daemonset_default_seccomp_profile_enabled, 87 | control.daemonset_host_network_access_disabled, 88 | control.daemonset_hostpid_hostipc_sharing_disabled, 89 | control.daemonset_immutable_container_filesystem, 90 | control.daemonset_memory_limit, 91 | control.daemonset_memory_request, 92 | control.daemonset_non_root_container 93 | ] 94 | 95 | tags = merge(local.all_controls_daemonset_common_tags, { 96 | type = "Benchmark" 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /all_controls/deployment.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_deployment_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Deployment" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_deployment" { 8 | title = "Deployment" 9 | description = "This section contains recommendations for configuring Deployment resources." 10 | children = [ 11 | control.deployment_container_admission_capability_restricted, 12 | control.deployment_container_admission_control_plugin_always_pull_images, 13 | control.deployment_container_admission_control_plugin_no_always_admit, 14 | control.deployment_container_arg_peer_client_cert_auth_enabled, 15 | control.deployment_container_argument_anonymous_auth_disabled, 16 | control.deployment_container_argument_audit_log_maxage_greater_than_30, 17 | control.deployment_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.deployment_container_argument_audit_log_maxsize_greater_than_100, 19 | control.deployment_container_argument_audit_log_path_configured, 20 | control.deployment_container_argument_authorization_mode_no_always_allow, 21 | control.deployment_container_argument_authorization_mode_node, 22 | control.deployment_container_argument_authorization_mode_rbac, 23 | control.deployment_container_argument_etcd_auto_tls_disabled, 24 | control.deployment_container_argument_etcd_cafile_configured, 25 | control.deployment_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.deployment_container_argument_etcd_client_cert_auth_enabled, 27 | control.deployment_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.deployment_container_argument_event_qps_less_than_5, 29 | control.deployment_container_argument_insecure_port_0, 30 | control.deployment_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.deployment_container_argument_kube_apiserver_profiling_disabled, 32 | control.deployment_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.deployment_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.deployment_container_argument_kube_controller_manager_profiling_disabled, 35 | control.deployment_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.deployment_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.deployment_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.deployment_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.deployment_container_argument_kube_scheduler_profiling_disabled, 40 | control.deployment_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.deployment_container_argument_kubelet_client_ca_file_configured, 42 | control.deployment_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.deployment_container_argument_kubelet_https_enabled, 44 | control.deployment_container_argument_kubelet_read_only_port_0, 45 | control.deployment_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.deployment_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.deployment_container_argument_make_iptables_util_chains_enabled, 48 | control.deployment_container_argument_namespace_lifecycle_enabled, 49 | control.deployment_container_argument_node_restriction_enabled, 50 | control.deployment_container_argument_pod_security_policy_enabled, 51 | control.deployment_container_argument_protect_kernel_defaults_enabled, 52 | control.deployment_container_argument_request_timeout_appropriate, 53 | control.deployment_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.deployment_container_argument_secure_port_not_0, 55 | control.deployment_container_argument_security_context_deny_enabled, 56 | control.deployment_container_argument_service_account_enabled, 57 | control.deployment_container_argument_service_account_key_file_appropriate, 58 | control.deployment_container_argument_service_account_lookup_enabled, 59 | control.deployment_container_capabilities_drop_all, 60 | control.deployment_container_encryption_providers_configured, 61 | control.deployment_container_host_port_not_specified, 62 | control.deployment_container_image_pull_policy_always, 63 | control.deployment_container_image_tag_specified, 64 | control.deployment_container_kubelet_certificate_authority_configured, 65 | control.deployment_container_kubernetes_dashboard_not_deployed, 66 | control.deployment_container_liveness_probe, 67 | control.deployment_container_no_argument_basic_auth_file, 68 | control.deployment_container_no_argument_hostname_override_configured, 69 | control.deployment_container_no_argument_insecure_bind_address, 70 | control.deployment_container_privilege_disabled, 71 | control.deployment_container_privilege_escalation_disabled, 72 | control.deployment_container_privilege_port_mapped, 73 | control.deployment_container_readiness_probe, 74 | control.deployment_container_rotate_certificate_enabled, 75 | control.deployment_container_secrets_defined_as_files, 76 | control.deployment_container_security_context_exists, 77 | control.deployment_container_streaming_connection_idle_timeout_not_zero, 78 | control.deployment_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.deployment_container_strong_kubelet_cryptographic_ciphers, 80 | control.deployment_container_sys_admin_capability_disabled, 81 | control.deployment_container_token_auth_file_not_configured, 82 | control.deployment_container_with_added_capabilities, 83 | control.deployment_cpu_limit, 84 | control.deployment_cpu_request, 85 | control.deployment_default_namespace_used, 86 | control.deployment_default_seccomp_profile_enabled, 87 | control.deployment_host_network_access_disabled, 88 | control.deployment_hostpid_hostipc_sharing_disabled, 89 | control.deployment_immutable_container_filesystem, 90 | control.deployment_memory_limit, 91 | control.deployment_memory_request, 92 | control.deployment_non_root_container, 93 | control.deployment_replica_minimum_3 94 | ] 95 | 96 | tags = merge(local.all_controls_deployment_common_tags, { 97 | type = "Benchmark" 98 | }) 99 | } 100 | -------------------------------------------------------------------------------- /all_controls/docs/all_controls_overview.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | We are adding additional checks to improve the information gathering around other Kubernetes compliance best practices, these checks are out of the scope of any predefined benchmarks for Kubernetes but we consider them very helpful. -------------------------------------------------------------------------------- /all_controls/endpoint.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_endpoint_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Endpoint" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_endpoint" { 8 | title = "Endpoint" 9 | description = "This section contains recommendations for configuring Endpoint resources." 10 | children = [ 11 | control.endpoint_api_serve_on_secure_port 12 | ] 13 | 14 | tags = merge(local.all_controls_endpoint_common_tags, { 15 | type = "Benchmark" 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /all_controls/ingress.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_ingress_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Ingress" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_ingress" { 8 | title = "Ingress" 9 | description = "This section contains recommendations for configuring Ingress resources." 10 | children = [ 11 | control.ingress_default_namespace_used, 12 | control.ingress_nginx_annotations_all_snippets_not_used, 13 | control.ingress_nginx_annotations_snippets_alias_not_used, 14 | control.ingress_nginx_annotations_snippets_lua_code_not_used 15 | ] 16 | 17 | tags = merge(local.all_controls_ingress_common_tags, { 18 | type = "Benchmark" 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /all_controls/job.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_job_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Job" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_job" { 8 | title = "Job" 9 | description = "This section contains recommendations for configuring Job resources." 10 | children = [ 11 | control.job_container_admission_capability_restricted, 12 | control.job_container_admission_control_plugin_always_pull_images, 13 | control.job_container_admission_control_plugin_no_always_admit, 14 | control.job_container_arg_peer_client_cert_auth_enabled, 15 | control.job_container_argument_anonymous_auth_disabled, 16 | control.job_container_argument_audit_log_maxage_greater_than_30, 17 | control.job_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.job_container_argument_audit_log_maxsize_greater_than_100, 19 | control.job_container_argument_audit_log_path_configured, 20 | control.job_container_argument_authorization_mode_no_always_allow, 21 | control.job_container_argument_authorization_mode_node, 22 | control.job_container_argument_authorization_mode_rbac, 23 | control.job_container_argument_etcd_auto_tls_disabled, 24 | control.job_container_argument_etcd_cafile_configured, 25 | control.job_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.job_container_argument_etcd_client_cert_auth_enabled, 27 | control.job_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.job_container_argument_event_qps_less_than_5, 29 | control.job_container_argument_insecure_port_0, 30 | control.job_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.job_container_argument_kube_apiserver_profiling_disabled, 32 | control.job_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.job_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.job_container_argument_kube_controller_manager_profiling_disabled, 35 | control.job_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.job_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.job_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.job_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.job_container_argument_kube_scheduler_profiling_disabled, 40 | control.job_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.job_container_argument_kubelet_client_ca_file_configured, 42 | control.job_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.job_container_argument_kubelet_https_enabled, 44 | control.job_container_argument_kubelet_read_only_port_0, 45 | control.job_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.job_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.job_container_argument_make_iptables_util_chains_enabled, 48 | control.job_container_argument_namespace_lifecycle_enabled, 49 | control.job_container_argument_node_restriction_enabled, 50 | control.job_container_argument_pod_security_policy_enabled, 51 | control.job_container_argument_protect_kernel_defaults_enabled, 52 | control.job_container_argument_request_timeout_appropriate, 53 | control.job_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.job_container_argument_secure_port_not_0, 55 | control.job_container_argument_security_context_deny_enabled, 56 | control.job_container_argument_service_account_enabled, 57 | control.job_container_argument_service_account_key_file_appropriate, 58 | control.job_container_argument_service_account_lookup_enabled, 59 | control.job_container_capabilities_drop_all, 60 | control.job_container_encryption_providers_configured, 61 | control.job_container_host_port_not_specified, 62 | control.job_container_image_pull_policy_always, 63 | control.job_container_image_tag_specified, 64 | control.job_container_kubelet_certificate_authority_configured, 65 | control.job_container_kubernetes_dashboard_not_deployed, 66 | control.job_container_liveness_probe, 67 | control.job_container_no_argument_basic_auth_file, 68 | control.job_container_no_argument_hostname_override_configured, 69 | control.job_container_no_argument_insecure_bind_address, 70 | control.job_container_privilege_disabled, 71 | control.job_container_privilege_escalation_disabled, 72 | control.job_container_privilege_port_mapped, 73 | control.job_container_readiness_probe, 74 | control.job_container_rotate_certificate_enabled, 75 | control.job_container_secrets_defined_as_files, 76 | control.job_container_security_context_exists, 77 | control.job_container_streaming_connection_idle_timeout_not_zero, 78 | control.job_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.job_container_strong_kubelet_cryptographic_ciphers, 80 | control.job_container_sys_admin_capability_disabled, 81 | control.job_container_token_auth_file_not_configured, 82 | control.job_container_with_added_capabilities, 83 | control.job_cpu_limit, 84 | control.job_cpu_request, 85 | control.job_default_namespace_used, 86 | control.job_default_seccomp_profile_enabled, 87 | control.job_host_network_access_disabled, 88 | control.job_hostpid_hostipc_sharing_disabled, 89 | control.job_immutable_container_filesystem, 90 | control.job_memory_limit, 91 | control.job_memory_request, 92 | control.job_non_root_container 93 | ] 94 | 95 | tags = merge(local.all_controls_job_common_tags, { 96 | type = "Benchmark" 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /all_controls/namespace.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_namespace_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Namespace" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_namespace" { 8 | title = "Namespace" 9 | description = "This section contains recommendations for configuring Namespace resources." 10 | children = [ 11 | control.namespace_limit_range_default_cpu_limit, 12 | control.namespace_limit_range_default_cpu_request, 13 | control.namespace_limit_range_default_memory_limit, 14 | control.namespace_limit_range_default_memory_request, 15 | control.namespace_resource_quota_cpu_limit, 16 | control.namespace_resource_quota_cpu_request, 17 | control.namespace_resource_quota_memory_limit, 18 | control.namespace_resource_quota_memory_request 19 | ] 20 | 21 | tags = merge(local.all_controls_namespace_common_tags, { 22 | type = "Benchmark" 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /all_controls/network_policy.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_network_policy_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/NetworkPolicy" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_network_policy" { 8 | title = "Network Policy" 9 | description = "This section contains recommendations for configuring Network Policy resources." 10 | children = [ 11 | control.network_policy_default_deny_egress, 12 | control.network_policy_default_deny_ingress, 13 | control.network_policy_default_dont_allow_egress, 14 | control.network_policy_default_dont_allow_ingress 15 | ] 16 | 17 | tags = merge(local.all_controls_network_policy_common_tags, { 18 | type = "Benchmark" 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /all_controls/pod.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_pod_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Pod" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_pod" { 8 | title = "Pod" 9 | description = "This section contains recommendations for configuring Pod resources." 10 | children = [ 11 | control.pod_container_admission_capability_restricted, 12 | control.pod_container_admission_control_plugin_always_pull_images, 13 | control.pod_container_admission_control_plugin_no_always_admit, 14 | control.pod_container_arg_peer_client_cert_auth_enabled, 15 | control.pod_container_argument_anonymous_auth_disabled, 16 | control.pod_container_argument_audit_log_maxage_greater_than_30, 17 | control.pod_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.pod_container_argument_audit_log_maxsize_greater_than_100, 19 | control.pod_container_argument_audit_log_path_configured, 20 | control.pod_container_argument_authorization_mode_no_always_allow, 21 | control.pod_container_argument_authorization_mode_node, 22 | control.pod_container_argument_authorization_mode_rbac, 23 | control.pod_container_argument_etcd_auto_tls_disabled, 24 | control.pod_container_argument_etcd_cafile_configured, 25 | control.pod_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.pod_container_argument_etcd_client_cert_auth_enabled, 27 | control.pod_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.pod_container_argument_event_qps_less_than_5, 29 | control.pod_container_argument_insecure_port_0, 30 | control.pod_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.pod_container_argument_kube_apiserver_profiling_disabled, 32 | control.pod_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.pod_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.pod_container_argument_kube_controller_manager_profiling_disabled, 35 | control.pod_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.pod_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.pod_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.pod_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.pod_container_argument_kube_scheduler_profiling_disabled, 40 | control.pod_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.pod_container_argument_kubelet_client_ca_file_configured, 42 | control.pod_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.pod_container_argument_kubelet_https_enabled, 44 | control.pod_container_argument_kubelet_read_only_port_0, 45 | control.pod_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.pod_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.pod_container_argument_make_iptables_util_chains_enabled, 48 | control.pod_container_argument_namespace_lifecycle_enabled, 49 | control.pod_container_argument_node_restriction_enabled, 50 | control.pod_container_argument_pod_security_policy_enabled, 51 | control.pod_container_argument_protect_kernel_defaults_enabled, 52 | control.pod_container_argument_request_timeout_appropriate, 53 | control.pod_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.pod_container_argument_secure_port_not_0, 55 | control.pod_container_argument_security_context_deny_enabled, 56 | control.pod_container_argument_service_account_enabled, 57 | control.pod_container_argument_service_account_key_file_appropriate, 58 | control.pod_container_argument_service_account_lookup_enabled, 59 | control.pod_container_capabilities_drop_all, 60 | control.pod_container_encryption_providers_configured, 61 | control.pod_container_host_port_not_specified, 62 | control.pod_container_image_pull_policy_always, 63 | control.pod_container_image_tag_specified, 64 | control.pod_container_kubelet_certificate_authority_configured, 65 | control.pod_container_kubernetes_dashboard_not_deployed, 66 | control.pod_container_liveness_probe, 67 | control.pod_container_memory_limit, 68 | control.pod_container_memory_request, 69 | control.pod_container_no_argument_basic_auth_file, 70 | control.pod_container_no_argument_hostname_override_configured, 71 | control.pod_container_no_argument_insecure_bind_address, 72 | control.pod_container_privilege_disabled, 73 | control.pod_container_privilege_escalation_disabled, 74 | control.pod_container_privilege_port_mapped, 75 | control.pod_container_readiness_probe, 76 | control.pod_container_rotate_certificate_enabled, 77 | control.pod_container_run_as_user_10000, 78 | control.pod_container_secrets_defined_as_files, 79 | control.pod_container_security_context_exists, 80 | control.pod_container_streaming_connection_idle_timeout_not_zero, 81 | control.pod_container_strong_kube_apiserver_cryptographic_ciphers, 82 | control.pod_container_strong_kubelet_cryptographic_ciphers, 83 | control.pod_container_sys_admin_capability_disabled, 84 | control.pod_container_token_auth_file_not_configured, 85 | control.pod_container_with_added_capabilities, 86 | control.pod_default_namespace_used, 87 | control.pod_default_seccomp_profile_enabled, 88 | control.pod_host_network_access_disabled, 89 | control.pod_hostpid_hostipc_sharing_disabled, 90 | control.pod_immutable_container_filesystem, 91 | control.pod_non_root_container, 92 | control.pod_service_account_not_exist, 93 | control.pod_service_account_token_disabled, 94 | control.pod_service_account_token_enabled, 95 | control.pod_volume_host_path 96 | ] 97 | 98 | tags = merge(local.all_controls_pod_common_tags, { 99 | type = "Benchmark" 100 | }) 101 | } 102 | -------------------------------------------------------------------------------- /all_controls/pod_security_policy.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_pod_security_policy_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/PodSecurityPolicy" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_pod_security_policy" { 8 | title = "Pod Security Policy" 9 | description = "This section contains recommendations for configuring Pod Security Policy resources." 10 | children = [ 11 | control.pod_security_policy_allowed_host_path, 12 | control.pod_security_policy_container_privilege_disabled, 13 | control.pod_security_policy_container_privilege_escalation_disabled, 14 | control.pod_security_policy_default_seccomp_profile_enabled, 15 | control.pod_security_policy_host_network_access_disabled, 16 | control.pod_security_policy_hostipc_sharing_disabled, 17 | control.pod_security_policy_hostpid_hostipc_sharing_disabled, 18 | control.pod_security_policy_hostpid_sharing_disabled, 19 | control.pod_security_policy_immutable_container_filesystem, 20 | control.pod_security_policy_non_root_container, 21 | control.pod_security_policy_security_services_hardening 22 | ] 23 | 24 | tags = merge(local.all_controls_pod_security_policy_common_tags, { 25 | type = "Benchmark" 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /all_controls/pod_template.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_pod_template_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/PodTemplate" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_pod_template" { 8 | title = "PodTemplate" 9 | description = "This section contains recommendations for configuring PodTemplate resources." 10 | 11 | children = [ 12 | control.pod_template_container_admission_capability_restricted, 13 | control.pod_template_container_admission_control_plugin_always_pull_images, 14 | control.pod_template_container_admission_control_plugin_no_always_admit, 15 | control.pod_template_container_argument_api_server_anonymous_auth_disabled, 16 | control.pod_template_container_argument_api_server_etcd_certfile_and_keyfile_configured, 17 | control.pod_template_container_argument_audit_log_maxage_greater_than_30, 18 | control.pod_template_container_argument_audit_log_maxbackup_greater_than_10, 19 | control.pod_template_container_argument_audit_log_maxsize_greater_than_100, 20 | control.pod_template_container_argument_audit_log_path_configured, 21 | control.pod_template_container_argument_authorization_mode_no_always_allow, 22 | control.pod_template_container_argument_authorization_mode_node, 23 | control.pod_template_container_argument_authorization_mode_rbac, 24 | control.pod_template_container_argument_bind_address_127_0_0_1, 25 | control.pod_template_container_argument_etcd_auto_tls_disabled, 26 | control.pod_template_container_argument_etcd_cafile_configured, 27 | control.pod_template_container_argument_etcd_certfile_and_keyfile_configured, 28 | control.pod_template_container_argument_etcd_client_cert_auth_enabled, 29 | control.pod_template_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 30 | control.pod_template_container_argument_event_qps_less_than_5, 31 | control.pod_template_container_argument_insecure_port_0, 32 | control.pod_template_container_argument_kube_apiserver_profiling_disabled, 33 | control.pod_template_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 34 | control.pod_template_container_argument_kube_controller_manager_bind_address_127_0_0_1, 35 | control.pod_template_container_argument_kube_controller_manager_profiling_disabled, 36 | control.pod_template_container_argument_kube_controller_manager_root_ca_file_configured, 37 | control.pod_template_container_argument_kube_controller_manager_service_account_credentials_enabled, 38 | control.pod_template_container_argument_kube_controller_manager_service_account_private_key_file_configured, 39 | control.pod_template_container_argument_kube_scheduler_profiling_disabled, 40 | control.pod_template_container_argument_kubelet_anonymous_auth_disabled, 41 | control.pod_template_container_argument_kubelet_authorization_mode_no_always_allow, 42 | control.pod_template_container_argument_kubelet_client_ca_file_configured, 43 | control.pod_template_container_argument_kubelet_client_certificate_and_key_configured, 44 | control.pod_template_container_argument_kubelet_https_enabled, 45 | control.pod_template_container_argument_kubelet_read_only_port_0, 46 | control.pod_template_container_argument_kubelet_terminated_pod_gc_threshold_configured, 47 | control.pod_template_container_argument_make_iptables_util_chains_enabled, 48 | control.pod_template_container_argument_namespace_lifecycle_enabled, 49 | control.pod_template_container_argument_node_restriction_enabled, 50 | control.pod_template_container_argument_pod_security_policy_enabled, 51 | control.pod_template_container_argument_protect_kernel_defaults_enabled, 52 | control.pod_template_container_argument_request_timeout_appropriate, 53 | control.pod_template_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.pod_template_container_argument_secure_port_not_0, 55 | control.pod_template_container_argument_security_context_deny_enabled, 56 | control.pod_template_container_argument_service_account_enabled, 57 | control.pod_template_container_argument_service_account_key_file_appropriate, 58 | control.pod_template_container_argument_service_account_lookup_enabled, 59 | control.pod_template_container_argument_tls_cert_file_and_tls_private_key_file_configured, 60 | control.pod_template_container_capabilities_drop_all, 61 | control.pod_template_container_encryption_providers_configured, 62 | control.pod_template_container_host_port_not_specified, 63 | control.pod_template_container_image_pull_policy_always, 64 | control.pod_template_container_image_tag_specified, 65 | control.pod_template_container_kubelet_certificate_authority_configured, 66 | control.pod_template_container_kubelet_streaming_connection_idle_timeout_not_zero, 67 | control.pod_template_container_kubernetes_dashboard_not_deployed, 68 | control.pod_template_container_liveness_probe, 69 | control.pod_template_container_no_argument_basic_auth_file, 70 | control.pod_template_container_no_argument_hostname_override_configured, 71 | control.pod_template_container_no_argument_insecure_bind_address, 72 | control.pod_template_container_privilege_disabled, 73 | control.pod_template_container_privilege_escalation_disabled, 74 | control.pod_template_container_readiness_probe, 75 | control.pod_template_container_rotate_certificate_enabled, 76 | control.pod_template_container_secrets_defined_as_files, 77 | control.pod_template_container_security_context_exists, 78 | control.pod_template_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.pod_template_container_strong_kubelet_cryptographic_ciphers, 80 | control.pod_template_container_sys_admin_capability_disabled, 81 | control.pod_template_container_token_auth_file_not_configured, 82 | control.pod_template_container_with_added_capabilities, 83 | control.pod_template_cpu_limit, 84 | control.pod_template_cpu_request, 85 | control.pod_template_immutable_container_filesystem, 86 | control.pod_template_memory_limit, 87 | control.pod_template_memory_request 88 | ] 89 | 90 | tags = merge(local.all_controls_pod_template_common_tags, { 91 | type = "Benchmark" 92 | }) 93 | } 94 | -------------------------------------------------------------------------------- /all_controls/replicaset.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_replicaset_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/ReplicaSet" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_replicaset" { 8 | title = "ReplicaSet" 9 | description = "This section contains recommendations for configuring ReplicaSet resources." 10 | children = [ 11 | control.replicaset_container_admission_capability_restricted, 12 | control.replicaset_container_admission_control_plugin_always_pull_images, 13 | control.replicaset_container_admission_control_plugin_no_always_admit, 14 | control.replicaset_container_arg_peer_client_cert_auth_enabled, 15 | control.replicaset_container_argument_anonymous_auth_disabled, 16 | control.replicaset_container_argument_audit_log_maxage_greater_than_30, 17 | control.replicaset_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.replicaset_container_argument_audit_log_maxsize_greater_than_100, 19 | control.replicaset_container_argument_audit_log_path_configured, 20 | control.replicaset_container_argument_authorization_mode_no_always_allow, 21 | control.replicaset_container_argument_authorization_mode_node, 22 | control.replicaset_container_argument_authorization_mode_rbac, 23 | control.replicaset_container_argument_etcd_auto_tls_disabled, 24 | control.replicaset_container_argument_etcd_cafile_configured, 25 | control.replicaset_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.replicaset_container_argument_etcd_client_cert_auth_enabled, 27 | control.replicaset_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.replicaset_container_argument_event_qps_less_than_5, 29 | control.replicaset_container_argument_insecure_port_0, 30 | control.replicaset_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.replicaset_container_argument_kube_apiserver_profiling_disabled, 32 | control.replicaset_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.replicaset_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.replicaset_container_argument_kube_controller_manager_profiling_disabled, 35 | control.replicaset_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.replicaset_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.replicaset_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.replicaset_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.replicaset_container_argument_kube_scheduler_profiling_disabled, 40 | control.replicaset_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.replicaset_container_argument_kubelet_client_ca_file_configured, 42 | control.replicaset_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.replicaset_container_argument_kubelet_https_enabled, 44 | control.replicaset_container_argument_kubelet_read_only_port_0, 45 | control.replicaset_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.replicaset_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.replicaset_container_argument_make_iptables_util_chains_enabled, 48 | control.replicaset_container_argument_namespace_lifecycle_enabled, 49 | control.replicaset_container_argument_node_restriction_enabled, 50 | control.replicaset_container_argument_pod_security_policy_enabled, 51 | control.replicaset_container_argument_protect_kernel_defaults_enabled, 52 | control.replicaset_container_argument_request_timeout_appropriate, 53 | control.replicaset_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.replicaset_container_argument_secure_port_not_0, 55 | control.replicaset_container_argument_security_context_deny_enabled, 56 | control.replicaset_container_argument_service_account_enabled, 57 | control.replicaset_container_argument_service_account_key_file_appropriate, 58 | control.replicaset_container_argument_service_account_lookup_enabled, 59 | control.replicaset_container_capabilities_drop_all, 60 | control.replicaset_container_encryption_providers_configured, 61 | control.replicaset_container_host_port_not_specified, 62 | control.replicaset_container_image_pull_policy_always, 63 | control.replicaset_container_image_tag_specified, 64 | control.replicaset_container_kubelet_certificate_authority_configured, 65 | control.replicaset_container_kubernetes_dashboard_not_deployed, 66 | control.replicaset_container_liveness_probe, 67 | control.replicaset_container_no_argument_basic_auth_file, 68 | control.replicaset_container_no_argument_hostname_override_configured, 69 | control.replicaset_container_no_argument_insecure_bind_address, 70 | control.replicaset_container_privilege_disabled, 71 | control.replicaset_container_privilege_escalation_disabled, 72 | control.replicaset_container_privilege_port_mapped, 73 | control.replicaset_container_readiness_probe, 74 | control.replicaset_container_rotate_certificate_enabled, 75 | control.replicaset_container_secrets_defined_as_files, 76 | control.replicaset_container_security_context_exists, 77 | control.replicaset_container_streaming_connection_idle_timeout_not_zero, 78 | control.replicaset_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.replicaset_container_strong_kubelet_cryptographic_ciphers, 80 | control.replicaset_container_sys_admin_capability_disabled, 81 | control.replicaset_container_token_auth_file_not_configured, 82 | control.replicaset_container_with_added_capabilities, 83 | control.replicaset_cpu_limit, 84 | control.replicaset_cpu_request, 85 | control.replicaset_default_namespace_used, 86 | control.replicaset_default_seccomp_profile_enabled, 87 | control.replicaset_host_network_access_disabled, 88 | control.replicaset_hostpid_hostipc_sharing_disabled, 89 | control.replicaset_immutable_container_filesystem, 90 | control.replicaset_memory_limit, 91 | control.replicaset_memory_request, 92 | control.replicaset_non_root_container 93 | ] 94 | 95 | 96 | tags = merge(local.all_controls_replicaset_common_tags, { 97 | type = "Benchmark" 98 | }) 99 | } 100 | -------------------------------------------------------------------------------- /all_controls/replication_controller.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_replication_controller_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/ReplicationController" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_replication_controller" { 8 | title = "ReplicationController" 9 | description = "This section contains recommendations for configuring ReplicationController resources." 10 | children = [ 11 | control.replication_controller_container_admission_capability_restricted, 12 | control.replication_controller_container_admission_control_plugin_always_pull_images, 13 | control.replication_controller_container_admission_control_plugin_no_always_admit, 14 | control.replication_controller_container_arg_peer_client_cert_auth_enabled, 15 | control.replication_controller_container_argument_anonymous_auth_disabled, 16 | control.replication_controller_container_argument_audit_log_maxage_greater_than_30, 17 | control.replication_controller_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.replication_controller_container_argument_audit_log_maxsize_greater_than_100, 19 | control.replication_controller_container_argument_audit_log_path_configured, 20 | control.replication_controller_container_argument_authorization_mode_no_always_allow, 21 | control.replication_controller_container_argument_authorization_mode_node, 22 | control.replication_controller_container_argument_authorization_mode_rbac, 23 | control.replication_controller_container_argument_etcd_auto_tls_disabled, 24 | control.replication_controller_container_argument_etcd_cafile_configured, 25 | control.replication_controller_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.replication_controller_container_argument_etcd_client_cert_auth_enabled, 27 | control.replication_controller_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.replication_controller_container_argument_event_qps_less_than_5, 29 | control.replication_controller_container_argument_insecure_port_0, 30 | control.replication_controller_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.replication_controller_container_argument_kube_apiserver_profiling_disabled, 32 | control.replication_controller_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.replication_controller_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.replication_controller_container_argument_kube_controller_manager_profiling_disabled, 35 | control.replication_controller_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.replication_controller_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.replication_controller_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.replication_controller_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.replication_controller_container_argument_kube_scheduler_profiling_disabled, 40 | control.replication_controller_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.replication_controller_container_argument_kubelet_client_ca_file_configured, 42 | control.replication_controller_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.replication_controller_container_argument_kubelet_https_enabled, 44 | control.replication_controller_container_argument_kubelet_read_only_port_0, 45 | control.replication_controller_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.replication_controller_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.replication_controller_container_argument_make_iptables_util_chains_enabled, 48 | control.replication_controller_container_argument_namespace_lifecycle_enabled, 49 | control.replication_controller_container_argument_node_restriction_enabled, 50 | control.replication_controller_container_argument_pod_security_policy_enabled, 51 | control.replication_controller_container_argument_protect_kernel_defaults_enabled, 52 | control.replication_controller_container_argument_request_timeout_appropriate, 53 | control.replication_controller_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.replication_controller_container_argument_secure_port_not_0, 55 | control.replication_controller_container_argument_security_context_deny_enabled, 56 | control.replication_controller_container_argument_service_account_enabled, 57 | control.replication_controller_container_argument_service_account_key_file_appropriate, 58 | control.replication_controller_container_argument_service_account_lookup_enabled, 59 | control.replication_controller_container_capabilities_drop_all, 60 | control.replication_controller_container_encryption_providers_configured, 61 | control.replication_controller_container_host_port_not_specified, 62 | control.replication_controller_container_image_pull_policy_always, 63 | control.replication_controller_container_image_tag_specified, 64 | control.replication_controller_container_kubelet_certificate_authority_configured, 65 | control.replication_controller_container_kubernetes_dashboard_not_deployed, 66 | control.replication_controller_container_liveness_probe, 67 | control.replication_controller_container_no_argument_basic_auth_file, 68 | control.replication_controller_container_no_argument_hostname_override_configured, 69 | control.replication_controller_container_no_argument_insecure_bind_address, 70 | control.replication_controller_container_privilege_disabled, 71 | control.replication_controller_container_privilege_escalation_disabled, 72 | control.replication_controller_container_privilege_port_mapped, 73 | control.replication_controller_container_readiness_probe, 74 | control.replication_controller_container_rotate_certificate_enabled, 75 | control.replication_controller_container_secrets_defined_as_files, 76 | control.replication_controller_container_security_context_exists, 77 | control.replication_controller_container_streaming_connection_idle_timeout_not_zero, 78 | control.replication_controller_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.replication_controller_container_strong_kubelet_cryptographic_ciphers, 80 | control.replication_controller_container_sys_admin_capability_disabled, 81 | control.replication_controller_container_token_auth_file_not_configured, 82 | control.replication_controller_container_with_added_capabilities, 83 | control.replication_controller_cpu_limit, 84 | control.replication_controller_cpu_request, 85 | control.replication_controller_default_namespace_used, 86 | control.replication_controller_default_seccomp_profile_enabled, 87 | control.replication_controller_host_network_access_disabled, 88 | control.replication_controller_hostpid_hostipc_sharing_disabled, 89 | control.replication_controller_immutable_container_filesystem, 90 | control.replication_controller_memory_limit, 91 | control.replication_controller_memory_request, 92 | control.replication_controller_non_root_container 93 | ] 94 | 95 | tags = merge(local.all_controls_replication_controller_common_tags, { 96 | type = "Benchmark" 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /all_controls/role.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_role_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Role" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_role" { 8 | title = "Role" 9 | description = "This section contains recommendations for configuring Role resources." 10 | children = [ 11 | control.cluster_role_with_validating_or_mutating_admission_webhook_configurations, 12 | control.role_default_namespace_used, 13 | control.role_with_bind_cluster_role_bindings, 14 | control.role_with_rbac_approve_certificate_signing_requests, 15 | control.role_with_rbac_escalate_permissions, 16 | control.role_with_wildcards_used 17 | ] 18 | 19 | tags = merge(local.all_controls_role_common_tags, { 20 | type = "Benchmark" 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /all_controls/role_binding.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_role_binding_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/RoleBinding" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_role_binding" { 8 | title = "Role Binding" 9 | description = "This section contains recommendations for configuring Role Binding resources." 10 | children = [ 11 | control.role_binding_default_namespace_used, 12 | control.role_binding_default_service_account_binding_not_active 13 | ] 14 | 15 | tags = merge(local.all_controls_role_binding_common_tags, { 16 | type = "Benchmark" 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /all_controls/secret.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_secret_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Secret" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_secret" { 8 | title = "Secret" 9 | description = "This section contains recommendations for configuring Secret resources." 10 | children = [ 11 | control.secret_default_namespace_used 12 | ] 13 | 14 | tags = merge(local.all_controls_secret_common_tags, { 15 | type = "Benchmark" 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /all_controls/service.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_service_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/Service" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_service" { 8 | title = "Service" 9 | description = "This section contains recommendations for configuring Service resources." 10 | children = [ 11 | control.service_default_namespace_used, 12 | control.service_no_tiller_deployed, 13 | control.service_no_tiller_service, 14 | control.service_type_forbidden 15 | ] 16 | 17 | tags = merge(local.all_controls_service_common_tags, { 18 | type = "Benchmark" 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /all_controls/service_account.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_service_account_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/ServiceAccount" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_service_account" { 8 | title = "Service Account" 9 | description = "This section contains recommendations for configuring Service Account resources." 10 | children = [ 11 | control.service_account_default_namespace_used, 12 | control.service_account_token_disabled 13 | ] 14 | 15 | tags = merge(local.all_controls_service_account_common_tags, { 16 | type = "Benchmark" 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /all_controls/statefulset.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | all_controls_statefulset_common_tags = merge(local.all_controls_common_tags, { 3 | service = "Kubernetes/StatefulSet" 4 | }) 5 | } 6 | 7 | benchmark "all_controls_statefulset" { 8 | title = "StatefulSet" 9 | description = "This section contains recommendations for configuring StatefulSet resources." 10 | children = [ 11 | control.statefulset_container_admission_capability_restricted, 12 | control.statefulset_container_admission_control_plugin_always_pull_images, 13 | control.statefulset_container_admission_control_plugin_no_always_admit, 14 | control.statefulset_container_arg_peer_client_cert_auth_enabled, 15 | control.statefulset_container_argument_anonymous_auth_disabled, 16 | control.statefulset_container_argument_audit_log_maxage_greater_than_30, 17 | control.statefulset_container_argument_audit_log_maxbackup_greater_than_10, 18 | control.statefulset_container_argument_audit_log_maxsize_greater_than_100, 19 | control.statefulset_container_argument_audit_log_path_configured, 20 | control.statefulset_container_argument_authorization_mode_no_always_allow, 21 | control.statefulset_container_argument_authorization_mode_node, 22 | control.statefulset_container_argument_authorization_mode_rbac, 23 | control.statefulset_container_argument_etcd_auto_tls_disabled, 24 | control.statefulset_container_argument_etcd_cafile_configured, 25 | control.statefulset_container_argument_etcd_certfile_and_keyfile_configured, 26 | control.statefulset_container_argument_etcd_client_cert_auth_enabled, 27 | control.statefulset_container_argument_etcd_peer_certfile_and_peer_keyfile_configured, 28 | control.statefulset_container_argument_event_qps_less_than_5, 29 | control.statefulset_container_argument_insecure_port_0, 30 | control.statefulset_container_argument_kube_apiserver_etcd_certfile_and_keyfile_configured, 31 | control.statefulset_container_argument_kube_apiserver_profiling_disabled, 32 | control.statefulset_container_argument_kube_apiserver_tls_cert_file_and_tls_private_key_file_configured, 33 | control.statefulset_container_argument_kube_controller_manager_bind_address_127_0_0_1, 34 | control.statefulset_container_argument_kube_controller_manager_profiling_disabled, 35 | control.statefulset_container_argument_kube_controller_manager_root_ca_file_configured, 36 | control.statefulset_container_argument_kube_controller_manager_service_account_credentials_enabled, 37 | control.statefulset_container_argument_kube_controller_manager_service_account_private_key_file_configured, 38 | control.statefulset_container_argument_kube_scheduler_bind_address_127_0_0_1, 39 | control.statefulset_container_argument_kube_scheduler_profiling_disabled, 40 | control.statefulset_container_argument_kubelet_authorization_mode_no_always_allow, 41 | control.statefulset_container_argument_kubelet_client_ca_file_configured, 42 | control.statefulset_container_argument_kubelet_client_certificate_and_key_configured, 43 | control.statefulset_container_argument_kubelet_https_enabled, 44 | control.statefulset_container_argument_kubelet_read_only_port_0, 45 | control.statefulset_container_argument_kubelet_terminated_pod_gc_threshold_configured, 46 | control.statefulset_container_argument_kubelet_tls_cert_file_and_tls_private_key_file_configured, 47 | control.statefulset_container_argument_make_iptables_util_chains_enabled, 48 | control.statefulset_container_argument_namespace_lifecycle_enabled, 49 | control.statefulset_container_argument_node_restriction_enabled, 50 | control.statefulset_container_argument_pod_security_policy_enabled, 51 | control.statefulset_container_argument_protect_kernel_defaults_enabled, 52 | control.statefulset_container_argument_request_timeout_appropriate, 53 | control.statefulset_container_argument_rotate_kubelet_server_certificate_enabled, 54 | control.statefulset_container_argument_secure_port_not_0, 55 | control.statefulset_container_argument_security_context_deny_enabled, 56 | control.statefulset_container_argument_service_account_enabled, 57 | control.statefulset_container_argument_service_account_key_file_appropriate, 58 | control.statefulset_container_argument_service_account_lookup_enabled, 59 | control.statefulset_container_capabilities_drop_all, 60 | control.statefulset_container_encryption_providers_configured, 61 | control.statefulset_container_host_port_not_specified, 62 | control.statefulset_container_image_pull_policy_always, 63 | control.statefulset_container_image_tag_specified, 64 | control.statefulset_container_kubelet_certificate_authority_configured, 65 | control.statefulset_container_kubernetes_dashboard_not_deployed, 66 | control.statefulset_container_liveness_probe, 67 | control.statefulset_container_no_argument_basic_auth_file, 68 | control.statefulset_container_no_argument_hostname_override_configured, 69 | control.statefulset_container_no_argument_insecure_bind_address, 70 | control.statefulset_container_privilege_disabled, 71 | control.statefulset_container_privilege_escalation_disabled, 72 | control.statefulset_container_privilege_port_mapped, 73 | control.statefulset_container_readiness_probe, 74 | control.statefulset_container_rotate_certificate_enabled, 75 | control.statefulset_container_secrets_defined_as_files, 76 | control.statefulset_container_security_context_exists, 77 | control.statefulset_container_streaming_connection_idle_timeout_not_zero, 78 | control.statefulset_container_strong_kube_apiserver_cryptographic_ciphers, 79 | control.statefulset_container_strong_kubelet_cryptographic_ciphers, 80 | control.statefulset_container_sys_admin_capability_disabled, 81 | control.statefulset_container_token_auth_file_not_configured, 82 | control.statefulset_container_with_added_capabilities, 83 | control.statefulset_cpu_limit, 84 | control.statefulset_cpu_request, 85 | control.statefulset_default_namespace_used, 86 | control.statefulset_default_seccomp_profile_enabled, 87 | control.statefulset_host_network_access_disabled, 88 | control.statefulset_hostpid_hostipc_sharing_disabled, 89 | control.statefulset_immutable_container_filesystem, 90 | control.statefulset_memory_limit, 91 | control.statefulset_memory_request, 92 | control.statefulset_non_root_container 93 | ] 94 | 95 | tags = merge(local.all_controls_statefulset_common_tags, { 96 | type = "Benchmark" 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /cis_kube_v120/cis_kube_v120.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | cis_kube_v120_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | cis = "true" 4 | kubernetes_version = "v1.20" 5 | }) 6 | } 7 | 8 | benchmark "cis_kube_v120" { 9 | title = "CIS Kubernetes v1.20" 10 | description = "CIS Kubernetes v1.20 benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes 1.19 - 1.20." 11 | children = [ 12 | benchmark.cis_kube_v120_v100 13 | ] 14 | 15 | tags = merge(local.cis_kube_v120_common_tags, { 16 | type = "Benchmark" 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_1_6.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Service accounts tokens should not be mounted in pods except where the workload 4 | running in the pod explicitly needs to communicate with the API server. 5 | 6 | Mounting service account tokens inside pods can provide an avenue for privilege escalation 7 | attacks where an attacker is able to compromise a single pod in the cluster. 8 | 9 | Avoiding mounting these tokens removes this attack avenue. 10 | 11 | ## Remediation 12 | 13 | Modify the definition of pods and service accounts which do not need to mount service account tokens to disable it. 14 | 15 | **References** 16 | 17 | 1. https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ 18 | -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_2_1.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Do not generally permit containers to be run with the **securityContext.privileged** flag 4 | set to **true**. 5 | 6 | Privileged containers have access to all Linux Kernel capabilities and devices. A container 7 | running with full privileges can do almost everything that the host can do. This flag exists 8 | to allow special use-cases, like manipulating the network stack and accessing devices. 9 | There should be at least one PodSecurityPolicy (PSP) defined which does not permit 10 | privileged containers. 11 | 12 | If you need to run privileged containers, this should be defined in a separate PSP and you 13 | should carefully check RBAC controls to ensure that only limited service accounts and 14 | users are given permission to access that PSP. 15 | 16 | ## Remediation 17 | 18 | Create a PSP as described in the Kubernetes documentation, ensuring that the **.spec.privileged** field is **omitted** or set to **false**. 19 | 20 | **References** 21 | 22 | 1. https://kubernetes.io/docs/concepts/policy/pod-security-policy/#enabling-pod-security-policies -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_2_2.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Do not generally permit containers to be run with the **hostPID** flag set to **true**. 4 | 5 | A container running in the host's PID namespace can inspect processes running outside the 6 | container. If the container also has access to ptrace capabilities this can be used to escalate 7 | privileges outside of the container. 8 | 9 | There should be at least one PodSecurityPolicy (PSP) defined which does not permit 10 | containers to share the host PID namespace. 11 | 12 | If you need to run containers which require hostPID, this should be defined in a separate 13 | PSP and you should carefully check RBAC controls to ensure that only limited service 14 | accounts and users are given permission to access that PSP. 15 | 16 | ## Remediation 17 | 18 | Create a PSP as described in the Kubernetes documentation, ensuring that the **.spec.hostPID** field is **omitted** or set to **false**. 19 | 20 | **References** 21 | 22 | 1. https://kubernetes.io/docs/concepts/policy/pod-security-policy/ -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_2_3.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Do not generally permit containers to be run with the **hostIPC** flag set to **true**. 4 | 5 | A container running in the host's IPC namespace can use IPC to interact with processes 6 | outside the container. 7 | 8 | There should be at least one PodSecurityPolicy (PSP) defined which does not permit 9 | containers to share the host IPC namespace. 10 | 11 | If you have a requirement to containers which require hostIPC, this should be defined in a 12 | separate PSP and you should carefully check RBAC controls to ensure that only limited 13 | service accounts and users are given permission to access that PSP. 14 | 15 | ## Remediation 16 | 17 | Create a PSP as described in the Kubernetes documentation, ensuring that the **.spec.hostIPC** field is **omitted** or set to **false**. 18 | 19 | **References** 20 | 21 | 1. https://kubernetes.io/docs/concepts/policy/pod-security-policy/ -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_2_4.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Do not generally permit containers to be run with the **hostNetwork** flag set to **true**. 4 | 5 | A container running in the host's network namespace could access the local loopback 6 | device, and could access network traffic to and from other pods. 7 | 8 | There should be at least one PodSecurityPolicy (PSP) defined which does not permit 9 | containers to share the host network namespace. 10 | 11 | If you have need to run containers which require hostNetwork, this should be defined in a 12 | separate PSP and you should carefully check RBAC controls to ensure that only limited 13 | service accounts and users are given permission to access that PSP. 14 | 15 | ## Remediation 16 | 17 | Create a PSP as described in the Kubernetes documentation, ensuring that the **.spec.hostNetwork** field is **omitted** or set to **false**. 18 | 19 | **References** 20 | 21 | 1. https://kubernetes.io/docs/concepts/policy/pod-security-policy/ -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_2_5.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Do not generally permit containers to be run with the **allowPrivilegeEscalation** flag set 4 | to **true**. 5 | 6 | A container running with the allowPrivilegeEscalation flag set to true may have 7 | processes that can gain more privileges than their parent. 8 | 9 | There should be at least one PodSecurityPolicy (PSP) defined which does not permit 10 | containers to allow privilege escalation. The option exists (and is defaulted to true) to 11 | permit setuid binaries to run. 12 | 13 | If you have need to run containers which use setuid binaries or require privilege escalation, 14 | this should be defined in a separate PSP and you should carefully check RBAC controls to 15 | ensure that only limited service accounts and users are given permission to access that 16 | PSP. 17 | 18 | ## Remediation 19 | 20 | Create a PSP as described in the Kubernetes documentation, ensuring that the **.spec.allowPrivilegeEscalation** field is **omitted** or set to **false**. 21 | 22 | **References** 23 | 24 | 1. https://kubernetes.io/docs/concepts/policy/pod-security-policy/ -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_2_6.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Do not generally permit containers to be run as the root user. 4 | 5 | Containers may run as any Linux user. Containers which run as the root user, whilst 6 | constrained by Container Runtime security features still have a escalated likelihood of 7 | container breakout. 8 | 9 | Ideally, all containers should run as a defined non-UID 0 user. 10 | 11 | There should be at least one PodSecurityPolicy (PSP) defined which does not permit root 12 | users in a container. 13 | 14 | If you need to run root containers, this should be defined in a separate PSP and you should 15 | carefully check RBAC controls to ensure that only limited service accounts and users are 16 | given permission to access that PSP. 17 | 18 | ## Remediation 19 | 20 | Create a PSP as described in the Kubernetes documentation, ensuring that the **.spec.runAsUser.rule** is set to either **MustRunAsNonRoot** or **MustRunAs** with the range of UIDs not including 0. 21 | 22 | **References** 23 | 24 | 1. https://kubernetes.io/docs/concepts/policy/pod-security-policy/#enabling-pod-security-policies -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_3_2.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Use network policies to isolate traffic in your cluster network. 4 | 5 | Running different applications on the same Kubernetes cluster creates a risk of one 6 | compromised application attacking a neighboring application. Network segmentation is 7 | important to ensure that containers can communicate only with those they are supposed 8 | to. A network policy is a specification of how selections of pods are allowed to 9 | communicate with each other and other network endpoints. 10 | 11 | Network Policies are namespace scoped. When a network policy is introduced to a given 12 | namespace, all traffic not allowed by the policy is denied. However, if there are no network 13 | policies in a namespace all traffic will be allowed into and out of the pods in that 14 | namespace. 15 | 16 | ## Remediation 17 | 18 | Follow the documentation and create **NetworkPolicy** objects as you need them. By default, network policies are not created. 19 | 20 | **References** 21 | 22 | 1. https://kubernetes.io/docs/concepts/services-networking/networkpolicies/ 23 | 2. https://octetz.com/posts/k8s-network-policy-apis 24 | 3. https://kubernetes.io/docs/tasks/configure-pod-container/declare-network-policy/ -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_7_2.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Enable docker/default seccomp profile in your pod definitions. 4 | 5 | Seccomp (secure computing mode) is used to restrict the set of system calls applications 6 | can make, allowing cluster administrators greater control over the security of workloads 7 | running in the cluster. Kubernetes disables seccomp profiles by default for historical 8 | reasons. You should enable it to ensure that the workloads have restricted actions available 9 | within the container. 10 | 11 | ## Remediation 12 | 13 | Use security context to enable the docker/default seccomp profile in your pod definitions. 14 | 15 | **References** 16 | 17 | 1. https://kubernetes.io/docs/tutorials/clusters/seccomp/ 18 | 2. https://docs.docker.com/engine/security/seccomp/ 19 | -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_5_7_4.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Kubernetes provides a default namespace, where objects are placed if no namespace is 4 | specified for them. Placing objects in this namespace makes application of RBAC and other 5 | controls more difficult. 6 | 7 | ## Remediation 8 | 9 | Ensure that namespaces are created to allow for appropriate segregation of Kubernetes 10 | resources and that all new resources are created in a specific namespace. -------------------------------------------------------------------------------- /cis_kube_v120/docs/cis_kube_v120_v100_overview.md: -------------------------------------------------------------------------------- 1 | To obtain the latest version of this guide, please visit http://www.cisecurity.org. 2 | 3 | ## Overview 4 | 5 | CIS Kubernetes v1.20 benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes 1.19 - 1.20. 6 | -------------------------------------------------------------------------------- /cis_v170/cis.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | cis_v170_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | cis = "true" 4 | cis_version = "v1.7.0" 5 | kubernetes_version = "v1.25" 6 | }) 7 | } 8 | 9 | benchmark "cis_v170" { 10 | title = "CIS v1.7.0" 11 | description = "CIS v1.7.0 benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes v1.25." 12 | documentation = file("./cis_v170/docs/cis_v170_overview.md") 13 | children = [ 14 | benchmark.cis_v170_5 15 | ] 16 | 17 | tags = merge(local.cis_v170_common_tags, { 18 | type = "Benchmark" 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_1.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This section contains recommendations for various Kubernetes RBAC policies which can also govern the behavior of software resources, that Kubernetes identifies as service accounts. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_1_3.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Kubernetes Roles and ClusterRoles provide access to resources based on sets of objects and actions that can be taken on those objects. It is possible to set either of these to be the wildcard "*" which matches all items. 4 | 5 | Use of wildcards is not optimal from a security perspective as it may allow for inadvertent access to be granted when new resources are added to the Kubernetes API either as CRDs or in later versions of the product. 6 | 7 | The principle of least privilege recommends that users are provided only the access required for their role and nothing more. The use of wildcard rights grants is likely to provide excessive rights to the Kubernetes API. 8 | 9 | ## Remediation 10 | 11 | Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_1_6.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Service accounts tokens should not be mounted in pods except where the workload running in the pod explicitly needs to communicate with the API server. 4 | 5 | Mounting service account tokens inside pods can provide an avenue for privilege escalation attacks where an attacker is able to compromise a single pod in the cluster. 6 | 7 | Avoiding mounting these tokens removes this attack avenue. 8 | 9 | ## Remediation 10 | 11 | Modify the definition of pods and service accounts which do not need to mount service account tokens to disable it. 12 | 13 | **Default Value:** By default, all pods get a service account token mounted in them. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_3.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This section contains recommendations for Network Policies and the Container Network Interface (CNI). It recommends implementing Network Policies ensuring that only authorized connections are allowed. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_3_2.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Use network policies to isolate traffic in your cluster network. 4 | 5 | Running different applications on the same Kubernetes cluster creates a risk of one compromised application attacking a neighboring application. Network segmentation is important to ensure that containers can communicate only with those they are supposed to. A network policy is a specification of how selections of pods are allowed to communicate with each other and other network endpoints. 6 | 7 | Network Policies are namespace scoped. When a network policy is introduced to a given namespace, all traffic not allowed by the policy is denied. However, if there are no network policies in a namespace all traffic will be allowed into and out of the pods in that namespace. 8 | 9 | ## Remediation 10 | 11 | Follow the documentation and create `NetworkPolicy` objects as you need them. By default, network policies are not created. 12 | 13 | **Default Value:** By default, network policies are not created. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_7.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | These policies relate to general cluster management topics, like namespace best practices and policies applied to pod objects in the cluster. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_7_2.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Enable `docker/default` seccomp profile in your pod definitions. 4 | 5 | Seccomp (secure computing mode) is used to restrict the set of system calls applications 6 | can make, allowing cluster administrators greater control over the security of workloads 7 | running in the cluster. Kubernetes disables seccomp profiles by default for historical 8 | reasons. You should enable it to ensure that the workloads have restricted actions available 9 | within the container. 10 | 11 | ## Remediation 12 | 13 | Use security context to enable the docker/default seccomp profile in your pod definitions. An example is as below: 14 | 15 | ```yaml 16 | securityContext: 17 | seccompProfile: 18 | type: RuntimeDefault 19 | ``` 20 | 21 | **Default Value:** By default, seccomp profile is set to unconfined which means that no seccomp profiles are enabled. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_5_7_4.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Kubernetes provides a default namespace, where objects are placed if no namespace is specified for them. Placing objects in this namespace makes application of RBAC and other controls more difficult. 4 | 5 | Resources in a Kubernetes cluster should be segregated by namespace, to allow for security controls to be applied at that level and to make it easier to manage resources. 6 | 7 | ## Remediation 8 | 9 | Ensure that namespaces are created to allow for appropriate segregation of Kubernetes resources and that all new resources are created in a specific namespace. 10 | 11 | **Default Value:** Unless a namespace is specific on object creation, the `default` namespace will be used. -------------------------------------------------------------------------------- /cis_v170/docs/cis_v170_overview.md: -------------------------------------------------------------------------------- 1 | To obtain the latest version of this guide, please visit http://www.cisecurity.org. 2 | 3 | ## Overview 4 | 5 | CIS v1.7.0 benchmark provides prescriptive guidance for establishing a secure configuration posture for Kubernetes v1.25. -------------------------------------------------------------------------------- /cis_v170/section_5.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | cis_v170_5_common_tags = merge(local.cis_v170_common_tags, { 3 | cis_section_id = "5" 4 | }) 5 | } 6 | 7 | locals { 8 | cis_v170_5_1_common_tags = merge(local.cis_v170_5_common_tags, { 9 | cis_section_id = "5.1" 10 | }) 11 | 12 | cis_v170_5_3_common_tags = merge(local.cis_v170_5_common_tags, { 13 | cis_section_id = "5.3" 14 | }) 15 | 16 | cis_v170_5_7_common_tags = merge(local.cis_v170_5_common_tags, { 17 | cis_section_id = "5.7" 18 | }) 19 | } 20 | 21 | benchmark "cis_v170_5" { 22 | title = "5 Policies" 23 | description = "This section contains recommendations for various Kubernetes policies which are important to the security of the environment." 24 | children = [ 25 | benchmark.cis_v170_5_1, 26 | benchmark.cis_v170_5_3, 27 | benchmark.cis_v170_5_7 28 | ] 29 | 30 | tags = merge(local.cis_v170_5_common_tags, { 31 | type = "Benchmark" 32 | }) 33 | } 34 | 35 | benchmark "cis_v170_5_1" { 36 | title = "5.1 RBAC and Service Accounts" 37 | description = "This section contains recommendations for various Kubernetes RBAC policies which can also govern the behavior of software resources, that Kubernetes identifies as service accounts." 38 | documentation = file("./cis_v170/docs/cis_v170_5_1.md") 39 | children = [ 40 | control.cis_v170_5_1_3, 41 | control.cis_v170_5_1_6 42 | ] 43 | 44 | tags = merge(local.cis_v170_5_1_common_tags, { 45 | type = "Benchmark" 46 | }) 47 | } 48 | 49 | control "cis_v170_5_1_3" { 50 | title = "5.1.3 Minimize wildcard use in Roles and ClusterRoles" 51 | description = "Kubernetes Roles and ClusterRoles provide access to resources based on sets of objects and actions that can be taken on those objects. It is possible to set either of these to be the wildcard \"*\" which matches all items. Use of wildcards is not optimal from a security perspective as it may allow for inadvertent access to be granted when new resources are added to the Kubernetes API either as CRDs or in later versions of the product." 52 | query = query.role_with_wildcards_used 53 | documentation = file("./cis_v170/docs/cis_v170_5_1_3.md") 54 | 55 | tags = merge(local.cis_v170_5_1_common_tags, { 56 | cis_level = "1" 57 | cis_item_id = "5.1.3" 58 | cis_type = "manual" 59 | service = "Kubernetes/Role" 60 | }) 61 | } 62 | 63 | control "cis_v170_5_1_6" { 64 | title = "5.1.6 Ensure that Service Account Tokens are only mounted where necessary" 65 | description = "Service accounts tokens should not be mounted in pods except where the workload running in the pod explicitly needs to communicate with the API server." 66 | query = query.pod_service_account_token_disabled 67 | documentation = file("./cis_v170/docs/cis_v170_5_1_6.md") 68 | 69 | tags = merge(local.cis_v170_5_1_common_tags, { 70 | cis_level = "1" 71 | cis_item_id = "5.1.6" 72 | cis_type = "manual" 73 | service = "Kubernetes/Pod" 74 | }) 75 | } 76 | 77 | benchmark "cis_v170_5_3" { 78 | title = "5.3 Network Policies and CNI" 79 | description = "This section contains recommendations for network policies and the Container Network Interface (CNI). It recommends implementing network policies ensuring that only authorized connections are allowed." 80 | documentation = file("./cis_v170/docs/cis_v170_5_3.md") 81 | children = [ 82 | benchmark.cis_v170_5_3_2 83 | ] 84 | 85 | tags = merge(local.cis_v170_5_3_common_tags, { 86 | type = "Benchmark" 87 | }) 88 | } 89 | 90 | benchmark "cis_v170_5_3_2" { 91 | title = "5.3.2 Ensure that all Namespaces have Network Policies defined" 92 | description = "Use network policies to isolate traffic in your cluster network." 93 | documentation = file("./cis_v170/docs/cis_v170_5_3_2.md") 94 | children = [ 95 | control.network_policy_default_deny_egress, 96 | control.network_policy_default_deny_ingress, 97 | control.network_policy_default_dont_allow_egress, 98 | control.network_policy_default_dont_allow_ingress 99 | ] 100 | 101 | tags = merge(local.cis_v170_5_3_common_tags, { 102 | cis_level = "2" 103 | cis_item_id = "5.3.2" 104 | cis_type = "manual" 105 | type = "Benchmark" 106 | }) 107 | } 108 | 109 | benchmark "cis_v170_5_7" { 110 | title = "5.7 General Policies" 111 | description = "These policies relate to general cluster management topics, like namespace best practices and policies applied to pod objects in the cluster." 112 | documentation = file("./cis_v170/docs/cis_v170_5_7.md") 113 | children = [ 114 | benchmark.cis_v170_5_7_2, 115 | benchmark.cis_v170_5_7_4 116 | ] 117 | 118 | tags = merge(local.cis_v170_5_7_common_tags, { 119 | type = "Benchmark" 120 | }) 121 | } 122 | 123 | benchmark "cis_v170_5_7_2" { 124 | title = "5.7.2 Ensure that the seccomp profile is set to docker/default in your Pod definitions" 125 | description = "Enable `docker/default` seccomp profile in your pod definitions." 126 | documentation = file("./cis_v170/docs/cis_v170_5_7_2.md") 127 | children = [ 128 | control.cronjob_default_seccomp_profile_enabled, 129 | control.daemonset_default_seccomp_profile_enabled, 130 | control.deployment_default_seccomp_profile_enabled, 131 | control.job_default_seccomp_profile_enabled, 132 | control.pod_default_seccomp_profile_enabled, 133 | control.replicaset_default_seccomp_profile_enabled, 134 | control.replication_controller_default_seccomp_profile_enabled, 135 | control.statefulset_default_seccomp_profile_enabled 136 | ] 137 | 138 | tags = merge(local.cis_v170_5_7_common_tags, { 139 | cis_level = "2" 140 | cis_item_id = "5.7.2" 141 | cis_type = "manual" 142 | type = "Benchmark" 143 | }) 144 | } 145 | 146 | benchmark "cis_v170_5_7_4" { 147 | title = "5.7.4 The default namespace should not be used" 148 | description = "Kubernetes provides a default namespace, where objects are placed if no namespace is specified for them. Placing objects in this namespace makes application of RBAC and other controls more difficult." 149 | documentation = file("./cis_v170/docs/cis_v170_5_7_4.md") 150 | children = [ 151 | control.config_map_default_namespace_used, 152 | control.cronjob_default_namespace_used, 153 | control.daemonset_default_namespace_used, 154 | control.deployment_default_namespace_used, 155 | control.ingress_default_namespace_used, 156 | control.job_default_namespace_used, 157 | control.pod_default_namespace_used, 158 | control.replicaset_default_namespace_used, 159 | control.replication_controller_default_namespace_used, 160 | control.role_binding_default_namespace_used, 161 | control.role_default_namespace_used, 162 | control.secret_default_namespace_used, 163 | control.service_account_default_namespace_used, 164 | control.service_default_namespace_used, 165 | control.statefulset_default_namespace_used 166 | ] 167 | 168 | tags = merge(local.cis_v170_5_7_common_tags, { 169 | cis_level = "2" 170 | cis_item_id = "5.7.4" 171 | cis_type = "manual" 172 | type = "Benchmark" 173 | }) 174 | } 175 | -------------------------------------------------------------------------------- /controls/cluster_role_binding.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | cluster_role_binding_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/ClusterRoleBinding" 4 | }) 5 | } 6 | 7 | control "cluster_role_binding_default_service_account_binding_not_active" { 8 | title = "ClusterRoleBinding subjects should not actively use default service accounts" 9 | description = "Default service accounts should not be used by ClusterRoleBinding subjects." 10 | query = query.cluster_role_binding_default_service_account_binding_not_active 11 | 12 | tags = local.cluster_role_binding_common_tags 13 | } 14 | -------------------------------------------------------------------------------- /controls/config_map.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | config_map_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/ConfigMap" 4 | }) 5 | } 6 | 7 | control "config_map_default_namespace_used" { 8 | title = "ConfigMap definition should not use default namespace" 9 | description = "Default namespace should not be used by ConfigMap definition. Placing objects in this namespace makes application of RBAC and other controls more difficult." 10 | query = query.config_map_default_namespace_used 11 | 12 | tags = merge(local.config_map_common_tags, { 13 | cis = "true" 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /controls/endpoint.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | endpoint_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/Endpoint" 4 | }) 5 | } 6 | 7 | control "endpoint_api_serve_on_secure_port" { 8 | title = "Kubernetes API should serve on secure port" 9 | description = "Kubernetes API should serve on port 443 or port 6443, protected by TLS. Once TLS is established, the HTTP request moves to the authentication step. If the request cannot be authenticated, it is rejected with HTTP status code 401." 10 | query = query.endpoint_api_serve_on_secure_port 11 | 12 | tags = merge(local.endpoint_common_tags, { 13 | nsa_cisa_v1 = "true" 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /controls/ingress.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | ingress_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/Ingress" 4 | }) 5 | } 6 | 7 | control "ingress_default_namespace_used" { 8 | title = "Ingress definition should not use default namespace" 9 | description = "Default namespace should not be used by Ingress definition. Placing objects in this namespace makes application of RBAC and other controls more difficult." 10 | query = query.ingress_default_namespace_used 11 | 12 | tags = merge(local.ingress_common_tags, { 13 | cis = "true" 14 | }) 15 | } 16 | 17 | control "ingress_nginx_annotations_snippets_alias_not_used" { 18 | title = "Ingress definition should not have NGINX ingress annotation snippets containing alias statements" 19 | description = "This check ensures that the NGINX ingress annotation snippets in the Ingress do not contain alias statements." 20 | query = query.ingress_nginx_annotations_snippets_alias_not_used 21 | 22 | tags = local.ingress_common_tags 23 | } 24 | 25 | control "ingress_nginx_annotations_all_snippets_not_used" { 26 | title = "Ingress definition should not allow any usage of NGINX ingress annotation snippets" 27 | description = "This check ensures that the NGINX ingress annotation snippets usage is not allowed in the Ingress." 28 | query = query.ingress_nginx_annotations_all_snippets_not_used 29 | 30 | tags = local.ingress_common_tags 31 | } 32 | 33 | control "ingress_nginx_annotations_snippets_lua_code_not_used" { 34 | title = "Ingress definition should not have NGINX ingress annotation snippets containing lua code snippets" 35 | description = "This check ensures that the NGINX ingress annotation snippets in the Ingress do not contain lua code snippets." 36 | query = query.ingress_nginx_annotations_snippets_lua_code_not_used 37 | 38 | tags = local.ingress_common_tags 39 | } 40 | -------------------------------------------------------------------------------- /controls/local.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | container_cpu_limit_title = "__KIND__ containers should have a CPU limit" 3 | container_cpu_limit_desc = "Containers in a __KIND__ should have CPU limit which restricts the container to use no more than a given amount of CPU." 4 | 5 | container_cpu_request_title = "__KIND__ containers should have a CPU request" 6 | container_cpu_request_desc = "Containers in a __KIND__ should have CPU request. If required Kubernetes will make sure your containers get the CPU they requested." 7 | 8 | container_memory_limit_title = "__KIND__ containers should have a memory limit" 9 | container_memory_limit_desc = "Containers in a __KIND__ should have memory limit which restricts the container to use no more than a given amount of user or system memory." 10 | 11 | container_memory_request_title = "__KIND__ containers should have a memory request" 12 | container_memory_request_desc = "Containers in a __KIND__ should have memory request. If required Kubernetes will make sure your containers get the memory they requested." 13 | 14 | container_disallow_host_path_title = "__KIND__ containers should not allow privilege escalation" 15 | container_disallow_host_path_desc = "Containers in a __KIND__ should not able to access any specific paths of the host file system. There are many ways a container with unrestricted access to the host filesystem can escalate privileges, including reading data from other containers, and abusing the credentials of system services, such as Kubelet." 16 | 17 | container_privilege_disabled_title = "__KIND__ containers should not have privileged access" 18 | container_privilege_disabled_desc = "Containers in a __KIND__ should not have privileged access. To prevent security issues, it is recommended that you do not run privileged containers in your environment. Instead, provide granular permissions and capabilities to the container environment. Giving containers full access to the host can create security flaws in your production environment." 19 | 20 | container_privilege_escalation_disabled_title = "__KIND__ containers should not allow privilege escalation" 21 | container_privilege_escalation_disabled_desc = "Containers in a __KIND__ should not allow privilege escalation. A container running with the `allowPrivilegeEscalation` flag set to true may have processes that can gain more privileges than their parent." 22 | 23 | host_network_access_disabled_title = "__KIND__ containers should not run with host network access" 24 | host_network_access_disabled_desc = "Containers in a __KIND__ should not run in the host network of the node where the pod is deployed. When running on the host network, the pod can use the network namespace and network resources of the node. In this case, the pod can access loopback devices, listen to addresses, and monitor the traffic of other pods on the node." 25 | 26 | hostpid_hostipc_sharing_disabled_title = "__KIND__ containers should not share the host process namespace" 27 | hostpid_hostipc_sharing_disabled_desc = "Containers in a __KIND__ should not share the host process PID or IPC namespace. Sharing the host’s process namespace allows the container to see all of the processes on the host system. This reduces the benefit of process level isolation between the host and the containers. Under these circumstances a malicious user who has access to a container could get access to processes on the host itself, manipulate them, and even be able to kill them." 28 | 29 | immutable_container_filesystem_title = "__KIND__ containers should run with a read only root file system" 30 | immutable_container_filesystem_desc = "Containers in a __KIND__ should always run with a read only root file system. Using an immutable root filesystem and a verified boot mechanism prevents against attackers from owning the machine through permanent local changes. An immutable root filesystem can also prevent malicious binaries from writing to the host system." 31 | 32 | non_root_container_title = "__KIND__ containers should not run with root privileges" 33 | non_root_container_desc = "Containers in a __KIND__ should not run with root privileges. By default, many container services run as the privileged root user, and applications execute inside the container as root despite not requiring privileged execution. Preventing root execution by using non-root containers or a rootless container engine limits the impact of a container compromise." 34 | 35 | pod_service_account_not_exist_desc = "Pods should not refer to a service account which is not available." 36 | 37 | service_account_token_disabled_desc = "Automatic mapping of service account token should be disabled. By default, Kubernetes automatically provisions a service account when creating a Pod and mounts the account’s secret token within the Pod at runtime. Many containerized applications do not require direct access to the service account as Kubernetes orchestration occurs transparently in the background. If an application is compromised, account tokens in Pods can be gleaned by cyber actors and used to further compromise the cluster. When an application does not need to access the service account directly, Kubernetes administrators should ensure that Pod specifications disable the secret token being mounted. This can be accomplished using the `automountServiceAccountToken: false` directive in the Pod's YAML specification." 38 | 39 | service_type_forbidden_desc = "Containers should not be exposed through a forbidden service type such as `NodePort` or `LoadBalancer`." 40 | } 41 | -------------------------------------------------------------------------------- /controls/namespace.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | namespace_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/Namespace" 4 | }) 5 | } 6 | 7 | control "namespace_limit_range_default_cpu_limit" { 8 | title = "Namespaces should have default CPU limit in limitRange policy" 9 | description = "Administrators should use default limitRange policy for CPU limit for each namespace." 10 | query = query.namespace_limit_range_default_cpu_limit 11 | 12 | tags = merge(local.namespace_common_tags, { 13 | nsa_cisa_v1 = "true" 14 | }) 15 | } 16 | 17 | control "namespace_resource_quota_cpu_limit" { 18 | title = "Namespaces should be restricted on CPU usage with resourceQuota CPU limit" 19 | description = "Administrators should use resourceQuota CPU limit to restrict namespaces CPU usage." 20 | query = query.namespace_resource_quota_cpu_limit 21 | 22 | tags = merge(local.namespace_common_tags, { 23 | nsa_cisa_v1 = "true" 24 | }) 25 | } 26 | 27 | control "namespace_limit_range_default_cpu_request" { 28 | title = "Namespaces should have default CPU request in limitRange policy" 29 | description = "Administrators should use default limitRange policy for CPU request for each namespace." 30 | query = query.namespace_limit_range_default_cpu_request 31 | 32 | tags = merge(local.namespace_common_tags, { 33 | nsa_cisa_v1 = "true" 34 | }) 35 | } 36 | 37 | control "namespace_resource_quota_cpu_request" { 38 | title = "Namespaces should have resourceQuota CPU request" 39 | description = "Administrators should use resourceQuota CPU request for each namespace." 40 | query = query.namespace_resource_quota_cpu_request 41 | 42 | tags = merge(local.namespace_common_tags, { 43 | nsa_cisa_v1 = "true" 44 | }) 45 | } 46 | 47 | control "namespace_limit_range_default_memory_limit" { 48 | title = "Namespaces should have default memory limit in limitRange policy" 49 | description = "Administrators should use default limitRange policy for memory limit for each namespace." 50 | query = query.namespace_limit_range_default_memory_limit 51 | 52 | tags = merge(local.namespace_common_tags, { 53 | nsa_cisa_v1 = "true" 54 | }) 55 | } 56 | 57 | control "namespace_resource_quota_memory_limit" { 58 | title = "Namespaces should be restricted on memory usage with resourceQuota memory limit" 59 | description = "Administrators should use resourceQuota memory limit to restrict namespaces memory usage." 60 | query = query.namespace_resource_quota_memory_limit 61 | 62 | tags = merge(local.namespace_common_tags, { 63 | nsa_cisa_v1 = "true" 64 | }) 65 | } 66 | 67 | control "namespace_limit_range_default_memory_request" { 68 | title = "Namespaces should have default memory request in limitRange policy" 69 | description = "Administrators should use default limitRange policy for memory request for each namespace." 70 | query = query.namespace_limit_range_default_memory_request 71 | 72 | tags = merge(local.namespace_common_tags, { 73 | nsa_cisa_v1 = "true" 74 | }) 75 | } 76 | 77 | control "namespace_resource_quota_memory_request" { 78 | title = "Namespaces should have resourceQuota memory request" 79 | description = "Administrators should use resourceQuota memory request for each namespace." 80 | query = query.namespace_resource_quota_memory_request 81 | 82 | tags = merge(local.namespace_common_tags, { 83 | nsa_cisa_v1 = "true" 84 | }) 85 | } 86 | -------------------------------------------------------------------------------- /controls/network_policy.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | network_policy_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/NetworkPolicy" 4 | }) 5 | } 6 | 7 | control "network_policy_default_deny_egress" { 8 | title = "Namespaces should have a default network policy to deny all egress traffic" 9 | description = "Administrators should use a default policy selecting all Pods to deny all egress traffic and ensure any unselected Pods are isolated. Additional policies could then relax these restrictions for permissible connections." 10 | query = query.network_policy_default_deny_egress 11 | 12 | tags = merge(local.network_policy_common_tags, { 13 | cis = "true" 14 | nsa_cisa_v1 = "true" 15 | }) 16 | } 17 | 18 | control "network_policy_default_deny_ingress" { 19 | title = "Namespaces should have a default network policy to deny all ingress traffic" 20 | description = "Administrators should use a default policy selecting all Pods to deny all ingress traffic and ensure any unselected Pods are isolated. Additional policies could then relax these restrictions for permissible connections." 21 | query = query.network_policy_default_deny_ingress 22 | 23 | tags = merge(local.network_policy_common_tags, { 24 | cis = "true" 25 | nsa_cisa_v1 = "true" 26 | }) 27 | } 28 | 29 | control "network_policy_default_dont_allow_egress" { 30 | title = "Network policies should not have a default policy to allow all egress traffic" 31 | description = "Administrators should use a default policy selecting all Pods to deny all ingress and egress traffic and ensure any unselected Pods are isolated. An 'allow all' policy would override this default and should not be used. Instead, use specific policies to relax these restrictions only for permissible connections. " 32 | query = query.network_policy_default_dont_allow_egress 33 | 34 | tags = merge(local.network_policy_common_tags, { 35 | cis = "true" 36 | nsa_cisa_v1 = "true" 37 | }) 38 | } 39 | 40 | control "network_policy_default_dont_allow_ingress" { 41 | title = "Network policies should not have a default policy to allow all ingress traffic" 42 | description = "Administrators should use a default policy selecting all Pods to deny all ingress and egress traffic and ensure any unselected Pods are isolated. An 'allow all' policy would override this default and should not be used. Instead, use specific policies to relax these restrictions only for permissible connections. " 43 | query = query.network_policy_default_dont_allow_ingress 44 | 45 | tags = merge(local.network_policy_common_tags, { 46 | cis = "true" 47 | nsa_cisa_v1 = "true" 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /controls/pod_security_policy.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | pod_security_policy_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/PodSecurityPolicy" 4 | }) 5 | } 6 | 7 | control "pod_security_policy_allowed_host_path" { 8 | title = "Pod Security Policy should prohibit hostPaths volumes" 9 | description = "The Pod Security Policy `allowedHostPaths` specifies a list of host paths that are allowed to be used by hostPath volumes. An empty list means there is no restriction on host paths used. This is defined as a list of objects with a single pathPrefix field, which allows hostPath volumes to mount a path that begins with an allowed prefix, and a readOnly field indicating it must be mounted read-only." 10 | query = query.pod_security_policy_allowed_host_path 11 | 12 | tags = merge(local.pod_security_policy_common_tags, { 13 | nsa_cisa_v1 = "true" 14 | }) 15 | } 16 | 17 | control "pod_security_policy_container_privilege_disabled" { 18 | title = "Pod Security Policy should prohibit containers to run with privilege access" 19 | description = "Pod Security Policy `privileged` controls whether the Pod containers may run with `privileged` access. ${replace(local.container_privilege_disabled_desc, "__KIND__", "Pod")}" 20 | query = query.pod_security_policy_container_privilege_disabled 21 | 22 | tags = merge(local.pod_security_policy_common_tags, { 23 | nsa_cisa_v1 = "true" 24 | }) 25 | } 26 | 27 | control "pod_security_policy_container_privilege_escalation_disabled" { 28 | title = "Pod Security Policy should prohibit privilege escalation" 29 | description = "Pod Security Policy `allowPrivilegeEscalation` controls whether the Pod containers may request for privilege escalation. ${replace(local.container_privilege_escalation_disabled_desc, "__KIND__", "Pod")}" 30 | query = query.pod_security_policy_container_privilege_escalation_disabled 31 | 32 | tags = merge(local.pod_security_policy_common_tags, { 33 | nsa_cisa_v1 = "true" 34 | }) 35 | } 36 | 37 | control "pod_security_policy_security_services_hardening" { 38 | title = "Containerized applications should use security services such as SELinux or AppArmor or Seccomp" 39 | description = "The underlying host OS needs to be secured in order to prevent container breaches from affecting the host. For this, Linux provides several out-of-the-box security modules. Some of the popular ones are SELinux, AppArmor and Seccomp." 40 | query = query.pod_security_policy_security_services_hardening 41 | 42 | tags = merge(local.pod_security_policy_common_tags, { 43 | nsa_cisa_v1 = "true" 44 | }) 45 | } 46 | 47 | control "pod_security_policy_host_network_access_disabled" { 48 | title = "Pod Security Policy should prohibit host network access " 49 | description = "Pod Security Policy host network controls whether the Pod may use the node network namespace. Doing so gives the Pod access to the loopback device, services listening on localhost, and could be used to snoop on network activity of other Pods on the same node." 50 | query = query.pod_security_policy_host_network_access_disabled 51 | 52 | tags = merge(local.pod_security_policy_common_tags, { 53 | nsa_cisa_v1 = "true" 54 | }) 55 | } 56 | 57 | control "pod_security_policy_hostpid_hostipc_sharing_disabled" { 58 | title = "Pod Security Policy should prohibit containers from sharing the host process namespaces" 59 | description = "Pod Security Policy `hostPID` and `hostIPC` controls whether the Pod may share the host process namespaces. ${replace(local.hostpid_hostipc_sharing_disabled_desc, "__KIND__", "Pod")}" 60 | query = query.pod_security_policy_hostpid_hostipc_sharing_disabled 61 | 62 | tags = merge(local.pod_security_policy_common_tags, { 63 | nsa_cisa_v1 = "true" 64 | }) 65 | } 66 | 67 | control "pod_security_policy_immutable_container_filesystem" { 68 | title = "Pod Security Policy should force containers to run with read-only root file system" 69 | description = "Pod Security Policy `readOnlyRootFilesystem` controls whether the Pod containers run with read-only root file system. ${replace(local.immutable_container_filesystem_desc, "__KIND__", "Pod")}" 70 | query = query.pod_security_policy_immutable_container_filesystem 71 | 72 | tags = merge(local.pod_security_policy_common_tags, { 73 | nsa_cisa_v1 = "true" 74 | }) 75 | } 76 | 77 | control "pod_security_policy_non_root_container" { 78 | title = "Pod Security Policy should prohibit containers from running as root" 79 | description = "Pod Security Policy should prohibit containers from running as root. ${replace(local.non_root_container_desc, "__KIND__", "Pod")}" 80 | query = query.pod_security_policy_non_root_container 81 | 82 | tags = merge(local.pod_security_policy_common_tags, { 83 | nsa_cisa_v1 = "true" 84 | }) 85 | } 86 | 87 | control "pod_security_policy_default_seccomp_profile_enabled" { 88 | title = "Seccomp profile is set to docker/default in Pod security policy" 89 | description = "In Pod security policy seccomp profile should be set to docker/default. Seccomp (secure computing mode) is used to restrict the set of system calls applications can make, allowing cluster administrators greater control over the security of workloads running in the cluster. Kubernetes disables seccomp profiles by default for historical reasons. It should be enabled to ensure that the workloads have restricted actions available within the container." 90 | query = query.pod_security_policy_default_seccomp_profile_enabled 91 | 92 | tags = merge(local.pod_security_policy_common_tags, { 93 | cis = "true" 94 | }) 95 | } 96 | 97 | control "pod_security_policy_hostpid_sharing_disabled" { 98 | title = "Minimize the admission of containers wishing to share the host process ID namespace" 99 | description = "A container running in the host's PID namespace can inspect processes running outside the container. If the container also has access to ptrace capabilities this can be used to escalate privileges outside of the container. There should be at least one PodSecurityPolicy (PSP) defined which does not permit containers to share the host PID namespace." 100 | query = query.pod_security_policy_hostpid_sharing_disabled 101 | 102 | tags = merge(local.pod_security_policy_common_tags, { 103 | cis = "true" 104 | }) 105 | } 106 | 107 | control "pod_security_policy_hostipc_sharing_disabled" { 108 | title = "Minimize the admission of containers wishing to share the host IPC namespace" 109 | description = "A container running in the host's IPC namespace can use IPC to interact with processes outside the container. There should be at least one PodSecurityPolicy (PSP) defined which does not permit containers to share the host IPC namespace." 110 | query = query.pod_security_policy_hostipc_sharing_disabled 111 | 112 | tags = merge(local.pod_security_policy_common_tags, { 113 | cis = "true" 114 | }) 115 | } 116 | -------------------------------------------------------------------------------- /controls/role.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | role_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/Role" 4 | }) 5 | } 6 | 7 | control "role_default_namespace_used" { 8 | title = "Role definition should not use default namespace" 9 | description = "Default namespace should not be used by Role definition. Placing objects in this namespace makes application of RBAC and other controls more difficult." 10 | query = query.role_default_namespace_used 11 | 12 | tags = merge(local.role_common_tags, { 13 | cis = "true" 14 | }) 15 | } 16 | 17 | control "role_with_wildcards_used" { 18 | title = "Minimize wildcard use in Roles and ClusterRoles" 19 | description = "Kubernetes Roles and ClusterRoles provide access to resources based on sets of objects and actions that can be taken on those objects. It is possible to set either of these to be the wildcard \"*\" which matches all items. Use of wildcards is not optimal from a security perspective as it may allow for inadvertent access to be granted when new resources are added to the Kubernetes API either as CRDs or in later versions of the product." 20 | query = query.role_with_wildcards_used 21 | 22 | tags = merge(local.role_common_tags, { 23 | cis = "true" 24 | }) 25 | } 26 | 27 | control "role_with_rbac_escalate_permissions" { 28 | title = "ClusterRoles permissions to escalate Roles or ClusterRoles should be minimized" 29 | description = "Minimize the permissions granted to ClusterRoles to escalate Roles or ClusterRoles. It is recommended to follow the principle of least privilege to enhance security." 30 | query = query.role_with_rbac_escalate_permissions 31 | 32 | tags = local.role_common_tags 33 | } 34 | 35 | control "role_with_bind_cluster_role_bindings" { 36 | title = "ClusterRoles permissions to bind RoleBindings or ClusterRoleBindings should be minimized" 37 | description = "Minimize the permissions granted to bind RoleBindings or ClusterRoleBinding. It is recommended to follow the principle of least privilege to enhance security." 38 | query = query.role_with_bind_cluster_role_bindings 39 | 40 | tags = local.role_common_tags 41 | } 42 | 43 | control "cluster_role_with_validating_or_mutating_admission_webhook_configurations" { 44 | title = "ClusterRoles permissions for managing the configuration of validation or mutation admission webhooks should be minimized" 45 | description = "Minimize the permissions granted to ClusterRoles for managing admission webhooks. It is recommended to follow the principle of least privilege to enhance security." 46 | query = query.cluster_role_with_validating_or_mutating_admission_webhook_configurations 47 | 48 | tags = local.role_common_tags 49 | } 50 | 51 | control "role_with_rbac_approve_certificate_signing_requests" { 52 | title = "ClusterRoles permissions for approving CertificateSigningRequests" 53 | description = "Minimize the permissions granted to ClusterRoles for approving CertificateSigningRequests. It is recommended to follow the principle of least privilege to enhance security." 54 | query = query.role_with_rbac_approve_certificate_signing_requests 55 | 56 | tags = local.role_common_tags 57 | } 58 | -------------------------------------------------------------------------------- /controls/role_binding.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | role_binding_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/RoleBinding" 4 | }) 5 | } 6 | 7 | control "role_binding_default_namespace_used" { 8 | title = "RoleBinding definition should not use default namespace" 9 | description = "Default namespace should not be used by RoleBinding definition. Placing objects in this namespace makes application of RBAC and other controls more difficult." 10 | query = query.role_binding_default_namespace_used 11 | 12 | tags = merge(local.role_binding_common_tags, { 13 | cis = "true" 14 | }) 15 | } 16 | 17 | control "role_binding_default_service_account_binding_not_active" { 18 | title = "RoleBinding subjects should not actively use default service accounts" 19 | description = "Default service accounts should not be used by RoleBinding subjects." 20 | query = query.role_binding_default_service_account_binding_not_active 21 | 22 | tags = local.role_binding_common_tags 23 | } 24 | -------------------------------------------------------------------------------- /controls/secret.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | secret_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/Secret" 4 | }) 5 | } 6 | 7 | control "secret_default_namespace_used" { 8 | title = "Secret definition should not use default namespace" 9 | description = "Default namespace should not be used by Secret definition. Placing objects in this namespace makes application of RBAC and other controls more difficult." 10 | query = query.secret_default_namespace_used 11 | 12 | tags = merge(local.secret_common_tags, { 13 | cis = "true" 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /controls/service.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | service_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/Service" 4 | }) 5 | } 6 | 7 | control "service_type_forbidden" { 8 | title = "Containers should not be exposed through a forbidden service type" 9 | description = local.service_type_forbidden_desc 10 | query = query.service_type_forbidden 11 | 12 | tags = merge(local.service_common_tags, { 13 | nsa_cisa_v1 = "true" 14 | }) 15 | } 16 | 17 | control "service_default_namespace_used" { 18 | title = "Services should not use default namespace" 19 | description = "Default namespace should not be used by services. Placing objects in this namespace makes application of RBAC and other controls more difficult." 20 | query = query.service_default_namespace_used 21 | 22 | tags = merge(local.service_common_tags, { 23 | cis = "true" 24 | }) 25 | } 26 | 27 | control "service_no_tiller_service" { 28 | title = "Services should not have tiller service" 29 | description = "Services should avoid using Tiller service as it is not recommended due to security concerns." 30 | query = query.service_no_tiller_service 31 | 32 | tags = local.service_common_tags 33 | } 34 | 35 | control "service_no_tiller_deployed" { 36 | title = "Services should not have tiller (helm v2) deployed" 37 | description = "Services should not deploy tiller (helm v2) as it is not recommended due to security concerns." 38 | query = query.service_no_tiller_deployed 39 | 40 | tags = local.service_common_tags 41 | } 42 | 43 | -------------------------------------------------------------------------------- /controls/service_account.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | service_account_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | service = "Kubernetes/ServiceAccount" 4 | }) 5 | } 6 | 7 | control "service_account_token_disabled" { 8 | title = "Automatic mapping of the service account tokens should be disabled in service account" 9 | description = local.service_account_token_disabled_desc 10 | query = query.service_account_token_disabled 11 | 12 | tags = merge(local.service_account_common_tags, { 13 | nsa_cisa_v1 = "true" 14 | }) 15 | } 16 | 17 | control "service_account_default_namespace_used" { 18 | title = "ServiceAccount definition should not use default namespace" 19 | description = "Default namespace should not be used by ServiceAccount definition. Placing objects in this namespace makes application of RBAC and other controls more difficult." 20 | query = query.service_account_default_namespace_used 21 | 22 | tags = merge(local.service_account_common_tags, { 23 | cis = "true" 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Kubernetes Compliance Mod 2 | 3 | Run individual controls or full compliance benchmarks for `NSA and CISA Kubernetes Hardening Guidance` and `CIS` across all of your Kubernetes clusters. 4 | 5 | 6 | 7 | 8 | 9 | 10 | ## Documentation 11 | 12 | - **[Benchmarks and controls →](https://hub.powerpipe.io/mods/turbot/kubernetes_compliance/controls)** 13 | - **[Named queries →](https://hub.powerpipe.io/mods/turbot/kubernetes_compliance/queries)** 14 | 15 | ## Getting Started 16 | 17 | ### Installation 18 | 19 | Install Powerpipe (https://powerpipe.io/downloads), or use Brew: 20 | 21 | ```sh 22 | brew install turbot/tap/powerpipe 23 | ``` 24 | 25 | This mod also requires [Steampipe](https://steampipe.io) with the [Kubernetes plugin](https://hub.steampipe.io/plugins/turbot/kubernetes) as the data source. Install Steampipe (https://steampipe.io/downloads), or use Brew: 26 | 27 | ```sh 28 | brew install turbot/tap/steampipe 29 | steampipe plugin install kubernetes 30 | ``` 31 | 32 | Steampipe will automatically use your default Kubernetes credentials. Optionally, you can [setup multiple context connections](https://hub.steampipe.io/plugins/turbot/kubernetes#multiple-context-connections) or [customize Kubernetes credentials](https://hub.steampipe.io/plugins/turbot/kubernetes#configuring-kubernetes-cluster-credentials). 33 | 34 | Finally, install the mod: 35 | 36 | ```sh 37 | mkdir dashboards 38 | cd dashboards 39 | powerpipe mod init 40 | powerpipe mod install github.com/turbot/steampipe-mod-kubernetes-compliance 41 | ``` 42 | 43 | ### Browsing Dashboards 44 | 45 | Start Steampipe as the data source: 46 | 47 | ```sh 48 | steampipe service start 49 | ``` 50 | 51 | Start the dashboard server: 52 | 53 | ```sh 54 | powerpipe server 55 | ``` 56 | 57 | Browse and view your dashboards at **http://localhost:9033**. 58 | 59 | ### Running Checks in Your Terminal 60 | 61 | Instead of running benchmarks in a dashboard, you can also run them within your 62 | terminal with the `powerpipe benchmark` command: 63 | 64 | List available benchmarks: 65 | 66 | ```sh 67 | powerpipe benchmark list 68 | ``` 69 | 70 | Run a benchmark: 71 | 72 | ```sh 73 | powerpipe benchmark run kubernetes_compliance.benchmark.cis_v170 74 | ``` 75 | 76 | Different output formats are also available, for more information please see 77 | [Output Formats](https://powerpipe.io/docs/reference/cli/benchmark#output-formats). 78 | 79 | ### Common and Tag Dimensions 80 | 81 | The benchmark queries use common properties (like `connection_name`, `context_name`, `namespace`, `path` and `source_type`) and tags that are defined in the form of a default list of strings in the `variables.sp` file. These properties can be overwritten in several ways: 82 | 83 | It's easiest to setup your vars file, starting with the sample: 84 | 85 | ```sh 86 | cp powerpipe.ppvars.example powerpipe.ppvars 87 | vi powerpipe.ppvars 88 | ``` 89 | 90 | Alternatively you can pass variables on the command line: 91 | 92 | ```sh 93 | powerpipe benchmark run kubernetes_compliance.benchmark.cis_v170 --var 'tag_dimensions=["Environment", "Owner"]' 94 | ``` 95 | 96 | Or through environment variables: 97 | 98 | ```sh 99 | export PP_VAR_common_dimensions='["connection_name", "context_name", "namespace", "path", "source_type"]' 100 | export PP_VAR_tag_dimensions='["Environment", "Owner"]' 101 | powerpipe benchmark run kubernetes_compliance.benchmark.cis_v170 102 | ``` 103 | 104 | ## Open Source & Contributing 105 | 106 | This repository is published under the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0). Please see our [code of conduct](https://github.com/turbot/.github/blob/main/CODE_OF_CONDUCT.md). We look forward to collaborating with you! 107 | 108 | [Steampipe](https://steampipe.io) and [Powerpipe](https://powerpipe.io) are products produced from this open source software, exclusively by [Turbot HQ, Inc](https://turbot.com). They are distributed under our commercial terms. Others are allowed to make their own distribution of the software, but cannot use any of the Turbot trademarks, cloud services, etc. You can learn more in our [Open Source FAQ](https://turbot.com/open-source). 109 | 110 | ## Get Involved 111 | 112 | **[Join #powerpipe on Slack →](https://turbot.com/community/join)** 113 | 114 | Want to help but don't know where to start? Pick up one of the `help wanted` issues: 115 | 116 | - [Powerpipe](https://github.com/turbot/powerpipe/labels/help%20wanted) 117 | - [Kubernetes Compliance Mod](https://github.com/turbot/steampipe-mod-kubernetes-compliance/labels/help%20wanted) 118 | -------------------------------------------------------------------------------- /docs/kubernetes_cis_v120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbot/steampipe-mod-kubernetes-compliance/eb10e73bd24c833a3ba65cb77a172cea1a55e299/docs/kubernetes_cis_v120.png -------------------------------------------------------------------------------- /docs/kubernetes_compliance_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbot/steampipe-mod-kubernetes-compliance/eb10e73bd24c833a3ba65cb77a172cea1a55e299/docs/kubernetes_compliance_dashboard.png -------------------------------------------------------------------------------- /docs/kubernetes_compliance_mod_console_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbot/steampipe-mod-kubernetes-compliance/eb10e73bd24c833a3ba65cb77a172cea1a55e299/docs/kubernetes_compliance_mod_console_output.png -------------------------------------------------------------------------------- /docs/kubernetes_nsa_csa_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbot/steampipe-mod-kubernetes-compliance/eb10e73bd24c833a3ba65cb77a172cea1a55e299/docs/kubernetes_nsa_csa_v1.png -------------------------------------------------------------------------------- /mod.pp: -------------------------------------------------------------------------------- 1 | mod "kubernetes_compliance" { 2 | # Hub metadata 3 | title = "Kubernetes Compliance" 4 | description = "Run individual controls or full compliance benchmarks for CIS, NSA CISA Kubernetes Hardening Guidance across all of your Kubernetes clusters using Powerpipe and Steampipe." 5 | color = "#0089D6" 6 | documentation = file("./docs/index.md") 7 | icon = "/images/mods/turbot/kubernetes-compliance.svg" 8 | categories = ["kubernetes", "compliance", "iac", "software development", "security"] 9 | 10 | opengraph { 11 | title = "Powerpipe Mod for Kubernetes Compliance" 12 | description = "Run individual controls or full compliance benchmarks for CIS, NSA CISA Kubernetes Hardening Guidance across all of your Kubernetes clusters using Powerpipe and Steampipe." 13 | image = "/images/mods/turbot/kubernetes-compliance-social-graphic.png" 14 | } 15 | requires { 16 | plugin "kubernetes" { 17 | min_version = "0.23.0" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /nsa_cisa_v1/docs/nsa_cisa_v1_overview.md: -------------------------------------------------------------------------------- 1 | To get the latest version of the official guide, please visit [here](https://media.defense.gov/2022/Aug/29/2003066362/-1/-1/0/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF). 2 | 3 | ## Overview 4 | 5 | Kubernetes is an open-source system that automates the deployment, scaling, and management of applications run in containers, and is often hosted in a cloud environment. The hardening guidance detailed in this report is designed to help organizations handle associated risks and enjoy the benefits of using this technology. 6 | 7 | ## Control Categories 8 | 9 | These are the available categories for Kubernetes Compliance controls. The category for a control reflects the security function that the control applies to. 10 | 11 | ### Kubernetes Pod Security 12 | 13 | A Pod Security Policy is a cluster-level resource that controls security sensitive aspects of the pod specification. The PodSecurityPolicy objects define a set of conditions that a pod must run with in order to be accepted into the system, as well as defaults for the related fields. 14 | 15 | ### Network Separation and Hardening 16 | 17 | Cluster networking is a central concept of Kubernetes. Communication between containers, Pods, services, and external services must be taken into consideration. By default, there are few network policies in place to separate resources and prevent lateral movement or escalation if a cluster is compromised. Resource separation and encryption can be an effective way to limit a cyber actor’s movement and escalation within a cluster. 18 | -------------------------------------------------------------------------------- /nsa_cisa_v1/nsa_cisa_v1.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | nsa_cisa_v1_common_tags = merge(local.kubernetes_compliance_common_tags, { 3 | nsa_cisa_v1 = "true" 4 | }) 5 | } 6 | 7 | benchmark "nsa_cisa_v1" { 8 | title = "NSA and CISA Kubernetes Hardening Guidance v1.0" 9 | documentation = file("./nsa_cisa_v1/docs/nsa_cisa_v1_overview.md") 10 | children = [ 11 | benchmark.nsa_cisa_v1_pod_security, 12 | benchmark.nsa_cisa_v1_network_hardening 13 | ] 14 | 15 | tags = merge(local.nsa_cisa_v1_common_tags, { 16 | type = "Benchmark" 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /nsa_cisa_v1/nsa_cisa_v1_network_hardening.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | nsa_cisa_v1_network_hardening_common_tags = merge(local.nsa_cisa_v1_common_tags, { 3 | }) 4 | } 5 | 6 | benchmark "nsa_cisa_v1_network_hardening" { 7 | title = "Network Separation and Hardening" 8 | children = [ 9 | benchmark.nsa_cisa_v1_network_hardening_cpu_limit, 10 | benchmark.nsa_cisa_v1_network_hardening_cpu_request, 11 | benchmark.nsa_cisa_v1_network_hardening_api_serve_on_secure_port_endpoint, 12 | benchmark.nsa_cisa_v1_network_hardening_memory_limit, 13 | benchmark.nsa_cisa_v1_network_hardening_memory_request, 14 | benchmark.nsa_cisa_v1_network_hardening_default_deny_network_policy 15 | ] 16 | 17 | tags = merge(local.nsa_cisa_v1_network_hardening_common_tags, { 18 | type = "Benchmark" 19 | }) 20 | } 21 | 22 | benchmark "nsa_cisa_v1_network_hardening_cpu_limit" { 23 | title = "Containers should have a CPU limit" 24 | description = "Containers should have CPU limit which restricts the container to use no more than a given amount of CPU." 25 | children = [ 26 | control.cronjob_cpu_limit, 27 | control.daemonset_cpu_limit, 28 | control.deployment_cpu_limit, 29 | control.job_cpu_limit, 30 | control.namespace_limit_range_default_cpu_limit, 31 | control.namespace_resource_quota_cpu_limit, 32 | control.replicaset_cpu_limit, 33 | control.replication_controller_cpu_limit, 34 | control.statefulset_cpu_limit 35 | ] 36 | 37 | tags = merge(local.nsa_cisa_v1_network_hardening_common_tags, { 38 | type = "Benchmark" 39 | }) 40 | } 41 | 42 | benchmark "nsa_cisa_v1_network_hardening_cpu_request" { 43 | title = "Containers should have a CPU request" 44 | description = "Containers should have CPU request. If required Kubernetes will make sure your containers get the CPU they requested." 45 | children = [ 46 | control.cronjob_cpu_request, 47 | control.daemonset_cpu_request, 48 | control.deployment_cpu_request, 49 | control.job_cpu_request, 50 | control.namespace_limit_range_default_cpu_request, 51 | control.namespace_resource_quota_cpu_request, 52 | control.replicaset_cpu_request, 53 | control.replication_controller_cpu_request, 54 | control.statefulset_cpu_request 55 | ] 56 | 57 | tags = merge(local.nsa_cisa_v1_network_hardening_common_tags, { 58 | type = "Benchmark" 59 | }) 60 | } 61 | 62 | benchmark "nsa_cisa_v1_network_hardening_api_serve_on_secure_port_endpoint" { 63 | title = "Kubernetes API should serve on secure port" 64 | description = "Kubernetes API should serve on port 443 or port 6443, protected by TLS. Once TLS is established, the HTTP request moves to the authentication step. If the request cannot be authenticated, it is rejected with HTTP status code 401." 65 | children = [ 66 | control.endpoint_api_serve_on_secure_port, 67 | ] 68 | 69 | tags = merge(local.nsa_cisa_v1_network_hardening_common_tags, { 70 | type = "Benchmark" 71 | }) 72 | } 73 | 74 | benchmark "nsa_cisa_v1_network_hardening_memory_limit" { 75 | title = "Containers should have a memory limit" 76 | description = "Containers should have a memory limit which restricts the container to use no more than a given amount of user or system memory." 77 | children = [ 78 | control.cronjob_memory_limit, 79 | control.daemonset_memory_limit, 80 | control.deployment_memory_limit, 81 | control.job_memory_limit, 82 | control.namespace_limit_range_default_memory_limit, 83 | control.namespace_resource_quota_memory_limit, 84 | control.replicaset_memory_limit, 85 | control.replication_controller_memory_limit, 86 | control.statefulset_memory_limit 87 | ] 88 | 89 | tags = merge(local.nsa_cisa_v1_network_hardening_common_tags, { 90 | type = "Benchmark" 91 | }) 92 | } 93 | 94 | benchmark "nsa_cisa_v1_network_hardening_memory_request" { 95 | title = "Containers should have a memory request" 96 | description = "Containers should have memory request. If required Kubernetes will make sure your containers get the memory they requested." 97 | children = [ 98 | control.cronjob_memory_request, 99 | control.daemonset_memory_request, 100 | control.deployment_memory_request, 101 | control.job_memory_request, 102 | control.namespace_limit_range_default_memory_request, 103 | control.namespace_resource_quota_memory_request, 104 | control.replicaset_memory_request, 105 | control.replication_controller_memory_request, 106 | control.statefulset_memory_request 107 | ] 108 | 109 | tags = merge(local.nsa_cisa_v1_network_hardening_common_tags, { 110 | type = "Benchmark" 111 | }) 112 | } 113 | 114 | benchmark "nsa_cisa_v1_network_hardening_default_deny_network_policy" { 115 | title = "Network policy should have a default policy to deny all ingress and egress traffic" 116 | description = "Administrators should use a default policy selecting all Pods to deny all ingress and egress traffic and ensure any unselected Pods are isolated. Additional policies could then relax these restrictions for permissible connections." 117 | children = [ 118 | control.network_policy_default_deny_egress, 119 | control.network_policy_default_deny_ingress, 120 | control.network_policy_default_dont_allow_egress, 121 | control.network_policy_default_dont_allow_ingress 122 | ] 123 | 124 | tags = merge(local.nsa_cisa_v1_network_hardening_common_tags, { 125 | type = "Benchmark" 126 | }) 127 | } 128 | -------------------------------------------------------------------------------- /nsa_cisa_v1/nsa_cisa_v1_pod_security.pp: -------------------------------------------------------------------------------- 1 | locals { 2 | nsa_cisa_v1_pod_security_common_tags = merge(local.nsa_cisa_v1_common_tags, { 3 | }) 4 | } 5 | 6 | benchmark "nsa_cisa_v1_pod_security" { 7 | title = "Kubernetes Pod Security" 8 | children = [ 9 | benchmark.nsa_cisa_v1_pod_security_container_disallow_host_path, 10 | benchmark.nsa_cisa_v1_pod_security_container_privilege_disabled, 11 | benchmark.nsa_cisa_v1_pod_security_container_privilege_escalation_disabled, 12 | benchmark.nsa_cisa_v1_pod_security_container_security_service_hardening, 13 | benchmark.nsa_cisa_v1_pod_security_host_network_access_disabled, 14 | benchmark.nsa_cisa_v1_pod_security_hostpid_hostipc_sharing_disabled, 15 | benchmark.nsa_cisa_v1_pod_security_immutable_container_filesystem, 16 | benchmark.nsa_cisa_v1_pod_security_non_root_container, 17 | benchmark.nsa_cisa_v1_pod_security_service_account_token_disabled 18 | ] 19 | 20 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 21 | type = "Benchmark" 22 | }) 23 | } 24 | 25 | benchmark "nsa_cisa_v1_pod_security_container_disallow_host_path" { 26 | title = "Containers should not use hostPath mounts" 27 | description = "Containers should not able to access any specific paths of the host file system. There are many ways a container with unrestricted access to the host filesystem can escalate privileges, including reading data from other containers, and abusing the credentials of system services, such as Kubelet." 28 | children = [ 29 | control.pod_security_policy_allowed_host_path, 30 | control.pod_volume_host_path 31 | ] 32 | 33 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 34 | type = "Benchmark" 35 | }) 36 | } 37 | 38 | benchmark "nsa_cisa_v1_pod_security_container_privilege_disabled" { 39 | title = "Containers should not have privileged access" 40 | description = "Containers should not have privileged access. To prevent security issues, it is recommended that you do not run privileged containers in your environment. Instead, provide granular permissions and capabilities to the container environment. Giving containers full access to the host can create security flaws in your production environment." 41 | children = [ 42 | control.cronjob_container_privilege_disabled, 43 | control.daemonset_container_privilege_disabled, 44 | control.deployment_container_privilege_disabled, 45 | control.job_container_privilege_disabled, 46 | control.pod_container_privilege_disabled, 47 | control.pod_security_policy_container_privilege_disabled, 48 | control.replicaset_container_privilege_disabled, 49 | control.replication_controller_container_privilege_disabled, 50 | control.statefulset_container_privilege_disabled 51 | ] 52 | 53 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 54 | type = "Benchmark" 55 | }) 56 | } 57 | 58 | benchmark "nsa_cisa_v1_pod_security_container_privilege_escalation_disabled" { 59 | title = "Containers should not allow privilege escalation" 60 | description = "Containers should not allow privilege escalation. A container running with the `allowPrivilegeEscalation` flag set to true may have processes that can gain more privileges than their parent." 61 | children = [ 62 | control.cronjob_container_privilege_escalation_disabled, 63 | control.daemonset_container_privilege_escalation_disabled, 64 | control.deployment_container_privilege_escalation_disabled, 65 | control.job_container_privilege_escalation_disabled, 66 | control.pod_container_privilege_escalation_disabled, 67 | control.pod_security_policy_container_privilege_escalation_disabled, 68 | control.replicaset_container_privilege_escalation_disabled, 69 | control.replication_controller_container_privilege_escalation_disabled, 70 | control.statefulset_container_privilege_escalation_disabled 71 | ] 72 | 73 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 74 | type = "Benchmark" 75 | }) 76 | } 77 | 78 | benchmark "nsa_cisa_v1_pod_security_container_security_service_hardening" { 79 | title = "Containerized applications should use security services" 80 | description = "Linux provides several out-of-the-box security modules. Some of the popular ones are SELinux, AppArmor and Seccomp. Containerized applications should use these security services." 81 | children = [ 82 | control.pod_security_policy_security_services_hardening, 83 | ] 84 | 85 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 86 | type = "Benchmark" 87 | }) 88 | } 89 | 90 | benchmark "nsa_cisa_v1_pod_security_host_network_access_disabled" { 91 | title = "Containers should not run with host network access" 92 | description = "Pod host network controls whether the Pod may use the node network namespace. Doing so gives the Pod access to the loopback device, services listening on localhost, and could be used to snoop on network activity of other Pods on the same node." 93 | children = [ 94 | control.cronjob_host_network_access_disabled, 95 | control.daemonset_host_network_access_disabled, 96 | control.deployment_host_network_access_disabled, 97 | control.job_host_network_access_disabled, 98 | control.pod_host_network_access_disabled, 99 | control.pod_security_policy_host_network_access_disabled, 100 | control.replicaset_host_network_access_disabled, 101 | control.replication_controller_host_network_access_disabled, 102 | control.statefulset_host_network_access_disabled 103 | ] 104 | 105 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 106 | type = "Benchmark" 107 | }) 108 | } 109 | 110 | benchmark "nsa_cisa_v1_pod_security_hostpid_hostipc_sharing_disabled" { 111 | title = "Containers should not share the host process namespace" 112 | description = "Containers should not share the host process PID or IPC namespace. Sharing the host’s process namespace allows the container to see all of the processes on the host system. This reduces the benefit of process level isolation between the host and the containers. Under these circumstances a malicious user who has access to a container could get access to processes on the host itself, manipulate them, and even be able to kill them." 113 | children = [ 114 | control.cronjob_hostpid_hostipc_sharing_disabled, 115 | control.daemonset_hostpid_hostipc_sharing_disabled, 116 | control.deployment_hostpid_hostipc_sharing_disabled, 117 | control.job_hostpid_hostipc_sharing_disabled, 118 | control.pod_hostpid_hostipc_sharing_disabled, 119 | control.pod_security_policy_hostpid_hostipc_sharing_disabled, 120 | control.replicaset_hostpid_hostipc_sharing_disabled, 121 | control.replication_controller_hostpid_hostipc_sharing_disabled, 122 | control.statefulset_hostpid_hostipc_sharing_disabled 123 | ] 124 | 125 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 126 | type = "Benchmark" 127 | }) 128 | } 129 | 130 | benchmark "nsa_cisa_v1_pod_security_immutable_container_filesystem" { 131 | title = "Containers should run with a read only root file system" 132 | description = "Containers should always run with a read only root file system. Using an immutable root filesystem and a verified boot mechanism prevents against attackers from owning the machine through permanent local changes. An immutable root filesystem can also prevent malicious binaries from writing to the host system." 133 | children = [ 134 | control.cronjob_immutable_container_filesystem, 135 | control.daemonset_immutable_container_filesystem, 136 | control.deployment_immutable_container_filesystem, 137 | control.job_immutable_container_filesystem, 138 | control.pod_immutable_container_filesystem, 139 | control.pod_security_policy_immutable_container_filesystem, 140 | control.replicaset_immutable_container_filesystem, 141 | control.replication_controller_immutable_container_filesystem, 142 | control.statefulset_immutable_container_filesystem 143 | ] 144 | 145 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 146 | type = "Benchmark" 147 | }) 148 | } 149 | 150 | benchmark "nsa_cisa_v1_pod_security_non_root_container" { 151 | title = "Containers should not run with root privileges" 152 | description = "Containers should not be deployed with root privileges. By default, many container services run as the privileged root user, and applications execute inside the container as root despite not requiring privileged execution. Preventing root execution by using non-root containers or a rootless container engine limits the impact of a container compromise." 153 | children = [ 154 | control.cronjob_non_root_container, 155 | control.daemonset_non_root_container, 156 | control.deployment_non_root_container, 157 | control.job_non_root_container, 158 | control.pod_non_root_container, 159 | control.pod_security_policy_non_root_container, 160 | control.replicaset_non_root_container, 161 | control.replication_controller_non_root_container, 162 | control.statefulset_non_root_container 163 | ] 164 | 165 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 166 | type = "Benchmark" 167 | }) 168 | } 169 | 170 | benchmark "nsa_cisa_v1_pod_security_service_account_token_disabled" { 171 | title = "Automatic mapping of the service account tokens should be disabled" 172 | description = local.service_account_token_disabled_desc 173 | children = [ 174 | control.pod_service_account_token_disabled, 175 | control.service_account_token_disabled 176 | ] 177 | 178 | tags = merge(local.nsa_cisa_v1_pod_security_common_tags, { 179 | type = "Benchmark" 180 | }) 181 | } 182 | -------------------------------------------------------------------------------- /powerpipe.ppvars.example: -------------------------------------------------------------------------------- 1 | # Dimensions 2 | # Possible values for common_dimensions include "connection_name", "context_name", "namespace", "path" and "source_type" 3 | common_dimensions = [ "context_name", "namespace", "path", "source_type" ] 4 | tag_dimensions = [] 5 | -------------------------------------------------------------------------------- /query/cluster_role_binding.pp: -------------------------------------------------------------------------------- 1 | query "cluster_role_binding_default_service_account_binding_not_active" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when (subject ->> 'kind') = 'ServiceAccount' and (subject ->> 'name') = 'default' then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when (subject ->> 'kind' = 'ServiceAccount') and (subject ->> 'name' = 'default') then name || ' default service accounts active.' 11 | else name || ' default service accounts not active.' 12 | end as reason, 13 | name as cluster_role_binding_name 14 | ${local.tag_dimensions_sql} 15 | ${local.common_dimensions_non_namespace_sql} 16 | from 17 | kubernetes_cluster_role_binding, 18 | jsonb_array_elements(subjects) as subject; 19 | EOQ 20 | } 21 | -------------------------------------------------------------------------------- /query/config_map.pp: -------------------------------------------------------------------------------- 1 | query "config_map_default_namespace_used" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when namespace = 'default' then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when namespace = 'default' then name || ' uses default namespace.' 11 | else name || ' not using the default namespace.' 12 | end as reason 13 | ${local.tag_dimensions_sql} 14 | ${local.common_dimensions_sql} 15 | from 16 | kubernetes_config_map; 17 | EOQ 18 | } 19 | 20 | -------------------------------------------------------------------------------- /query/endpoint.pp: -------------------------------------------------------------------------------- 1 | query "endpoint_api_serve_on_secure_port" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when p ->> 'name' = 'https' and (p ->> 'port' = '443' or p ->> 'port' = '6443') then 'ok' 7 | else 'alarm' 8 | end as status, 9 | case 10 | when p ->> 'name' = 'https' and (p ->> 'port' = '443' or p ->> 'port' = '6443') then name || ' Kubernetes API serving on secure port.' 11 | else name || ' Kubernetes API not serving on secure port.' 12 | end as reason, 13 | name as endpoint_name 14 | ${local.tag_dimensions_sql} 15 | ${local.common_dimensions_sql} 16 | from 17 | kubernetes_endpoint, 18 | jsonb_array_elements(subsets) as s, 19 | jsonb_array_elements(s -> 'ports') as p 20 | where name = 'kubernetes'; 21 | EOQ 22 | } 23 | 24 | -------------------------------------------------------------------------------- /query/ingress.pp: -------------------------------------------------------------------------------- 1 | query "ingress_default_namespace_used" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when namespace = 'default' then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when namespace = 'default' then name || ' uses default namespace.' 11 | else name || ' not using the default namespace.' 12 | end as reason, 13 | name as ingress_name 14 | ${local.tag_dimensions_sql} 15 | ${local.common_dimensions_sql} 16 | from 17 | kubernetes_ingress; 18 | EOQ 19 | } 20 | 21 | query "ingress_nginx_annotations_snippets_alias_not_used" { 22 | sql = <<-EOQ 23 | select 24 | coalesce(uid, concat(path, ':', start_line)) as resource, 25 | case when a.key like '%snippet%' and a.value like '%alias%' then 'alarm' 26 | else 'ok' 27 | end as status, 28 | case 29 | when a.key like '%snippet%' and a.value like '%alias%' then a.key || ' annotation snippet contains alias statements.' 30 | else a.key || ' annotation snippet not containing alias statements.' 31 | end as reason, 32 | name as ingress_name 33 | ${local.tag_dimensions_sql} 34 | ${local.common_dimensions_sql} 35 | from 36 | kubernetes_ingress, 37 | jsonb_each_text(annotations) as a; 38 | EOQ 39 | } 40 | 41 | query "ingress_nginx_annotations_all_snippets_not_used" { 42 | sql = <<-EOQ 43 | select 44 | coalesce(uid, concat(path, ':', start_line)) as resource, 45 | case when a.key like '%snippet%' then 'alarm' 46 | else 'ok' 47 | end as status, 48 | case 49 | when a.key like '%snippet%' then a.key || ' annotation snippet used.' 50 | else a.key || ' annotation snippet not used.' 51 | end as reason, 52 | name as ingress_name 53 | ${local.tag_dimensions_sql} 54 | ${local.common_dimensions_sql} 55 | from 56 | kubernetes_ingress, 57 | jsonb_each_text(annotations) as a; 58 | EOQ 59 | } 60 | 61 | query "ingress_nginx_annotations_snippets_lua_code_not_used" { 62 | sql = <<-EOQ 63 | select 64 | coalesce(uid, concat(path, ':', start_line)) as resource, 65 | case when a.key like '%snippet%' and a.value ~ '(lua_|_lua|_lua_|kubernetes\.io)' then 'alarm' 66 | else 'ok' 67 | end as status, 68 | case 69 | when a.key like '%snippet%' and a.value ~ '(lua_|_lua|_lua_|kubernetes\.io)' then a.key || ' annotation snippet contains lua code execution.' 70 | else a.key || ' annotation snippet does not contain lua code execution.' 71 | end as reason, 72 | name as ingress_name 73 | ${local.tag_dimensions_sql} 74 | ${local.common_dimensions_sql} 75 | from 76 | kubernetes_ingress, 77 | jsonb_each_text(annotations) as a; 78 | EOQ 79 | } -------------------------------------------------------------------------------- /query/namespace.pp: -------------------------------------------------------------------------------- 1 | query "namespace_limit_range_default_memory_limit" { 2 | sql = <<-EOQ 3 | with default_limit_range as ( 4 | select 5 | namespace, 6 | l -> 'default' as default_limit, 7 | l -> 'defaultRequest' as default_request 8 | from 9 | kubernetes_limit_range, 10 | jsonb_array_elements(spec_limits) as l 11 | ) 12 | select 13 | coalesce(n.uid, concat(n.path, ':', n.start_line)) as resource, 14 | case 15 | when default_limit ->> 'memory' is null then 'alarm' 16 | else 'ok' 17 | end as status, 18 | case 19 | when default_limit ->> 'memory' is null then n.name || ' do not have LimitRange default memory limit.' 20 | else n.name || ' has LimitRange default memory limit.' 21 | end as reason 22 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 23 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 24 | from 25 | kubernetes_namespace n 26 | left join default_limit_range r 27 | on n.name = r.namespace; 28 | EOQ 29 | } 30 | 31 | query "namespace_resource_quota_memory_limit" { 32 | sql = <<-EOQ 33 | select 34 | distinct(coalesce(n.uid, concat(n.path, ':', n.start_line))) as resource, 35 | case 36 | when q.spec_hard -> 'limits.memory' is null then 'alarm' 37 | else 'ok' 38 | end as status, 39 | case 40 | when q.spec_hard -> 'limits.memory' is null then n.name || ' do not have ResourceQuota for memory limit.' 41 | else n.name || ' have ResourceQuota for memory limit.' 42 | end as reason 43 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 44 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 45 | from 46 | kubernetes_namespace n 47 | left join kubernetes_resource_quota q 48 | on n.name = q.namespace; 49 | EOQ 50 | } 51 | 52 | query "namespace_resource_quota_cpu_limit" { 53 | sql = <<-EOQ 54 | select 55 | distinct(coalesce(n.uid, concat(n.path, ':', n.start_line))) as resource, 56 | case 57 | when q.spec_hard -> 'limits.cpu' is null then 'alarm' 58 | else 'ok' 59 | end as status, 60 | case 61 | when q.spec_hard -> 'limits.cpu' is null then n.name || ' do not have ResourceQuota for CPU limit.' 62 | else n.name || ' have ResourceQuota for CPU limit.' 63 | end as reason 64 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 65 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 66 | from 67 | kubernetes_namespace n 68 | left join kubernetes_resource_quota q 69 | on n.name = q.namespace; 70 | EOQ 71 | } 72 | 73 | query "namespace_limit_range_default_memory_request" { 74 | sql = <<-EOQ 75 | with default_limit_range as ( 76 | select 77 | namespace, 78 | l -> 'default' as default_limit, 79 | l -> 'defaultRequest' as default_request 80 | from 81 | kubernetes_limit_range, 82 | jsonb_array_elements(spec_limits) as l 83 | ) 84 | select 85 | coalesce(n.uid, concat(n.path, ':', n.start_line)) as resource, 86 | case 87 | when default_request ->> 'memory' is null then 'alarm' 88 | else 'ok' 89 | end as status, 90 | case 91 | when default_request ->> 'memory' is null then n.name || ' do not have LimitRange default memory request.' 92 | else n.name || ' has LimitRange default memory request.' 93 | end as reason 94 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 95 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 96 | from 97 | kubernetes_namespace n 98 | left join default_limit_range r 99 | on n.name = r.namespace; 100 | EOQ 101 | } 102 | 103 | query "namespace_limit_range_default_cpu_request" { 104 | sql = <<-EOQ 105 | with default_limit_range as ( 106 | select 107 | namespace, 108 | l -> 'default' as default_limit, 109 | l -> 'defaultRequest' as default_request 110 | from 111 | kubernetes_limit_range, 112 | jsonb_array_elements(spec_limits) as l 113 | ) 114 | select 115 | coalesce(n.uid, concat(n.path, ':', n.start_line)) as resource, 116 | case 117 | when default_request ->> 'cpu' is null then 'alarm' 118 | else 'ok' 119 | end as status, 120 | case 121 | when default_request ->> 'cpu' is null then n.name || ' do not have LimitRange default CPU request.' 122 | else n.name || ' has LimitRange default CPU request.' 123 | end as reason 124 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 125 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 126 | from 127 | kubernetes_namespace n 128 | left join default_limit_range r 129 | on n.name = r.namespace; 130 | EOQ 131 | } 132 | 133 | query "namespace_resource_quota_memory_request" { 134 | sql = <<-EOQ 135 | select 136 | distinct(coalesce(n.uid, concat(n.path, ':', n.start_line))) as resource, 137 | case 138 | when q.spec_hard -> 'requests.memory' is null and q.spec_hard -> 'memory' is null then 'alarm' 139 | else 'ok' 140 | end as status, 141 | case 142 | when q.spec_hard -> 'requests.memory' is null and q.spec_hard -> 'memory' is null then n.name || ' do not have ResourceQuota for memory request.' 143 | else n.name || ' have ResourceQuota for memory request.' 144 | end as reason 145 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 146 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 147 | from 148 | kubernetes_namespace n 149 | left join kubernetes_resource_quota q 150 | on n.name = q.namespace; 151 | EOQ 152 | } 153 | 154 | query "namespace_limit_range_default_cpu_limit" { 155 | sql = <<-EOQ 156 | with default_limit_range as ( 157 | select 158 | namespace, 159 | l -> 'default' as default_limit, 160 | l -> 'defaultRequest' as default_request 161 | from 162 | kubernetes_limit_range, 163 | jsonb_array_elements(spec_limits) as l 164 | ) 165 | select 166 | coalesce(n.uid, concat(n.path, ':', n.start_line)) as resource, 167 | case 168 | when default_limit ->> 'cpu' is null then 'alarm' 169 | else 'ok' 170 | end as status, 171 | case 172 | when default_limit ->> 'cpu' is null then n.name || ' do not have LimitRange default CPU limit.' 173 | else n.name || ' has LimitRange default CPU limit.' 174 | end as reason 175 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 176 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 177 | from 178 | kubernetes_namespace n 179 | left join default_limit_range r 180 | on n.name = r.namespace; 181 | EOQ 182 | } 183 | 184 | query "namespace_resource_quota_cpu_request" { 185 | sql = <<-EOQ 186 | select 187 | distinct(coalesce(n.uid, concat(n.path, ':', n.start_line))) as resource, 188 | case 189 | when q.spec_hard -> 'requests.cpu' is null and q.spec_hard -> 'cpu' is null then 'alarm' 190 | else 'ok' 191 | end as status, 192 | case 193 | when q.spec_hard -> 'requests.cpu' is null and q.spec_hard -> 'cpu' is null then n.name || ' do not have ResourceQuota for CPU request.' 194 | else n.name || ' have ResourceQuota for CPU request.' 195 | end as reason 196 | ${replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "n.")} 197 | ${replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "n.")} 198 | from 199 | kubernetes_namespace n 200 | left join kubernetes_resource_quota q 201 | on n.name = q.namespace; 202 | EOQ 203 | } 204 | 205 | -------------------------------------------------------------------------------- /query/network_policy.pp: -------------------------------------------------------------------------------- 1 | query "network_policy_default_dont_allow_ingress" { 2 | sql = <<-EOQ 3 | with default_allows_all_ingress_count as ( 4 | select 5 | namespace, 6 | name, 7 | uid, 8 | context_name, 9 | _ctx, 10 | tags, 11 | p.path, 12 | p.start_line, 13 | p.end_line, 14 | p.source_type, 15 | -- Get the count of default allow Ingress policy 16 | count(*) filter (where rule = '{}') as num_allow_all_rules 17 | from 18 | kubernetes_network_policy p 19 | left join jsonb_array_elements(ingress) as rule on true 20 | group by 21 | namespace, 22 | name, 23 | uid, 24 | context_name, 25 | rule, 26 | policy_types, 27 | tags, 28 | _ctx, 29 | p.path, 30 | p.start_line, 31 | p.end_line, 32 | p.source_type 33 | ) 34 | select 35 | coalesce(uid, concat(p.path, ':', p.start_line)) as resource, 36 | case 37 | when num_allow_all_rules > 0 then 'alarm' 38 | else 'ok' 39 | end as status, 40 | case 41 | when num_allow_all_rules > 0 then name || ' allows all ingress' 42 | else name || ' does not allow all ingress' 43 | end as reason, 44 | name as network_policy_name 45 | ${local.tag_dimensions_sql} 46 | ${local.common_dimensions_sql} 47 | from 48 | default_allows_all_ingress_count p; 49 | EOQ 50 | } 51 | 52 | query "network_policy_default_dont_allow_egress" { 53 | sql = <<-EOQ 54 | with default_allows_all_egress_count as ( 55 | select 56 | namespace, 57 | name, 58 | uid, 59 | context_name, 60 | tags, 61 | _ctx, 62 | p.path, 63 | p.start_line, 64 | p.end_line, 65 | p.source_type, 66 | -- Get the count of default allow Egress policy 67 | count(*) filter (where rule = '{}') as num_allow_all_rules 68 | from 69 | kubernetes_network_policy p 70 | left join jsonb_array_elements(egress) as rule on true 71 | group by 72 | namespace, 73 | name, 74 | uid, 75 | context_name, 76 | rule, 77 | policy_types, 78 | tags, 79 | _ctx, 80 | p.path, 81 | p.start_line, 82 | p.end_line, 83 | p.source_type 84 | ) 85 | select 86 | coalesce(uid, concat(path, ':', start_line)) as resource, 87 | case 88 | when num_allow_all_rules > 0 then 'alarm' 89 | else 'ok' 90 | end as status, 91 | case 92 | when num_allow_all_rules > 0 then name || ' allows all egress' 93 | else name || ' does not allow all egress' 94 | end as reason, 95 | name as network_policy_name 96 | ${local.tag_dimensions_sql} 97 | ${local.common_dimensions_sql} 98 | from 99 | default_allows_all_egress_count; 100 | EOQ 101 | } 102 | 103 | query "network_policy_default_deny_ingress" { 104 | sql = <<-EOQ 105 | with default_deny_ingress_count as ( 106 | select 107 | ns.uid, 108 | ns.name as namespace, 109 | ns.context_name, 110 | count(pol.*) as num_netpol, 111 | ns.tags, 112 | ns._ctx, 113 | ns.path, 114 | ns.start_line, 115 | ns.end_line, 116 | ns.source_type, 117 | -- Get the count of default deny Ingress policy assoicated to each namespace 118 | count(*) filter (where policy_types @> '["Ingress"]' and pod_selector = '{}' and ingress is null) AS num_default_deny 119 | from kubernetes_namespace as ns 120 | left join kubernetes_network_policy as pol on pol.namespace = ns.name and pol.source_type = ns.source_type 121 | group by 122 | ns.name, 123 | ns.uid, 124 | ns.context_name, 125 | ns.tags, 126 | ns._ctx, 127 | ns.path, 128 | ns.start_line, 129 | ns.end_line, 130 | ns.source_type 131 | ) 132 | select 133 | coalesce(uid, concat(path, ':', start_line)) as resource, 134 | case 135 | when num_default_deny > 0 then 'ok' 136 | else 'alarm' 137 | end as status, 138 | namespace || ' has ' || num_default_deny || ' default deny ingress policies.' as reason 139 | ${local.tag_dimensions_sql} 140 | ${local.common_dimensions_sql} 141 | from 142 | default_deny_ingress_count; 143 | EOQ 144 | } 145 | 146 | query "network_policy_default_deny_egress" { 147 | sql = <<-EOQ 148 | with default_deny_egress_count as ( 149 | select 150 | ns.uid, 151 | ns.name as namespace, 152 | ns.context_name, 153 | ns._ctx, 154 | count(pol.*) as num_netpol, 155 | ns.tags, 156 | ns.path, 157 | ns.start_line, 158 | ns.end_line, 159 | ns.source_type, 160 | -- Get the count of default deny Egress policy assoicated to each namespace 161 | COUNT(*) FILTER (where policy_types @> '["Egress"]' and pod_selector = '{}' and egress is null) AS num_default_deny 162 | from kubernetes_namespace as ns 163 | left join kubernetes_network_policy as pol on pol.namespace = ns.name and pol.source_type = ns.source_type 164 | group by 165 | ns.name, 166 | ns.uid, 167 | ns.context_name, 168 | ns.tags, 169 | ns._ctx, 170 | ns.path, 171 | ns.start_line, 172 | ns.end_line, 173 | ns.source_type 174 | ) 175 | select 176 | coalesce(uid, concat(path, ':', start_line)) as resource, 177 | case 178 | when num_default_deny > 0 then 'ok' 179 | else 'alarm' 180 | end as status, 181 | namespace || ' has ' || num_default_deny || ' default deny egress policies.' as reason 182 | ${local.tag_dimensions_sql} 183 | ${local.common_dimensions_sql} 184 | from 185 | default_deny_egress_count; 186 | EOQ 187 | } 188 | 189 | -------------------------------------------------------------------------------- /query/pod_security_policy.pp: -------------------------------------------------------------------------------- 1 | query "pod_security_policy_host_network_access_disabled" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when host_network then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when host_network then 'Pod security policy ' || name || ' pods can use the host network.' 11 | else 'Pod security policy ' || name || ' pods cannot use the host network.' 12 | end as reason 13 | ${local.tag_dimensions_sql} 14 | ${local.common_dimensions_non_namespace_sql} 15 | from 16 | kubernetes_pod_security_policy; 17 | EOQ 18 | } 19 | 20 | query "pod_security_policy_allowed_host_path" { 21 | sql = <<-EOQ 22 | select 23 | coalesce(uid, concat(path, ':', start_line)) as resource, 24 | case 25 | when allowed_host_paths is null then 'alarm' 26 | else 'ok' 27 | end as status, 28 | case 29 | when allowed_host_paths is null then 'Pod security policy ' || name || ' containers can use all host paths.' 30 | else 'Pod security policy ' || name || ' containers using specified host path.' 31 | end as reason 32 | ${local.tag_dimensions_sql} 33 | ${local.common_dimensions_non_namespace_sql} 34 | from 35 | kubernetes_pod_security_policy; 36 | EOQ 37 | } 38 | 39 | query "pod_security_policy_container_privilege_escalation_disabled" { 40 | sql = <<-EOQ 41 | select 42 | coalesce(uid, concat(path, ':', start_line)) as resource, 43 | case 44 | when not allow_privilege_escalation then 'ok' 45 | else 'alarm' 46 | end as status, 47 | case 48 | when not allow_privilege_escalation then 'Pod security policy ' || name || ' pods can not request to allow privilege escalation.' 49 | else 'Pod security policy ' || name || ' pods can request to allow privilege escalation.' 50 | end as reason 51 | ${local.tag_dimensions_sql} 52 | ${local.common_dimensions_non_namespace_sql} 53 | from 54 | kubernetes_pod_security_policy; 55 | EOQ 56 | } 57 | 58 | query "pod_security_policy_non_root_container" { 59 | sql = <<-EOQ 60 | select 61 | coalesce(uid, concat(path, ':', start_line)) as resource, 62 | case 63 | when run_as_user ->> 'rule' = 'MustRunAsNonRoot' then 'ok' 64 | else 'alarm' 65 | end as status, 66 | case 67 | when run_as_user ->> 'rule' = 'MustRunAsNonRoot' then 'Pod security policy ' || name || ' restrict containers to run as non-root user.' 68 | else 'Pod security policy ' || name || ' does not restrict containers to run as non-root user.' 69 | end as reason 70 | ${local.tag_dimensions_sql} 71 | ${local.common_dimensions_non_namespace_sql} 72 | from 73 | kubernetes_pod_security_policy; 74 | EOQ 75 | } 76 | 77 | query "pod_security_policy_hostpid_hostipc_sharing_disabled" { 78 | sql = <<-EOQ 79 | select 80 | coalesce(uid, concat(path, ':', start_line)) as resource, 81 | case 82 | when host_pid or host_ipc then 'alarm' 83 | else 'ok' 84 | end as status, 85 | case 86 | when host_pid then 'Pod security policy ' || name || ' pods can share host PID namespaces.' 87 | when host_ipc then 'Pod security policy ' || name || ' pods can share host IPC namespaces.' 88 | else 'Pod security policy ' || name || ' pods cannot share host process namespaces.' 89 | end as reason 90 | ${local.tag_dimensions_sql} 91 | ${local.common_dimensions_non_namespace_sql} 92 | from 93 | kubernetes_pod_security_policy; 94 | EOQ 95 | } 96 | 97 | query "pod_security_policy_immutable_container_filesystem" { 98 | sql = <<-EOQ 99 | select 100 | coalesce(uid, concat(path, ':', start_line)) as resource, 101 | case 102 | when read_only_root_filesystem then 'ok' 103 | else 'alarm' 104 | end as status, 105 | case 106 | when read_only_root_filesystem then 'Pod security policy ' || name || ' containers running with read-only root file system.' 107 | else 'Pod security policy ' || name || ' containers not running with read-only root file system.' 108 | end as reason 109 | ${local.tag_dimensions_sql} 110 | ${local.common_dimensions_non_namespace_sql} 111 | from 112 | kubernetes_pod_security_policy; 113 | EOQ 114 | } 115 | 116 | query "pod_security_policy_container_privilege_disabled" { 117 | sql = <<-EOQ 118 | select 119 | coalesce(uid, concat(path, ':', start_line)) as resource, 120 | case 121 | when privileged then 'alarm' 122 | else 'ok' 123 | end as status, 124 | case 125 | when privileged then 'Pod security policy ' || name || ' pods can run privileged containers.' 126 | else 'Pod security policy ' || name || ' pods can not run privileged containers.' 127 | end as reason 128 | ${local.tag_dimensions_sql} 129 | ${local.common_dimensions_non_namespace_sql} 130 | from 131 | kubernetes_pod_security_policy; 132 | EOQ 133 | } 134 | 135 | query "pod_security_policy_hostipc_sharing_disabled" { 136 | sql = <<-EOQ 137 | select 138 | coalesce(uid, concat(path, ':', start_line)) as resource, 139 | case 140 | when host_ipc then 'alarm' 141 | else 'ok' 142 | end as status, 143 | case 144 | when host_ipc then 'Pod security policy ' || name || ' pods can share host IPC namespaces.' 145 | else 'Pod security policy ' || name || ' pods cannot share host IPC namespaces.' 146 | end as reason 147 | ${local.tag_dimensions_sql} 148 | ${local.common_dimensions_non_namespace_sql} 149 | from 150 | kubernetes_pod_security_policy; 151 | EOQ 152 | } 153 | 154 | query "pod_security_policy_hostpid_sharing_disabled" { 155 | sql = <<-EOQ 156 | select 157 | coalesce(uid, concat(path, ':', start_line)) as resource, 158 | case 159 | when host_pid then 'alarm' 160 | else 'ok' 161 | end as status, 162 | case 163 | when host_pid then 'Pod security policy ' || name || ' pods can share host PID namespaces.' 164 | else 'Pod security policy ' || name || ' pods cannot share host PID namespaces.' 165 | end as reason 166 | ${local.tag_dimensions_sql} 167 | ${local.common_dimensions_non_namespace_sql} 168 | from 169 | kubernetes_pod_security_policy; 170 | EOQ 171 | } 172 | 173 | query "pod_security_policy_security_services_hardening" { 174 | sql = <<-EOQ 175 | select 176 | coalesce(uid, concat(path, ':', start_line)) as resource, 177 | case 178 | when se_linux -> 'rule' = '"MustRunAs"' then 'ok' 179 | when annotations -> 'apparmor.security.beta.kubernetes.io/defaultProfileName' = '"runtime/default"' then 'ok' 180 | when annotations -> 'seccomp.security.alpha.kubernetes.io/defaultProfileName' = '"runtime/default"' then 'ok' 181 | else 'alarm' 182 | end as status, 183 | case 184 | when se_linux -> 'rule' = '"MustRunAs"' then 'Applications using SELinux security service.' 185 | when annotations -> 'apparmor.security.beta.kubernetes.io/defaultProfileName' = '"runtime/default"' then 'Pod security policy ' || name || ' using AppArmor security service.' 186 | when annotations -> 'seccomp.security.alpha.kubernetes.io/defaultProfileName' = '"runtime/default"' then 'Pod security policy ' || name || ' using Seccomp security service.' 187 | else 'Pod security policy ' || name || ' not using securty services.' 188 | end as reason 189 | ${local.tag_dimensions_sql} 190 | ${local.common_dimensions_non_namespace_sql} 191 | from 192 | kubernetes_pod_security_policy; 193 | EOQ 194 | } 195 | 196 | query "pod_security_policy_default_seccomp_profile_enabled" { 197 | sql = <<-EOQ 198 | select 199 | coalesce(uid, concat(path, ':', start_line)) as resource, 200 | case 201 | when annotations -> 'seccomp.security.alpha.kubernetes.io/defaultProfileName' = '"docker/default"' then 'ok' 202 | else 'alarm' 203 | end as status, 204 | case 205 | when annotations -> 'seccomp.security.alpha.kubernetes.io/defaultProfileName' = '"docker/default"' then name || ' seccompProfile enabled.' 206 | else name || ' seccompProfile disabled.' 207 | end as reason 208 | ${local.tag_dimensions_sql} 209 | ${local.common_dimensions_non_namespace_sql} 210 | from 211 | kubernetes_pod_security_policy; 212 | EOQ 213 | } 214 | -------------------------------------------------------------------------------- /query/role.pp: -------------------------------------------------------------------------------- 1 | query "role_default_namespace_used" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when namespace = 'default' then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when namespace = 'default' then name || ' uses default namespace.' 11 | else name || ' not using the default namespace.' 12 | end as reason, 13 | name as role_name 14 | ${local.tag_dimensions_sql} 15 | ${local.common_dimensions_sql} 16 | from 17 | kubernetes_role; 18 | EOQ 19 | } 20 | 21 | query "role_with_wildcards_used" { 22 | sql = <<-EOQ 23 | select 24 | coalesce(uid, concat(path, ':', start_line)) as resource, 25 | case 26 | when rule ->> 'apiGroups' like '%*%' 27 | or rule ->> 'resources' like '%*%' 28 | or rule ->> 'verbs' like '%*%' then 'alarm' 29 | else 'ok' 30 | end as status, 31 | case 32 | when rule ->> 'apiGroups' like '%*%' then name || ' api groups use wildcards.' 33 | when rule ->> 'resources' like '%*%' then name || ' resources use wildcards.' 34 | when rule ->> 'verbs' like '%*%' then name || ' actions use wildcards.' 35 | else name || ' uses no wildcard.' 36 | end as reason, 37 | name as role_name 38 | ${local.tag_dimensions_sql} 39 | ${local.common_dimensions_non_namespace_sql} 40 | from 41 | kubernetes_cluster_role, 42 | jsonb_array_elements(rules) rule 43 | where 44 | name not like '%system%' 45 | group by 46 | uid, 47 | status, 48 | reason, 49 | role_name, 50 | path, 51 | start_line, 52 | end_line, 53 | source_type, 54 | context_name, 55 | tags, 56 | _ctx; 57 | EOQ 58 | } 59 | 60 | query "role_with_rbac_escalate_permissions" { 61 | sql = <<-EOQ 62 | with role_with_escalate as ( 63 | select 64 | uid, 65 | count(*) as num 66 | from 67 | kubernetes_cluster_role, 68 | jsonb_array_elements(rules) rule 69 | where 70 | rule -> 'apiGroups' @> '["rbac.authorization.k8s.io"]' 71 | and ( 72 | rule -> 'resources' @> '["roles"]' 73 | or rule -> 'resources' @> '["clusterroles"]' 74 | ) 75 | and rule -> 'verbs' @> '["escalate"]' 76 | group by 77 | uid 78 | union 79 | select 80 | uid, 81 | count(*) as num 82 | from 83 | kubernetes_role, 84 | jsonb_array_elements(rules) rule 85 | where 86 | rule -> 'apiGroups' @> '["rbac.authorization.k8s.io"]' 87 | and ( 88 | rule -> 'resources' @> '["roles"]' 89 | or rule -> 'resources' @> '["clusterroles"]' 90 | ) 91 | and rule -> 'verbs' @> '["escalate"]' 92 | group by 93 | uid 94 | ), union_role_and_cluster_role as ( 95 | select 96 | uid, 97 | path, 98 | name, 99 | start_line, 100 | end_line, 101 | source_type, 102 | context_name, 103 | tags, 104 | _ctx 105 | from 106 | kubernetes_role 107 | union 108 | select 109 | uid, 110 | path, 111 | name, 112 | start_line, 113 | end_line, 114 | source_type, 115 | context_name, 116 | tags, 117 | _ctx 118 | from 119 | kubernetes_cluster_role 120 | ) 121 | select 122 | coalesce(r.uid, concat(r.path, ':', r.start_line)) as resource, 123 | case 124 | when e.num > 0 then 'alarm' 125 | else 'ok' 126 | end as status, 127 | case 128 | when e.num > 0 then name || ' contains ' || e.num || ' RBAC escalate permissions.' 129 | else name || ' does not contain any RBAC escalate permissions.' 130 | end as reason, 131 | name as role_name 132 | ${local.tag_dimensions_sql} 133 | ${local.common_dimensions_non_namespace_sql} 134 | from 135 | union_role_and_cluster_role as r 136 | left join role_with_escalate as e on e.uid = r.uid 137 | EOQ 138 | } 139 | 140 | query "role_with_bind_cluster_role_bindings" { 141 | sql = <<-EOQ 142 | with role_with_escalate as ( 143 | select 144 | uid, 145 | count(*) as num 146 | from 147 | kubernetes_cluster_role, 148 | jsonb_array_elements(rules) rule 149 | where 150 | rule -> 'apiGroups' @> '["rbac.authorization.k8s.io"]' 151 | and ( 152 | rule -> 'resources' @> '["rolebindings"]' 153 | or rule -> 'resources' @> '["clusterrolebindings"]' 154 | ) 155 | and rule -> 'verbs' @> '["bind"]' 156 | group by 157 | uid 158 | union 159 | select 160 | uid, 161 | count(*) as num 162 | from 163 | kubernetes_role, 164 | jsonb_array_elements(rules) rule 165 | where 166 | rule -> 'apiGroups' @> '["rbac.authorization.k8s.io"]' 167 | and ( 168 | rule -> 'resources' @> '["rolebindings"]' 169 | or rule -> 'resources' @> '["clusterrolebindings"]' 170 | ) 171 | and rule -> 'verbs' @> '["bind"]' 172 | group by 173 | uid 174 | ), union_role_and_cluster_role as ( 175 | select 176 | uid, 177 | path, 178 | name, 179 | start_line, 180 | end_line, 181 | source_type, 182 | context_name, 183 | tags, 184 | _ctx 185 | from 186 | kubernetes_role 187 | union 188 | select 189 | uid, 190 | path, 191 | name, 192 | start_line, 193 | end_line, 194 | source_type, 195 | context_name, 196 | tags, 197 | _ctx 198 | from 199 | kubernetes_cluster_role 200 | ) 201 | select 202 | coalesce(r.uid, concat(r.path, ':', r.start_line)) as resource, 203 | case 204 | when e.num > 0 then 'alarm' 205 | else 'ok' 206 | end as status, 207 | case 208 | when e.num > 0 then name || ' contains ' || e.num || ' RBAC bind role bindings or cluster role bindings permissions.' 209 | else name || ' does not contain any RBAC bind role bindings or cluster role bindings permissions.' 210 | end as reason, 211 | name as role_name 212 | ${local.tag_dimensions_sql} 213 | ${local.common_dimensions_non_namespace_sql} 214 | from 215 | union_role_and_cluster_role as r 216 | left join role_with_escalate as e on e.uid = r.uid; 217 | EOQ 218 | } 219 | 220 | query "cluster_role_with_validating_or_mutating_admission_webhook_configurations" { 221 | sql = <<-EOQ 222 | with role_with_escalate as ( 223 | select 224 | uid, 225 | count(*) as num 226 | from 227 | kubernetes_cluster_role, 228 | jsonb_array_elements(rules) rule 229 | where 230 | rule -> 'apiGroups' @> '["admissionregistration.k8s.io"]' 231 | and ( 232 | rule -> 'resources' @> '["mutatingwebhookconfigurations"]' 233 | or rule -> 'resources' @> '["validatingwebhookconfigurations"]' 234 | ) 235 | and rule -> 'verbs' @> '["create", "update", "patch"]' 236 | group by 237 | uid 238 | ) 239 | select 240 | coalesce(r.uid, concat(r.path, ':', r.start_line)) as resource, 241 | case 242 | when e.num > 0 then 'alarm' 243 | else 'ok' 244 | end as status, 245 | case 246 | when e.num > 0 then name || ' contains ' || e.num || ' RBAC cluster role validating or mutating admission webhook configurations permissions.' 247 | else name || ' does not contain any bind role bindings or cluster role validating or mutating admission webhook configurations permissions.' 248 | end as reason, 249 | name as role_name 250 | ${local.tag_dimensions_sql} 251 | ${local.common_dimensions_non_namespace_sql} 252 | from 253 | kubernetes_cluster_role as r 254 | left join role_with_escalate as e on e.uid = r.uid; 255 | EOQ 256 | } 257 | 258 | query "role_with_rbac_approve_certificate_signing_requests" { 259 | sql = <<-EOQ 260 | with role_with_escalate as ( 261 | select 262 | uid, 263 | count(*) as num 264 | from 265 | kubernetes_cluster_role, 266 | jsonb_array_elements(rules) rule 267 | where 268 | rule -> 'apiGroups' @> '["certificates.k8s.io"]' 269 | and 270 | ((rule -> 'resources' @> '["certificatesigningrequests/approval"]' and rule -> 'verbs' @> '["update", "patch"]') 271 | or (rule -> 'resources' @> '["signers"]' and rule -> 'verbs' @> '["approve"]')) 272 | group by 273 | uid 274 | ) 275 | select 276 | coalesce(r.uid, concat(r.path, ':', r.start_line)) as resource, 277 | case 278 | when e.num > 0 then 'alarm' 279 | else 'ok' 280 | end as status, 281 | case 282 | when e.num > 0 then name || ' contains ' || e.num || ' RBAC cluster role grant permissions to approve CertificateSigningRequests.' 283 | else name || ' does not contains any cluster role granting permissions to approve CertificateSigningRequests.' 284 | end as reason, 285 | name as role_name 286 | ${local.tag_dimensions_sql} 287 | ${local.common_dimensions_non_namespace_sql} 288 | from 289 | kubernetes_cluster_role as r 290 | left join role_with_escalate as e on e.uid = r.uid; 291 | EOQ 292 | } -------------------------------------------------------------------------------- /query/role_binding.pp: -------------------------------------------------------------------------------- 1 | query "role_binding_default_namespace_used" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when namespace = 'default' then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when namespace = 'default' then name || ' uses default namespace.' 11 | else name || ' not using the default namespace.' 12 | end as reason, 13 | name as role_binding_name 14 | ${local.tag_dimensions_sql} 15 | ${local.common_dimensions_sql} 16 | from 17 | kubernetes_role_binding; 18 | EOQ 19 | } 20 | 21 | query "role_binding_default_service_account_binding_not_active" { 22 | sql = <<-EOQ 23 | select 24 | coalesce(uid, concat(path, ':', start_line)) as resource, 25 | case 26 | when (subject ->> 'kind') = 'ServiceAccount' and (subject ->> 'name') = 'default' then 'alarm' 27 | else 'ok' 28 | end as status, 29 | case 30 | when (subject ->> 'kind' = 'ServiceAccount') and (subject ->> 'name' = 'default') then name || ' default service accounts active.' 31 | else name || ' default service accounts not active.' 32 | end as reason, 33 | name as role_binding_name 34 | ${local.tag_dimensions_sql} 35 | ${local.common_dimensions_sql} 36 | from 37 | kubernetes_role_binding, 38 | jsonb_array_elements(subjects) as subject; 39 | EOQ 40 | } 41 | -------------------------------------------------------------------------------- /query/secret.pp: -------------------------------------------------------------------------------- 1 | query "secret_default_namespace_used" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when namespace = 'default' then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when namespace = 'default' then name || ' uses default namespace.' 11 | else name || ' not using the default namespace.' 12 | end as reason, 13 | name as secret_name 14 | ${local.tag_dimensions_sql} 15 | ${local.common_dimensions_sql} 16 | from 17 | kubernetes_secret; 18 | EOQ 19 | } 20 | 21 | -------------------------------------------------------------------------------- /query/service.pp: -------------------------------------------------------------------------------- 1 | query "service_default_namespace_used" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when namespace = 'default' then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when namespace = 'default' then name || ' uses default namespace.' 11 | else name || ' not using the default namespace.' 12 | end as reason 13 | ${local.tag_dimensions_sql} 14 | ${local.common_dimensions_sql} 15 | from 16 | kubernetes_service; 17 | EOQ 18 | } 19 | 20 | query "service_type_forbidden" { 21 | sql = <<-EOQ 22 | select 23 | coalesce(uid, concat(path, ':', start_line)) as resource, 24 | case 25 | when type in ('NodePort','LoadBalancer') then 'alarm' 26 | else 'ok' 27 | end as status, 28 | case 29 | when type in ('NodePort','LoadBalancer') then 'Containers using ' || name || ' service exposed through ' || type || ' service type.' 30 | else 'Containers using ' || name || ' service not exposed through a forbidden service type.' 31 | end as reason 32 | ${local.tag_dimensions_sql} 33 | ${local.common_dimensions_sql} 34 | from 35 | kubernetes_service; 36 | EOQ 37 | } 38 | 39 | query "service_no_tiller_service" { 40 | sql = <<-EOQ 41 | with tiller_service as ( 42 | select 43 | distinct uid 44 | from 45 | kubernetes_service 46 | where 47 | (select 'tiller' ilike any (select jsonb_object_keys(tags)::text)) 48 | or (select 'tiller' ilike any (select jsonb_object_keys(selector)::text)) 49 | ) 50 | select 51 | coalesce(s.uid, concat(s.path, ':', s.start_line)) as resource, 52 | case 53 | when t.uid is not null then 'alarm' 54 | else 'ok' 55 | end as status, 56 | case 57 | when t.uid is not null then name || ' using tiller service.' 58 | else name || ' not using tiller service.' 59 | end as reason 60 | ${local.tag_dimensions_sql} 61 | ${local.common_dimensions_sql} 62 | from 63 | kubernetes_service as s 64 | left join tiller_service as t on t.uid = s.uid; 65 | EOQ 66 | } 67 | 68 | query "service_no_tiller_deployed" { 69 | sql = <<-EOQ 70 | select 71 | coalesce(uid, concat(path, ':', start_line)) as resource, 72 | name, 73 | case 74 | when labels ->> 'app' = 'helm' or labels ->> 'name' = 'tiller' then 'alarm' 75 | else 'ok' 76 | end as status, 77 | case 78 | when labels ->> 'app' = 'helm' or labels ->> 'name' = 'tiller' then name || ' has tiller deployed.' 79 | else name || ' does not have tiller deployed.' 80 | end as reason 81 | ${local.tag_dimensions_sql} 82 | ${local.common_dimensions_sql} 83 | from 84 | kubernetes_service; 85 | EOQ 86 | } -------------------------------------------------------------------------------- /query/service_account.pp: -------------------------------------------------------------------------------- 1 | query "service_account_token_disabled" { 2 | sql = <<-EOQ 3 | select 4 | coalesce(uid, concat(path, ':', start_line)) as resource, 5 | case 6 | when automount_service_account_token then 'alarm' 7 | else 'ok' 8 | end as status, 9 | case 10 | when automount_service_account_token then name || ' service account token will be automatically mounted.' 11 | else name || ' service account token will not be automatically mounted.' 12 | end as reason, 13 | name as service_account_name 14 | ${local.tag_dimensions_sql} 15 | ${local.common_dimensions_sql} 16 | from 17 | kubernetes_service_account; 18 | EOQ 19 | } 20 | 21 | query "service_account_default_namespace_used" { 22 | sql = <<-EOQ 23 | select 24 | coalesce(uid, concat(path, ':', start_line)) as resource, 25 | case 26 | when namespace = 'default' then 'alarm' 27 | else 'ok' 28 | end as status, 29 | case 30 | when namespace = 'default' then name || ' uses default namespace.' 31 | else name || ' not using the default namespace.' 32 | end as reason, 33 | name as service_account_name 34 | ${local.tag_dimensions_sql} 35 | ${local.common_dimensions_sql} 36 | from 37 | kubernetes_service_account; 38 | EOQ 39 | } 40 | 41 | -------------------------------------------------------------------------------- /variables.pp: -------------------------------------------------------------------------------- 1 | // Benchmarks and controls for specific services should override the "service" tag 2 | locals { 3 | kubernetes_compliance_common_tags = { 4 | category = "Compliance" 5 | plugin = "kubernetes" 6 | service = "Kubernetes" 7 | } 8 | } 9 | 10 | variable "common_dimensions" { 11 | type = list(string) 12 | description = "A list of common dimensions to add to each control." 13 | # Define which common dimensions should be added to each control. 14 | # - connection_name (_ctx ->> 'connection_name') 15 | # - context_name 16 | # - namespace 17 | # - path 18 | # - source_type 19 | default = ["context_name", "namespace", "path", "source_type"] 20 | } 21 | 22 | variable "tag_dimensions" { 23 | type = list(string) 24 | description = "A list of tags to add as dimensions to each control." 25 | # A list of tag names to include as dimensions for resources that support 26 | # tags (e.g. "Owner", "Environment"). Default to empty since tag names are 27 | # a personal choice - for commonly used tag names see 28 | # https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ 29 | default = [] 30 | } 31 | 32 | locals { 33 | 34 | # Local internal variable to build the SQL select clause for common 35 | # dimensions using a table name qualifier if required. Do not edit directly. 36 | common_dimensions_qualifier_sql = <<-EOQ 37 | %{~if contains(var.common_dimensions, "connection_name")}, __QUALIFIER___ctx ->> 'connection_name' as connection_name%{endif~} 38 | %{~if contains(var.common_dimensions, "context_name")}, coalesce(__QUALIFIER__context_name, '') as context_name%{endif~} 39 | %{~if contains(var.common_dimensions, "namespace")}, __QUALIFIER__namespace%{endif~} 40 | %{~if contains(var.common_dimensions, "source_type")}, __QUALIFIER__source_type%{endif~} 41 | %{~if contains(var.common_dimensions, "path")}, coalesce(__QUALIFIER__path || ':' || __QUALIFIER__start_line || '-' || __QUALIFIER__end_line, '') as path%{endif~} 42 | EOQ 43 | 44 | common_dimensions_qualifier_namespace_sql = <<-EOQ 45 | %{~if contains(var.common_dimensions, "connection_name")}, __QUALIFIER___ctx ->> 'connection_name' as connection_name%{endif~} 46 | %{~if contains(var.common_dimensions, "context_name")}, coalesce(__QUALIFIER__context_name, '') as context_name%{endif~} 47 | %{~if contains(var.common_dimensions, "namespace")}, __QUALIFIER__name%{endif~} 48 | %{~if contains(var.common_dimensions, "source_type")}, __QUALIFIER__source_type%{endif~} 49 | %{~if contains(var.common_dimensions, "path")}, coalesce(__QUALIFIER__path || ':' || __QUALIFIER__start_line || '-' || __QUALIFIER__end_line, '') as path%{endif~} 50 | EOQ 51 | 52 | common_dimensions_non_namespace_qualifier_sql = <<-EOQ 53 | %{~if contains(var.common_dimensions, "connection_name")}, __QUALIFIER___ctx ->> 'connection_name' as connection_name%{endif~} 54 | %{~if contains(var.common_dimensions, "context_name")}, coalesce(__QUALIFIER__context_name, '') as context_name%{endif~} 55 | %{~if contains(var.common_dimensions, "source_type")}, __QUALIFIER__source_type%{endif~} 56 | %{~if contains(var.common_dimensions, "path")}, coalesce(__QUALIFIER__path || ':' || __QUALIFIER__start_line || '-' || __QUALIFIER__end_line, '') as path%{endif~} 57 | EOQ 58 | 59 | # Local internal variable to build the SQL select clause for tag 60 | # dimensions. Do not edit directly. 61 | tag_dimensions_qualifier_sql = <<-EOQ 62 | %{~for dim in var.tag_dimensions}, __QUALIFIER__tags ->> '${dim}' as "${replace(dim, "\"", "\"\"")}"%{endfor~} 63 | EOQ 64 | } 65 | 66 | locals { 67 | 68 | # Local internal variable with the full SQL select clause for common 69 | # dimensions. Do not edit directly. 70 | common_dimensions_sql = replace(local.common_dimensions_qualifier_sql, "__QUALIFIER__", "") 71 | common_dimensions_namespace_sql = replace(local.common_dimensions_qualifier_namespace_sql, "__QUALIFIER__", "") 72 | common_dimensions_non_namespace_sql = replace(local.common_dimensions_non_namespace_qualifier_sql, "__QUALIFIER__", "") 73 | tag_dimensions_sql = replace(local.tag_dimensions_qualifier_sql, "__QUALIFIER__", "") 74 | } 75 | --------------------------------------------------------------------------------