Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARO-1423 and ARO-1422: Deny Editing ClusterVersion and UpgradeConfig #2975

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
68c9fc1
ARO-1422: UpgradeConfig Policy source codes
edisonLcardenas May 23, 2023
9f1b11c
ARO-1422: Update opa and gator tests. Add documentation to run opa do…
edisonLcardenas May 25, 2023
943adcf
ARO-1422: Update names and add missing constraint for UpgradeConfig p…
edisonLcardenas May 26, 2023
e69d5e7
ARO-1422: Add logic to retrieve data.inventory
edisonLcardenas May 30, 2023
1063b0f
ARO-1422: Update implementation to retrieve from data.inventory docum…
edisonLcardenas May 31, 2023
beb28ee
ARO-1422: Fixed formatting and removed unnecessary print statemenets.
edisonLcardenas Jun 1, 2023
363cd48
ARO-1422: Document process of syncing data into OPA and testing your …
edisonLcardenas Jun 1, 2023
8bbcd65
ARO-1423: Create rego src, templates, and tests
edisonLcardenas Jun 6, 2023
cc03132
ARO-1422: Rename gatekeeper-config.yaml to sync.yaml, to indicate tha…
edisonLcardenas Jun 7, 2023
3ffda71
Merge branch 'feature/guardrails-policy' into feature/aro-1423_guardr…
edisonLcardenas Jun 20, 2023
ec1d943
ARO-1423: Refactor name
edisonLcardenas Jun 21, 2023
053d77d
Merge branch 'feature/aro-1423_guardrails_cluster_version_policy' int…
edisonLcardenas Jun 22, 2023
000cedf
Merge branch 'feature/guardrails-policy-m2' into feature/ARO-1422_Upg…
edisonLcardenas Jun 27, 2023
6e5ff58
ARO-1423: Fix yaml lint issue with missing new line at end of file.
edisonLcardenas Jun 23, 2023
fc16f03
ARO-1422 & ARO-1423: Merge logic of two policies. They have similar l…
edisonLcardenas Jun 28, 2023
1d3fc2e
ARO-1422 & ARO-1423: Refactor redundant test data and update deny mes…
edisonLcardenas Jun 29, 2023
747d3fb
ARO-1422 & ARO-1422: Modify metadata name, update deny message, and m…
edisonLcardenas Jun 29, 2023
cb88f6b
ARO-1422 & ARO-1423: Remove 'excludedNamespaces' in sync.yaml. It pr…
edisonLcardenas Jul 3, 2023
d8aea5e
ARO-1422 & ARO-1423: Add missing documentation for 'data.inventory'.
edisonLcardenas Jul 3, 2023
4318d7c
Fix lint issues
edisonLcardenas Jul 5, 2023
3dec559
ARO-1422 & ARO-1423: Fixed lint issues on whitespaces
edisonLcardenas Jul 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 133 additions & 1 deletion pkg/operator/controllers/guardrails/policies/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,94 @@ spec:
- apiGroups: ["policy"]
kinds: ["PodDisruptionBudget"]
```

Make sure the filename of constraint is the same as the .metadata.name of the Constraint object, as it is the feature flag name that will be used to turn on / off the policy.


# Syncing of data into OPA using `data.inventory`

* Not all data you need are found on the `'input.review'` object. For example, if your policy is for blocking modification of the UpgradeConfig, and you need to check if the cluster is connected to OCM via the ConfigMap of `'openshift-managed-upgrade-operator'`, the info you need will not available on the `'input.review'` object because it only contains data from the UpgradeConfig the user is trying to modify. In this case, you need to sync data of the ConfigMap into OPA via `'data.inventory'` document so your rule can access it. In order to create such policies, you need to follow the steps below:

* Set the `'audit-from-cache'` flag to true in ".../gktemplates/aro-deny-upgradeconfig.yaml".
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
control-plane: audit-controller
gatekeeper.sh/operation: audit
gatekeeper.sh/system: "yes"
name: gatekeeper-audit
namespace: {{.Namespace}}
spec:
replicas: 1
selector:
matchLabels:
control-plane: audit-controller
gatekeeper.sh/operation: audit
gatekeeper.sh/system: "yes"
template:
metadata:
labels:
control-plane: audit-controller
gatekeeper.sh/operation: audit
gatekeeper.sh/system: "yes"
spec:
automountServiceAccountToken: true
containers:
- args:
- --audit-from-cache=true ----->>>>>SET THIS FLAG TO TRUE
```
* Create and apply the sync config resource to the cluster. Only resources in syncOnly will be synced into OPA. See template below. For more info, please check https://open-policy-agent.github.io/gatekeeper/website/docs/v3.10.x/exempt-namespaces

```yaml
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: "openshift-azure-guardrails"
spec:
match:
- excludedNamespaces: [""] # Namespaces to exclude from the sync data. It is always best to remove any data that is not needed for your policy
processes: [""] # Includes all processes
sync:
syncOnly:
- group: "" # Populate as needed
version: "" # Populate as needed
kind: "" # Populate as needed
# Add resources as needed
```
* Below is a sample implementation of a sync config resource which allows syncing data of all ConfigMap and Namespace resources with the version `v1`. Avoid using `excludedNamespaces` because it prevents other policies from woring.
```yaml
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: "openshift-azure-guardrails"
spec:
sync:
syncOnly:
- group: ""
version: "v1"
kind: "ConfigMap"
- group: ""
version: "v1"
kind: "Namespace"

```
* Write your rego rule. To access data from `'data.inventory'`, follow the format below:

* For cluster-scoped objects: `'data.inventory.cluster[<groupVersion>][<kind>][<name>]'`. Example below.

```Rego
data.inventory.cluster["v1"].Namespace["gatekeeper"]
```
* For namespace-scoped objects: `'data.inventory.namespace[<namespace>][groupVersion][<kind>][<name>]'`. Example below.
```Rego
data.inventory.namespace["openshift-managed-upgrade-operator"]["v1"]["ConfigMap"]["managed-upgrade-operator-config"]["data"]["config.yaml"]
```
* For more info on syncing your data into OPA, please check the official Gatekeeper documentation https://open-policy-agent.github.io/gatekeeper/website/docs/v3.10.x/sync


## Test Rego source code

* install opa cli, refer https://github.com/open-policy-agent/opa/releases/
Expand All @@ -147,6 +232,32 @@ Make sure the filename of constraint is the same as the .metadata.name of the Co
opa test ../library/common.rego *.rego [-v] #-v for verbose
```

* Using docker, get the OPA docker image - https://hub.docker.com/r/openpolicyagent/opa/.
Run the test as:
```sh
#### Format ####
docker run -it <HOST_SOURCE_DIRECTORY>:<CONTAINER_TARGET_DIRECTORY>:Z openpolicyagent/opa test [<LIBRARY>/*.rego] <CONTAINER_TARGET_DIRECTORY>/src.rego <CONTAINER_TARGET_DIRECTORY>/src_test.rego


##### Example #####
$ docker run -it -v /home/ecardena/dev/ARO-RP/pkg/operator/controllers/guardrails/policies/gktemplates-src:/gktemplates-src:Z openpolicyagent/opa test /gktemplates-src/library/common.rego /gktemplates-src/aro-deny-upgradeconfig/src.rego /gktemplates-src/aro-deny-upgradeconfig/src_test.rego -v
```


### Testing rego using `data.inventory`

When checking for violation on your test case, append `'with data.inventory as <inventory_data_variable_name>'`. For example, on your src_test.rego:

```Rego
test_input_allowed_system_user_update_upgradeconfig {
input := {"review": input_configmap("system:admin", "system:admin", "UPDATE")}
inv := inv_data(create_data_ocm([]))
results := violation with input as input with data.inventory as inv
count(results) == 0
}
```


## Generate the Constraint Templates

* install gomplate which is used by generate.sh, see https://docs.gomplate.ca/installing/
Expand Down Expand Up @@ -240,7 +351,28 @@ or below cmd after test.sh has been executed:
```sh
gator verify . [-v] #-v for verbose
```
<br>

### Gator test your policy using `data.inventory`
* In order to test your rego policy that's using `data.inventory`, you need to add `'inventory: <path to your mock data.inventory>'`. For example:

```yaml
kind: Suite
apiVersion: test.gatekeeper.sh/v1alpha1
metadata:
name: upgradeconfig
tests:
- name: upgradeconfig-tests
template: ../../gktemplates/aro-deny-upgradeconfig.yaml
constraint: ../../gkconstraints-test/aro-upgradeconfig-deny.yaml
cases:
- name: create-upgradeconfig-allowed-regular-user
object: gator-test/regular_user_create_managed_upgrade_operator.yaml
inventory:
- gator-test/inventory_config_local.yaml
assertions:
- violations: no
```
Sometimes we need to mock kube admission review request especially as Gator test inputs when verifying policies that check specific operations (e.g., CREATE, DELETE or UPDATE).

Please refer the yaml file below as a sample of kube admission review request:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: ARODenyClusterVersionUpgradeConfig
metadata:
name: aro-clusterversion-upgradeconfig-deny
spec:
enforcementAction: {{.Enforcement}}
match:
kinds:
- apiGroups: [""]
kinds: ["ConfigMap"]
- apiGroups: ["upgrade.managed.openshift.io"]
kinds: ["UpgradeConfig"]
- apiGroups: ["config.openshift.io"]
kinds: ["ClusterVersion"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# UpgradeConfig Policy

This policy needs the 'sync.yaml' applied to the cluster in order to retrieve data from data.inventory document.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: arodenyclusterversionupgradeconfig
annotations:
metadata.gatekeeper.sh/title: "ClusterVersion-UpgradeConfig"
metadata.gatekeeper.sh/version: 1.0.0
description: >-
Disallows editing of ClusterVersioin and UpgradeConfig by regular users if there is a "cloud.openshift.com" entry in "openshift-config/pull-secret".

spec:
crd:
spec:
names:
kind: ARODenyClusterVersionUpgradeConfig
validation:
# Schema for the `parameters` field
openAPIV3Schema:
type: object
description: >-
Disallows editing of ClusterVersioin and UpgradeConfi by regular users if there is a "cloud.openshift.com" entry in "openshift-config/pull-secret".
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
{{ file.Read "gktemplates-src/aro-deny-clusterversion-upgradeconfig/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }}
libs:
- |
{{ file.Read "gktemplates-src/library/common.rego" | strings.Indent 10 | strings.TrimSuffix "\n" }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
kind: ConfigMap
metadata:
creationTimestamp: "2023-05-31T03:24:37Z"
name: managed-upgrade-operator-config
namespace: openshift-managed-upgrade-operator
apiVersion: v1
name: managed-upgrade-operator-config
data:
config.yaml: "configManager:\n source: LOCAL\n \n localConfigName: managed-upgrade-config\n
\ watchInterval: 15\nmaintenance:\n controlPlaneTime: 90\n ignoredAlerts:\n
\ controlPlaneCriticals:\n - ClusterOperatorDown\n - ClusterOperatorDegraded\nupgradeType:
ARO\nupgradeWindow:\n delayTrigger: 30\n timeOut: 120\nnodeDrain:\n timeOut:
45\n expectedNodeDrainTime: 8\nscale:\n timeOut: 30\nhealthCheck:\n ignoredCriticals:\n
\ - PrometheusRuleFailures\n - CannotRetrieveUpdates\n - FluentdNodeDown\n ignoredNamespaces:\n
\ - openshift-logging\n - openshift-redhat-marketplace\n - openshift-operators\n
\ - openshift-user-workload-monitoring\n - openshift-pipelines\n - openshift-azure-logging\n"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
kind: ConfigMap
metadata:
creationTimestamp: "2023-06-31T03:24:37Z"
name: managed-upgrade-operator-config
namespace: openshift-managed-upgrade-operator
apiVersion: v1
name: managed-upgrade-operator-config
data:
config.yaml: "configManager:\n source: LOCAL\n \n localConfigName: managed-upgrade-config\n
\ watchInterval: 15\nmaintenance:\n controlPlaneTime: 90\n ignoredAlerts:\n
\ controlPlaneCriticals:\n - ClusterOperatorDown\n - ClusterOperatorDegraded\nupgradeType:
ARO\nupgradeWindow:\n delayTrigger: 30\n timeOut: 120\nnodeDrain:\n timeOut:
45\n expectedNodeDrainTime: 8\nscale:\n timeOut: 30\nhealthCheck:\n ignoredCriticals:\n
\ - PrometheusRuleFailures\n - CannotRetrieveUpdates\n - FluentdNodeDown\n ignoredNamespaces:\n
\ - openshift-logging\n - openshift-redhat-marketplace\n - openshift-operators\n
\ - openshift-user-workload-monitoring\n - openshift-pipelines\n - openshift-azure-logging\n"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
kind: ConfigMap
metadata:
creationTimestamp: "2023-05-31T03:24:37Z"
name: managed-upgrade-operator-config
namespace: openshift-managed-upgrade-operator
apiVersion: v1
name: managed-upgrade-operator-config
data:
config.yaml: "configManager:\n source: OCM\n \n localConfigName: managed-upgrade-config\n
\ watchInterval: 15\nmaintenance:\n controlPlaneTime: 90\n ignoredAlerts:\n
\ controlPlaneCriticals:\n - ClusterOperatorDown\n - ClusterOperatorDegraded\nupgradeType:
ARO\nupgradeWindow:\n delayTrigger: 30\n timeOut: 120\nnodeDrain:\n timeOut:
45\n expectedNodeDrainTime: 8\nscale:\n timeOut: 30\nhealthCheck:\n ignoredCriticals:\n
\ - PrometheusRuleFailures\n - CannotRetrieveUpdates\n - FluentdNodeDown\n ignoredNamespaces:\n
\ - openshift-logging\n - openshift-redhat-marketplace\n - openshift-operators\n
\ - openshift-user-workload-monitoring\n - openshift-pipelines\n - openshift-azure-logging\n"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
kind: ConfigMap
metadata:
creationTimestamp: "2023-06-31T03:24:37Z"
name: managed-upgrade-operator-config
namespace: openshift-managed-upgrade-operator
apiVersion: v1
name: managed-upgrade-operator-config
data:
config.yaml: "configManager:\n source: OCM\n \n localConfigName: managed-upgrade-config\n
\ watchInterval: 15\nmaintenance:\n controlPlaneTime: 90\n ignoredAlerts:\n
\ controlPlaneCriticals:\n - ClusterOperatorDown\n - ClusterOperatorDegraded\nupgradeType:
ARO\nupgradeWindow:\n delayTrigger: 30\n timeOut: 120\nnodeDrain:\n timeOut:
45\n expectedNodeDrainTime: 8\nscale:\n timeOut: 30\nhealthCheck:\n ignoredCriticals:\n
\ - PrometheusRuleFailures\n - CannotRetrieveUpdates\n - FluentdNodeDown\n ignoredNamespaces:\n
\ - openshift-logging\n - openshift-redhat-marketplace\n - openshift-operators\n
\ - openshift-user-workload-monitoring\n - openshift-pipelines\n - openshift-azure-logging\n"
Loading