• tl;dr sec
  • Posts
  • Authorization in the Micro Services World with Kubernetes, ISTIO and Open Policy Agent

Authorization in the Micro Services World with Kubernetes, ISTIO and Open Policy Agent

The history of authz implementation approaches, the value of externalizing authz from code, authz in Kubernetes, and the power of using Open Policy Agent (OPA) for authz with Kubernetes and ISTIO.

Sitaraman Lakshminarayanan, Senior Security Architect, Pure Storage 
abstract slides video

The history of authz implementation approaches, the value of externalizing authz from code, authz in Kubernetes, and the power of using Open Policy Agent (OPA) for authz with Kubernetes and ISTIO.

Types of Access Control

Sitaraman describes 3 types of access control:

  • Role based: A set of roles are defined which map to API endpoints that may be hit or permissions the role has.

    • Then there are checks in code for the current users’s role or set of permissions.

  • Attribute based: Various aspects of a user or a request are used to make the decision, for example, the user’s age, title, location / IP address, or other attributes.

    • This may be a combination of inline code and external API calls to systems that have this additional info.

  • Policy based: A combination of the above two types, in which you define what role or group can perform what actions on a resource under certain conditions.

    • For example, Admin users who are on the VPN can add new Admin users to the system.

History of Access Control Implementations

Sitaraman describes how implementing acccess controls in web applications has evolved over time.

Firewalls could perform very crude access controls (mostly by network location and port), external API gateways can restrict access to specific endpoints, internal API gateways can protect internal only services you don’t want to expose, and custom business logic can be implemented in code for more nuanced, endpoint-speccific decisions.

Challenges to Access Control Approaches

Implementing access controls in code means that the code must be updated whenever you want to modify authorization logic.

  • The update may not be quick and easy, meaning that fixing a bug takes time.

  • Updating a service in a complicated ecosystem with interdependencies between services may be hard.

  • If the expectations of what a role should or should not be able to do changes over time, assumptions about the purpose of a role are littered throughout a code base.

  • Understanding the expected permissions for a role may be non obvious, as the decisions are potentially littered through one or more large, complicated code bases.

  • Code changes require solid regression testing for access control bugs.

Pushing all access control decisions to API gateways can quickly become hard to manage in complex ecosystems with many roles and rules. Ops teams typically own the API gateway, so devs can’t directly make these changes, slowing down velocity due to the additional communication and process overhead.

How Do We Move Forward?

The goal is to externalize authorization from code, and not just with a gateway that acts as a checkpoint. It needs to be developer-friendly, and easy to developer, deploy and change policies.

The idea of externalizing authorization from code is actually not new, API gateways did this, as did the Extensible Access Control Markup Language (XACML) standard. It allowed the security or product teams to set authorization rules, not just devs.

However, XACML ended up failing because it required learning a separate, complicated syntax, causing more work for developers, and there weren’t many open source integrations.

What About Building Your Own Authorization API?

Implementing authorization as a separate service or library that applications call

Pros:

  • As you own it, you can have it work exactly how you want, making it fit into your ecosystem nicely.

Cons:

  • Your security or engineering team will have to build and maintain it.

  • You’ll likely need to build (and maintain) client library SDKs for every language you use at your enterprise.

  • You’ll need to train every dev on your API and integration, and there’s no open source community to source information from.

In the end, Sitaraman argues that for many companies this isn’t a worthwhile investment due to both the upfront and recurring time costs. All of these efforts detract from building new features and improving your company’s product, which delivers business value.

Kubernetes Authorization

Kubernetes web hook authz uses the following 3 aspects to make decisions: the resource being accessed, the action being performed (GET, POST, …), and the incoming user identity / token. Once enabled, every request to the Kubernetes will invoke the web hook and return an Allow or Deny.

Why Sitaraman Loves the K8 AuthZ Model

  • It provides the framework and lets customers manage their own Risk.

  • There’s no one size fits all RBAC model that you have to conform your usage to, as is the case in some vendor models.

  • API-first design – everything is a Resource.

  • Externalized Authorization through the web hook lets you manage risk and implement policy and process around your deployment.

However, K8z authz can’t be used for your microservices and business-specific APIs. Instead, you need something like ISTIO.

ISTIO Overview

ISTIO acts like a proxy for you, handling protocol translation, and makes it easy to enforce authorization, do logging, collect telemetry, and set quotas. Typically you deploy the Envoy proxy as a sidecar.

In short, ISTIO is a lightweight proxy in front of your API Services and operates at the Ingress and Egress layers

ISTIO Authorization

ISTIO authz is specified in YAML files. Fine-grained ACLs can be challenging, and while this authz is external to the primary code, it still requires re-deployment when authz rules are changed.

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: tester
  namespace: default
spec:
  rules:
  - services: ["test-*"]
    methods: ["*"]
  - services: ["bookstore.default.svc.cluster.local"]
    paths: ["*/reviews"]
    methods: ["GET"]

ISTIO Service to Service

While deploying ISTIO hides the complexity of service discovery and service invocation (e.g. mTLS, protocol translation, etc.), we still need to do authz locally to each service.

We’re still reinventing the wheel: each client has its own authz embedded in the code or at the proxy level.

Externalizing AuthZ in a Microservices World

Let’s take a step back. What do we need to do authz in a microservices world? We need:

  • The Resource (end point being invoked)

  • The Operations / Actions being performed

  • Identity of Caller

  • Payload

You could build your own solution, or use Open Policy Agent!

Open Policy Agent

OPA is a policy engine, available as a RESTful JSON API, in which policies are written in the declarative language Rego. Policies are updated in OPA via the /v1/policies API endpoint.

OPA Policy Walkthrough

# Package Name
package httpapi.authz

# Static Data
subordinates = {"alice": [], "charlie": [], 
               "bob": ["alice"], "betty": ["charlie"]} 

# "input" is a keyword. 
# Assign input as the http_api variable
import input as http_api

# Examines the input to see if the request should be allowed.
# In this case, if the HTTP method is GET and the path is
# /finance/salary/<username>, where <username> is http_api.user
# Returns True if everything evaluates to True
allow {
  http_api.method = "GET" 	
  http_api.path = ["finance", "salary", username] 	
  username = http_api.user 
}

An example Python script to invoke this OPA policy:

# Gather Input. 
# HTTP Filter that gathers all the data,
# such as User, Method, URL Path, etc.

# Create input to hand to OPA "input": 
input_dict = { 
  { "user": api_user_from_jwt, 
	  "path": “finance”, 
	  "method": “GET”
	} 
}

# Call OPA via POST to /v1/data/{PolicyName}
# and supply the Input. Decision returned as JSON
rsp = requests.post("http://example.com/v1/data/httpapi/authz", 
        data=json.dumps(input_dict)) 

# JSON is returned with allow:True or can be any specific data
if rsp.json()["allow"]

Ar

Benefits of OPA

  • You can update the authz policy without changing the source code. Policies can be hot swapped.

  • There’s an API where you can get what authz decisions have been made, for example, how many were successful, how many were denied, etc.

  • Policy definitions can be left to development teams to implement, but left outside of the core business API.

  • OPA can be used beyond the REST API: any external system that has support for plugins, OPA can be integrated as a plugin (e.g. Kafka topics, SSH auth, thrift, AWS console, and more).