• Stars
    star
    233
  • Rank 172,230 (Top 4 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Kubernetes operator to produce egress gateway Envoy pods and control access to them with network policies

egress-operator

An operator to produce egress gateway pods and control access to them with network policies, and a coredns plugin to route egress traffic to these pods.

The idea is that instead of authorizing egress traffic with protocol inspection, you instead create a internal clusterIP for every external service you use, lock it down to only a few pods via a network policy, and then set up your dns server to resolve the external service to that clusterIP.

Built with kubebuilder: https://book.kubebuilder.io/

The operator accepts ExternalService objects, which aren't namespaced, which define a dns name and ports for an external service. In the egress-operator-system namespace, it creates:

  • An envoy configmap for a TCP/UDP proxy to that service (UDP not working until the next envoy release that enables it)
  • A deployment for some envoy pods with that config
  • A horizontal pod autoscaler to keep the deployment correctly sized
  • A service for that deployment
  • A network policy only allowing pods in other namespaces with the label egress.monzo.com/allowed-<yourservice>: true

Pre-requisites

  1. You need to have a private container repository for hosting the egress-operator image, such as an AWS Elastic Container Repository (ECR) or a GCP Container Registry (GCR), which needs to be accessible from your cluster. This will be referred to as yourrepo in the instructions below.
  2. Your local system must have a recent version of golang for building the code, which you can install by following instructions here.
  3. Your local system must have Kubebuilder for code generation, which you can install by following instructions here.
  4. Your local system must have Kustomize for building the Kubernetes manifests, which you can install by following instructions here.
  5. Your cluster must be running CoreDNS instead of kube-dns, which may not be the case if you are using a managed Kubernetes service. This article provides some help for GCP Kubernetes Engine, and guidance for AWS Elastic Kubernetes Service can be found here.

Installing

Testing locally against a remote cluster

make run

This creates an ExternalService object to see the controller-manager creating managed resources in the remote cluster.

Setting up CoreDNS plugin

The CoreDNS plugin rewrites responses for external service hostnames managed by egress-operator.

Build a CoreDNS image which contains the plugin:

cd coredns-plugin
make docker-build docker-push IMG=yourrepo/egress-operator-coredns:latest

You'll need to swap out the image of your coredns kubedns Deployment for yourrepo/egress-operator-coredns:latest:

kubectl edit deploy coredns -n kube-system   # Your Deployment name may vary

And edit the coredns Corefile in ConfigMap to put in egressoperator egress-operator-system cluster.local:

kubectl edit configmap coredns-config -n kube-system   # Your ConfigMap name may vary

Example CoreDNS config:

.:53 {
    egressoperator egress-operator-system cluster.local
    kubernetes cluster.local
    forward . /etc/resolv.conf
}

Set up the controller manager and its CustomResourceDefinition in the cluster

make docker-build docker-push install IMG=yourrepo/egress-operator:v0.1
make deploy IMG=yourrepo/egress-operator:v0.1

Usage

Once the controller and dns server are running, create ExternalService objects which denote what dns name you want to capture traffic for. Dns queries for this name will be rewritten to point to gateway pods.

By default, your client pods need a label egress.monzo.com/allowed-gateway: nameofgateway to be able to reach the destination, but you can always write an additional NetworkPolicy selecting gateway pods and allowing all traffic, for testing purposes.

An example ExternalService:

apiVersion: egress.monzo.com/v1
kind: ExternalService
metadata:
  name: google
spec:
  dnsName: google.com
  # optional, defaults to false, instructs dns server to rewrite queries for dnsName
  hijackDns: true
  ports:
  - port: 443
    # optional, defaults to TCP
    protocol: TCP
  # optional, defaults to 3
  minReplicas: 5
  # optional, defaults to 12
  maxReplicas: 10
  # optional, defaults to 50
  targetCPUUtilizationPercentage: 30
  # optional, if not provided then defaults to 100m, 50Mi, 2, 1Gi
  resources:
    requests:
      cpu: 1
      memory: 100Mi
    limits:
      cpu: 2
      memory: 200Mi

Blocking non-gateway traffic

This operator won't block any traffic for you, it simply sets up some permitted routes for traffic through the egress gateways. You'll need a default-deny policy to block traffic that doesn't go through gateways. To do that, you probably need a policy like this in every namespace that you want to control:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-external-egress
  namespace: your-application-namespace
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        # ensure your internal IP range is allowed here
        # traffic to external IPs will not be allowed from this namespace.
        # therefore, pods will have to use egress gateways
        cidr: 10.0.0.0/8

If you already have a default deny egress policy, the above won't be needed. You'll instead want to explicitly allow egress from your pods to all gateway pods. The ingress policies on gateway pods will ensure that only correct traffic is allowed.

Configuration

Global configuration of the operator is set using environment variables.

Node Selectors and Taint tolerations can be added to gateway pods to ensure pods run on nodes that are permitted to access the internet. Example:

env:
- name: NODE_SELECTOR_KEY
  value: role
- name: NODE_SELECTOR_VALUE
  value: egress-pods
- name: TAINT_TOLERATION_KEY
  value: egress-pods
- name: TAINT_TOLERATION_VALUE
  value: "true"

Results in this gateway pod configuration:

spec:
  nodeSelector:
    role: egress-pods
  tolerations:
  - effect: NoSchedule
    key: egress-pods
    value: "true"
  ...

You can also configure the pod topology spread constraint

env:
- name: ENABLE_POD_TOPOLOGY_SPREAD
  value: "true"
- name: POD_TOPOLOGY_ZONE_MAX_SKEW
  value: 1
- name: POD_TOPOLOGY_HOSTNAME_MAX_SKEW
  value: 1

This will inject a topology spread constraint into the gateway pods, which will ensure that pods are spread across zones and hosts.

spec:
  topologySpreadConstraints:
    - labelSelector:
        matchLabels:
          app: egress-gateway
          egress.monzo.com/gateway: egress-gateway-name
      maxSkew: 1
      topologyKey: topology.kubernetes.io/zone
      whenUnsatisfiable: ScheduleAnyway
    - labelSelector:
        matchLabels:
          app: egress-gateway
          egress.monzo.com/gateway: egress-gateway-name
Variable name Default Description
ENVOY_IMAGE envoyproxy/envoy-alpine:v1.16.5 Name of the Envoy Proxy image to use
TAINT_TOLERATION_KEY Empty, no tolerations applied Toleration key to apply to gateway pods
TAINT_TOLERATION_VALUE Empty, no tolerations applied Toleration value to apply to gateway pods
NODE_SELECTOR_KEY Empty, no node selector added Node selector label key to apply to gateway pods
NODE_SELECTOR_VALUE Empty, no node selector added Node selector label value to apply to gateway pods
POD_TOPOLOGY_ZONE_MAX_SKEW_KEY topology.kubernetes.io/zone Topology key for the zone constraint
POD_TOPOLOGY_ZONE_MAX_SKEW Empty, won't inject a zone constraint Value of maxSkew for the zone constraint
POD_TOPOLOGY_HOSTNAME_MAX_SKEW_KEY kubernetes.io/hostname Topology key for the hostname constraint
POD_TOPOLOGY_HOSTNAME_MAX_SKEW Empty, won't inject a hostname constraint Value of maxSkew for the hostname constraint

More Repositories

1

response

Monzo's real-time incident response and reporting tool ⚑️
JavaScript
1,460
star
2

typhon

A wrapper around Go's net/http to provide safety and convenience. At Monzo, Typhon forms the basis of most clients and servers in our microservices platform.
Go
713
star
3

phosphor

Distributed System Tracing in Go
Go
375
star
4

progression-framework

The Monzo Progression Framework site, built with Gatsby.
JavaScript
291
star
5

envoy-preflight

A wrapper for applications to help with running envoy as a sidecar
Go
134
star
6

docs

Public API documentation
SCSS
101
star
7

calico-accountant

A Prometheus exporter for Calico policy packet counts
Go
87
star
8

terrors

Go
71
star
9

ddbt

Dom's Data Build Tool
Go
70
star
10

file-cleaner

JavaScript
64
star
11

etcd3-terraform

A Terraform recipe for a robust etcd cluster, based on how Monzo runs its clusters. πŸ’ͺ
HCL
46
star
12

slog

Structured logging
Go
46
star
13

mondo-ruby

Ruby Client
Ruby
45
star
14

reference-receipts-app

A simple Monzo third party API client for demonstrating the new Receipts API.
Python
19
star
15

web-exercise

Take-home exercise for web engineer hiring πŸš€
11
star
16

kotlin-synthetics-migrator

An Intellij Plugin for migrating an Android app from Kotlin Synthetics to findById
Kotlin
10
star
17

kontrast

Go
10
star
18

phosphord

Trace Forwarding Daemon
Go
9
star
19

phosphor-go

Go client for Phosphor
Go
7
star
20

vault-plugin-database-k8s-controller

A fork of Vault's database credential plugin allowing the use of annotations on service accounts as parameters in statements
Go
7
star
21

etcd3-bootstrap

Bootstraps an etcd3 cluster node
Go
6
star
22

drbd9_exporter

Exports status and metrics of DRBD 9.0 volumes
Go
6
star
23

code-of-conduct

The Monzo Community Code of Conduct
5
star
24

verifiedsms

A go library for interacting with Google Verified SMS
Go
3
star
25

file-score

JavaScript
3
star
26

web-code-test-server

Server for the frontend web dev code test in our interview process
JavaScript
2
star
27

gosquared

A golang gosquared client
Go
2
star
28

Judo-Swift

Judo Swift SDK for Swift 2.0/Xcode 7
Swift
2
star
29

guepacket

GUE (Generic UDP Encapsulation) layer for gopacket πŸ“¦
Go
2
star
30

CHCSVParser

Objective-C
1
star
31

libPhoneNumber-iOS

Objective-C
1
star