Policy Management

Module goals

  • Create build, deploy and runtime policies

  • Create policies from filters

  • Clone and edit policies based on the ACS defaults

RHACS Policy Management Basics

RHACS has built-in policies to detect activities linked to attacker goals, like gaining access, maintaining presence, moving laterally, and exfiltrating data. Continuous runtime monitoring watches all container activities and automatically responds with enforcement and notifications. However, RHACS aims to go beyond this by leveraging the ephemeral, immutable nature of containers to improve security.

We want to turn runtime incidents and vulnerabilities into opportunities for better security by restricting container actions. This is done by creating and implementing policies early in the CI/CD process.

In the next section, we’ll focus on identifying and enforcing a runtime policy in the cluster. For this example, we’ll prevent the Alpine Linux package manager from running on pods in our cluster. We’ll use the frontend container, which includes this package manager, and ensure it cannot update while in the cluster.

Introduction to Runtime Policy Creation and Enforcement

RHACS monitors container processes and collects data to help create policies that block unwanted behavior. It also helps establish baseline policies that users can adjust. Runtime policies can include criteria from build-time and deploy-time but also account for process executions during runtime. However, runtime policies based on audit logs can’t use build and deploy criteria, as these logs are Kubernetes-specific events.

The example below shows how security may block a package manager from downloading packages. This runtime enforcement is the first step in shifting security left. After enforcing runtime policies, the next step will be to prevent the package manager from being used in the container entirely.

For the Runtime stage, RHACS stops all pods that match the conditions of the policy. It does not scale the deployment down to zero.
Procedure
  1. On the left-hand side of the application, click the Platform Configuration tab and select Policy Management.

04 policy 00
  1. Filter through the policies to find Alpine Linux Package Manager Execution or use the search bar to select Policy.

04 policy 01
  1. Once you have found the policy Alpine Linux Package Manager (apk) in Image, click on it to learn more.

04 policy 02

Prevent execution of package manager binary

Package managers like apt (Ubuntu), apk (Alpine), and yum/dnf (RedHat) are used to manage and update software on Linux hosts, including virtual machines. However, using a package manager to install or remove software on a running container breaks the container’s immutable nature.

This policy shows how RHACS detects and prevents such violations by using Linux kernel instrumentation to identify the running process and OpenShift to terminate the pod for enforcement. Enforcing runtime policy through OpenShift is preferred over doing it directly in the container or container engine. This ensures consistency between the state OpenShift manages and the state of the container. Additionally, since runtime policies might only detect part of an attack, removing the container entirely helps stop the attack.

Enable enforcement of policy

Procedure

  1. Click the Actions button, then click CLONE policy. Then give it the name "Alpine Linux Package Manager Execution - Runtime"

Alpine Linux Package Manager Execution - Runtime
04 policy 03
  1. Select Policy Behavior → Actions

04 policy 04
  1. Enable runtime enforcement by clicking the inform and enforce button.

  2. Configure enforcement behavior by selecting Enforce at Runtime.

04 policy 03
  1. Click Next

  2. Review the changes then click save

Make sure to save the policy changes! If you do not save the policy, the process will not be blocked!

Testing the configured policy

Next, we will use tmux to watch OpenShift events while running the test so you can see how RHACS enforces the policy at runtime.

Make sure that you are signed into the bastion host with OpenShift access when running the following commands.
Procedure
  1. In the terminal, start tmux with two panes:

tmux new-session \; split-window -v \; attach
  1. Next, run a watch on OpenShift events in the first shell pane:

oc get events -n patient-portal -w
  1. Press Ctrl+b first, and then press o to switch to the next pane. (Hold ctrl+b then press o)

  2. Exec into our Java application by getting the pod details and adding them to the following command.

POD=$(oc get pod -l app=frontend -n patient-portal -o jsonpath="{.items[0].metadata.name}")
oc exec $POD -n patient-portal -i --tty -- /bin/bash
[demo-user@bastion ~]$ POD=$(oc get pod -l app=frontend -o jsonpath="{.items[0].metadata.name}")
oc exec $POD -i --tty -- /bin/bash
node@frontend-6db858448f-hz6j2:/app$

If you see /home/fritz you’ve confirmed you have a shell and access to the Java application.

  1. Run the apk package manager in this shell:

apk update

Sample output

node@frontend-6db858448f-stwhq:/$ apt update
Reading package lists... Done
E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied)
node@frontend-6db858448f-stwhq:/$ command terminated with exit code 137
  1. Examine the output and expect to see that the package manager attempts to perform an update operation

  2. Examine the oc get events tmux pane (The pane on the bottom), and note that it shows that RHACS detected the package manager invocation and deleted the pod:

0s          Normal    Killing                pod/frontend-78795c75fc-7nhs4             Stopping container frontend
0s          Normal    SuccessfulCreate       replicaset/frontend-78795c75fc            Created pod: frontend-78795c75fc-8q9fn
0s          Normal    Scheduled              pod/frontend-78795c75fc-8q9fn             Successfully assigned patient-portal/frontend-78795c75fc-8q9fn to ip-10-0-108-51.us-east-2.compute.internal
0s          Normal    AddedInterface         pod/frontend-78795c75fc-8q9fn             Add eth0 [10.129.3.148/23] from ovn-kubernetes
0s          Normal    Pulling                pod/frontend-78795c75fc-8q9fn             Pulling image "quay-88k5s.apps.cluster-88k5s.88k5s.sandbox139.opentlc.com/quayadmin/frontend:0.1"
0s          Normal    Pulled                 pod/frontend-78795c75fc-8q9fn             Successfully pulled image "quay-88k5s.apps.cluster-88k5s.88k5s.sandbox139.opentlc.com/quayadmin/frontend:0.1" in 61ms (61ms including waiting). Image size: 119108884 bytes.
0s          Normal    Created                pod/frontend-78795c75fc-8q9fn             Created container: frontend
0s          Normal    Started                pod/frontend-78795c75fc-8q9fn             Started container frontend
After a few seconds, you can see the pod is deleted and recreated. In your tmux shell pane, note that your shell session has terminated and that you are returned to the Bastion VM command line.

Congrats!

The security investigative process continues, as you have now raised a flag that must be triaged! We will triage our violations later in this module.

Type exit in the terminal, use ctrl+c to stop the 'watch' command, and type exit one more time to get back to the default terminal.

Introduction to deploy-time policy enforcement

Deploy-time policy enforces configuration controls both before deployment in the CI/CD process and within the cluster itself. It can include build-time policies and cluster configurations, such as privileged mode or mounting the Docker socket.

There are two ways to enforce deploy-time policies in RHACS:

  • With listen and enforce options enabled, RHACS rejects deployments that violate the policy using the admission controller.

  • When the admission controller is disabled, RHACS scales pod replicas to zero for deployments that violate the policy.

Next, we’ll set up a Deploy-Time policy to block applications from deploying into the default namespace if the image contains the apt|dpkg application.

Prevent the Alpine Linux Package Manager in the frontend image from being deployed

Procedure

  1. First, delete the deployment from the cluster, we will redeploy the application after creating the policy.

oc delete -f $APP_HOME/skupper-demo/frontend.yml

Sample output

[lab-user@bastion ~]$ oc delete -f $APP_HOME/skupper-demo/
namespace "patient-portal" deleted
deployment.apps "database" deleted
service "database" deleted
deployment.apps "frontend" deleted
route.route.openshift.io "frontend-patient-route" deleted
service "frontend-service" deleted
deployment.apps "payment-processor" deleted
service "payment-service" deleted
  1. Navigate to Platform Configuration → Policy Management

  2. On the Policy Management page, type Policy then Alpine Linux Package Manager (apk) in Image into the filter bar at the top.

This time you are going to edit a different policy for the Alpine Linux Package Manager (apk), specifically related to the Build & Deploy phases.
  1. Click on the Alpine Linux Package Manager (apk) in Image options (The three dots on the right side of the screen) and select Clone policy

Make sure to CLONE the policy. Cloning policies ensure the default policies don’t aren’t altered.
04 deploy 00
  1. Give the policy a new name, such as Alpine Linux Package Manager in Image - Enforce Deploy. The best practice would be to add a description for future policy enforcers as well.

Alpine Linux Package Manager in Image - Enforce Deploy
  1. Click Next

  2. Next, deselect Build stage so that only the Deploy stage is selected.

04 deploy 01
Since certain policy criteria is specific to each stage you have to reset the policy criteria

Now, we want to target our specific deployment with an image label.

  1. Click Next

  2. Click on the Image contents dropdown on the right side of the browser.

  3. Find the Image component label and drag it to the default policy criteria.

  4. Type apk-tools under the criteria

Your policy should look like this,

04 deploy 02
  1. In Policy behavior → Actions, click Inform and enforce + Enforce on Deploy

04 deploy 03
  1. Click Next

  2. Review the changes

  3. Click Save

Now, let’s test it out! We’re going to redeploy the frontend application from earlier.

In case you forgot to run the command earlier

oc delete -f $APP_HOME/skupper-demo/frontend.yml

Now reapply the frontend service and deployment

oc apply -f $APP_HOME/skupper-demo/frontend.yml
route.route.openshift.io/frontend-patient-route created
service/frontend-service created
Error from server (Failed currently enforced policies from RHACS): error when creating "/home/lab-user/skupper-app/skupper-demo/frontend.yml": admission webhook "policyeval.stackrox.io" denied the request:
The attempted operation violated 1 enforced policy, described below:

Policy: Alpine Linux Package Manager in Image - Enforce Deploy
- Description:
    ↳ Alert on deployments with the Alpine Linux package manager (apk) present
- Rationale:
    ↳ Package managers make it easier for attackers to use compromised containers,
      since they can easily add software.
- Remediation:
    ↳ Run `apk --purge del apk-tools` in the image build for production containers.
- Violations:
    - Container 'frontend' includes component 'apk-tools' (version 2.14.6-r2)


In case of emergency, add the annotation {"admission.stackrox.io/break-glass": "ticket-1234"} to your deployment with an updated ticket number

Another option for enforcement is to use the "deployment check" CLI command.

  1. Verify the frontend application against the policies you’ve created.

roxctl -e $ROX_CENTRAL_ADDRESS:443 deployment check --file $APP_HOME/skupper-demo/frontend.yml --insecure-skip-tls-verify
04 deploy 04

The new policy will fail the check when in enforce mode. In inform mode you will get a policy violation without the "Failed policy" error.

Congrats!

You’re now enforcing against the Alpine Linux package manager at runtime and deploy time. Let’s finish with enforcing at build-time!

Introduction to build-time policy enforcement

Build time policies for container images are guidelines that define how container images should be constructed. These policies aim to achieve several goals, including:

  • Security: Minimizing vulnerabilities and ensuring images are built with secure practices.

  • Efficiency: Reducing image size and build times for faster deployments.

  • Consistency: Maintaining a uniform structure and content across all images. Here are some key areas covered by build time policies:

  • Base Image: Specifying a minimal base image that only contains essential components.

  • Package Management: Encouraging the use of package managers for dependency installation and updates.

  • File Copying: Limiting what gets copied into the image to only required files and avoiding unnecessary bloat.

  • User Management: Defining a non-root user for the application process to run as.

  • Environment Variables: Storing sensitive information in environment variables outside the image.

In RHACS, build-time policies apply to image fields such as CVEs and Dockerfile instructions.

Prevent the Alpine Linux package manager in the frontend image from being pushed to Quay

  1. Verify that the variables are correct to make this section smoother

echo $QUAY_USER
echo $QUAY_URL
echo $ROX_CENTRAL_ADDRESS
  1. Make sure you are logged in to Quay

podman login $QUAY_URL -u $QUAY_USER -p sample_LSncwGJkXcayY1tUMmr8
Use the quay admin credentials, Username: sample_quayadmin & password: sample_LSncwGJkXcayY1tUMmr8. You can create unique user and group credentials in Quay for proper segmentation.
  1. Let’s pretend as if the developers are pushing an update to the frontend application. First, pull and scan the related image.

The following command is designed to mimic and build a pipeline where a container build is going through a commit/promotion step. You download the image, scan for vulnerabilities, tag a newer version and upload to Quay.

podman pull $QUAY_URL/$QUAY_USER/frontend:0.1
roxctl --insecure-skip-tls-verify -e "$ROX_CENTRAL_ADDRESS:443" image check --image=$QUAY_URL/$QUAY_USER/frontend:0.1
--------------------------------------------------------------------------------------------------------------------------------------------------------+
|  Alpine Linux Package Manager  |   LOW    |      -       | Alert on deployments with the  |   - Image includes component   |      Run `apk --purge del      |
|         (apk) in Image         |          |              |  Alpine Linux package manager  |      'apk-tools' (version      | apk-tools` in the image build  |
|                                |          |              |         (apk) present          |           2.14.6-r3)           |   for production containers.   |
--------------------------------------------------------------------------------------------------------------------------------------------------------+
|  Alpine Linux Package Manager  |   LOW    |      -       | Alert on deployments with the  |   - Image includes component   |      Run `apk --purge del      |
|    in Image - Enforce Build    |          |              |  Alpine Linux package manager  |      'apk-tools' (version      | apk-tools` in the image build  |
|                                |          |              |         (apk) present          |           2.14.6-r3)           |   for production containers.   |
--------------------------------------------------------------------------------------------------------------------------------------------------------+
WARN:   A total of 3 policies have been violated

With the Image Check cli command you can check against the created policies

podman tag $QUAY_URL/$QUAY_USER/frontend:0.1 $QUAY_URL/$QUAY_USER/frontend:0.2
podman push $QUAY_URL/$QUAY_USER/frontend:0.2 --remove-signatures
[lab-user@bastion ~]$ podman tag $QUAY_URL/$QUAY_USER/frontend:1.0 $QUAY_URL/$QUAY_USER/frontend:1.1
podman push $QUAY_URL/$QUAY_USER/frontend:1.1 --remove-signatures
Copying blob 308102f44919 skipped: already exists
Copying blob b8d9a96d44df skipped: already exists
....
Copying config 1cbb2b7908 done   |
Writing manifest to image destination
Now RHACS hasn’t broken the command since there is no enforcement of any build policies. Letting the developer build tag and push a new image.

Let’s make a copy of the build & deploy-time policy and enforce it during the build phase.

Procedure

  1. Navigate to Platform Configuration → Policy Management

  2. On the Policy Management page, type Policy then Alpine Linux into the filter bar at the top.

  3. Click on the Alpine Linux Package Manager in Image options (The three dots on the right side of the screen) and select Clone policy

Make sure to CLONE the policy
04 deploy 05
  1. Give the policy the name Alpine Linux Package Manager in Image - Enforce Build. The best practice would be to add a description for future policy enforcers as well.

Alpine Linux Package Manager in Image - Enforce Build
  1. Unselect the "Deploy" stage, and reset the policy criteria.

  2. Click "Next"

  3. Add the "image component - apk-tools" to the Rules

  4. Click "Next"

  5. Remove all of the exclusion scopes. You can do this by clicking the garbage tags in the scope. Exclusion scopes are limited to the build and runtime stages.

  6. Click "Next"

  7. Update the policy to inform and enforce while ensuring the Build stage checkbox is selected And select Enforce on Build at the bottom of the page.

04 deploy 06
  1. Go to the Review Policy tab

  2. Review the changes.

  3. Click Save

Now let’s test it out!

Run the following in the terminal.

podman pull $QUAY_URL/$QUAY_USER/frontend:0.1
roxctl image check --insecure-skip-tls-verify -e "$ROX_CENTRAL_ADDRESS:443"  --image=$QUAY_URL/$QUAY_USER/frontend:0.1
WARN:   A total of 3 policies have been violated
ERROR:  failed policies found: 1 policies violated that are failing the check
ERROR:  Policy "Alpine Linux Package Manager in Image - Enforce Build" - Possible remediation: "Run `apk --purge del apk-tools` in the image build for production containers."
ERROR:  checking image failed: failed policies found: 1 policies violated that are failing the check
You should see the same violations from the previous command EXCEPT now you have a failed policy check. This would send an exit 0 command if this was run in any pipeline.

Summary

giphy

AMAZING!

Before you head to the next module. Make sure to run the following commands to redploy our example app.

POLICY_ID=$(curl -X GET \
  -H "Authorization: Bearer $ROX_API_TOKEN" \
  -H "Content-Type: application/json" \
  https://$ROX_CENTRAL_ADDRESS/v1/policies | jq -r '.policies[] | select(.name=="Alpine Linux Package Manager in Image - Enforce Deploy") | .id')

curl -X DELETE \
  -H "Authorization: Bearer $ROX_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
        "id": "$POLICY_ID"
      }' \
  https://$ROX_CENTRAL_ADDRESS/v1/policies/$POLICY_ID

oc apply -f $APP_HOME/skupper-demo/

In summary, we made use of the features provided by Red Hat Advanced Cluster Security for Kubernetes to display potential security violations in your cluster in a central dashboard. You crafted both deploy-time and runtime policies to help prevent malicious events from occurring in our cluster. Hopefully this lab has helped demonstrate to you the immense value provided by RHACS and OpenShift Platform Plus. Please feel free to continue and explore the RHACS lab environment.

On to CI/CD and Automation!