Skip to content

Commit ed7cdcb

Browse files
feat(3-fleetscope): adding tests and docs for OPA policies (GoogleCloudPlatform#389)
1 parent 5d878d1 commit ed7cdcb

6 files changed

Lines changed: 240 additions & 3 deletions

File tree

3-fleetscope/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The following resources are created:
1818
- Service Mesh
1919
- Multicluster Ingress
2020
- Multicluster Service
21+
- Policy Controller
2122

2223
## Prerequisites
2324

@@ -237,3 +238,8 @@ If you receive any errors or made any changes to the Terraform config or `terraf
237238
1. Repeat the same series of terraform commands but replace `-chdir=./envs/production` with `-chdir=./envs/nonproduction` to deploy the nonproduction environment.
238239

239240
1. Repeat the same series of terraform commands but replace `-chdir=./envs/production` with `-chdir=./envs/development` to deploy the development environment.
241+
242+
### Policy Controller
243+
244+
For more information on Policies, refer to the [following documentation](../docs/opa_policies.md)
245+

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ example-organization
5353

5454
The purpose of this stage is to deploy the per-environment fleet resources via the fleetscope infrastructure pipeline. This stage does not create any new projects, but creates resources within the existing multitenant infrastructure projects.
5555

56-
The fleet-scope pipeline manages configuration and resources related to [GKE Fleets](https://cloud.google.com/kubernetes-engine/docs/fleets-overview). This stage manages the creation of namespaces in the GKE clusters via [team scopes and fleet namespaces](https://cloud.google.com/kubernetes-engine/fleet-management/docs/team-management#fleet_team_management_overview). This pipeline also enables the [Config Sync](https://cloud.google.com/anthos-config-management/docs/config-sync-overview) and [Service Mesh](https://cloud.google.com/service-mesh/docs) features for the fleet and thus the member clusters.
56+
The fleet-scope pipeline manages configuration and resources related to [GKE Fleets](https://cloud.google.com/kubernetes-engine/docs/fleets-overview). This stage manages the creation of namespaces in the GKE clusters via [team scopes and fleet namespaces](https://cloud.google.com/kubernetes-engine/fleet-management/docs/team-management#fleet_team_management_overview). This pipeline also enables the [Config Sync](https://cloud.google.com/anthos-config-management/docs/config-sync-overview), [Service Mesh](https://cloud.google.com/service-mesh/docs), and [Policy Controller](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/overview) features for the fleet and thus the member clusters.
5757

5858
[Fleet team management](https://cloud.google.com/kubernetes-engine/fleet-management/docs/team-management-overview) makes it easier for platform admins to provision and manage the necessary infrastructure resources that application and service teams might need to run their workloads, with the appropriate access control. Each team acts as a separate "tenant" on your fleet. In this repository, for demonstration purposes, the `ADMIN` permission is assigned on the fleet scope for each Group/Namespace.
5959

60+
Based on the open source [Open Policy Agent Gatekeeper](https://open-policy-agent.github.io/gatekeeper/website/docs/) project, [Policy Controller](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/overview) is fully integrated with Google Cloud, includes a built-in dashboard, for observability, and comes with a full library of pre-built policies for common security and compliance controls.
61+
6062
### [4. app-factory](/4-app-factory/)
6163

6264
The purpose of this stage is to set up the application-specific projects. This includes a single project in the common folder, and a project in each of the environment folders. The app-infra pipeline creates the application CI/CD pipeline, responsible for deploying applications to the multitenant infrastructure. The app-infra pipeline also creates any application-specific infrastructure, such as databases or other managed services. The resulting project hierarchy is as follows:

docs/images/policies_dashboard.png

80.3 KB
Loading

docs/opa_policies.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# OPA Policies on GKE
2+
3+
## Overview
4+
5+
[Policy Controller benefits](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/overview#benefits):
6+
7+
- Integrated with Google Cloud: Platform admins can install Policy Controller by using the Google Cloud console, by using Terraform, or by using Google Cloud CLI on any cluster connected to your fleet. Policy Controller works with other Google Cloud services like Config Sync, metrics, and Cloud Monitoring.
8+
- Supports multiple enforcement points: In addition to both audit and admission control for your cluster, Policy Controller can optionally enable a shift-left approach to analyse and catch non-compliant changes prior to application.
9+
- Pre-built policy bundles: Policy Controller comes with a full library of pre-built policies for common security and compliance controls. These include both Policy bundles, which are built and maintained by Google, and the constraint template library.
10+
- Supports custom policies: If policy customization is required beyond what is available using the constraint template library, Policy Controller additionally supports the development of custom constraint templates.
11+
- Built-in observability: Policy Controller includes a Google Cloud console dashboard, providing an overview for the state of all the policies applied to your fleet (including unregistered clusters). From the dashboard, view compliance and enforcement status to help you troubleshoot, and get opinionated recommendations to resolve policy violations.
12+
13+
Policy Controller is installed in this repository on the 3-fleetscope stage.
14+
15+
For more information on the dashboard, see [Policy Controller Status](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/how-to/policy-controller-status).
16+
17+
## Installed Bundles
18+
19+
In this repository, two policies bundles are installed by default on the cluster:
20+
21+
Bundle Code | Name | Description |
22+
--- | -- | -- |
23+
pss-baseline-v2022 | Pod Security Standards Baseline | Apply protections based on the Kubernetes Pod Security Standards (PSS) Baseline policy. |
24+
policy-essentials-v2022 | Policy Essentials | Apply best practices to your cluster resources |
25+
26+
### `pss-baseline-v2022` details
27+
28+
| Constraint Name | Description | Control Name |
29+
|---------------------------------------------------|------------------------------------------------------|-------------------------------|
30+
| pss-baseline-v2022-apparmor | The AppArmor profile used by containers | AppArmor |
31+
| pss-baseline-v2022-capabilities | Linux capabilities | Capabilities |
32+
| pss-baseline-v2022-host-namespaces-host-pid-ipc | Usage of host namespaces | Host Namespaces |
33+
| pss-baseline-v2022-host-namespaces-hostnetwork | Use of host networking | Host Networking |
34+
| pss-baseline-v2022-host-ports | Usage of host ports | Host Ports (configurable) |
35+
| pss-baseline-v2022-hostpath-volumes | Usage of the host filesystem | HostPath Volumes |
36+
| pss-baseline-v2022-hostprocess | Usage of Windows HostProcess | HostProcess |
37+
| pss-baseline-v2022-privileged-containers | Running of privileged containers | Privileged Containers |
38+
| pss-baseline-v2022-proc-mount-type | The Allowed Proc Mount types for the container | /proc Mount Type |
39+
| pss-baseline-v2022-seccomp | The seccomp profile used by containers | Seccomp |
40+
| pss-baseline-v2022-selinux | The SELinux context of the container | SELinux |
41+
| pss-baseline-v2022-sysctls | The sysctl profile used by containers | Sysctls |
42+
43+
### `policy-essentials-v2022` details
44+
45+
This bundle of constraints addresses and enforces policies in the following domains:
46+
47+
- RBAC and service accounts
48+
- Pod Security Policies
49+
- Container Network Interface (CNI)
50+
- Secrets management
51+
- General policies
52+
53+
Constraint | Description |
54+
| - | - |
55+
policy-essentials-v2022-no-secrets-as-env-vars | Prefer using Secrets as files over Secrets as environment variables
56+
policy-essentials-v2022-pods-require-security-context | Apply Security Context to your Pods and containers
57+
policy-essentials-v2022-prohibit-role-wildcard-access | Minimize the use of wildcards in Roles and ClusterRoles.
58+
policy-essentials-v2022-psp-allow-privilege-escalation-container | Minimize the admission of containers with allowPrivilegeEscalation
59+
policy-essentials-v2022-psp-capabilities | Containers must drop the `NET_RAW` capability and aren't permitted to add back any capabilities.
60+
policy-essentials-v2022-psp-host-namespace | Minimize the admission of containers with `hostPID` or `hostIPC` set to `true`.
61+
policy-essentials-v2022-psp-host-network-ports | Minimize the admission of containers wanting to share the host network namespace
62+
policy-essentials-v2022-psp-pods-must-run-as-nonroot | Minimize the admission of root containers
63+
policy-essentials-v2022-psp-privileged-container | Minimize the admission of privileged containers
64+
policy-essentials-v2022-psp-seccomp-default | Ensure that the seccomp profile is set to `runtime/default` or `docker/default` in your Pod definitions
65+
policy-essentials-v2022-restrict-clusteradmin-rolebindings | Minimize the use of the cluster-admin role.
66+
67+
## Validating Correct Installation
68+
69+
After installing Policy Controller, you can verify that it completed successfully by running the following command:
70+
71+
```bash
72+
gcloud container fleet policycontroller describe --memberships=MEMBERSHIP_NAME
73+
```
74+
75+
You can also validate the installed constraints by running:
76+
77+
```bash
78+
kubectl get constrainttemplates
79+
```
80+
81+
## Violations Validation Example
82+
83+
If you want to validate the violations for the `pss-baseline-v2022` policy bundle, for example, you can run the following command:
84+
85+
```bash
86+
kubectl get constraint -l policycontroller.gke.io/bundleName=pss-baseline-v2022 -o json | jq -cC '.items[]| [.metadata.name,.status.totalViolations]'
87+
```
88+
89+
You can also see policies summary on GKE Dashboard, for example:
90+
![dashboard](./images/policies_dashboard.png)
91+
92+
### Enforcing policy to `warn` or `deny`
93+
94+
Once you've reviewed policy violations on your cluster, you can consider changing the enforcement mode so the Admission Controller will either warn on or even deny block non-compliant resource from getting applied to the cluster. Here is an example on how to update it to warn:
95+
96+
```bash
97+
kubectl get constraint -l policycontroller.gke.io/bundleName=pss-baseline-v2022 -o name | xargs -I {} kubectl patch {} --type='json' -p='[{"op":"replace","path":"/spec/enforcementAction","value":"warn"}]'
98+
```
99+
100+
> **Warning**: The deny enforcement action should be used with care as it can potentially block required changes resulting in interruption to critical workloads or the cluster.
101+
102+
## Additional Policies
103+
104+
You have three options for adding new policies:
105+
106+
1. **Add a Bundle of Policies**: Deploy a comprehensive set of policies as a bundle with common security and compliance controls.
107+
108+
2. **Add Individual Constraints**: Create policies by adding individual constraints based on the available constraint templates.
109+
110+
3. **Write Custom Policies**: Develop tailored policies by writing custom constraints to meet specific requirements.
111+
112+
### Adding a Bundle of Policies
113+
114+
You can add additional Bundles by editing the policy baseline on [3-fleetscope/modules/env_baseline/policy.tf](../3-fleetscope/modules/env_baseline/policy.tf).
115+
116+
For all the available bundles, see [Policy Controller Bundles on GKE](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/concepts/policy-controller-bundles)
117+
118+
### Adding Individual Constraints Policies
119+
120+
To explore the complete library of available constraint templates, please visit:
121+
122+
[Constraint Template Library](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/latest/reference/constraint-template-library)
123+
124+
For detailed instructions on how to utilize the constraint library, refer to the following guide:
125+
126+
[Creating Policy Controller Constraints](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/how-to/creating-policy-controller-constraints)
127+
128+
The recommended way of adding new individual policies, is to clone the `config-sync` repository and add the individual policies, for example:
129+
130+
### Example for Config Sync with Gitlab Repository
131+
132+
1. Clone config sync repository:
133+
134+
```bash
135+
git clone https://GIT_URL/namespace/config-sync-development.git && cd config-sync-development
136+
```
137+
138+
1. Create a file for your policy, here is an example for `K8sRequiredLabels`:
139+
140+
```YAML
141+
apiVersion: constraints.gatekeeper.sh/v1beta1
142+
kind: K8sRequiredLabels
143+
metadata:
144+
name: ns-must-have-geo
145+
spec:
146+
match:
147+
kinds:
148+
- apiGroups: [""]
149+
kinds: ["Namespace"]
150+
parameters:
151+
labels:
152+
- key: "geo"
153+
```
154+
155+
1. Commit to sync branch and wait for the policy to be applied on the cluster
156+
157+
```bash
158+
git add .
159+
git commit -am "require 'geo' label policy"
160+
git push origin master
161+
```
162+
163+
1. Wait for sync:
164+
165+
```bash
166+
kubectl get rootsyncs.configsync.gke.io -n config-management-system root-sync -o yaml
167+
```
168+
169+
### Writing Custom Policies
170+
171+
For guidance on creating custom policies, please refer to the official documentation available at the following link:
172+
173+
[How to Write Custom Constraint Templates](https://cloud.google.com/kubernetes-engine/enterprise/policy-controller/docs/how-to/write-custom-constraint-templates)

test/integration/fleetscope/fleetscope_test.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func TestFleetscope(t *testing.T) {
159159
tft.WithVars(vars),
160160
tft.WithRetryableTerraformErrors(testutils.RetryableTransientErrors, 3, 2*time.Minute),
161161
tft.WithBackendConfig(backendConfig),
162-
tft.WithParallelism(1),
162+
tft.WithParallelism(3),
163163
)
164164

165165
fleetscope.DefineInit(func(assert *assert.Assertions) {
@@ -275,6 +275,7 @@ func TestFleetscope(t *testing.T) {
275275

276276
assert.Equal("INSTALL_SPEC_ENABLED", gkeFeatureOp.Get(policycontrollerPath+".policyControllerHubConfig.installSpec").String(), fmt.Sprintf("Hub Feature %s policy controller should be INSTALL_SPEC_ENABLED", membershipName))
277277
assert.Equal("ALL", gkeFeatureOp.Get(policycontrollerPath+".policyControllerHubConfig.policyContent.templateLibrary.installation").String(), fmt.Sprintf("Hub Feature %s policy controller templateLibrary should be ALL", membershipName))
278+
278279
}
279280
}
280281
}
@@ -325,8 +326,40 @@ func TestFleetscope(t *testing.T) {
325326
return retry, nil
326327
}
327328
}
328-
utils.Poll(t, pollMeshProvisioning(gkeMeshCommand), 40, 60*time.Second)
329329

330+
pollPolicyControllerState := func() (bool, error) {
331+
booleans := make([]bool, len(membershipNamesProjectNumber))
332+
for i, membershipName := range membershipNamesProjectNumber {
333+
gcloudCmdOutput := gcloud.Runf(t, "container fleet policycontroller describe --memberships=%s --project=%s", membershipName, clusterProjectID)
334+
if len(gcloudCmdOutput.Array()) < 1 {
335+
return true, nil
336+
}
337+
admissionState := gcloudCmdOutput.Get("membershipStates").Get(membershipName).Get("policycontroller.componentStates.admission.state").String()
338+
auditState := gcloudCmdOutput.Get("membershipStates").Get(membershipName).Get("policycontroller.componentStates.audit.state").String()
339+
booleans[i] = (auditState == "ACTIVE" && admissionState == "ACTIVE")
340+
}
341+
// stop retrying when all clusters have the policy controller in the active state
342+
return !testutils.AllTrue(booleans), nil
343+
}
344+
345+
pollPoliciesInstallationState := func() (bool, error) {
346+
booleans := make([]bool, len(membershipNamesProjectNumber))
347+
for i, membershipName := range membershipNamesProjectNumber {
348+
gcloudCmdOutput := gcloud.Runf(t, "container fleet policycontroller describe --memberships=%s --project=%s", membershipName, clusterProjectID)
349+
if len(gcloudCmdOutput.Array()) < 1 {
350+
return true, nil
351+
}
352+
pss := gcloudCmdOutput.Get("membershipStates").Get(membershipName).Get("policycontroller.policyContentState.bundleStates.pss-baseline-v2022.state").String()
353+
policyessentials := gcloudCmdOutput.Get("membershipStates").Get(membershipName).Get("policycontroller.policyContentState.bundleStates.policy-essentials-v2022.state").String()
354+
booleans[i] = (pss == "ACTIVE" && policyessentials == "ACTIVE")
355+
t.Logf("booleans[%d]: %v", i, booleans[i])
356+
}
357+
return !testutils.AllTrue(booleans), nil
358+
}
359+
360+
utils.Poll(t, pollMeshProvisioning(gkeMeshCommand), 40, 60*time.Second)
361+
utils.Poll(t, pollPolicyControllerState, 6, 20*time.Second)
362+
utils.Poll(t, pollPoliciesInstallationState, 6, 20*time.Second)
330363
})
331364

332365
fleetscope.Test()

test/integration/testutils/bool.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2025 Google LLC
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package testutils
15+
16+
func AllTrue(arr []bool) bool {
17+
for _, value := range arr {
18+
if !value {
19+
return false
20+
}
21+
}
22+
return true
23+
}

0 commit comments

Comments
 (0)