Reader small image

You're reading from  Kubernetes – An Enterprise Guide - Second Edition

Product typeBook
Published inDec 2021
PublisherPackt
ISBN-139781803230030
Edition2nd Edition
Right arrow
Authors (2):
Marc Boorshtein
Marc Boorshtein
author image
Marc Boorshtein

Marc Boorshtein has been a software engineer and consultant for 20 years and is currently the CTO (Chief Technology Officer) of Tremolo Security, Inc. Marc has spent most of his career building identity management solutions for large enterprises, U.S. Government civilian agencies, and local government public safety systems.
Read more about Marc Boorshtein

Scott Surovich
Scott Surovich
author image
Scott Surovich

Scott Surovich has been involved in the industry for over 25 years and is currently the Global Container Engineering Lead at a tier 1 bank as the Global on-premises Kubernetes product owner architecting and, delivering cluster standards, including the surrounding ecosystem. His previous roles include working on other global engineering teams, including Windows, Linux, and virtualization.
Read more about Scott Surovich

View More author details
Right arrow

Extending Security Using Open Policy Agent

So far, we have covered Kubernetes' built-in authentication and authorization capabilities, which help to secure a cluster. While this will cover most use cases, it doesn't cover all of them. Several security best practices that Kubernetes can't handle are pre-authorizing container registries and ensuring that resource requests are on all Pod objects.

These tasks are left to outside systems and are called dynamic admission controllers. Open Policy Agent (OPA), and its Kubernetes native sub-project, Gatekeeper, is one of the most popular ways to handle these use cases. This chapter will detail the deployment of OPA and Gatekeeper, how OPA is architected, and how to develop policies.

In this chapter, we will cover the following topics:

  • Introduction to validating webhooks
  • What is OPA and how does it work?
  • Using Rego to write policies
  • Enforcing memory constraints
  • Enforcing Pod security...

Technical requirements

To complete the hands-on exercises in this chapter, you will require an Ubuntu 20.04 server, running a KinD cluster with the configuration from Chapter 6, RBAC Policies and Auditing.

You can access the code for this chapter at the following GitHub repository: https://github.com/PacktPublishing/Kubernetes---An-Enterprise-Guide-2E/tree/main/chapter8.

Introduction to dynamic admission controllers

There are two ways to extend Kubernetes:

  • Build a custom resource definition so that you can define your own objects and APIs.
  • Implement a webhook that listens for requests from the API server and responds with the necessary information. You may recall that in Chapter 5, Integrating Authentication into Your Cluster, we explained that a custom webhook could be used to validate tokens.

Starting in Kubernetes 1.9, a webhook can be defined as a dynamic admission controller, and in 1.16, the dynamic admission controller API became Generally Available (GA).

There are two types of dynamic admission controllers, validating and mutating. Validating admission controllers verify that a new object, update, or delete can move forward. Mutation allows a webhook to change the payload of an object's creation, deletion, or update. This section will focus on the details of admission controllers. We'll talk more...

What is OPA and how does it work?

OPA is a lightweight authorization engine that fits well in Kubernetes. It didn't get its start in Kubernetes, but it's certainly found a home there. There's no requirement to build dynamic admission controllers in OPA, but it's very good at it and there are extensive resources and existing policies that can be used to start your policy library.

This section provides a high-level overview of OPA and its components with the rest of the chapter getting into the details of an OPA implementation in Kubernetes.

OPA architecture

OPA comprises three components – the HTTP listener, the policy engine, and the database:

Figure 8.1: OPA architecture

The database used by OPA is in memory and ephemeral. It doesn't persist information used to make policy decisions. On the one hand, this makes OPA very scalable since it is essentially an authorization microservice. On the other hand, this means that every...

Using Rego to write policies

Rego is a language specifically designed for policy writing. It is different from most languages you have likely written code in. Typical authorization code will look something like the following:

//assume failure
boolean allowed = false;
//on certain conditions allow access
if (someCondition) {
  allowed = true;
}
//are we authorized?
if (allowed) {
  doSomething();
}

Authorization code will generally default to unauthorized, with a specific condition having to happen in order to allow the final action to be authorized. Rego takes a different approach. Rego is generally written to authorize everything unless a specific set of conditions happens.

Another major difference between Rego and more general programming languages is that there are no explicit if/then/else control statements. When a line of Rego is going to make a decision, the code is interpreted as "if this line is false, stop execution." For instance, the following code...

Enforcing memory constraints

So far in this chapter, we've built policies that are self-contained. When checking whether an image is coming from a pre-authorized registry, the only data we needed was from the policy and the containers. This is often not enough information to make a policy decision. In this section, we'll work on building a policy that relies on other objects in your cluster to make policy decisions.

Before diving into the implementation, let's talk about the use case. It's a good idea to include at least memory requirements on any Pod submitted to the API server. There are certain namespaces though where this doesn't make as much sense. For instance, many of the containers in the kube-system namespace don't have CPU and memory resource requests.

There are multiple ways we could handle this. One way is to deploy a constraint template and apply it to every namespace we want to enforce memory resource requests on. This can lead to...

Mutating objects and default values

To this point, everything we have discussed has been about how to use Gatekeeper to enforce a policy. Kubernetes has another feature called mutating admission webhooks that allow a webhook to change, or mutate, an object before the API server processes it and runs validating admission controllers.

A common usage of a mutating webhook is to explicitly set security context information on pods that don't have it set. For instance, if you create a Pod with no spec.securityContext.runAsUser then the Pod will run as the user the Docker container was built to run as using the USER directive (or root by default) when it was built. This is insecure, since it means you could be running as root, especially if the container in question is from Docker Hub. While you can have a policy that blocks running as root, you could also have a mutating webhook that will set a default user ID if it's not specified to make it a default. This makes for a better...

Summary

In this chapter, we explored how to use Gatekeeper as a dynamic admission controller to provide additional authorization policies on top of Kubernetes' built-in RBAC capabilities. We looked at how Gatekeeper and OPA are architected. Then, we learned how to build, deploy, and test policies in Rego. Finally, you were shown how to use Gatekeeper's built-in mutation support to create default configuration options in pods.

Extending Kubernetes' policies leads to a stronger security profile in your clusters and provides greater confidence in the integrity of the workloads you are running.

Using Gatekeeper can also help catch previously missed policy violations through its application of continuous audits. Using these capabilities will provide a stronger foundation for your cluster.

This chapter focused on whether or not to launch a Pod based on our specific policies. In the next chapter, we'll learn how to protect your nodes from the processes running...

Questions

  1. Are OPA and Gatekeeper the same thing?
    1. Yes
    2. No
  2. How is Rego code stored in Gatekeeper?
    1. It is stored as ConfigMap objects that are watched
    2. Rego has to be mounted to the Pod
    3. Rego needs to be stored as secret objects
    4. Rego is saved as a ConstraintTemplate
  3. How do you test Rego policies?
    1. In production
    2. Using an automated framework built directly into OPA
    3. By first compiling to WebAssembly
  4. In Rego, how do you write a for loop?
    1. You don't need to; Rego will identify iterative steps.
    2. By using the for all syntax.
    3. By initializing counters in a loop.
    4. There are no loops in Rego.
  5. What is the best way to debug Rego policies?
    1. Use an IDE to attach to the Gatekeeper container in a cluster
    2. In production
    3. Add trace functions to your code and...
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Kubernetes – An Enterprise Guide - Second Edition
Published in: Dec 2021Publisher: PacktISBN-13: 9781803230030
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Authors (2)

author image
Marc Boorshtein

Marc Boorshtein has been a software engineer and consultant for 20 years and is currently the CTO (Chief Technology Officer) of Tremolo Security, Inc. Marc has spent most of his career building identity management solutions for large enterprises, U.S. Government civilian agencies, and local government public safety systems.
Read more about Marc Boorshtein

author image
Scott Surovich

Scott Surovich has been involved in the industry for over 25 years and is currently the Global Container Engineering Lead at a tier 1 bank as the Global on-premises Kubernetes product owner architecting and, delivering cluster standards, including the surrounding ecosystem. His previous roles include working on other global engineering teams, including Windows, Linux, and virtualization.
Read more about Scott Surovich