├── .gitignore
├── .rubocop.yml
├── AUTHORS
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── LICENSE
├── README.md
├── cloudbuild.yml
├── controls
├── 1.01-iam.rb
├── 1.02-iam.rb
├── 1.03-iam.rb
├── 1.04-iam.rb
├── 1.05-iam.rb
├── 1.06-iam.rb
├── 1.07-iam.rb
├── 1.08-iam.rb
├── 1.09-iam.rb
├── 1.10-iam.rb
├── 1.11-iam.rb
├── 1.12-iam.rb
├── 1.13-iam.rb
├── 1.14-iam.rb
├── 1.15-iam.rb
├── 2.01-logging.rb
├── 2.02-logging.rb
├── 2.03-logging.rb
├── 2.04-logging.rb
├── 2.05-logging.rb
├── 2.06-logging.rb
├── 2.07-logging.rb
├── 2.08-logging.rb
├── 2.09-logging.rb
├── 2.10-logging.rb
├── 2.11-logging.rb
├── 3.01-networking.rb
├── 3.02-networking.rb
├── 3.03-networking.rb
├── 3.04-networking.rb
├── 3.05-networking.rb
├── 3.06-networking.rb
├── 3.07-networking.rb
├── 3.08-networking.rb
├── 3.09-networking.rb
├── 4.01-vms.rb
├── 4.02-vms.rb
├── 4.03-vms.rb
├── 4.04-vms.rb
├── 4.05-vms.rb
├── 4.06-vms.rb
├── 4.07-vms.rb
├── 4.08-vms.rb
├── 5.01-storage.rb
├── 5.02-storage.rb
├── 6.01-db.rb
├── 6.02-db.rb
├── 6.03-db.rb
├── 6.04-db.rb
├── 6.05-db.rb
├── 6.06-db.rb
├── 6.07-db.rb
├── 7.01-bq.rb
├── 7.02-bq.rb
└── 7.03-bq.rb
├── inspec.yml
├── renovate.json
└── walkthrough.md
/.gitignore:
--------------------------------------------------------------------------------
1 | **/.tmp
2 | inspec.lock
3 | attrs.yml
4 | Gemfile.lock
5 | inputs.yml
6 | vendor
7 | .DS_Store
8 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | ---
2 | AllCops:
3 | TargetRubyVersion: 2.6.3p62
4 | Exclude:
5 | - Gemfile
6 |
7 | Layout/LineLength:
8 | Enabled: false
9 |
10 | Naming/FileName:
11 | Enabled: true
12 | Regex: !ruby/regexp '/^.{3,100}$/'
13 |
14 | Metrics/BlockLength:
15 | Enabled: false
16 |
17 | Style/FrozenStringLiteralComment:
18 | Enabled: false
19 |
20 | Style/IdenticalConditionalBranches:
21 | Enabled: false
22 |
23 | Layout/EmptyLineAfterGuardClause:
24 | Enabled: false
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | # This is the list of inspec-gcp-cis-benchmark authors for copyright purposes.
2 | #
3 | # This does not necessarily list everyone who has contributed code, since in
4 | # some cases, their employer may be the copyright holder. To see the full list
5 | # of contributors, see the revision history in source control.
6 | Google LLC
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows
28 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/).
29 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Copyright 2020 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | FROM cincproject/auditor:4.22.0
16 |
17 | COPY . /share/.
18 |
19 | RUN gem install rubocop
20 |
21 | ENTRYPOINT ["cinc-auditor"]
22 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | source 'https://rubygems.org'
16 |
17 | gem 'inspec', '>= 3', '< 5'
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GCP CIS 1.2.0 Benchmark Inspec Profile
2 |
3 | This repository holds the [Google Cloud Platform (GCP)](https://cloud.google.com/) [Center for Internet Security (CIS)](https://www.cisecurity.org) [version 1.2 Benchmark](https://www.cisecurity.org/benchmark/google_cloud_computing_platform/) [Inspec](https://www.inspec.io/) Profile.
4 |
5 | ## Required Disclaimer
6 |
7 | This is not an officially supported Google product. This code is intended to help users assess their security posture on the Google Cloud against the CIS Benchmark. This code is not certified by CIS.
8 |
9 | ## Coverage
10 |
11 | The following GCP CIS v1.2.0 Benchmark Controls are not covered:
12 |
13 | - Identity and Access Management 1.2 - "Ensure that multi-factor authentication is enabled for all non-service accounts"
14 | - Identity and Access Management 1.3 - "Ensure that Security Key Enforcement is enabled for all admin accounts"
15 | - Identity and Access Management 1.12 - "Ensure API keys are not created for a project"
16 | - Identity and Access Management 1.13 - "Ensure API keys are restricted to use by only specified Hosts and Apps"
17 | - Identity and Access Management 1.14 - "Ensure API keys are restricted to only APIs that application needs access"
18 | - Identity and Access Management 1.15 - "Ensure API keys are rotated every 90 days"
19 | - Cloud SQL Database Services 6.3 - "Ensure that MySql database instance does not allow anyone to connect with administrative privileges"
20 | - Cloud SQL Database Services 6.4 - "Ensure that MySQL Database Instance does not allows root login from any Host"
21 |
22 | ## Usage
23 |
24 | ### Profile Inputs (see `inspec.yml` file)
25 |
26 | This profile uses InSpec Inputs to make the tests more flexible. You are able to provide inputs at runtime either via the `cli` or via `YAML files` to help the profile work best in your deployment.
27 |
28 | **pro tip**: Do not change the inputs in the `inspec.yml` file directly, either:
29 |
30 | - update them via the cli - via the `--input` flag
31 | - pass them in via a YAML file as shown in the `Example` - via the `--input-file` flag
32 |
33 | Further details can be found here:
34 |
35 | ### (Required) User Provided Inputs - via the CLI or Input Files
36 |
37 | - **gcp_project_id** - (Default: null, type: String) - The target GCP Project you are scanning.
38 |
39 | ### (Optional) User Provided Inputs
40 |
41 | - **sa_key_older_than_seconds** - (Default: 7776000, type: int, CIS IAM 1.15) - The maximum allowed age of GCP User-managed Service Account Keys (90 days in seconds).
42 | - **kms_rotation_period_seconds** - (Default: 7776000, type: int, CIS IAM 1.10) - The maximum allowed age of KMS keys (90 days in seconds).
43 |
44 | ### Cloud Shell Walkthrough
45 |
46 | Use this Cloud Shell Walkthrough for a hands-on example.
47 |
48 | [](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark&page=editor&tutorial=walkthrough.md)
49 |
50 | ### CLI Example
51 |
52 | #### Ruby Gem
53 |
54 | ```
55 | #install inspec
56 | $ gem install inspec-bin -v 4.26.15 --no-document --quiet
57 | ```
58 |
59 | ```
60 | # make sure you're authenticated to GCP
61 | $ gcloud auth list
62 |
63 | # acquire credentials to use with Application Default Credentials
64 | $ gcloud auth application-default login
65 |
66 | ```
67 |
68 | ```
69 | # scan a project with this profile, replace {{project-id}} with your project ID
70 | $ inspec exec https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark.git -t gcp:// --input gcp_project_id={{project-id}} --reporter cli json:{{project-id}}_scan.json
71 | ...snip...
72 | Profile Summary: 48 successful controls, 5 control failures, 7 controls skipped
73 | Test Summary: 166 successful, 7 failures, 7 skipped
74 | ```
75 |
76 | #### Docker
77 | ```
78 | # pull inspec image
79 | $ docker pull chef/inspec:4.26.15
80 | ```
81 |
82 | ```
83 | # make sure you're authenticated to GCP
84 | $ gcloud auth list
85 |
86 | # acquire credentials to use with Application Default Credentials
87 | $ gcloud auth application-default login
88 |
89 | ```
90 |
91 | ```
92 | # create function for convenience
93 | $ function inspec-docker { docker run -it -e GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS=true --rm -v ~/.config:/root/.config -v $(pwd):/share chef/inspec:4.26.15 "$@"; }
94 |
95 | # scan a project with this profile, replace {{project-id}} with your project ID
96 | $ inspec-docker exec https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark.git -t gcp:// --input gcp_project_id={{project-id}} --reporter cli json:{{project-id}}_scan.json
97 | ...snip...
98 | Profile Summary: 48 successful controls, 5 control failures, 7 controls skipped
99 | Test Summary: 166 successful, 7 failures, 7 skipped
100 | ```
101 |
102 | ### Required APIs
103 |
104 | Consider these GCP projects, which may all be the same or different:
105 |
106 | - the project of the Service Account that's used to authenticate the scan
107 | - the project from which the benchmark is called
108 | - the project to be scanned
109 |
110 | The following GCP APIs should be enabled in **all** of these projects:
111 |
112 | - cloudkms.googleapis.com
113 | - cloudresourcemanager.googleapis.com
114 | - compute.googleapis.com
115 | - dns.googleapis.com
116 | - iam.googleapis.com
117 | - logging.googleapis.com
118 | - monitoring.googleapis.com
119 | - sqladmin.googleapis.com
120 | - storage-api.googleapis.com
121 |
122 | ### Required Permissions
123 |
124 | The following permissions are required to run the CIS benchmark profile:
125 |
126 | On organization level:
127 |
128 | - resourcemanager.organizations.get
129 | - resourcemanager.projects.get
130 | - resourcemanager.projects.getIamPolicy
131 | - resourcemanager.folders.get
132 |
133 | On project level:
134 |
135 | - cloudkms.cryptoKeys.get
136 | - cloudkms.cryptoKeys.getIamPolicy
137 | - cloudkms.cryptoKeys.list
138 | - cloudkms.keyRings.list
139 | - cloudsql.instances.get
140 | - cloudsql.instances.list
141 | - compute.firewalls.get
142 | - compute.firewalls.list
143 | - compute.instances.get
144 | - compute.instances.list
145 | - compute.networks.get
146 | - compute.networks.list
147 | - compute.projects.get
148 | - compute.regions.list
149 | - compute.sslPolicies.get
150 | - compute.sslPolicies.list
151 | - compute.subnetworks.get
152 | - compute.subnetworks.list
153 | - compute.targetHttpsProxies.get
154 | - compute.targetHttpsProxies.list
155 | - compute.zones.list
156 | - dns.managedZones.get
157 | - dns.managedZones.list
158 | - iam.serviceAccountKeys.list
159 | - iam.serviceAccounts.list
160 | - logging.logMetrics.list
161 | - logging.sinks.get
162 | - logging.sinks.list
163 | - monitoring.alertPolicies.list
164 | - resourcemanager.projects.get
165 | - resourcemanager.projects.getIamPolicy
166 | - storage.buckets.get
167 | - storage.buckets.getIamPolicy
168 | - storage.buckets.list
169 |
--------------------------------------------------------------------------------
/cloudbuild.yml:
--------------------------------------------------------------------------------
1 | # Copyright 2020 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | substitutions:
16 | _GCP_PROJECT_ID: ''
17 | _REPORTS_BUCKET: ''
18 |
19 | timeout: 3000s
20 | steps:
21 | - id: 'Build Docker container'
22 | name: 'gcr.io/cloud-builders/docker'
23 | args: [ 'build', '-t', 'gcr.io/${_GCP_PROJECT_ID}/inspec-gcp-cis-benchmark:${_PR_NUMBER}', '.' ]
24 |
25 | - id: 'Verify InSpec controls'
26 | waitFor: ['Build Docker container']
27 | name: gcr.io/${_GCP_PROJECT_ID}/inspec-gcp-cis-benchmark:${_PR_NUMBER}
28 | entrypoint: '/bin/sh'
29 | args:
30 | - '-c'
31 | - |
32 | cinc-auditor vendor /share/.
33 | cinc-auditor check /share/.
34 |
35 | - id: 'Rubocop'
36 | waitFor: ['Verify InSpec controls']
37 | name: gcr.io/${_GCP_PROJECT_ID}/inspec-gcp-cis-benchmark:${_PR_NUMBER}
38 | entrypoint: '/bin/sh'
39 | args:
40 | - '-c'
41 | - |
42 | rubocop /share/.
43 |
44 | - id: 'Write input file'
45 | waitFor: ['Rubocop']
46 | name: gcr.io/${_GCP_PROJECT_ID}/inspec-gcp-cis-benchmark:${_PR_NUMBER}
47 | entrypoint: '/bin/sh'
48 | args:
49 | - '-c'
50 | - |
51 | cat < /workspace/inputs.yml
52 | gcp_project_id: "${_GCP_PROJECT_ID}"
53 | gcp_gke_locations:
54 | - 'us-central1'
55 | gce_zones:
56 | - 'us-central1'
57 | - 'us-central1-a'
58 | - 'us-central1-b'
59 | - 'us-central1-c'
60 | - 'us-central1-d'
61 | - 'us-central1-e'
62 | - 'us-central1-f'
63 | EOF
64 | cat /workspace/inputs.yml
65 |
66 | - id: 'Run CIS Profile on in-scope project'
67 | waitFor: ['Write input file']
68 | name: gcr.io/${_GCP_PROJECT_ID}/inspec-gcp-cis-benchmark:${_PR_NUMBER}
69 | entrypoint: '/bin/sh'
70 | args:
71 | - '-c'
72 | - |
73 | cinc-auditor exec /share/. -t gcp:// \
74 | --input-file /workspace/inputs.yml \
75 | --reporter cli json:/workspace/cis_report.json html:/workspace/cis_report.html | tee out.json
76 |
77 | - id: 'Test Compliance'
78 | waitFor: ['Run CIS Profile on in-scope project']
79 | name: mitre/inspec_tools
80 | args: ['compliance', '-j', '/workspace/cis_report.json', '-i', '{failed.total.max: 1}']
81 |
82 | - id: 'Store json Report'
83 | waitFor: ['Test Compliance']
84 | name: gcr.io/cloud-builders/gsutil
85 | args:
86 | - cp
87 | - /workspace/cis_report.json
88 | - gs://${_REPORTS_BUCKET}/cis_report-${BUILD_ID}.json
--------------------------------------------------------------------------------
/controls/1.01-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that corporate login credentials are used'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.1'
21 | control_abbrev = 'iam'
22 |
23 | iam_bindings_cache = IAMBindingsCache(project: gcp_project_id)
24 |
25 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
26 | impact 'high'
27 |
28 | title "[#{control_abbrev.upcase}] Ensure that corporate login credentials are used"
29 |
30 | desc 'Use corporate login credentials instead of personal accounts, such as Gmail accounts.'
31 | desc 'rationale', "It is recommended fully-managed corporate Google accounts be used for increased visibility, auditing, and controlling access to Cloud Platform resources. Email accounts based outside of the user's organization, such as personal accounts, should not be used for business purposes."
32 |
33 | tag cis_scored: true
34 | tag cis_level: 1
35 | tag cis_gcp: control_id.to_s
36 | tag cis_version: cis_version.to_s
37 | tag project: gcp_project_id.to_s
38 | tag nist: ['AC-2']
39 |
40 | ref 'CIS Benchmark', url: cis_url.to_s
41 | ref 'GCP Docs', url: 'https://cloud.google.com/docs/enterprise/best-practices-for-enterprise-organizations#use_corporate_login_credentials'
42 |
43 | # determine the organization's email domain
44 | case google_project(project: gcp_project_id).parent.type
45 | when 'organization'
46 | org_domain = google_organization(name: "organizations/#{google_project(project: gcp_project_id).parent.id}").display_name
47 | when 'folder'
48 | parent = 'folder'
49 | folder_id = google_project(project: gcp_project_id).parent.id
50 | while parent == 'folder'
51 | if google_resourcemanager_folder(name: "folders/#{folder_id}").parent.include?('folders')
52 | folder_id = google_resourcemanager_folder(name: "folders/#{folder_id}").parent.sub('folders/', '')
53 | else
54 | parent = 'organization'
55 | org_domain = google_organization(name: google_resourcemanager_folder(name: "folders/#{folder_id}").parent.to_s).display_name
56 | end
57 | end
58 | end
59 |
60 | iam_bindings_cache.iam_binding_roles.each do |role|
61 | iam_bindings_cache.iam_bindings[role].members.each do |member|
62 | next if member.to_s.end_with?('.gserviceaccount.com')
63 | describe "[#{gcp_project_id}] [Role:#{role}] Its member #{member}" do
64 | subject { member.to_s }
65 | it { should match(/@#{org_domain}/) }
66 | end
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/controls/1.02-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that multi-factor authentication is enabled for all non-service accounts'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.2'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that multi-factor authentication is enabled for all non-service accounts"
27 |
28 | desc 'Setup multi-factor authentication for Google Cloud Platform accounts.'
29 | desc 'rationale', 'Multi-factor authentication requires more than one mechanism to authenticate a user. This secures your logins from attackers exploiting stolen or weak credentials.'
30 |
31 | tag cis_scored: false
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: ['IA-2']
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/solutions/securing-gcp-account-u2f'
40 |
41 | describe 'This control is not scored' do
42 | skip 'This control is not scored'
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/controls/1.03-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Security Key Enforcement is enabled for all admin accounts'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.3'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that Security Key Enforcement is enabled for all admin accounts"
27 |
28 | desc 'Setup Security Key Enforcement for Google Cloud Platform admin accounts.'
29 | desc 'rationale', 'Google Cloud Platform users with Organization Administrator roles have the highest level of privilege in the organization. These accounts should be protected with the strongest form of two-factor authentication: Security Key Enforcement. Ensure that admins use Security Keys to log in instead of weaker second factors like SMS or one-time passwords (OTP). Security Keys are actual physical keys used to access Google Organization Administrator Accounts. They send an encrypted signature rather than a code, ensuring that logins cannot be phished.'
30 |
31 | tag cis_scored: false
32 | tag cis_level: 2
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: ['IA-2']
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/security-key/'
40 |
41 | describe 'This control is not scored' do
42 | skip 'This control is not scored'
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/controls/1.04-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that there are only GCP-managed service account keys for each service account'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.4'
21 | control_abbrev = 'iam'
22 |
23 | service_account_cache = ServiceAccountCache(project: gcp_project_id)
24 |
25 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
26 | impact 'none'
27 |
28 | title "[#{control_abbrev.upcase}] Ensure that there are only GCP-managed service account keys for each service account"
29 |
30 | desc 'User managed service account should not have user managed keys.'
31 | desc 'rationale', 'Anyone who has access to the keys will be able to access resources through the service account. GCP-managed keys are used by Cloud Platform services such as App Engine and Compute Engine. These keys cannot be downloaded. Google will keep the keys and automatically rotate them on an approximately weekly basis. User-managed keys are created, downloadable, and managed by users. They expire 10 years from creation.
32 |
33 | For user-managed keys, user have to take ownership of key management activities which includes:
34 | - Key storage
35 | - Key distribution
36 | - Key revocation
37 | - Key rotation
38 | - Protecting the keys from unauthorized users
39 | - Key recovery
40 |
41 | Even after owners precaution, keys can be easily leaked by common development malpractices like checking keys into the source code or leaving them in Downloads directory, or accidentally leaving them on support blogs/channels. It is recommended to prevent use of User-managed service account keys.'
42 |
43 | tag cis_scored: true
44 | tag cis_level: 1
45 | tag cis_gcp: control_id.to_s
46 | tag cis_version: cis_version.to_s
47 | tag project: gcp_project_id.to_s
48 | tag nist: ['AC-2']
49 |
50 | ref 'CIS Benchmark', url: cis_url.to_s
51 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/understanding-service-accounts#managing_service_account_keys'
52 |
53 | service_account_cache.service_account_emails.each do |sa_email|
54 | if service_account_cache.service_account_keys[sa_email].key_names.count > 1
55 | impact 'medium'
56 | describe "[#{gcp_project_id}] Service Account: #{sa_email}" do
57 | subject { service_account_cache.service_account_keys[sa_email] }
58 | its('key_types') { should_not include 'USER_MANAGED' }
59 | end
60 | else
61 | describe "[#{gcp_project_id}] ServiceAccount [#{sa_email}] does not have user-managed keys. This test is Not Applicable." do
62 | skip "[#{gcp_project_id}] ServiceAccount [#{sa_email}] does not have user-managed keys."
63 | end
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/controls/1.05-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that ServiceAccount has no Admin privileges.'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.5'
21 | control_abbrev = 'iam'
22 |
23 | iam_bindings_cache = IAMBindingsCache(project: gcp_project_id)
24 |
25 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
26 | impact 'medium'
27 |
28 | title "[#{control_abbrev.upcase}] Ensure that ServiceAccount has no Admin privileges."
29 |
30 | desc "A service account is a special Google account that belongs to your application or a VM, instead of to an individual end user. Your application uses the service account to call the Google API of a service, so that the users aren't directly involved. It's recommended not to use admin access for ServiceAccount."
31 | desc 'rationale', "Service accounts represent service-level security of the Resources (application or a VM) which can be determined by the roles assigned to it. Enrolling ServiceAccount with Admin rights gives full access to assigned application or a VM, ServiceAccount Access holder can perform critical actions like delete, update change settings etc. without the intervention of user, so It's recommended not to have Admin rights.
32 | This recommendation is applicable only for User-Managed user created service account (Service account with nomenclature: SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com)."
33 |
34 | tag cis_scored: true
35 | tag cis_level: 1
36 | tag cis_gcp: control_id.to_s
37 | tag cis_version: cis_version.to_s
38 | tag project: gcp_project_id.to_s
39 | tag nist: ['AC-2']
40 |
41 | ref 'CIS Benchmark', url: cis_url.to_s
42 | ref 'GCP Docs', url: 'https://cloud.google.com/sdk/gcloud/reference/iam/service-accounts/'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/understanding-roles'
44 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/understanding-service-accounts'
45 |
46 | iam_bindings_cache.iam_bindings.keys.grep(/admin/i).each do |role|
47 | role_bindings = iam_bindings_cache.iam_bindings[role]
48 | if role_bindings.members.nil?
49 | impact 'none'
50 | describe "[#{gcp_project_id}] Role bindings for role [#{role}] do not contain any members. This test is Not Applicable." do
51 | skip "[#{gcp_project_id}] role bindings for role [#{role}] do not contain any members."
52 | end
53 | else
54 | describe "[#{gcp_project_id}] Admin role [#{role}]" do
55 | subject { role_bindings }
56 | its('members') { should_not include(/@[a-z][a-z0-9|-]{4,28}[a-z].iam.gserviceaccount.com/) }
57 | end
58 | end
59 | end
60 |
61 | iam_bindings_cache.iam_bindings.keys.grep(%r{roles/editor}).each do |role|
62 | members_in_scope = []
63 | iam_bindings_cache.iam_bindings[role].members.each do |member|
64 | next if member.include? '@containerregistry.iam.gserviceaccount.com'
65 | members_in_scope.push(member)
66 | end
67 | describe "[#{gcp_project_id}] Project Editor Role" do
68 | subject { members_in_scope }
69 | it { should_not include(/@[a-z][a-z0-9|-]{4,28}[a-z].iam.gserviceaccount.com/) }
70 | end
71 | end
72 |
73 | iam_bindings_cache.iam_bindings.keys.grep(%r{roles/owner}).each do |role|
74 | describe "[#{gcp_project_id}] Project Owner Role" do
75 | subject { iam_bindings_cache.iam_bindings[role] }
76 | its('members') { should_not include(/@[a-z][a-z0-9|-]{4,28}[a-z].iam.gserviceaccount.com/) }
77 | end
78 | end
79 | end
80 |
--------------------------------------------------------------------------------
/controls/1.06-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that IAM users are not assigned Service Account User role at project level'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.6'
21 | control_abbrev = 'iam'
22 |
23 | iam_bindings_cache = IAMBindingsCache(project: gcp_project_id)
24 |
25 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
26 | impact 'medium'
27 |
28 | title "[#{control_abbrev.upcase}] Ensure that IAM users are not assigned Service Account User role at project level"
29 |
30 | desc "It is recommended to assign Service Account User (iam.serviceAccountUser) role to a
31 | user for a specific service account rather than assigning the role to a user at project level."
32 | desc 'rationale', "A service account is a special Google account that belongs to application or a virtual machine (VM), instead of to an individual end user. Application/VM-Instance uses the service account to call the Google API of a service, so that the users aren't directly involved. In addition to being an identity, a service account is a resource which has IAM policies attached to it. These policies determine who can use the service account.
33 |
34 | Users with IAM roles to update the App Engine and Compute Engine instances (such as App Engine Deployer or Compute Instance Admin) can effectively run code as the service accounts used to run these instances, and indirectly gain access to all the resources for which the service accounts has access. Similarly, SSH access to a Compute Engine instance may also provide the ability to execute code as that instance/Service account.
35 |
36 | As per business needs, there could be multiple user-managed service accounts configured for a project. Granting the iam.serviceAccountUser role to a user for a project gives the user access to all service accounts in the project, including service accounts that may be created in the future. This can result into elevation of privileges by using service accounts and corresponding Compute Engine instances.
37 |
38 | In order to implement least privileges best practices, IAM users should not be assigned Service Account User role at project level. Instead iam.serviceAccountUser role should be assigned to a user for a specific service account giving a user access to the service account."
39 |
40 | tag cis_scored: true
41 | tag cis_level: 1
42 | tag cis_gcp: control_id.to_s
43 | tag cis_version: cis_version.to_s
44 | tag project: gcp_project_id.to_s
45 | tag nist: %w[AC-2 AC-3]
46 |
47 | ref 'CIS Benchmark', url: cis_url.to_s
48 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/service-accounts'
49 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/granting-roles-to-service-accounts'
50 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/understanding-roles'
51 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/granting-changing-revoking-access'
52 |
53 | describe "[#{gcp_project_id}] A project-level binding of ServiceAccountUser" do
54 | subject { iam_bindings_cache.iam_bindings['roles/iam.serviceAccountUser'] }
55 | it { should eq nil }
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/controls/1.07-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure user-managed/external keys for service accounts are rotated every 90 days or less'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.7'
21 | control_abbrev = 'iam'
22 | sa_key_older_than_seconds = input('sa_key_older_than_seconds')
23 |
24 | service_account_cache = ServiceAccountCache(project: gcp_project_id)
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'none'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure user-managed/external keys for service accounts are rotated every 90 days or less"
30 |
31 | desc 'Service Account keys consist of a key ID (Private_key_Id) and Private key, which are used to sign programmatic requests that you make to Google cloud services accessible to that particular Service account. It is recommended that all Service Account keys are regularly rotated.'
32 | desc 'rationale', "Rotating Service Account keys will reduce the window of opportunity for an access key that is associated with a compromised or terminated account to be used. Service Account keys should be rotated to ensure that data cannot be accessed with an old key which might have been lost, cracked, or stolen.
33 |
34 | Each service account is associated with a key pair, which is managed by Google Cloud Platform (GCP). It is used for service-to-service authentication within GCP. Google rotates the keys daily.
35 |
36 | GCP provides option to create one or more user-managed (also called as external key pairs) key pairs for use from outside GCP (for example, for use with Application Default Credentials). When a new key pair is created, user is enforced download the private key (which is not retained by Google). With external keys, users are responsible for security of the private key and other management operations such as key rotation. External keys can be managed by the IAM API, gcloud command-line tool, or the Service Accounts page in the Google Cloud Platform Console. GCP facilitates up to 10 external service account keys per service account to facilitate key rotation."
37 |
38 | tag cis_scored: true
39 | tag cis_level: 1
40 | tag cis_gcp: control_id.to_s
41 | tag cis_version: cis_version.to_s
42 | tag project: gcp_project_id.to_s
43 | tag nist: ['AC-2']
44 |
45 | ref 'CIS Benchmark', url: cis_url.to_s
46 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/understanding-service-accounts#managing_service_account_keys'
47 | ref 'GCP Docs', url: 'https://cloud.google.com/sdk/gcloud/reference/iam/service-accounts/keys/list'
48 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/service-accounts'
49 |
50 | service_account_cache.service_account_emails.each do |sa_email|
51 | if service_account_cache.service_account_keys[sa_email].key_names.count > 1
52 | impact 'medium'
53 | describe "[#{gcp_project_id}] ServiceAccount Keys for #{sa_email} older than #{sa_key_older_than_seconds} seconds" do
54 | subject { service_account_cache.service_account_keys[sa_email].where { (Time.now - sa_key_older_than_seconds > valid_after_time) } }
55 | it { should_not exist }
56 | end
57 | else
58 | describe "[#{gcp_project_id}] ServiceAccount [#{sa_email}] does not have user-managed keys. This test is Not Applicable." do
59 | skip "[#{gcp_project_id}] ServiceAccount [#{sa_email}] does not have user-managed keys."
60 | end
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/controls/1.08-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Separation of duties is enforced while assigning service account related roles to users'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.8'
21 | control_abbrev = 'iam'
22 |
23 | iam_bindings_cache = IAMBindingsCache(project: gcp_project_id)
24 |
25 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
26 | impact 'none'
27 |
28 | title "[#{control_abbrev.upcase}] Ensure that Separation of duties is enforced while assigning service account related roles to users"
29 |
30 | desc "It is recommended that the principle of 'Separation of Duties' is enforced while assigning service account related roles to users."
31 | desc 'rationale', "Built-in/Predefined IAM role Service Account admin allows user/identity to create, delete, manage service account(s). Built-in/Predefined IAM role Service Account User allows user/identity (with adequate privileges on Compute and App Engine) to assign service account(s) to Apps/Compute Instances.
32 |
33 | Separation of duties is the concept of ensuring that one individual does not have all necessary permissions to be able to complete a malicious action. In Cloud IAM - service accounts, this could be an action such as using a service account to access resources that user should not normally have access to. Separation of duties is a business control typically used in larger organizations, meant to help avoid security or privacy incidents and errors. It is considered best practice.
34 |
35 | Any user(s) should not have Service Account Admin and Service Account User, both roles assigned at a time."
36 |
37 | tag cis_scored: false
38 | tag cis_level: 2
39 | tag cis_gcp: control_id.to_s
40 | tag cis_version: cis_version.to_s
41 | tag project: gcp_project_id.to_s
42 | tag nist: %w[AC-2 AC-3]
43 |
44 | ref 'CIS Benchmark', url: cis_url.to_s
45 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/service-accounts'
46 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/understanding-roles'
47 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/granting-roles-to-service-accounts'
48 |
49 | sa_admins = iam_bindings_cache.iam_bindings['roles/iam.serviceAccountAdmin']
50 | if sa_admins.nil? || sa_admins.members.count.zero?
51 | describe "[#{gcp_project_id}] does not contain users with roles/serviceAccountAdmin. This test is Not Applicable." do
52 | skip "[#{gcp_project_id}] does not contain users with roles/serviceAccountAdmin"
53 | end
54 | elsif iam_bindings_cache.iam_bindings['roles/iam.serviceAccountUser'].nil?
55 | describe "[#{gcp_project_id}] does not contain users with roles/serviceAccountUser. This test is Not Applicable." do
56 | skip "[#{gcp_project_id}] does not contain users with roles/serviceAccountUser"
57 | end
58 | else
59 | impact 'medium'
60 | describe "[#{gcp_project_id}] roles/serviceAccountUser" do
61 | subject { iam_bindings_cache.iam_bindings['roles/iam.serviceAccountUser'] }
62 | sa_admins.members.each do |sa_admin|
63 | its('members.to_s') { should_not match sa_admin }
64 | end
65 | end
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/controls/1.09-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Cloud KMS cryptokeys are not anonymously or publicly accessible'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.9'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'none'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that Cloud KMS cryptokeys are not anonymously or publicly accessible"
27 |
28 | desc 'It is recommended that the IAM policy on Cloud KMS cryptokeys should restrict anonymous and/or public access.'
29 |
30 | desc 'rationale', 'Granting permissions to allUsers or allAuthenticatedUsers allows anyone to access the dataset. Such access might not be desirable if sensitive data is stored at the location. In this case, ensure that anonymous and/or public access to a Cloud KMS cryptokey is not allowed.'
31 |
32 | tag cis_scored: true
33 | tag cis_level: 1
34 | tag cis_gcp: control_id.to_s
35 | tag cis_version: cis_version.to_s
36 | tag project: gcp_project_id.to_s
37 | tag nist: ['AC-3']
38 |
39 | ref 'CIS Benchmark', url: cis_url.to_s
40 | ref 'GCP Docs', url: 'https://cloud.google.com/kms/docs/key-rotation#frequency_of_key_rotation'
41 |
42 | # Get all "normal" regions and add dual/multi regions
43 | locations = google_compute_regions(project: gcp_project_id).region_names
44 | locations << 'global' << 'asia' << 'europe' << 'us' << 'eur4' << 'nam4'
45 | kms_cache = KMSKeyCache(project: gcp_project_id, locations: locations)
46 |
47 | # Ensure that keys aren't publicly accessible
48 | locations.each do |location|
49 | if kms_cache.kms_key_ring_names[location].empty?
50 | describe "[#{gcp_project_id}] does not contain any key rings in [#{location}]. This test is Not Applicable." do
51 | skip "[#{gcp_project_id}] does not contain any key rings in [#{location}]"
52 | end
53 | else
54 | kms_cache.kms_key_ring_names[location].each do |keyring|
55 | if kms_cache.kms_crypto_keys[location][keyring].empty?
56 | describe "[#{gcp_project_id}] key ring [#{keyring}] does not contain any cryptographic keys. This test is Not Applicable." do
57 | skip "[#{gcp_project_id}] key ring [#{keyring}] does not contain any cryptographic keys"
58 | end
59 | else
60 | kms_cache.kms_crypto_keys[location][keyring].each do |keyname|
61 | if google_kms_crypto_key_iam_policy(project: gcp_project_id, location: location, key_ring_name: keyring, crypto_key_name: keyname).bindings.nil?
62 | describe "[#{gcp_project_id}] key ring [#{keyring}] key [#{keyname}] does not have any IAM bindings. This test is Not Applicable." do
63 | skip "[#{gcp_project_id}] key ring [#{keyring}] key [#{keyname}] does not have any IAM bindings"
64 | end
65 | else
66 | impact 'medium'
67 | google_kms_crypto_key_iam_policy(project: gcp_project_id, location: location, key_ring_name: keyring, crypto_key_name: keyname).bindings.each do |binding|
68 | describe binding do
69 | its('members') { should_not include 'allUsers' }
70 | its('members') { should_not include 'allAuthenticatedUsers' }
71 | end
72 | end
73 | end
74 | end
75 | end
76 | end
77 | end
78 | end
79 | end
80 |
--------------------------------------------------------------------------------
/controls/1.10-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure Encryption keys are rotated within a period of 90 days'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.10'
21 | control_abbrev = 'iam'
22 | kms_rotation_period_seconds = input('kms_rotation_period_seconds')
23 |
24 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
25 | impact 'none'
26 |
27 | title "[#{control_abbrev.upcase}] Ensure Encryption keys are rotated within a period of 90 days"
28 |
29 | desc "Google Cloud Key Management Service (KMS) stores cryptographic keys in a hierarchical structure designed for useful and elegant access control management.
30 |
31 | Automatic cryptographic key rotation is only available for symmetric keys. Cloud KMS does not support automatic rotation of asymmetric keys so such keys are out of scope for this control. More information can be found in the GCP documentation references of this control.
32 |
33 | The format for the rotation schedule depends on the client library that is used. For the gcloud command-line tool, the next rotation time must be in ISO or RFC3339 format, and the rotation period must be in the form INTEGER[UNIT], where units can be one of seconds (s), minutes (m), hours (h) or days (d)."
34 |
35 | desc 'rationale', "Set a key rotation period and starting time. A key can be created with a specified rotation period, which is the time between when new key versions are generated automatically. A key can also be created with a specified next rotation time. A key is a named object representing a cryptographic key used for a specific purpose. The key material, the actual bits used for encryption, can change over time as new key versions are created.
36 |
37 | A key is used to protect some corpus of data. You could encrypt a collection of files with the same key, and people with decrypt permissions on that key would be able to decrypt those files. Hence it's necessary to make sure rotation period is set to specific time."
38 |
39 | tag cis_scored: true
40 | tag cis_level: 1
41 | tag cis_gcp: control_id.to_s
42 | tag cis_version: cis_version.to_s
43 | tag project: gcp_project_id.to_s
44 | tag nist: ['AC-2']
45 |
46 | ref 'CIS Benchmark', url: cis_url.to_s
47 | ref 'GCP Docs', url: 'https://cloud.google.com/kms/docs/key-rotation#frequency_of_key_rotation'
48 | ref 'GCP Docs', url: 'https://cloud.google.com/kms/docs/key-rotation#asymmetric'
49 |
50 | # Get all "normal" regions and add dual/multi regions
51 | locations = google_compute_regions(project: gcp_project_id).region_names
52 | locations << 'global' << 'asia' << 'europe' << 'us' << 'eur4' << 'nam4'
53 |
54 | kms_cache = KMSKeyCache(project: gcp_project_id, locations: locations)
55 |
56 | # Ensure KMS keys autorotate 90d or less
57 | locations.each do |location|
58 | if kms_cache.kms_key_ring_names[location].empty?
59 | describe "[#{gcp_project_id}] does not contain any key rings in [#{location}]. This test is Not Applicable." do
60 | skip "[#{gcp_project_id}] does not contain any key rings in [#{location}]"
61 | end
62 | else
63 | kms_cache.kms_key_ring_names[location].each do |keyring|
64 | if kms_cache.kms_crypto_keys[location][keyring].empty?
65 | describe "[#{gcp_project_id}] key ring [#{keyring}] does not contain any cryptographic keys. This test is Not Applicable." do
66 | skip "[#{gcp_project_id}] key ring [#{keyring}] does not contain any cryptographic keys"
67 | end
68 | else
69 | kms_cache.kms_crypto_keys[location][keyring].each do |keyname|
70 | key = google_kms_crypto_key(project: gcp_project_id, location: location, key_ring_name: keyring, name: keyname)
71 | next unless key.purpose == 'ENCRYPT_DECRYPT' && key.primary_state == 'ENABLED'
72 | impact 'medium'
73 | describe "[#{gcp_project_id}] #{key.crypto_key_name}" do
74 | subject { key }
75 | its('rotation_period') { should_not eq nil }
76 | unless key.rotation_period.nil?
77 | rotation_period_int = key.rotation_period.delete_suffix('s').to_i
78 | it "should have a lower or equal rotation period than #{kms_rotation_period_seconds}" do
79 | expect(rotation_period_int).to be <= kms_rotation_period_seconds
80 | end
81 | its('next_rotation_time') { should be <= (Time.now + kms_rotation_period_seconds) }
82 | end
83 | end
84 | end
85 | end
86 | end
87 | end
88 | end
89 | end
90 |
--------------------------------------------------------------------------------
/controls/1.11-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Separation of duties is enforced while assigning KMS related roles to users'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.11'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that Separation of duties is enforced while assigning KMS related roles to users"
27 |
28 | desc "It is recommended that the principle of 'Separation of Duties' is enforced while assigning KMS related roles to users."
29 |
30 | desc 'rationale', "Built-in/Predefined IAM role Cloud KMS Admin allows user/identity to create, delete, and manage service account(s). Built-in/Predefined IAM role Cloud KMS CryptoKey Encrypter/Decrypter allows user/identity (with adequate privileges on concerned resources) to encrypt and decrypt data at rest using encryption key(s). Built-in/Predefined IAM role Cloud KMS CryptoKey Encrypter allows user/identity (with adequate privileges on concerned resources) to encrypt data at rest using encryption key(s). Builtin/Predefined IAM role Cloud KMS CryptoKey Decrypter allows user/identity (with adequate privileges on concerned resources) to decrypt data at rest using encryption key(s).
31 |
32 | Separation of duties is the concept of ensuring that one individual does not have all necessary permissions to be able to complete a malicious action. In Cloud KMS, this could be an action such as using a key to access and decrypt data that that user should not normally have access to. Separation of duties is a business control typically used in larger organizations, meant to help avoid security or privacy incidents and errors. It is considered best practice.
33 |
34 | Any user(s) should not have Cloud KMS Admin and any of the Cloud KMS CryptoKey Encrypter/Decrypter, Cloud KMS CryptoKey Encrypter, Cloud KMS CryptoKey Decrypter roles assigned at a time."
35 |
36 | tag cis_scored: true
37 | tag cis_level: 2
38 | tag cis_gcp: control_id.to_s
39 | tag cis_version: cis_version.to_s
40 | tag project: gcp_project_id.to_s
41 | tag nist: %w[AC-2 AC-3 AC-6]
42 |
43 | ref 'CIS Benchmark', url: cis_url.to_s
44 | ref 'GCP Docs', url: 'https://cloud.google.com/kms/docs/separation-of-duties'
45 |
46 | kms_admins = google_project_iam_binding(project: gcp_project_id, role: 'roles/cloudkms.admin')
47 |
48 | if kms_admins.members.nil? || kms_admins.members.count.zero?
49 | impact 'none'
50 | describe "[#{gcp_project_id}] does not have users with roles/CloudKMSAdmin. This test is Not Applicable." do
51 | skip "[#{gcp_project_id}] does not have users with roles/CloudKMSAdmin"
52 | end
53 | else
54 | describe "[#{gcp_project_id}] roles/cloudkms.cryptoKeyEncrypter" do
55 | subject { google_project_iam_binding(project: gcp_project_id, role: 'roles/cloudkms.cryptoKeyEncrypter') }
56 | kms_admins.members.each do |kms_admin|
57 | its('members.to_s') { should_not match kms_admin }
58 | end
59 | end
60 | describe "[#{gcp_project_id}] roles/cloudkms.cryptoKeyDecrypter" do
61 | subject { google_project_iam_binding(project: gcp_project_id, role: 'roles/cloudkms.cryptoKeyDecrypter') }
62 | kms_admins.members.each do |kms_admin|
63 | its('members.to_s') { should_not match kms_admin }
64 | end
65 | end
66 | describe "[#{gcp_project_id}] roles/cloudkms.cryptoKeyEncrypterDecrypter" do
67 | subject { google_project_iam_binding(project: gcp_project_id, role: 'roles/cloudkms.cryptoKeyEncrypterDecrypter') }
68 | kms_admins.members.each do |kms_admin|
69 | its('members.to_s') { should_not match kms_admin }
70 | end
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/controls/1.12-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure API keys are not created for a project'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.12'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure API keys are not created for a project"
27 |
28 | desc 'Keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to use standard authentication flow instead.'
29 | desc 'rationale', "Security risks involved in using API-Keys are below:
30 |
31 | - API keys are a simple encrypted strings
32 | - API keys do not identify the user or the application making the API request
33 | - API keys are typically accessible to clients, making it easy to discover and steal an API key
34 |
35 | To avoid security risk by using API keys, it is recommended to use standard authentication
36 | flow instead."
37 |
38 | tag cis_scored: false
39 | tag cis_level: 2
40 | tag cis_gcp: control_id.to_s
41 | tag cis_version: cis_version.to_s
42 | tag project: gcp_project_id.to_s
43 | tag nist: ['AC-2']
44 |
45 | ref 'CIS Benchmark', url: cis_url.to_s
46 | ref 'GCP Docs', url: 'https://cloud.google.com/docs/authentication/api-keys'
47 |
48 | describe 'This control is not scored' do
49 | skip 'This control is not scored'
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/controls/1.13-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure API keys are restricted to use by only specified Hosts and Apps'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.13'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure API keys are restricted to use by only specified Hosts and Apps"
27 |
28 | desc 'Unrestricted keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API key usage only from trusted hosts, HTTP referrers and apps.'
29 | desc 'rationale', "Security risks involved in using API-Keys are below:
30 |
31 | - API keys are a simple encrypted strings
32 | - API keys do not identify the user or the application making the API request
33 | - API keys are typically accessible to clients, making it easy to discover and steal an API key
34 |
35 | Because of this Google recommend using the standard authentication flow instead. However, there are limited cases where API keys are more appropriate. For example, if there is a mobile application that needs to use the Google Cloud Translation API, but doesn't otherwise need a back-end server, API keys are the simplest way to authenticate to that API.
36 |
37 | In order to reduce attack vector, API-Keys can be restricted only to the trusted hosts, HTTP referrers and applications."
38 |
39 | tag cis_scored: false
40 | tag cis_level: 1
41 | tag cis_gcp: control_id.to_s
42 | tag cis_version: cis_version.to_s
43 | tag project: gcp_project_id.to_s
44 | tag nist: ['AC-2']
45 |
46 | ref 'CIS Benchmark', url: cis_url.to_s
47 | ref 'GCP Docs', url: 'https://cloud.google.com/docs/authentication/api-keys'
48 |
49 | describe 'This control is not scored' do
50 | skip 'This control is not scored'
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/controls/1.14-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure API keys are restricted to only APIs that application needs access'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.14'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure API keys are restricted to only APIs that application needs access"
27 |
28 | desc 'API keys are insecure because they can be viewed publicly, such as from within a browser, or they can be accessed on a device where the key resides. It is recommended to restrict API keys to use (call) only APIs required by an application.'
29 | desc 'rationale', "Security risks involved in using API-Keys are below:
30 |
31 | - API keys are a simple encrypted strings
32 | - API keys do not identify the user or the application making the API request
33 | - API keys are typically accessible to clients, making it easy to discover and steal an API key
34 |
35 | Because of this Google recommend using the standard authentication flow instead. However, there are limited cases where API keys are more appropriate. For example, if there is a mobile application that needs to use the Google Cloud Translation API, but doesn't otherwise need a back-end server, API keys are the simplest way to authenticate to that API.
36 |
37 | In order to reduce attack surface by providing least privileges, API-Keys can be
38 | restricted to use (call) only APIs required by an application."
39 |
40 | tag cis_scored: false
41 | tag cis_level: 1
42 | tag cis_gcp: control_id.to_s
43 | tag cis_version: cis_version.to_s
44 | tag project: gcp_project_id.to_s
45 | tag nist: ['AC-2']
46 |
47 | ref 'CIS Benchmark', url: cis_url.to_s
48 | ref 'GCP Docs', url: 'https://cloud.google.com/docs/authentication/api-keys'
49 | ref 'GCP Docs', url: 'https://cloud.google.com/apis/docs/overview'
50 |
51 | describe 'This control is not scored' do
52 | skip 'This control is not scored'
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/controls/1.15-iam.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure API keys are rotated every 90 days'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '1.15'
21 | control_abbrev = 'iam'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure API keys are rotated every 90 days"
27 |
28 | desc 'It is recommended to rotate API keys every 90 days.'
29 | desc 'rationale', "Security risks involved in using API-Keys are below:
30 |
31 | - API keys are a simple encrypted strings
32 | - API keys do not identify the user or the application making the API request
33 | - API keys are typically accessible to clients, making it easy to discover and steal an API key
34 |
35 | Because of this Google recommend using the standard authentication flow instead. However, there are limited cases where API keys are more appropriate. For example, if there is a mobile application that needs to use the Google Cloud Translation API, but doesn't otherwise need a backend server, API keys are the simplest way to authenticate to that API.
36 |
37 | Once the key is stolen, it has no expiration, so it may be used indefinitely, unless the project owner revokes or regenerates the key. Rotating API keys will reduce the window of opportunity for an access key that is associated with a compromised or terminated account to be used. API keys should be rotated to ensure that data cannot be accessed with an old key which might have been lost, cracked, or stolen."
38 |
39 | tag cis_scored: false
40 | tag cis_level: 1
41 | tag cis_gcp: control_id.to_s
42 | tag cis_version: cis_version.to_s
43 | tag project: gcp_project_id.to_s
44 | tag nist: ['AC-2']
45 |
46 | ref 'CIS Benchmark', url: cis_url.to_s
47 |
48 | describe 'This control is not scored' do
49 | skip 'This control is not scored'
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/controls/2.01-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Cloud Audit Logging is configured properly across all services and all users from a project '
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.1'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that Cloud Audit Logging is configured properly across all services and a
27 | ll users from a project "
28 |
29 | desc "It is recommended that Cloud Audit Logging is configured to track all Admin activities and
30 | read, write access to user data."
31 | desc 'rationale', "Cloud Audit Logging maintains two audit logs for each project and organization: Admin Activity
32 | nd Data Access.
33 |
34 | 1. Admin Activity logs contain log entries for API calls or other administrative actions that modify the configurati
35 | n or metadata of resources. Admin Activity audit logs are enabled for all services and cannot be configured.
36 | 2. Data Access audit logs record API calls that create, modify, or read user-provided data. These are disabled by de
37 | ault and should be enabled. There are three kinds of Data Access audit log information:
38 | - Admin read: Records operations that read metadata or configuration information. Admin Activity audit logs recor
39 | writes of metadata and configuration information which cannot be disabled.
40 | - Data read: Records operations that read user-provided data.
41 | - Data write: Records operations that write user-provided data.
42 |
43 | It is recommended to have effective default audit config configured in such a way that:
44 | 1. logtype is set to DATA_READ (to logs user activity tracking) and DATA_WRITES (to log changes/tampering to user data)
45 | 2. audit config is enabled for all the services supported by Data Access audit logs feature
46 | 3. Logs should be captured for all users. i.e. there are no exempted users in any of the audit config section. This will ensure overriding audit config will not contradict the requirement."
47 |
48 | tag cis_scored: true
49 | tag cis_level: 1
50 | tag cis_gcp: control_id.to_s
51 | tag cis_version: cis_version.to_s
52 | tag project: gcp_project_id.to_s
53 | tag nist: %w[AU-6 AU-12]
54 |
55 | ref 'CIS Benchmark', url: cis_url.to_s
56 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/audit/'
57 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/audit/configure-data-access'
58 |
59 | describe google_project_logging_audit_config(project: gcp_project_id) do
60 | its('default_types') { should include 'DATA_READ' }
61 | its('default_types') { should include 'DATA_WRITE' }
62 | it { should_not have_default_exempted_members }
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/controls/2.02-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that sinks are configured for all Log entries'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.2'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that sinks are configured for all Log entries"
27 |
28 | desc 'It is recommended to create sink which will export copies of all the log entries.'
29 | desc 'rationale', 'Log entries are held in Stackdriver Logging for a limited time known as the retention period. After that, the entries are deleted. To keep log entries longer, sink can export them outside of Stackdriver Logging. Exporting involves writing a filter that selects the log entries to export, and choosing a destination in Cloud Storage, BigQuery, or Cloud Pub/Sub. The filter and destination are held in an object called a sink. To ensure all log entries are exported using sink ensure that there is no filter configured for a sink. Sinks can be created in projects, organizations, folders, and billing accounts.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[AU-4 AU-12]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/quotas'
41 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/export/'
42 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/export/using_exported_logs'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/export/configure_export_v2'
44 |
45 | empty_filter_sinks = []
46 | google_logging_project_sinks(project: gcp_project_id).names.each do |sink_name|
47 | empty_filter_sinks.push(sink_name) if google_logging_project_sink(project: gcp_project_id,
48 | name: sink_name).filter.nil?
49 | end
50 | describe "[#{gcp_project_id}] Project level Log sink with an empty filter" do
51 | subject { empty_filter_sinks }
52 | it 'is expected to exist' do
53 | expect(empty_filter_sinks.count).to be_positive
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/controls/2.03-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that retention policies on log buckets are configured using Bucket Lock'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.3'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that retention policies on log buckets are configured using Bucket Lock"
27 |
28 | desc 'It is recommended to set up retention policies and configure Bucket Lock on all storage buckets that are used as log sinks.'
29 | desc 'rationale', "Logs can be exported by creating one or more sinks that include a log filter and a destination. As Stackdriver Logging receives new log entries, they are compared against each sink. If a log entry matches a sink's filter, then a copy of the log entry is written to the destination.
30 |
31 | Sinks can be configured to export logs in storage buckets. It is recommended to configure a data retention policy for these cloud storage buckets and to lock the data retention policy; thus permanently preventing the policy from being reduced or removed. This way, if the system is ever compromised by an attacker or a malicious insider who wants to cover their tracks, the activity logs are definitely preserved for forensics and security investigations."
32 |
33 | tag cis_scored: true
34 | tag cis_level: 1
35 | tag cis_gcp: control_id.to_s
36 | tag cis_version: cis_version.to_s
37 | tag project: gcp_project_id.to_s
38 | tag nist: ['AU-6']
39 |
40 | ref 'CIS Benchmark', url: cis_url.to_s
41 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/bucket-lock'
42 |
43 | if google_logging_project_sinks(project: gcp_project_id).where(destination: /storage.googleapis.com/).destinations.empty?
44 | describe "[#{gcp_project_id}] does not have logging sinks configured." do
45 | subject { google_logging_project_sinks(project: gcp_project_id).where(destination: /storage.googleapis.com/).destinations }
46 | it { should_not be_empty }
47 | end
48 | else
49 | google_logging_project_sinks(project: gcp_project_id).where(destination: /storage.googleapis.com/).destinations.each do |sink|
50 | bucket = sink.split('/').last
51 | describe "[#{gcp_project_id}] Logging bucket #{bucket} retention policy Bucket Lock status" do
52 | subject { google_storage_bucket(name: bucket).retention_policy }
53 | its('is_locked') { should be true }
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/controls/2.04-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure log metric filter and alerts exists for Project Ownership assignments/changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.4'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for Project Ownership assignments/changes"
27 |
28 | desc "In order to prevent unnecessarily project ownership assignments to users/serviceaccounts and further misuses of project and resources, all roles/Owner assignments should be monitored.
29 |
30 | Members (users/Service-Accounts) with role assignment to primitive role roles/owner are Project Owners.
31 |
32 | Project Owner has all the privileges on a project it belongs to. These can be summarized as below:
33 |
34 | - All viewer permissions on All GCP Services part within the project
35 | - Permissions for actions that modify state of All GCP Services within the
36 | project
37 | - Manage roles and permissions for a project and all resources within the
38 | project
39 | - Set up billing for a project
40 |
41 | Granting owner role to a member (user/Service-Account) will allow members to modify the IAM policy. Therefore grant the owner role only if the member has a legitimate purpose to manage the IAM policy. This is because as project IAM policy contains sensitive access control data and having a minimal set of users manage it will simplify any auditing that you may have to do."
42 | desc 'rationale', "Project Ownership Having highest level of privileges on a project, to avoid misuse of project resources project ownership assignment/change actions mentioned should be monitored and alerted to concerned recipients.
43 |
44 | - Sending project ownership Invites
45 | - Acceptance/Rejection of project ownership invite by user
46 | - Adding `role\owner` to a user/service-account
47 | - Removing a user/Service account from `role\owner`"
48 |
49 | tag cis_scored: true
50 | tag cis_level: 1
51 | tag cis_gcp: control_id.to_s
52 | tag cis_version: cis_version.to_s
53 | tag project: gcp_project_id.to_s
54 | tag nist: ['AU-12']
55 |
56 | ref 'CIS Benchmark', url: cis_url.to_s
57 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
58 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
59 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
60 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
61 |
62 | log_filter = 'resource.type=audited_resource AND (protoPayload.serviceName="cloudresourcemanager.googleapis.com") AND (ProjectOwnership OR projectOwnerInvitee) OR (protoPayload.serviceData.policyDelta.bindingDeltas.action="REMOVE" AND protoPayload.serviceData.policyDelta.bindingDeltas.role="roles/owner") OR (protoPayload.serviceData.policyDelta.bindingDeltas.action="ADD" AND protoPayload.serviceData.policyDelta.bindingDeltas.role="roles/owner")'
63 | describe "[#{gcp_project_id}] Project Ownership changes filter" do
64 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
65 | it { should exist }
66 | end
67 |
68 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
69 | describe.one do
70 | filter = "metric.type=\"#{metrictype}\" resource.type=\"audited_resource\""
71 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
72 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
73 | describe "[#{gcp_project_id}] Project Ownership changes alert policy" do
74 | subject { condition }
75 | it { should exist }
76 | end
77 | end
78 | end
79 | end
80 | end
81 |
--------------------------------------------------------------------------------
/controls/2.05-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure log metric filter and alerts exists for Audit Configuration Changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.5'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for Audit Configuration Changes"
27 |
28 | desc "Google Cloud Platform services write audit log entries to Admin Activity and Data Access logs to helps answer the questions of 'who did what, where, and when?' within Google Cloud Platform projects. Cloud Audit logging records information includes the identity of the API caller, the time of the API call, the source IP address of the API caller, the request parameters, and the response elements returned by the GCP services. Cloud Audit logging provides a history of AWS API calls for an account, including API calls made via the Console, SDKs, command line tools, and other GCP services."
29 | desc 'rationale', 'Admin activity and Data access logs produced by Cloud audit logging enables security analysis, resource change tracking, and compliance auditing. Configuring metric filter and alerts for Audit Configuration Changes ensures recommended state of audit configuration and hence, all the activities in project are audit-able at any point in time.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[AU-3 AU-12]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
41 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
42 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/audit/configure-data-access#getiampolicy-setiampolicy'
44 |
45 | log_filter = 'resource.type=audited_resource AND protoPayload.methodName="SetIamPolicy" AND protoPayload.serviceData.policyDelta.auditConfigDeltas:*'
46 | describe "[#{gcp_project_id}] Audit configuration changes filter" do
47 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
48 | it { should exist }
49 | end
50 |
51 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
52 | describe.one do
53 | filter = "metric.type=\"#{metrictype}\" resource.type=\"audited_resource\""
54 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
55 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
56 | describe "[#{gcp_project_id}] Audit configuration changes alert policy" do
57 | subject { condition }
58 | it { should exist }
59 | end
60 | end
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/controls/2.06-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure log metric filter and alerts exists for Custom Role changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.6'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for Custom Role changes"
27 |
28 | desc 'It is recommended that a metric filter and alarm be established for changes IAM Role creation, deletion and updating activities.'
29 | desc 'rationale', 'Google Cloud Identity and Access Management (Cloud IAM) provides predefined roles that give granular access to specific Google Cloud Platform resources and prevent unwanted access to other resources. However to cater organization specific needs, Cloud IAM also provides ability to create custom roles. Project Owner and administrators with Organization Role Administrator role or the IAM Role Administrator role can create custom roles. Monitoring role creation, deletion and updating activities will help in identifying over-privileged role at early stages.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[AU-3 AU-12]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
41 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
42 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/iam/docs/understanding-custom-roles'
44 |
45 | log_filter = 'resource.type=audited_resource AND protoPayload.methodName="google.iam.admin.v1.CreateRole" OR protoPayload.methodName="google.iam.admin.v1.DeleteRole" OR protoPayload.methodName="google.iam.admin.v1.UpdateRole"'
46 | describe "[#{gcp_project_id}] Custom Role changes filter" do
47 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
48 | it { should exist }
49 | end
50 |
51 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
52 | describe.one do
53 | filter = "metric.type=\"#{metrictype}\" resource.type=\"audited_resource\""
54 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
55 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
56 | describe "[#{gcp_project_id}] Custom Role changes alert policy" do
57 | subject { condition }
58 | it { should exist }
59 | end
60 | end
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/controls/2.07-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure log metric filter and alerts exists for VPC Network Firewall rule changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.7'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for VPC Network Firewall rule changes"
27 |
28 | desc 'It is recommended that a metric filter and alarm be established for VPC Network Firewall rule changes.'
29 | desc 'rationale', 'Monitoring for Create or Update firewall rule events gives insight network access changes and may reduce the time it takes to detect suspicious activity.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[AU-3 AU-12]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
41 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
42 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/vpc/docs/firewalls'
44 |
45 | log_filter = 'resource.type=global AND jsonPayload.event_subtype="compute.firewalls.patch" OR jsonPayload.event_subtype="compute.firewalls.insert"'
46 | describe "[#{gcp_project_id}] VPC FW Rule changes filter" do
47 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
48 | it { should exist }
49 | end
50 |
51 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
52 | describe.one do
53 | filter = "metric.type=\"#{metrictype}\" resource.type=\"global\""
54 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
55 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
56 | describe "[#{gcp_project_id}] VPC FW Rule changes alert policy" do
57 | subject { condition }
58 | it { should exist }
59 | end
60 | end
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/controls/2.08-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure log metric filter and alerts exists for VPC network route changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.8'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for VPC network route changes "
27 |
28 | desc 'It is recommended that a metric filter and alarm be established for VPC network route changes.'
29 | desc 'rationale', "Google Cloud Platform (GCP) routes define the paths network traffic takes from a VM instance to another destinations. The other destination can be inside your VPC network (such as another VM) or outside of it. Every route consists of a destination and a next hop. Traffic whose destination IP is within the destination range is sent to the next hop for delivery.
30 |
31 | Monitoring changes to route tables will help ensure that all VPC traffic flows through an expected path."
32 |
33 | tag cis_scored: true
34 | tag cis_level: 1
35 | tag cis_gcp: control_id.to_s
36 | tag cis_version: cis_version.to_s
37 | tag project: gcp_project_id.to_s
38 | tag nist: %w[AU-3 AU-12]
39 |
40 | ref 'CIS Benchmark', url: cis_url.to_s
41 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
42 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
44 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
45 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/access-control/iam'
46 |
47 | log_filter = 'resource.type=global AND jsonPayload.event_subtype="compute.routes.delete" OR jsonPayload.event_subtype="compute.routes.insert"'
48 | describe "[#{gcp_project_id}] VPC Route changes filter" do
49 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
50 | it { should exist }
51 | end
52 |
53 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
54 | describe.one do
55 | filter = "metric.type=\"#{metrictype}\" resource.type=\"global\""
56 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
57 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
58 | describe "[#{gcp_project_id}] VPC Route changes alert policy" do
59 | subject { condition }
60 | it { should exist }
61 | end
62 | end
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/controls/2.09-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure log metric filter and alerts exists for VPC network changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.9'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for VPC network changes "
27 |
28 | desc 'It is recommended that a metric filter and alarm be established for VPC network changes.'
29 | desc 'rationale', "It is possible to have more than 1 VPC within an project, in addition it is also possible to create a peer connection between 2 VPCs enabling network traffic to route between VPCs.
30 |
31 | Monitoring changes to VPC will help ensure VPC traffic flow is not getting impacted."
32 |
33 | tag cis_scored: true
34 | tag cis_level: 1
35 | tag cis_gcp: control_id.to_s
36 | tag cis_version: cis_version.to_s
37 | tag project: gcp_project_id.to_s
38 | tag nist: %w[AU-3 AU-12]
39 |
40 | ref 'CIS Benchmark', url: cis_url.to_s
41 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
42 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
44 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
45 | ref 'GCP Docs', url: 'https://cloud.google.com/vpc/docs/overview'
46 |
47 | log_filter = 'resource.type=audited_resource AND jsonPayload.event_subtype="compute.networks.insert" OR jsonPayload.event_subtype="compute.networks.patch" OR jsonPayload.event_subtype="compute.networks.delete" OR jsonPayload.event_subtype="compute.networks.removePeering" OR jsonPayload.event_subtype="compute.networks.addPeering"'
48 | describe "[#{gcp_project_id}] VPC Network changes filter" do
49 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
50 | it { should exist }
51 | end
52 |
53 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
54 | describe.one do
55 | filter = "metric.type=\"#{metrictype}\" resource.type=\"audited_resource\""
56 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
57 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
58 | describe "[#{gcp_project_id}] VPC Network changes alert policy" do
59 | subject { condition }
60 | it { should exist }
61 | end
62 | end
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/controls/2.10-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure log metric filter and alerts exists for Cloud Storage IAM permission changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.10'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for Cloud Storage IAM permission changes"
27 |
28 | desc 'It is recommended that a metric filter and alarm be established for Cloud Storage Bucket IAM changes.'
29 | desc 'rationale', 'Monitoring changes to Cloud Storage bucket permissions may reduce time to detect and correct permissions on sensitive Cloud Storage bucket and objects inside the bucket.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[AU-3 AU-12]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
41 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
42 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/overview'
44 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/access-control/iam-roles'
45 |
46 | log_filter = 'resource.type=gcs_bucket AND protoPayload.methodName="storage.setIamPermissions"'
47 | describe "[#{gcp_project_id}] Cloud Storage changes filter" do
48 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
49 | it { should exist }
50 | end
51 |
52 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
53 | describe.one do
54 | filter = "metric.type=\"#{metrictype}\" resource.type=\"gcs_bucket\""
55 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
56 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
57 | describe "[#{gcp_project_id}] Cloud Storage changes alert policy" do
58 | subject { condition }
59 | it { should exist }
60 | end
61 | end
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/controls/2.11-logging.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title ' Ensure log metric filter and alerts exists for SQL instance configuration changes'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '2.11'
21 | control_abbrev = 'logging'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure log metric filter and alerts exists for SQL instance configuration changes"
27 |
28 | desc 'It is recommended that a metric filter and alarm be established for SQL Instance configuration changes.'
29 | desc 'rationale', "Monitoring changes to Sql Instance configuration changes may reduce time to detect and correct misconfigurations done on sql server.
30 |
31 | Below are the few of configurable Options which may impact security posture of a SQL Instance:
32 |
33 | - Enable auto backups and high availability: Misconfiguration may adversely impact Business continuity, Disaster Recovery and High Availability
34 | - Authorize networks : Misconfiguration may increase exposure to the untrusted networks"
35 |
36 | tag cis_scored: true
37 | tag cis_level: 1
38 | tag cis_gcp: control_id.to_s
39 | tag cis_version: cis_version.to_s
40 | tag project: gcp_project_id.to_s
41 | tag nist: %w[AU-3 AU-12]
42 |
43 | ref 'CIS Benchmark', url: cis_url.to_s
44 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/logs-based-metrics/'
45 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/custom-metrics/'
46 | ref 'GCP Docs', url: 'https://cloud.google.com/monitoring/alerts/'
47 | ref 'GCP Docs', url: 'https://cloud.google.com/logging/docs/reference/tools/gcloud-logging'
48 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/overview'
49 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/'
50 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/'
51 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/postgres/'
52 |
53 | log_filter = 'resource.type=audited_resource AND protoPayload.methodName="cloudsql.instances.update"'
54 | describe "[#{gcp_project_id}] Cloud SQL changes filter" do
55 | subject { google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter) }
56 | it { should exist }
57 | end
58 |
59 | google_project_metrics(project: gcp_project_id).where(metric_filter: log_filter).metric_types.each do |metrictype|
60 | describe.one do
61 | filter = "metric.type=\"#{metrictype}\" resource.type=\"audited_resource\""
62 | google_project_alert_policies(project: gcp_project_id).where(policy_enabled_state: true).policy_names.each do |policy|
63 | condition = google_project_alert_policy_condition(policy: policy, filter: filter)
64 | describe "[#{gcp_project_id}] Cloud SQL changes alert policy" do
65 | subject { condition }
66 | it { should exist }
67 | end
68 | end
69 | end
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/controls/3.01-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure the default network does not exist in a project'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.1'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure the default network does not exist in a project"
27 |
28 | desc 'To prevent use of default network, a project should not have a default network.'
29 | desc 'rationale', 'The default network has automatically created firewall rules and has pre-fabricated network configuration. Based on your security and networking requirements, you should create your network and delete the default network.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 2
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: ['CM-6']
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/networking#firewall_rules'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/reference/latest/networks/insert'
41 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/reference/latest/networks/delete'
42 |
43 | describe "[#{gcp_project_id}] Subnets" do
44 | subject { google_compute_networks(project: gcp_project_id) }
45 | its('network_names') { should_not include 'default' }
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/controls/3.02-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure legacy networks do not exists for a project'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.2'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure legacy networks does not exists for a project"
27 |
28 | desc 'In order to prevent use of legacy networks, a project should not have a legacy network configured.'
29 | desc 'rationale', 'Legacy networks have a single network IPv4 prefix range and a single gateway IP address for the whole network. The network is global in scope and spans all cloud regions. You cannot create subnetworks in a legacy network or switch from legacy to auto or custom subnet networks. Legacy networks can thus have an impact for high network traffic projects and subject to the single point of contention or failure.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: ['CM-6']
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/networking#creating_a_legacy_network'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/networking#legacy_non-subnet_network'
41 |
42 | network_names = google_compute_networks(project: gcp_project_id).network_names
43 |
44 | if network_names.empty?
45 | describe "[#{gcp_project_id}] does not have any networks. This test is Not Applicable." do
46 | skip "[#{gcp_project_id}] does not have any networks."
47 | end
48 | else
49 | google_compute_networks(project: gcp_project_id).network_names.each do |network|
50 | describe "[#{gcp_project_id}] Network [#{network}] " do
51 | subject { google_compute_network(project: gcp_project_id, name: network) }
52 | it { should_not be_legacy }
53 | end
54 | end
55 | end
56 | end
57 |
--------------------------------------------------------------------------------
/controls/3.03-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that DNSSEC is enabled for Cloud DNS'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.3'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that DNSSEC is enabled for Cloud DNS"
27 |
28 | desc 'Cloud DNS is a fast, reliable and cost-effective Domain Name System that powers millions of domains on the internet. DNSSEC in Cloud DNS enables domain owners to take easy steps to protect their domains against DNS hijacking and man-in-the-middle and other attacks.'
29 | desc 'rationale', 'Domain Name System Security Extensions (DNSSEC) adds security to the Domain Name System (DNS) protocol by enabling DNS responses to be validated. Having a trustworthy Domain Name System (DNS) that translates a domain name like www.example.com into its associated IP address is an increasingly important building block of today’s web-based applications. Attackers can hijack this process of domain/IP lookup and redirect users to a malicious site through DNS hijacking and man-in-the-middle attacks. DNSSEC helps mitigate the risk of such attacks by cryptographically signing DNS records. As a result, it prevents attackers from issuing fake DNS responses that may misdirect browsers to nefarious websites.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: ['CM-6']
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloudplatform.googleblog.com/2017/11/DNSSEC-now-available-in-Cloud-DNS.html'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/dns/dnssec-config#enabling'
41 | ref 'GCP Docs', url: 'https://cloud.google.com/dns/dnssec'
42 |
43 | managed_zone_names = google_dns_managed_zones(project: gcp_project_id).where(visibility: 'public').zone_names
44 | if managed_zone_names.empty?
45 | impact 'none'
46 | describe "[#{gcp_project_id}] does not have DNS Zones with Public visibility. This test is Not Applicable." do
47 | skip "[#{gcp_project_id}] does not have DNS Zones with Public visibility."
48 | end
49 | else
50 | managed_zone_names.each do |dnszone|
51 | describe "[#{gcp_project_id}] DNS Zone [#{dnszone}] with DNSSEC" do
52 | subject { google_dns_managed_zone(project: gcp_project_id, zone: dnszone) }
53 | its('dnssec_config.state') { should cmp 'on' }
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/controls/3.04-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that RSASHA1 is not used for key-signing key in Cloud DNS DNSSEC'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.4'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'none'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that RSASHA1 is not used for key-signing key in Cloud DNS DNSSEC"
27 |
28 | desc 'DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be recommended one and it should not be weak.'
29 | desc 'rationale', 'DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zonesigning (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be recommended one and it should not be weak.
30 |
31 | When enabling DNSSEC for a managed zone, or creating a managed zone with DNSSEC, you can select the DNSSEC signing algorithms and the denial-of-existence type. Changing the DNSSEC settings is only effective for a managed zone if DNSSEC is not already enabled. If you need to change the settings for a managed zone where it has been enabled, you can turn DNSSEC off and then re-enable it with different settings.'
32 |
33 | tag cis_scored: false
34 | tag cis_level: 1
35 | tag cis_gcp: control_id.to_s
36 | tag cis_version: cis_version.to_s
37 | tag project: gcp_project_id.to_s
38 | tag nist: ['CM-6']
39 |
40 | ref 'CIS Benchmark', url: cis_url.to_s
41 | ref 'GCP Docs', url: 'https://cloud.google.com/dns/dnssec-advanced#advanced_signing_options'
42 |
43 | managed_zone_names = google_dns_managed_zones(project: gcp_project_id).zone_names
44 |
45 | if managed_zone_names.empty?
46 | describe "[#{gcp_project_id}] does not have DNS Zones. This test is Not Applicable." do
47 | skip "[#{gcp_project_id}] does not have DNS Zones."
48 | end
49 | else
50 | managed_zone_names.each do |dnszone|
51 | zone = google_dns_managed_zone(project: gcp_project_id, zone: dnszone)
52 | if zone.visibility == 'private'
53 | describe "[#{gcp_project_id}] DNS zone #{dnszone} has private visibility. This test is not applicable for private zones." do
54 | skip "[#{gcp_project_id}] DNS zone #{dnszone} has private visibility."
55 | end
56 | elsif zone.dnssec_config.state == 'on'
57 | zone.dnssec_config.default_key_specs.select { |spec| spec.key_type == 'keySigning' }.each do |spec|
58 | impact 'medium'
59 | describe "[#{gcp_project_id}] DNS Zone [#{dnszone}] with DNSSEC key-signing" do
60 | subject { spec }
61 | its('algorithm') { should_not cmp 'RSASHA1' }
62 | its('algorithm') { should_not cmp nil }
63 | end
64 | end
65 | else
66 | impact 'medium'
67 | describe "[#{gcp_project_id}] DNS Zone [#{dnszone}] DNSSEC" do
68 | subject { 'off' }
69 | it { should cmp 'on' }
70 | end
71 | end
72 | end
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/controls/3.05-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that RSASHA1 is not used for zone-signing key in Cloud DNS DNSSEC'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.5'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'none'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that RSASHA1 is not used for zone-signing key in Cloud DNS DNSSEC"
27 |
28 | desc 'DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zone signing (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms. The algorithm used for key signing should be recommended one and it should not be weak.'
29 | desc 'rationale', "DNSSEC algorithm numbers in this registry may be used in CERT RRs. Zonesigning (DNSSEC) and transaction security mechanisms (SIG(0) and TSIG) make use of particular subsets of these algorithms.
30 |
31 | The algorithm used for key signing should be recommended one and it should not be weak. When enabling DNSSEC for a managed zone, or creating a managed zone with DNSSEC, you can select the DNSSEC signing algorithms and the denial-of-existence type. Changing the DNSSEC settings is only effective for a managed zone if DNSSEC is not already enabled. If you need to change the settings for a managed zone where it has been enabled, you can turn DNSSEC off and then re-enable it with different settings."
32 |
33 | tag cis_scored: false
34 | tag cis_level: 1
35 | tag cis_gcp: control_id.to_s
36 | tag cis_version: cis_version.to_s
37 | tag project: gcp_project_id.to_s
38 | tag nist: ['CM-6']
39 |
40 | ref 'CIS Benchmark', url: cis_url.to_s
41 | ref 'GCP Docs', url: 'https://cloud.google.com/dns/dnssec-advanced#advanced_signing_options'
42 |
43 | managed_zone_names = google_dns_managed_zones(project: gcp_project_id).zone_names
44 |
45 | if managed_zone_names.empty?
46 | describe "[#{gcp_project_id}] does not have DNS Zones. This test is Not Applicable." do
47 | skip "[#{gcp_project_id}] does not have DNS Zones."
48 | end
49 | else
50 | managed_zone_names.each do |dnszone|
51 | zone = google_dns_managed_zone(project: gcp_project_id, zone: dnszone)
52 | if zone.visibility == 'private'
53 | describe "[#{gcp_project_id}] DNS zone #{dnszone} has private visibility. This test is not applicable for private zones." do
54 | skip "[#{gcp_project_id}] DNS zone #{dnszone} has private visibility."
55 | end
56 | elsif zone.dnssec_config.state == 'on'
57 | zone.dnssec_config.default_key_specs.select { |spec| spec.key_type == 'zoneSigning' }.each do |spec|
58 | impact 'medium'
59 | describe "[#{gcp_project_id}] DNS Zone [#{dnszone}] with DNSSEC zone-signing" do
60 | subject { spec }
61 | its('algorithm') { should_not cmp 'RSASHA1' }
62 | its('algorithm') { should_not cmp nil }
63 | end
64 | end
65 | else
66 | impact 'medium'
67 | describe "[#{gcp_project_id}] DNS Zone [#{dnszone}] DNSSEC" do
68 | subject { 'off' }
69 | it { should cmp 'on' }
70 | end
71 | end
72 | end
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/controls/3.06-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that SSH access is restricted from the internet'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.6'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'high'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that SSH access is restricted from the internet"
27 |
28 | desc 'GCP Firewall Rules are specific to a VPC Network. Each rule either allows or denies traffic when its conditions are met. Its conditions allow you to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances. Firewall rules are defined at the VPC network level, and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, you can only use an IPv4 address or IPv4 block in CIDR notation. Generic (0.0.0.0/0) incoming traffic from internet to VPC or VM instance using SSH on Port 22 can be avoided.'
29 | desc 'rationale', 'GCP Firewall Rules within a VPC Network. These rules apply to outgoing (egress) traffic from instances and incoming (ingress) traffic to instances in the network. Egress and ingress traffic are controlled even if the traffic stays within the network (for example, instance-to-instance communication). For an instance to have outgoing Internet access, the network must have a valid Internet gateway route or custom route whose destination IP is specified. This route simply defines the path to the Internet, to avoid the most general (0.0.0.0/0) destination IP Range specified from Internet through SSH with default Port 22. We need to restrict generic access from Internet to specific IP Range.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 2
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[CM-7 CA-3 SC-7]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/vpc/docs/firewalls#blockedtraffic'
40 |
41 | google_compute_firewalls(project: gcp_project_id).where(firewall_direction: 'INGRESS').firewall_names.each do |firewall_name|
42 | describe "[#{gcp_project_id}] #{firewall_name}" do
43 | subject { google_compute_firewall(project: gcp_project_id, name: firewall_name) }
44 | it 'should not allow SSH from 0.0.0.0/0' do
45 | expect(subject.allowed_ssh? && (subject.allow_ip_ranges? ['0.0.0.0/0'])).to be false
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/controls/3.07-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that RDP access is restricted from the internet'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.7'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'high'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that RDP access is restricted from the internet"
27 |
28 | desc 'GCP Firewall Rules are specific to a VPC Network. Each rule either allows or denies traffic when its conditions are met. Its conditions allow you to specify the type of traffic, such as ports and protocols, and the source or destination of the traffic, including IP addresses, subnets, and instances. Firewall rules are defined at the VPC network level, and are specific to the network in which they are defined. The rules themselves cannot be shared among networks. Firewall rules only support IPv4 traffic. When specifying a source for an ingress rule or a destination for an egress rule by address, you can only use an IPv4 address or IPv4 block in CIDR notation. Generic (0.0.0.0/0) incoming traffic from internet to VPC or VM instance using RDP on Port 3389 can be avoided.'
29 | desc 'rationale', 'GCP Firewall Rules within a VPC Network. These rules apply to outgoing (egress) traffic from instances and incoming (ingress) traffic to instances in the network. Egress and ingress traffic are controlled even if the traffic stays within the network (for example, instance-to-instance communication). For an instance to have outgoing Internet access, the network must have a valid Internet gateway route or custom route whose destination IP is specified. This route simply defines the path to the Internet, to avoid the most general (0.0.0.0/0) destination IP Range specified from Internet through RDP with default Port 3389. We need to restrict generic access from Internet to specific IP Range.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 2
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[CM-7 CA-3 SC-7]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/vpc/docs/firewalls#blockedtraffic'
40 |
41 | google_compute_firewalls(project: gcp_project_id).where(firewall_direction: 'INGRESS').firewall_names.each do |firewall_name|
42 | describe "[#{gcp_project_id}] #{firewall_name}" do
43 | subject { google_compute_firewall(project: gcp_project_id, name: firewall_name) }
44 | it 'Should not allow RDP from 0.0.0.0/0' do
45 | expect(subject.allowed_rdp? && (subject.allow_ip_ranges? ['0.0.0.0/0'])).to be false
46 | end
47 | end
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/controls/3.08-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure VPC Flow logs is enabled for every subnet in VPC Network'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '3.8'
21 | control_abbrev = 'networking'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'low'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure VPC Flow logs is enabled for every subnet in VPC Network"
27 |
28 | desc "Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC Subnets. After you've created a flow log, you can view and retrieve its data in Stackdriver Logging. It is recommended that Flow Logs be enabled for every business critical VPC subnet."
29 | desc 'rationale', "VPC networks and subnetworks provide logically isolated and secure network partitions where you can launch GCP resources. When Flow Logs is enabled for a subnet, VMs within subnet starts reporting on all TCP and UDP flows. Each VM samples the TCP and UDP flows it sees, inbound and outbound, whether the flow is to or from another VM, a host in your on-premises datacenter, a Google service, or a host on the Internet. If two GCP VMs are communicating, and both are in subnets that have VPC Flow Logs enabled, both VMs report the flows.
30 |
31 | Flow Logs supports following use cases:
32 |
33 | - Network monitoring
34 | - Understanding network usage and optimizing network traffic expenses
35 | - Network forensics
36 | - Real-time security analysis
37 |
38 | Flow Logs provide visibility into network traffic for each VM inside the subnet and can be used to detect anomalous traffic or insight during security workflows."
39 |
40 | tag cis_scored: true
41 | tag cis_level: 1
42 | tag cis_gcp: control_id.to_s
43 | tag cis_version: cis_version.to_s
44 | tag project: gcp_project_id.to_s
45 | tag nist: %w[AU-12 SI-4]
46 |
47 | ref 'CIS Benchmark', url: cis_url.to_s
48 | ref 'GCP Docs', url: 'https://cloud.google.com/vpc/docs/using-flow-logs#enabling_vpc_flow_logging'
49 | ref 'GCP Docs', url: 'https://cloud.google.com/vpc/'
50 |
51 | google_compute_regions(project: gcp_project_id).region_names.each do |region|
52 | google_compute_subnetworks(project: gcp_project_id, region: region).subnetwork_names.each do |subnet|
53 | subnet_obj = google_compute_subnetwork(project: gcp_project_id, region: region, name: subnet)
54 | if subnet_obj.purpose == 'INTERNAL_HTTPS_LOAD_BALANCER' # filter subnets for internal HTTPs Load Balancing
55 | describe "[#{gcp_project_id} #{region}/#{subnet}] does not support VPC Flow Logs. This test is Not Applicable." do
56 | skip "[#{gcp_project_id} #{region}/#{subnet}] does not support VPC Flow Logs."
57 | end
58 | else
59 | describe "[#{gcp_project_id}] #{region}/#{subnet}" do
60 | subject { subnet_obj }
61 | if subnet_obj.methods.include?(:log_config) == true
62 | it 'should have logging enabled' do
63 | expect(subnet_obj.log_config.enable).to be true
64 | end
65 | end
66 | end
67 | end
68 | end
69 | end
70 | end
71 |
--------------------------------------------------------------------------------
/controls/3.09-networking.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure no HTTPS or SSL proxy load balancers permit SSL policies with
16 | weak cipher suites'
17 |
18 | gcp_project_id = input('gcp_project_id')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '3.9'
22 | control_abbrev = 'networking'
23 |
24 | gcp_https_proxies = google_compute_target_https_proxies(project: gcp_project_id).names
25 | gcp_ssl_policies = google_compute_ssl_policies(project: gcp_project_id).names
26 |
27 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
28 | impact 'low'
29 |
30 | title "[#{control_abbrev.upcase}] Ensure no HTTPS or SSL proxy load balancers permit SSL policies with weak cipher suites"
31 |
32 | desc 'Secure Sockets Layer (SSL) policies determine what port Transport Layer Security (TLS) features clients are permitted to use when connecting to load balancers. To prevent usage of insecure features, SSL policies should use (a) at least TLS 1.2 with the MODERN profile; or (b) the RESTRICTED profile, because it effectively requires clients to use TLS 1.2 regardless of the chosen minimum TLS version; or (3) a CUSTOM profile that does not support any of the following features: TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA'
33 | desc 'rationale', 'Load balancers are used to efficiently distribute traffic across multiple servers. Both SSL proxy and HTTPS load balancers are external load balancers, meaning they distribute traffic from the Internet to a GCP network. GCP customers can configure load balancer SSL policies with a minimum TLS version (1.0, 1.1, or 1.2) that clients can use to establish a connection, along with a profile (Compatible, Modern, Restricted, or Custom) that specifies permissible cipher suites. To comply with users using outdated protocols, GCP load balancers can be configured to permit insecure cipher suites. In fact, the GCP default SSL policy uses a minimum TLS versionls of 1.0 and a Compatible profile, which allows the widest range of insecure cipher suites. As a result, it is easy for customers to configure a load balancer without even knowing that they are permitting outdated cipher suites.'
34 |
35 | tag cis_scored: false
36 | tag cis_level: 1
37 | tag cis_gcp: control_id.to_s
38 | tag cis_version: cis_version.to_s
39 | tag project: gcp_project_id.to_s
40 | tag nist: ['SC-1']
41 |
42 | ref 'CIS Benchmark', url: cis_url.to_s
43 | ref 'GCP Docs', url: 'https://cloud.google.com/load-balancing/docs/use-ssl-policies'
44 | ref 'GCP Docs', url: 'https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-52r.pdf'
45 |
46 | # All load balancers have custom/strong TLS profiles set
47 |
48 | gcp_https_proxies.each do |proxy|
49 | describe "[#{gcp_project_id}] HTTPS Proxy: #{proxy}" do
50 | subject { google_compute_target_https_proxy(project: gcp_project_id, name: proxy) }
51 | it 'should have a custom SSL policy configured' do
52 | expect(subject.ssl_policy).to_not cmp(nil)
53 | end
54 | end
55 | end
56 | # Ensure SSL Policies use strong TLS
57 | gcp_ssl_policies.each do |policy|
58 | case google_compute_ssl_policy(project: gcp_project_id, name: policy).profile
59 | when 'MODERN'
60 | describe "[#{gcp_project_id}] SSL Policy: #{policy}" do
61 | subject { google_compute_ssl_policy(project: gcp_project_id, name: policy) }
62 | it 'should minimally require TLS 1.2' do
63 | expect(subject.min_tls_version).to cmp('TLS_1_2')
64 | end
65 | end
66 |
67 | when 'RESTRICTED'
68 | describe "[#{gcp_project_id}] SSL Policy: #{policy} profile should be RESTRICTED" do
69 | subject { google_compute_ssl_policy(project: gcp_project_id, name: policy).profile }
70 | it { should cmp 'RESTRICTED' }
71 | end
72 |
73 | when 'CUSTOM'
74 | describe "[#{gcp_project_id}] SSL Policy: #{policy} profile CUSTOM should not contain these cipher suites [TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA] " do
75 | subject { google_compute_ssl_policy(project: gcp_project_id, name: policy) }
76 | its('custom_features') { should_not be_in %w[TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA] }
77 | end
78 | end
79 | end
80 |
81 | if gcp_https_proxies.empty? && gcp_ssl_policies.empty?
82 | impact 'none'
83 | describe "[#{gcp_project_id}] No HTTPS or SSL proxy load balancers found. This test is Not Applicable." do
84 | skip "[#{gcp_project_id}] No HTTPS or SSL proxy load balancers found"
85 | end
86 | end
87 | end
88 |
--------------------------------------------------------------------------------
/controls/4.01-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title ' Ensure that instances are not configured to use the default service account '
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | gce_zones = input('gce_zones')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '4.1'
22 | control_abbrev = 'vms'
23 |
24 | gce_instances = GCECache(project: gcp_project_id, gce_zones: gce_zones).gce_instances_cache
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure that instances are not configured to use the default compute engine service account with full access to all Cloud APIs"
30 |
31 | desc 'To support principle of least privileges and prevent potential privilege escalation it is recommended that instances are not assigned to default service account Compute Engine default service account'
32 | desc 'rationale', 'The default Compute Engine service account has the Editor role on the project, which allows read and write access to most Google Cloud Services. To defend against privilege escalations if your VM is compromised and prevent an attacker from gaining access to all of your project, it is recommended to not use the default Compute Engine service account. Instead, you should create a new service account and assigning only the permissions needed by your instance.'
33 |
34 | tag cis_scored: true
35 | tag cis_level: 1
36 | tag cis_gcp: control_id.to_s
37 | tag cis_version: cis_version.to_s
38 | tag project: gcp_project_id.to_s
39 | tag nist: %w[AC-2 AC-6]
40 |
41 | ref 'CIS Benchmark', url: cis_url.to_s
42 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances'
43 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/access/service-accounts'
44 |
45 | project_number = google_project(project: gcp_project_id).project_number
46 | gce_instances.each do |instance|
47 | next if instance[:name] =~ /^gke-/
48 | google_compute_instance(project: gcp_project_id, zone: instance[:zone], name: instance[:name]).service_accounts.each do |serviceaccount|
49 | describe "VM #{instance[:name]} should not include the default compute engine service account" do
50 | subject { serviceaccount.email }
51 | it { should_not include("#{project_number}-compute@developer.gserviceaccount.com") }
52 | end
53 | end
54 | end
55 |
56 | if gce_instances.empty?
57 | impact 'none'
58 | describe "[#{gcp_project_id}] No Google Compute Engine instances were found. This test is Not Applicable." do
59 | skip "[#{gcp_project_id}] No Google Compute Engine instances were found"
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/controls/4.02-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that instances are not configured to use the default service account with full access to all Cloud APIs'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | gce_zones = input('gce_zones')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '4.2'
22 | control_abbrev = 'vms'
23 |
24 | gce_instances = GCECache(project: gcp_project_id, gce_zones: gce_zones).gce_instances_cache
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure that instances are not configured to use the default service account with full access to all Cloud APIs"
30 |
31 | desc 'To support principle of least privileges and prevent potential privilege escalation it is recommended that instances are not assigned to default service account Compute Engine default service account with Scope Allow full access to all Cloud APIs.'
32 | desc 'rationale', "Along with ability to optionally create, manage and use user managed custom service accounts, Google Compute Engine provides default service account Compute Engine default service account for an instances to access necessary cloud services. Project Editor role is assigned to Compute Engine default service account hence, This service account has almost all capabilities over all cloud services except billing. However, when Compute Engine default service account assigned to an instance it can operate in 3 scopes.
33 |
34 | 1. Allow default access: Allows only minimum access required to run an Instance (Least Privileges)
35 | 2. Allow full access to all Cloud APIs: Allow full access to all the cloud APIs/Services (Too much access)
36 | 3. Set access for each API: Allows Instance administrator to choose only those APIs that are needed to perform specific business functionality expected by instance
37 |
38 | When an instance is configured with Compute Engine default service account with Scope Allow full access to all Cloud APIs, based on IAM roles assigned to the user(s) accessing Instance, it may allow user to perform cloud operations/API calls that user is not supposed to perform leading to successful privilege escalation."
39 |
40 | tag cis_scored: true
41 | tag cis_level: 1
42 | tag cis_gcp: control_id.to_s
43 | tag cis_version: cis_version.to_s
44 | tag project: gcp_project_id.to_s
45 | tag nist: %w[AC-2 AC-6]
46 |
47 | ref 'CIS Benchmark', url: cis_url.to_s
48 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances'
49 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/access/service-accounts'
50 |
51 | project_number = google_project(project: gcp_project_id).project_number
52 | gce_instances.each do |instance|
53 | next if instance[:name] =~ /^gke-/
54 | google_compute_instance(project: gcp_project_id, zone: instance[:zone], name: instance[:name]).service_accounts.each do |serviceaccount|
55 | next if serviceaccount.email != "#{project_number}-compute@developer.gserviceaccount.com"
56 | describe "[#{gcp_project_id}] Instance #{instance[:zone]}/#{instance[:name]}" do
57 | subject { serviceaccount.scopes }
58 | it { should_not include 'https://www.googleapis.com/auth/cloud-platform' }
59 | end
60 | end
61 | end
62 |
63 | if gce_instances.empty?
64 | impact 'none'
65 | describe "[#{gcp_project_id}] No Google Compute Engine instances were found. This test is Not Applicable." do
66 | skip "[#{gcp_project_id}] No Google Compute Engine instances were found"
67 | end
68 | end
69 | end
70 |
--------------------------------------------------------------------------------
/controls/4.03-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title "Ensure 'Block Project-wide SSH keys' is enabled for VM instances"
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | gce_zones = input('gce_zones')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '4.3'
22 | control_abbrev = 'vms'
23 |
24 | gce_instances = GCECache(project: gcp_project_id, gce_zones: gce_zones).gce_instances_cache
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure 'Block Project-wide SSH keys' enabled for VM instances"
30 |
31 | desc 'It is recommended to user Instance specific SSH key(s) instead of using common/shared project-wide SSH key(s) to access Instances.'
32 | desc 'rationale', 'Project-wide SSH keys are stored in Compute/Project-meta-data. Project wide SSH keys can be used to login into all the instances within project. Using project-wide SSH keys eases the SSH key management but if compromised, poses the security risk which can impact all the instances within project. It is recommended to use Instance specific SSH keys which can limit the attack surface if the SSH keys are compromised.'
33 |
34 | tag cis_scored: true
35 | tag cis_level: 1
36 | tag cis_gcp: control_id.to_s
37 | tag cis_version: cis_version.to_s
38 | tag project: gcp_project_id.to_s
39 | tag nist: ['AC-2']
40 |
41 | ref 'CIS Benchmark', url: cis_url.to_s
42 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys'
43 |
44 | gce_instances.each do |instance|
45 | next if instance[:name] =~ /^gke-/
46 | describe "[#{gcp_project_id}] Instance #{instance[:zone]}/#{instance[:name]}" do
47 | subject { google_compute_instance(project: gcp_project_id, zone: instance[:zone], name: instance[:name]) }
48 | its('block_project_ssh_keys') { should be true }
49 | end
50 | end
51 |
52 | if gce_instances.empty?
53 | impact 'none'
54 | describe "[#{gcp_project_id}] No Google Compute Engine instances were found. This test is Not Applicable." do
55 | skip "[#{gcp_project_id}] No Google Compute Engine instances were found"
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/controls/4.04-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure oslogin is enabled for a Project'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '4.4'
21 | control_abbrev = 'vms'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure oslogin is enabled for a Project"
27 |
28 | desc 'Enabling OS login binds SSH certificates to IAM users and facilitates effective SSH certificate management.'
29 | desc 'rationale', 'Enabling osLogin ensures that SSH keys used to connect to instances are mapped with IAM users. Revoking access to IAM user will revoke all the SSH keys associated with that particular user. It facilitates centralized and automated SSH key pair management which is useful in handling cases like response to compromised SSH key pairs and/or revocation of external/third-party/Vendor users.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: ['AC-2']
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/instances/managing-instance-access'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/instances/managing-instance-access#enable_oslogin'
41 |
42 | describe "[#{gcp_project_id}]" do
43 | subject { google_compute_project_info(project: gcp_project_id) }
44 | it { should have_enabled_oslogin }
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/controls/4.05-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title "Ensure 'Enable connecting to serial ports' is not enabled for VM Instance"
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | gce_zones = input('gce_zones')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '4.5'
22 | control_abbrev = 'vms'
23 |
24 | gce_instances = GCECache(project: gcp_project_id, gce_zones: gce_zones).gce_instances_cache
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure 'Enable connecting to serial ports' is not enabled for VM Instance"
30 |
31 | desc "Interacting with a serial port is often referred to as the serial console, which is similar to using a terminal window, in that input and output is entirely in text mode and there is no graphical interface or mouse support.
32 |
33 | If you enable the interactive serial console on an instance, clients can attempt to connect to that instance from any IP address. Therefore interactive serial console support should be disabled."
34 | desc 'rationale', "A virtual machine instance has four virtual serial ports. Interacting with a serial port is similar to using a terminal window, in that input and output is entirely in text mode and there is no graphical interface or mouse support. The instance's operating system, BIOS, and other system-level entities often write output to the serial ports, and can accept input such as commands or answers to prompts. Typically, these system-level entities use the first serial port (port 1) and serial port 1 is often referred to as the serial console.
35 |
36 | The interactive serial console does not support IP-based access restrictions such as IP whitelists. If you enable the interactive serial console on an instance, clients can attempt to connect to that instance from any IP address. This allows anybody to connect to that instance if they know the correct SSH key, username, project ID, zone, and instance name.
37 |
38 | Therefore interactive serial console support should be disabled."
39 |
40 | tag cis_scored: true
41 | tag cis_level: 1
42 | tag cis_gcp: control_id.to_s
43 | tag cis_version: cis_version.to_s
44 | tag project: gcp_project_id.to_s
45 | tag nist: ['CM-7']
46 |
47 | ref 'CIS Benchmark', url: cis_url.to_s
48 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/instances/interacting-with-serial-console'
49 |
50 | gce_instances.each do |instance|
51 | describe "[#{gcp_project_id}] Instance #{instance[:zone]}/#{instance[:name]}" do
52 | subject { google_compute_instance(project: gcp_project_id, zone: instance[:zone], name: instance[:name]) }
53 | it { should have_serial_port_disabled }
54 | end
55 | end
56 |
57 | if gce_instances.empty?
58 | impact 'none'
59 | describe "[#{gcp_project_id}] No Google Compute Engine instances were found. This test is Not Applicable." do
60 | skip "[#{gcp_project_id}] No Google Compute Engine instances were found"
61 | end
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/controls/4.06-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that IP forwarding is not enabled on Instances'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | gce_zones = input('gce_zones')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '4.6'
22 | control_abbrev = 'vms'
23 |
24 | gce_instances = GCECache(project: gcp_project_id, gce_zones: gce_zones).gce_instances_cache
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure that IP forwarding is not enabled on Instances"
30 |
31 | desc "Compute Engine instance cannot forward a packet unless the source IP address of the packet matches the IP address of the instance. Similarly, GCP won't deliver a packet whose destination IP address is different than the IP address of the instance receiving the packet. However, both capabilities are required if you want to use instances to help route packets. Forwarding of data packets should be disabled to prevent data loss or information disclosure."
32 | desc 'rationale', "Compute Engine instance cannot forward a packet unless the source IP address of the packet matches the IP address of the instance. Similarly, GCP won't deliver a packet whose destination IP address is different than the IP address of the instance receiving the packet. However, both capabilities are required if you want to use instances to help route packets. To enable this source and destination IP check, disable the canIpForward field, which allows an instance to send and receive packets with non-matching destination or source IPs."
33 |
34 | tag cis_scored: true
35 | tag cis_level: 1
36 | tag cis_gcp: control_id.to_s
37 | tag cis_version: cis_version.to_s
38 | tag project: gcp_project_id.to_s
39 | tag nist: %w[CM-6 CM-8]
40 |
41 | ref 'CIS Benchmark', url: cis_url.to_s
42 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/networking#canipforward'
43 |
44 | gce_instances.each do |instance|
45 | next if instance[:name] =~ /^gke-/
46 | gce = google_compute_instance(project: gcp_project_id, zone: instance[:zone], name: instance[:name])
47 | describe.one do
48 | describe "[#{gcp_project_id}] Instance #{instance[:zone]}/#{instance[:name]}" do
49 | subject { gce }
50 | its('can_ip_forward') { should be false }
51 | end
52 | describe "[#{gcp_project_id}] Instance #{instance[:zone]}/#{instance[:name]} ip-forwarding disabled" do
53 | subject { gce }
54 | it { should exist }
55 | end
56 | end
57 | end
58 |
59 | if gce_instances.empty?
60 | impact 'none'
61 | describe "[#{gcp_project_id}] No Google Compute Engine instances were found. This test is Not Applicable." do
62 | skip "[#{gcp_project_id}] No Google Compute Engine instances were found"
63 | end
64 | end
65 | end
66 |
--------------------------------------------------------------------------------
/controls/4.07-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure VM disks for critical VMs are encrypted with CustomerSupplied Encryption Keys (CSEK)'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | gce_zones = input('gce_zones')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '4.7'
22 | control_abbrev = 'vms'
23 |
24 | gce_instances = GCECache(project: gcp_project_id, gce_zones: gce_zones).gce_instances_cache
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure VM disks for critical VMs are encrypted with CustomerSupplied Encryption Keys (CSEK)"
30 |
31 | desc 'Customer-Supplied Encryption Keys (CSEK) are a feature in Google Cloud Storage and Google Compute Engine. If you supply your own encryption keys, Google uses your key to protect the Google-generated keys used to encrypt and decrypt your data. By default, Google Compute Engine encrypts all data at rest. Compute Engine handles and manages this encryption for you without any additional actions on your part. However, if you wanted to control and manage this encryption yourself, you can provide your own encryption keys.'
32 | desc 'rationale', "By default, Google Compute Engine encrypts all data at rest. Compute Engine handles and manages this encryption for you without any additional actions on your part. However, if you wanted to control and manage this encryption yourself, you can provide your own encryption keys.
33 |
34 | If you provide your own encryption keys, Compute Engine uses your key to protect the Google-generated keys used to encrypt and decrypt your data. Only users who can provide the correct key can use resources protected by a customer-supplied encryption key.
35 |
36 | Google does not store your keys on its servers and cannot access your protected data unless you provide the key. This also means that if you forget or lose your key, there is no way for Google to recover the key or to recover any data encrypted with the lost key.
37 |
38 | At least business critical VMs should have VM disks encrypted with CSEK."
39 |
40 | tag cis_scored: true
41 | tag cis_level: 2
42 | tag cis_gcp: control_id.to_s
43 | tag cis_version: cis_version.to_s
44 | tag project: gcp_project_id.to_s
45 | tag nist: ['SC-1']
46 |
47 | ref 'CIS Benchmark', url: cis_url.to_s
48 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/disks/customer-supplied-encryption#encrypt_a_new_persistent_disk_with_your_own_keys'
49 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/reference/rest/v1/disks/get'
50 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/disks/customer-supplied-encryption#key_file'
51 |
52 | gce_instances.each do |instance|
53 | next if instance[:name] =~ /^gke-/
54 | describe "[#{gcp_project_id}] Instance #{instance[:zone]}/#{instance[:name]}" do
55 | subject { google_compute_instance(project: gcp_project_id, zone: instance[:zone], name: instance[:name]) }
56 | it { should have_disks_encrypted_with_csek }
57 | end
58 | end
59 |
60 | if gce_instances.empty?
61 | impact 'none'
62 | describe "[#{gcp_project_id}] No Google Compute Engine instances were found. This test is Not Applicable." do
63 | skip "[#{gcp_project_id}] No Google Compute Engine instances were found"
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/controls/4.08-vms.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure Compute instances are launched with Shielded VM enabled'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | gce_zones = input('gce_zones')
19 | cis_version = input('cis_version')
20 | cis_url = input('cis_url')
21 | control_id = '4.8'
22 | control_abbrev = 'vms'
23 |
24 | gce_instances = GCECache(project: gcp_project_id, gce_zones: gce_zones).gce_instances_cache
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure Compute instances are launched with Shielded VM enabled"
30 |
31 | desc 'To defend against against advanced threats and ensure that the boot loader and firmware
32 | on your VMs are signed and untampered, it is recommended that Compute instances are
33 | launched with Shielded VM enabled.'
34 | desc 'rationale', "Shielded VMs are virtual machines (VMs) on Google Cloud Platform hardened by a set of
35 | security controls that help defend against rootkits and bootkits.
36 | Shielded VM offers verifiable integrity of your Compute Engine VM instances, so you can be
37 | confident your instances haven't been compromised by boot- or kernel-level malware or
38 | rootkits. Shielded VM's verifiable integrity is achieved through the use of Secure Boot,
39 | virtual trusted platform module (vTPM)-enabled Measured Boot, and integrity monitoring.
40 | Shielded VM instances run firmware which is signed and verified using Google's Certificate
41 | Authority, ensuring that the instance's firmware is unmodified and establishing the root of
42 | trust for Secure Boot.
43 | Integrity monitoring helps you understand and make decisions about the state of your VM
44 | instances and the Shielded VM vTPM enables Measured Boot by performing the
45 | measurements needed to create a known good boot baseline, called the integrity policy
46 | baseline. The integrity policy baseline is used for comparison with measurements from
47 | subsequent VM boots to determine if anything has changed.
48 | Secure Boot helps ensure that the system only runs authentic software by verifying the
49 | digital signature of all boot components, and halting the boot process if signature
50 | verification fails."
51 |
52 | tag cis_scored: true
53 | tag cis_level: 2
54 | tag cis_gcp: control_id.to_s
55 | tag cis_version: cis_version.to_s
56 | tag project: gcp_project_id.to_s
57 | tag nist: ['SC-1']
58 |
59 | ref 'CIS Benchmark', url: cis_url.to_s
60 | ref 'GCP Docs', url: 'https://cloud.google.com/compute/docs/instances/modifying-shielded-vm'
61 | ref 'GCP Docs', url: 'https://cloud.google.com/shielded-vm'
62 | ref 'GCP Docs', url: 'https://cloud.google.com/security/shielded-cloud/shielded-vm#organization-policy-constraint'
63 |
64 | gce_instances.each do |instance|
65 | instance_object = google_compute_instance(project: gcp_project_id, zone: instance[:zone], name: instance[:name])
66 | describe "[#{gcp_project_id}] Instance #{instance[:zone]}/#{instance[:name]}" do
67 | if instance_object.shielded_instance_config.nil?
68 | it 'should have a shielded instance config' do
69 | expect(false).to be true
70 | end
71 | else
72 | it 'should have secure boot enabled' do
73 | expect(instance_object.shielded_instance_config.enable_secure_boot).to be true
74 | end
75 | it 'should have integrity monitoring enabled' do
76 | expect(instance_object.shielded_instance_config.enable_integrity_monitoring).to be true
77 | end
78 | it 'should have virtual trusted platform module (vTPM) enabled' do
79 | expect(instance_object.shielded_instance_config.enable_vtpm).to be true
80 | end
81 | end
82 | end
83 | end
84 |
85 | if gce_instances.empty?
86 | impact 'none'
87 | describe "[#{gcp_project_id}] No Google Compute Engine instances were found. This test is Not Applicable." do
88 | skip "[#{gcp_project_id}] No Google Compute Engine instances were found"
89 | end
90 | end
91 | end
92 |
--------------------------------------------------------------------------------
/controls/5.01-storage.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Cloud Storage bucket is not anonymously or publicly accessible'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '5.1'
21 | control_abbrev = 'storage'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'high'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that Cloud Storage bucket is not anonymously or publicly accessible"
27 |
28 | desc 'It is recommended that IAM policy on Cloud Storage bucket does not allows anonymous and/or public access.'
29 | desc 'rationale', 'Allowing anonymous and/or public access grants permissions to anyone to access bucket content. Such access might not be desired if you are storing any sensitive data. Hence, ensure that anonymous and/or public access to a bucket is not allowed.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: %w[AC-2 CA-3]
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/access-control/iam-reference'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/access-control/making-data-public'
41 |
42 | storage_buckets = google_storage_buckets(project: gcp_project_id).bucket_names
43 |
44 | storage_buckets.each do |bucket|
45 | google_storage_bucket_iam_bindings(bucket: bucket).iam_binding_roles.each do |role|
46 | describe "[#{gcp_project_id}] GCS Bucket #{bucket}, Role: #{role}" do
47 | subject { google_storage_bucket_iam_binding(bucket: bucket, role: role) }
48 | its('members') { should_not include 'allUsers' }
49 | its('members') { should_not include 'allAuthenticatedUsers' }
50 | end
51 | end
52 | end
53 |
54 | if storage_buckets.empty?
55 | impact 'none'
56 | describe "[#{gcp_project_id}] No Google Storage Buckets were found. This test is Not Applicable." do
57 | skip "[#{gcp_project_id}] No Google Storage Buckets were found"
58 | end
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/controls/5.02-storage.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Cloud Storage buckets have uniform bucket-level access enabled'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '5.2'
21 | control_abbrev = 'storage'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'medium'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that Cloud Storage buckets have uniform bucket-level access enabled"
27 |
28 | desc 'It is recommended that uniform bucket-level access is enabled on Cloud Storage buckets.'
29 | desc 'rationale', "It is recommended to use uniform bucket-level access to unify and simplify how you grant
30 | access to your Cloud Storage resources.
31 | Cloud Storage offers two systems for granting users permission to access your buckets and
32 | objects: Cloud Identity and Access Management (Cloud IAM) and Access Control Lists
33 | (ACLs). These systems act in parallel - in order for a user to access a Cloud Storage
34 | resource, only one of the systems needs to grant the user permission. Cloud IAM is used
35 | throughout Google Cloud and allows you to grant a variety of permissions at the bucket and
36 | project levels. ACLs are used only by Cloud Storage and have limited permission options,
37 | but they allow you to grant permissions on a per-object basis.
38 |
39 | In order to support a uniform permissioning system, Cloud Storage has uniform bucket-
40 | level access. Using this feature disables ACLs for all Cloud Storage resources: access to
41 |
42 | Cloud Storage resources then is granted exclusively through Cloud IAM. Enabling uniform
43 | bucket-level access guarantees that if a Storage bucket is not publicly accessible, no object
44 | in the bucket is publicly accessible either."
45 |
46 | tag cis_scored: true
47 | tag cis_level: 2
48 | tag cis_gcp: control_id.to_s
49 | tag cis_version: cis_version.to_s
50 | tag project: gcp_project_id.to_s
51 | tag nist: ['AC-3']
52 |
53 | ref 'CIS Benchmark', url: cis_url.to_s
54 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/uniform-bucket-level-access'
55 |
56 | storage_buckets = google_storage_buckets(project: gcp_project_id).bucket_names
57 |
58 | storage_buckets.each do |bucket|
59 | uniform_bucket_level_access = google_storage_bucket(name: bucket).acl.nil?
60 | describe "[#{gcp_project_id}] GCS Bucket #{bucket}" do
61 | it 'should have uniform bucket-level access enabled' do
62 | expect(uniform_bucket_level_access).to be true
63 | end
64 | end
65 | end
66 |
67 | if storage_buckets.empty?
68 | impact 'none'
69 | describe "[#{gcp_project_id}] No Google Storage Buckets were found. This test is Not Applicable." do
70 | skip "[#{gcp_project_id}] No Google Storage Buckets were found"
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/controls/6.01-db.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that MySql database instances are secure.'
16 |
17 | # title 'Ensure that MySql database instance does not allow anyone to connect with administrative privileges.'
18 |
19 | gcp_project_id = input('gcp_project_id')
20 | cis_version = input('cis_version')
21 | cis_url = input('cis_url')
22 | control_id = '6.1'
23 | control_abbrev = 'db'
24 |
25 | sql_cache = CloudSQLCache(project: gcp_project_id)
26 | sql_instance_names = sql_cache.instance_names
27 |
28 | # 6.1.1
29 | sub_control_id = "#{control_id}.1"
30 | control "cis-gcp-#{sub_control_id}-#{control_abbrev}" do
31 | impact 'high'
32 |
33 | title "[#{control_abbrev.upcase}] Ensure that MySql database instance does not allow anyone to connect with administrative privileges."
34 |
35 | desc "It is recommended to set a password for the administrative user (root by default) to prevent unauthorized access to the SQL database Instances.
36 | This recommendation is applicable only for MySql Instances. PostgreSQL does not offer any setting for No Password from cloud console."
37 | desc 'rationale', 'At the time of MySql Instance creation, not providing a administrative password allows anyone to connect to the SQL database instance with administrative privileges. Root password should be set to ensure only authorized users have these privileges.'
38 |
39 | tag cis_scored: true
40 | tag cis_level: 1
41 | tag cis_gcp: sub_control_id.to_s
42 | tag cis_version: cis_version.to_s
43 | tag project: gcp_project_id.to_s
44 | tag nist: ['IA-5']
45 |
46 | ref 'CIS Benchmark', url: cis_url.to_s
47 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/create-manage-users'
48 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/create-instance'
49 |
50 | describe 'This control is not scored' do
51 | skip 'This control is not scored'
52 | end
53 | end
54 |
55 | # 6.1.2
56 | sub_control_id = "#{control_id}.2"
57 | control "cis-gcp-#{sub_control_id}-#{control_abbrev}" do
58 | impact 'none'
59 |
60 | title "[#{control_abbrev.upcase}] Ensure 'skip_show_database' database flag for Cloud SQL Mysql
61 | instance is set to 'on'"
62 |
63 | desc 'It is recommended to set skip_show_database database flag for Cloud SQL Mysql instance to on'
64 | desc 'rationale', "'skip_show_database' database flag prevents people from using the SHOW DATABASES
65 | statement if they do not have the SHOW DATABASES privilege. This can improve security if
66 | you have concerns about users being able to see databases belonging to other users. Its
67 | effect depends on the SHOW DATABASES privilege: If the variable value is ON, the SHOW
68 | DATABASES statement is permitted only to users who have the SHOW DATABASES
69 | privilege, and the statement displays all database names. If the value is OFF, SHOW
70 | DATABASES is permitted to all users, but displays the names of only those databases for
71 | which the user has the SHOW DATABASES or other privilege. This recommendation is
72 | applicable to Mysql database instances."
73 |
74 | tag cis_scored: true
75 | tag cis_level: 1
76 | tag cis_gcp: sub_control_id.to_s
77 | tag cis_version: cis_version.to_s
78 | tag project: gcp_project_id.to_s
79 | tag nist: ['AC-3']
80 |
81 | ref 'CIS Benchmark', url: cis_url.to_s
82 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/flags'
83 |
84 | sql_instance_names.each do |db|
85 | if sql_cache.instance_objects[db].database_version.include? 'MYSQL'
86 | impact 'medium'
87 | if sql_cache.instance_objects[db].settings.database_flags.nil?
88 | describe "[#{gcp_project_id} , #{db} ] does not any have database flags." do
89 | subject { false }
90 | it { should be true }
91 | end
92 | else
93 | describe.one do
94 | sql_cache.instance_objects[db].settings.database_flags.each do |flag|
95 | next unless flag.name == 'skip_show_database'
96 | describe flag do
97 | its('name') { should cmp 'skip_show_database' }
98 | its('value') { should cmp 'on' }
99 | end
100 | end
101 | end
102 | end
103 | else
104 | describe "[#{gcp_project_id}] [#{db}] is not a MySQL database. This test is Not Applicable." do
105 | skip "[#{gcp_project_id}] [#{db}] is not a MySQL database"
106 | end
107 | end
108 | end
109 |
110 | if sql_instance_names.empty?
111 | describe 'There are no Cloud SQL Instances in this project. This test is Not Applicable.' do
112 | skip 'There are no Cloud SQL Instances in this project'
113 | end
114 | end
115 | end
116 |
117 | # 6.1.3
118 | sub_control_id = "#{control_id}.3"
119 | control "cis-gcp-#{sub_control_id}-#{control_abbrev}" do
120 | impact 'none'
121 |
122 | title "[#{control_abbrev.upcase}] Ensure that the 'local_infile' database flag for a Cloud SQL Mysql instance is set to 'off'"
123 |
124 | desc 'It is recommended to set the local_infile database flag for a Cloud SQL MySQL instance to off.'
125 | desc 'rationale', "The local_infile flag controls the server-side LOCAL capability for LOAD DATA statements. Depending on the
126 | local_infile setting, the server refuses or permits local data loading by clients that have LOCAL enabled on
127 | the client side."
128 |
129 | tag cis_scored: true
130 | tag cis_level: 1
131 | tag cis_gcp: sub_control_id.to_s
132 | tag cis_version: cis_version.to_s
133 | tag project: gcp_project_id.to_s
134 | tag nist: ['SC-1']
135 |
136 | ref 'CIS Benchmark', url: cis_url.to_s
137 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/flags'
138 |
139 | sql_instance_names.each do |db|
140 | if sql_cache.instance_objects[db].database_version.include? 'MYSQL'
141 | impact 'medium'
142 | if sql_cache.instance_objects[db].settings.database_flags.nil?
143 | describe "[#{gcp_project_id} , #{db} ] does not any have database flags." do
144 | subject { false }
145 | it { should be true }
146 | end
147 | else
148 | describe.one do
149 | sql_cache.instance_objects[db].settings.database_flags.each do |flag|
150 | next unless flag.name == 'local_infile'
151 | describe flag do
152 | its('name') { should cmp 'local_infile' }
153 | its('value') { should cmp 'off' }
154 | end
155 | end
156 | end
157 | end
158 | else
159 | describe "[#{gcp_project_id}] [#{db}] is not a MySQL database. This test is Not Applicable." do
160 | skip "[#{gcp_project_id}] [#{db}] is not a MySQL database"
161 | end
162 | end
163 | end
164 |
165 | if sql_instance_names.empty?
166 | describe "[#{gcp_project_id}] does not have CloudSQL instances. This test is Not Applicable." do
167 | skip "[#{gcp_project_id}] does not have CloudSQL instances."
168 | end
169 | end
170 | end
171 |
--------------------------------------------------------------------------------
/controls/6.04-db.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Cloud SQL database instance requires all incoming connections to use SSL'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '6.4'
21 | control_abbrev = 'db'
22 |
23 | sql_cache = CloudSQLCache(project: gcp_project_id)
24 | sql_instance_names = sql_cache.instance_names
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'high'
28 |
29 | title "[#{control_abbrev.upcase}] Ensure that Cloud SQL database instance requires all incoming connections to use SSL"
30 |
31 | desc 'It is recommended to enforce all incoming connections to SQL database instance to use SSL.'
32 | desc 'rationale', 'SQL database connections if successfully trapped (MITM); can reveal sensitive data like credentials, database queries, query outputs etc. For security, it is recommended to always use SSL encryption when connecting to your instance. This recommendation is applicable for Postgresql, MySql generation 1 and MySql generation 2 Instances.'
33 |
34 | tag cis_scored: true
35 | tag cis_level: 1
36 | tag cis_gcp: control_id.to_s
37 | tag cis_version: cis_version.to_s
38 | tag project: gcp_project_id.to_s
39 | tag nist: %w[SC-1 SC-8]
40 |
41 | ref 'CIS Benchmark', url: cis_url.to_s
42 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/postgres/configure-ssl-instance'
43 |
44 | if sql_instance_names.empty?
45 | impact 'none'
46 | describe "[#{gcp_project_id}] does not have CloudSQL instances. This test is Not Applicable." do
47 | skip "[#{gcp_project_id}] does not have CloudSQL instances."
48 | end
49 | else
50 | sql_instance_names.each do |db|
51 | describe "[#{gcp_project_id}] CloudSQL #{db}" do
52 | subject { sql_cache.instance_objects[db] }
53 | it { should have_ip_configuration_require_ssl }
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/controls/6.05-db.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Database Server should accept connections only from trusted Network(s)/IP(s) and restrict access from the world'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '6.5'
21 | control_abbrev = 'db'
22 |
23 | sql_cache = CloudSQLCache(project: gcp_project_id)
24 | sql_instance_names = sql_cache.instance_names
25 |
26 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
27 | impact 'medium'
28 |
29 | title "[#{control_abbrev.upcase}] Database Server should accept connections only from trusted Network(s)/IP(s) and restrict access from the world"
30 |
31 | desc 'Database Server should accept connections only from trusted Network(s)/IP(s) and restrict access from the world.'
32 | desc 'rationale', 'To minimize attack surface on a Database server instance, only trusted/known and required IP(s) should be white-listed to connect to it.'
33 |
34 | tag cis_scored: true
35 | tag cis_level: 1
36 | tag cis_gcp: control_id.to_s
37 | tag cis_version: cis_version.to_s
38 | tag project: gcp_project_id.to_s
39 | tag nist: %w[SC-1 AC-3]
40 |
41 | ref 'CIS Benchmark', url: cis_url.to_s
42 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/configure-ip'
43 |
44 | if sql_instance_names.empty?
45 | impact 'none'
46 | describe "[#{gcp_project_id}] does not have CloudSQL instances. This test is Not Applicable." do
47 | skip "[#{gcp_project_id}] does not have CloudSQL instances."
48 | end
49 | else
50 | sql_instance_names.each do |db|
51 | describe "[#{gcp_project_id}] CloudSQL #{db}" do
52 | subject { sql_cache.instance_objects[db].settings.ip_configuration.authorized_networks }
53 | it { should_not include('0.0.0.0/0') }
54 | end
55 | end
56 | end
57 | end
58 |
--------------------------------------------------------------------------------
/controls/6.06-db.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Cloud SQL database instances do not have public IPs'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '6.6'
21 | control_abbrev = 'db'
22 |
23 | sql_cache = CloudSQLCache(project: gcp_project_id)
24 |
25 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
26 | impact 'high'
27 |
28 | title "[#{control_abbrev.upcase}] Ensure that Cloud SQL database instances do not have public IPs"
29 |
30 | desc 'It is recommended to configure Second Generation Sql instance to use private IPs instead of public IPs.'
31 | desc 'rationale', "To lower the organization's attack surface, Cloud SQL databases should not have public IPs. Private IPs provide improved network security and lower latency for your application."
32 |
33 | tag cis_scored: true
34 | tag cis_level: 2
35 | tag cis_gcp: control_id.to_s
36 | tag cis_version: cis_version.to_s
37 | tag project: gcp_project_id.to_s
38 | tag nist: ['SC-1']
39 |
40 | ref 'CIS Benchmark', url: cis_url.to_s
41 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/configure-private-ip'
42 |
43 | if sql_cache.instance_names.empty?
44 | impact 'none'
45 | describe "[#{gcp_project_id}] does not have CloudSQL instances. This test is Not Applicable." do
46 | skip "[#{gcp_project_id}] does not have CloudSQL instances."
47 | end
48 | else
49 | sql_cache.instance_names.each do |db|
50 | sql_cache.instance_objects[db].ip_addresses.each do |ip_address|
51 | describe "[#{gcp_project_id}] CloudSQL #{db}" do
52 | subject { ip_address }
53 | its('type') { should_not include('PRIMARY') }
54 | end
55 | end
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/controls/6.07-db.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that Cloud SQL database instances are configured with automated backups'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '6.7'
21 | control_abbrev = 'db'
22 |
23 | sql_cache = CloudSQLCache(project: gcp_project_id)
24 |
25 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
26 | impact 'medium'
27 |
28 | title "[#{control_abbrev.upcase}] Ensure that Cloud SQL database instances are configured with automated backups"
29 |
30 | desc 'It is recommended to have all SQL database instances set to enable automated backups.'
31 | desc 'rationale', 'Backups provide a way to restore a Cloud SQL instance to recover lost data or recover from a problem
32 | with that instance. Automated backups need to be set for any instance that contains data that should
33 | be protected from loss or damage'
34 |
35 | tag cis_scored: true
36 | tag cis_level: 1
37 | tag cis_gcp: control_id.to_s
38 | tag cis_version: cis_version.to_s
39 | tag project: gcp_project_id.to_s
40 | tag nist: ['CP-9']
41 |
42 | ref 'CIS Benchmark', url: cis_url.to_s
43 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/mysql/backup-recovery/backups'
44 | ref 'GCP Docs', url: 'https://cloud.google.com/sql/docs/postgres/backup-recovery/backing-up'
45 |
46 | if sql_cache.instance_names.empty?
47 | impact 'none'
48 | describe "[#{gcp_project_id}] does not have any CloudSQL instances, this test is Not Applicable" do
49 | skip "[#{gcp_project_id}] does not have any CloudSQL instances"
50 | end
51 | else
52 | sql_cache.instance_names.each do |db|
53 | describe "[#{gcp_project_id}] CloudSQL #{db} should have automated backups enabled and have a start time" do
54 | subject { sql_cache.instance_objects[db].settings.backup_configuration }
55 | its('enabled') { should cmp true }
56 | its('start_time') { should_not eq '' }
57 | end
58 | end
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/controls/7.01-bq.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that BigQuery datasets are not anonymously or publicly accessible'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '7.1'
21 | control_abbrev = 'storage'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'high'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that BigQuery datasets are not anonymously or publicly accessible"
27 |
28 | desc 'It is recommended that the IAM policy on BigQuery datasets does not allow anonymous and/or public access.'
29 | desc 'rationale', 'Granting permissions to allUsers or allAuthenticatedUsers allows anyone to access the dataset. Such access might not be desirable if sensitive data is being stored in the dataset. Therefore, ensure that anonymous and/or public access to a dataset is not allowed.'
30 |
31 | tag cis_scored: true
32 | tag cis_level: 1
33 | tag cis_gcp: control_id.to_s
34 | tag cis_version: cis_version.to_s
35 | tag project: gcp_project_id.to_s
36 | tag nist: ['AC-3']
37 |
38 | ref 'CIS Benchmark', url: cis_url.to_s
39 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/access-control/iam-reference'
40 | ref 'GCP Docs', url: 'https://cloud.google.com/storage/docs/access-control/making-data-public'
41 |
42 | if google_bigquery_datasets(project: gcp_project_id).ids.empty?
43 | impact 'none'
44 | describe "[#{gcp_project_id}] does not have BigQuery Datasets, this test is Not Applicable." do
45 | skip "[#{gcp_project_id}] does not have BigQuery Datasets"
46 | end
47 | else
48 | google_bigquery_datasets(project: gcp_project_id).ids.each do |name|
49 | google_bigquery_dataset(project: gcp_project_id, name: name.split(':').last).access.each do |access|
50 | describe "[#{gcp_project_id}] BigQuery Dataset #{name} should not be anonymously or publicly accessible," do
51 | subject { access }
52 | its('iam_member') { should_not cmp 'allUsers' }
53 | its('special_group') { should_not cmp 'allAuthenticatedUsers' }
54 | end
55 | end
56 | end
57 | end
58 | end
59 |
--------------------------------------------------------------------------------
/controls/7.02-bq.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that all BigQuery Tables are encrypted with Customermanaged encryption key (CMEK)'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '7.2'
21 | control_abbrev = 'storage'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'high'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that all BigQuery Tables are encrypted with Customermanaged encryption key (CMEK)"
27 |
28 | desc 'BigQuery by default encrypts the data as rest by employing Envelope Encryption using
29 | Google managed cryptographic keys. The data is encrypted using the data encryption
30 | keys and data encryption keys themselves are further encrypted using key encryption
31 | keys. This is seamless and do not require any additional input from the user. However, if
32 | you want to have greater control, Customer-managed encryption keys (CMEK) can be used
33 | as encryption key management solution for BigQuery Data Sets. If CMEK is used, the CMEK
34 | is used to encrypt the data encryption keys instead of using google-managed encryption
35 | keys.'
36 | desc 'rationale', 'BigQuery by default encrypts the data as rest by employing Envelope Encryption using
37 | Google managed cryptographic keys. This is seamless and does not require any additional
38 | input from the user.
39 | For greater control over the encryption, customer-managed encryption keys (CMEK) can
40 | be used as encryption key management solution for BigQuery tables. The CMEK is used to
41 | encrypt the data encryption keys instead of using google-managed encryption keys.
42 | BigQuery stores the table and CMEK association and the encryption/decryption is done
43 | automatically.
44 | Applying the Default Customer-managed keys on BigQuery data sets ensures that all the
45 | new tables created in the future will be encrypted using CMEK but existing tables need to
46 | be updated to use CMEK individually.'
47 |
48 | tag cis_scored: true
49 | tag cis_level: 2
50 | tag cis_gcp: control_id.to_s
51 | tag cis_version: cis_version.to_s
52 | tag project: gcp_project_id.to_s
53 | tag nist: ['SC-1']
54 |
55 | ref 'CIS Benchmark', url: cis_url.to_s
56 | ref 'GCP Docs', url: 'https://cloud.google.com/bigquery/docs/customer-managed-encryption'
57 |
58 | if google_bigquery_datasets(project: gcp_project_id).ids.empty?
59 | impact 'none'
60 | describe "[#{gcp_project_id}] does not have BigQuery Datasets, this test is Not Applicable." do
61 | skip "[#{gcp_project_id}] does not have BigQuery Datasets"
62 | end
63 | else
64 | google_bigquery_datasets(project: gcp_project_id).ids.each do |dataset_name|
65 | google_bigquery_tables(project: gcp_project_id, dataset: dataset_name.split(':').last).table_references.each do |table_reference|
66 | describe "[#{gcp_project_id}] BigQuery Table #{table_reference.table_id} should use customer-managed encryption keys (CMEK)" do
67 | subject { google_bigquery_table(project: gcp_project_id, dataset: dataset_name.split(':').last, name: table_reference.table_id).encryption_configuration }
68 | its('kms_key_name') { should_not eq nil }
69 | end
70 | end
71 | end
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/controls/7.03-bq.rb:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | title 'Ensure that a Default Customer-managed encryption key (CMEK) is specified for all BigQuery Data Sets'
16 |
17 | gcp_project_id = input('gcp_project_id')
18 | cis_version = input('cis_version')
19 | cis_url = input('cis_url')
20 | control_id = '7.3'
21 | control_abbrev = 'storage'
22 |
23 | control "cis-gcp-#{control_id}-#{control_abbrev}" do
24 | impact 'high'
25 |
26 | title "[#{control_abbrev.upcase}] Ensure that a Default Customer-managed encryption key (CMEK) is
27 | specified for all BigQuery Data Sets"
28 |
29 | desc 'BigQuery by default encrypts the data as rest by employing Envelope Encryption using
30 | Google managed cryptographic keys. The data is encrypted using the data encryption
31 | keys and data encryption keys themselves are further encrypted using key encryption
32 | keys. This is seamless and do not require any additional input from the user. However, if
33 | you want to have greater control, Customer-managed encryption keys (CMEK) can be used
34 | as encryption key management solution for BigQuery Data Sets.'
35 | desc 'rationale', 'BigQuery by default encrypts the data as rest by employing Envelope Encryption using
36 | Google managed cryptographic keys. This is seamless and does not require any additional
37 | input from the user.
38 | For greater control over the encryption, customer-managed encryption keys (CMEK) can
39 | be used as encryption key management solution for BigQuery Data Sets. Setting a Default
40 | Customer-managed encryption key (CMEK) for a data set ensure any tables created in
41 | future will use the specified CMEK if none other is provided.'
42 |
43 | tag cis_scored: true
44 | tag cis_level: 2
45 | tag cis_gcp: control_id.to_s
46 | tag cis_version: cis_version.to_s
47 | tag project: gcp_project_id.to_s
48 | tag nist: ['SC-1']
49 |
50 | ref 'CIS Benchmark', url: cis_url.to_s
51 | ref 'GCP Docs', url: 'https://cloud.google.com/bigquery/docs/customer-managed-encryption'
52 |
53 | if google_bigquery_datasets(project: gcp_project_id).ids.empty?
54 | impact 'none'
55 | describe "[#{gcp_project_id}] does not have BigQuery Datasets, this test is Not Applicable." do
56 | skip "[#{gcp_project_id}] does not have BigQuery Datasets"
57 | end
58 | else
59 | google_bigquery_datasets(project: gcp_project_id).ids.each do |name|
60 | describe "[#{gcp_project_id}] BigQuery Dataset #{name} should use customer-managed encryption keys (CMEK)" do
61 | subject { google_bigquery_dataset(project: gcp_project_id, name: name.split(':').last).default_encryption_configuration }
62 | its('kms_key_name') { should_not eq nil }
63 | end
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/inspec.yml:
--------------------------------------------------------------------------------
1 | # Copyright 2019 The inspec-gcp-cis-benchmark Authors
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | name: inspec-gcp-cis-benchmark
16 | title: "InSpec GCP CIS 1.2 Benchmark"
17 | maintainer: "Google Cloud Platform"
18 | copyright: "(c) 2022, Google, Inc."
19 | copyright_email: "copyright@google.com"
20 | license: "Apache-2.0"
21 | summary: "Inspec Google Cloud Platform Center for Internet Security Benchmark v1.2 Profile"
22 | version: 1.2.0-0
23 |
24 | supports:
25 | - platform: gcp
26 |
27 | depends:
28 | - name: inspec-gcp-helpers
29 | url: https://github.com/GoogleCloudPlatform/inspec-gcp-helpers/archive/1.0.9.tar.gz
30 |
31 | inputs:
32 | # {{gcp_project_id}}
33 | # must be defined at runtime by the user
34 | - name: gcp_project_id
35 | description: "The GCP project identifier."
36 | type: String
37 | required: true
38 | value: 'aaa-bbb-ccc-ddd'
39 |
40 | - name: cis_version
41 | description: "The short version of the GCP CIS Benchmark"
42 | value: "1.2"
43 | type: String
44 |
45 | - name: cis_url
46 | description: "The URL to the GCP CIS Benchmark"
47 | value: "https://www.cisecurity.org/benchmark/google_cloud_computing_platform/"
48 | type: String
49 |
50 | - name: sa_key_older_than_seconds
51 | description: "How many seconds SA keys should not be older than"
52 | value: 7776000
53 | type: Numeric
54 |
55 | - name: kms_rotation_period_seconds
56 | description: "How many seconds KMS Keys should be last rotated (90 days)"
57 | value: 7776000
58 | type: Numeric
59 |
60 | - name: gcp_gke_locations
61 | description: "The list of regions and/or zone names where GKE clusters are running. An empty array searches all locations"
62 | type: Array
63 | value:
64 | - ""
65 |
66 | - name: gce_zones
67 | description: "The list of zone names where GCE instances are running. An empty array searches all locations"
68 | type: Array
69 | value:
70 | - ""
71 |
72 | - name: log_min_messages
73 | description: "(Cloud SQL PostgreSQL) The log_min_messages flag controls which message levels are written to the server log (see control 6.2.13). ERROR is cosidered best practice."
74 | value: "ERROR"
75 | type: String
76 |
77 | - name: log_min_error_statement
78 | description: "(Cloud SQL PostgreSQL) The log_min_error_statement flag controls which SQL statements that cause an error condition are recorded in the server log (see control 6.2.14). ERROR is cosidered best practice."
79 | value: "ERROR"
80 | type: String
81 |
82 | - name: log_error_verbosity
83 | description: "(Cloud SQL PostgreSQL) The log_min_error_statement flag controls the amount of detail written in the server log for each message that is logged (see control 6.2.2). DEFAULT is cosidered best practice."
84 | value: "DEFAULT"
85 | type: String
86 |
87 | - name: log_statement
88 | description: "(Cloud SQL PostgreSQL) The log_statement flag controls which SQL statements are logged. Valid values are none (off), ddl, mod, and all (all statements) (see control 6.2.7). ddl is cosidered best practice."
89 | value: "ddl"
90 | type: String
91 |
92 | - name: log_hostname
93 | description: "(Cloud SQL PostgreSQL) By default, connection log messages only show the IP address of the connecting host. Turning this parameter on causes logging of the host name as well (see control 6.2.8)."
94 | value: "off"
95 | type: String
96 |
97 | - name: user_connections
98 | description: "(Cloud SQL SQL Server) The user connections option specifies the maximum number of simultaneous user connections that are allowed on an instance of SQL Server. (see control 6.3.3)."
99 | value: "0"
100 | type: String
101 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": [
4 | "config:recommended"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/walkthrough.md:
--------------------------------------------------------------------------------
1 | # Introduction to Running InSpec in Cloud Shell
2 |
3 | ## Getting Started
4 |
5 | This guide will show you how to install InSpec on your Cloud Shell instance and how to use InSpec to check the infrastructure in your Google Cloud Project against the CIS GCP Benchmark.
6 |
7 | **Time to complete**: About 5 minutes
8 |
9 | Click the **Start** button to move to the next step.
10 |
11 | ## What is InSpec?
12 |
13 | Before we jump in, let's briefly go over what InSpec can do.
14 |
15 | [InSpec](https://github.com/inspec/inspec), a popular framework in the DevSecOps community, checks the configuration state of resources within virtual machines, containers, and cloud providers such as GCP, AWS, and Azure. InSpec's lightweight nature, approachable domain specific Language (DSL) and extensibility, make it a valuable tool for:
16 |
17 | - Expressing compliance policies as code
18 | - Enabling development teams to add application-specific tests and assess the compliance of their applications to security policies before pushing changes to the production environment.
19 | - Automating compliance verification in CI/CD pipelines and as part of the release process
20 | - Unifying compliance assessments across multiple cloud providers and on premises environments
21 |
22 | Continue on to the next step to start setting up your tutorial.
23 |
24 | ## Installing InSpec
25 |
26 | InSpec is distributed as a Docker image. All you need to do is pull the image from the repository and create a function to run Inspec:
27 |
28 | ```bash
29 | docker pull chef/inspec:4.26.15
30 |
31 | function inspec-docker { docker run -it -e GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS=true -e CHEF_LICENSE=accept-no-persist --rm -v ~/.config:/root/.config -v $(pwd):/share chef/inspec:4.26.15 "$@"; }
32 | ```
33 |
34 | **Tip**: Click the Copy to Cloud Shell button on the side of the code box and then hit Enter in your terminal. You can also click the copy button on the side of the code box and paste the command in the Cloud Shell terminal to run it.
35 |
36 | Next, you’ll select a Google Cloud Project to scan with InSpec.
37 |
38 | ## Select the Google Cloud Project to scan
39 |
40 | Pick a project where you have sufficient permissions. We'll use your user credentials in Cloud Shell to scan the project.
41 |
42 |
43 |
44 | The project you selected is **{{project-id}}**. If this is blank, make sure you selected a project using the dropdown box above.
45 |
46 | Hit Next after you successfully selected your project.
47 |
48 | ## Scan Your Project
49 |
50 | To scan your project against the CIS GCP Benchmark with InSpec, run:
51 |
52 | ```bash
53 | inspec-docker exec https://github.com/GoogleCloudPlatform/inspec-gcp-cis-benchmark.git -t gcp:// --input gcp_project_id={{project-id}} --reporter cli json:{{project-id}}_scan.json
54 | ```
55 |
56 | This should take about two minutes to complete.
57 |
58 | Once complete, your terminal output should look something like this:
59 |
60 | ```bash
61 | Profile Summary: 14 successful controls, 34 control failures, 7 controls skipped
62 | Test Summary: 107 successful, 88 failures, 7 skipped
63 | ```
64 |
65 | You can scroll up to see the details of passing and failing controls.
66 |
67 | To scan another project, press the Previous button and select a different project.
68 |
69 | Press Next if you're done scanning projects.
70 |
71 | ## Review your scan results with [Heimdall-Lite](https://heimdall-lite.mitre.org)
72 |
73 | ### What is Heimdall-Lite?
74 |
75 | Heimdall-Lite is a great open-source Security Results Viewer by the [MITRE Corporation](https://www.mitre.org) for reviewing your GCP CIS Benchmark scan results.
76 |
77 | Heimdall-Lite is one of many MITRE [Security Automation Framework](https://saf.mitre.org) (SAF) Supporting Tools working to enhance the Security Automation and DevSecOps communities.
78 |
79 | The [MITRE SAF](https://saf.mitre.org) is an open-source community partnership including Government, Industry and the Open Community working together to make truly automated security a reality. It also hosts many InSpec profiles created by the SAF and references to many partner developed profiles - **_including this one_**.
80 |
81 | **Tip**: MITRE hosts Heimdall-Lite on GitHub pages, but you can easily run it in your environment via Docker or NPM or whatever suites your need. See the projects GitHub more information.
82 |
83 | ### Download your JSON formatted results
84 |
85 | 1. Right click on your `{{project-id}}_scan.json` file
86 | 2. Then select `Download` to save the `{{project-id}}_scan.json` file locally
87 |
88 | ### Go to Heimdall Lite and Load your JSON formatted Results
89 |
90 | 1. Navigate to [Heimdall Lite](https://heimdall-lite.mitre.org)
91 | 2. Click `Local Files` on the left side of the loader
92 | 3. Drag and Drop or select and load your `{{project-id}}_scan.json` file to review your results.
93 |
94 | ## Congratulations
95 |
96 |
97 |
98 | You’re all set!
99 |
100 | You can now scan your Google Cloud Projects with InSpec directly from Cloud Shell.
101 |
--------------------------------------------------------------------------------