Secure your applications with Pomerium Ingress Controller

In this blog post, I will show you how you can install Pomerium Ingress Controller and use it to secure your application.

I a previous post I showed how you can authenticate users for specific ingresses by oauth2-proxy and nginx ingress controller. That solution works grate, but it has a flow. If you want not just authenticate but authorize users based on groups, you need multiple oauth2-proxy. That is not ideal. But wit Pomerium Ingress Controller you can configure authentication and authorization by annotations on the ingress.

Pomerium use certificate-manager to generates certificates for secure connections. So first I will install that:

kubectl create ns cert-manager
kubens cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager \
--create-namespace --set installCRDs=true

To install Pomerium Ingress Controller I will use it’s helm chart:

kubectl create ns ingress-system
kubens ingress-system
helm repo add pomerium https://helm.pomerium.io
helm repo update

Now I will create the values file:

nano values.yaml
---
authenticate:
  idp:
    provider: "oidc"
    clientID: "oauth2_proxy"
    clientSecret: "1e8ee274-513e-41c0-903f-b3cg13147dgb"
    url: "https://sso.k8s.intra/auth/realms/cl12"
    serviceAccount: "pomerium-authenticate"
  ingress:
    annotations:
      cert-manager.io/cluster-issuer: ca-issuer
    tls:
      secretName: authenticate.k8s.intra
redis:
  enabled: false
  generateTLS: true
ingressController:
  enabled: true
  ingressClassResource:
    enabled: true
    default: true
    name: "pomerium"
config:
  rootDomain: k8s.intra #Change this to your reserved domain space.
  generateTLS: true # On by default, disabled when cert-manager or another solution is in place.
ingress:
  enabled: false
helm upgrade --install pomerium pomerium/pomerium --values ./pomerium-values.yaml

To demonstrate the functionality of Pomerium Ingress Controller I will create a deo application:

nano demo_app.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kuard
  namespace: default
spec:
  selector:
    matchLabels:
      app: kuard
  replicas: 1
  template:
    metadata:
      labels:
        app: kuard
    spec:
      containers:
      - image: gcr.io/kuar-demo/kuard-amd64:1
        imagePullPolicy: Always
        name: kuard
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: kuard
  namespace: default
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: kuard

Now I will show so a few Ingress examples for this app. I the firs example we wil allow the authentication for a specific user by its email.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    ingress.pomerium.io/policy: '[{"allow":{"and":[{"email":{"is":"user@mydomain.intra"}}]}}]' # This can also be a yaml block quote
spec:
  rules:
  - host: kuard.k8s.intra
    http:
      paths:
      - backend:
          service:
            name: kuard
            port:
              name: http
        path: /
        pathType: Prefix

As you can see you can add the policy as a yaml block quote.

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    ingress.pomerium.io/policy: |
      - allow:
          and:
            - email:
                is: user@mydomain.intra      
spec:
  rules:
  - host: kuard.k8s.intra
    http:
      paths:
      - backend:
          service:
            name: kuard
            port:
              name: http
        path: /
        pathType: Prefix

In the second example I will allow the authentication for all user from a specific domain.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    ingress.pomerium.io/policy: |
      - allow:
          and:
            - email:
                ends_with: "@mydomain.intra"      
spec:
  rules:
  - host: kuard.k8s.intra
    http:
      paths:
      - backend:
          service:
            name: kuard
            port:
              name: http
        path: /
        pathType: Prefix

OR:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    ingress.pomerium.io/policy: |
      - allow:
          and:
            - domain:
                is: "mydomain.intra"      
spec:
  rules:
  - host: kuard.k8s.intra
    http:
      paths:
      - backend:
          service:
            name: kuard
            port:
              name: http
        path: /
        pathType: Prefix

The last example shows you how you can use regex in your ingress.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/issuer: example-issuer
    ingress.pomerium.io/policy: |
      - allow:
          and:
            - domain:
                is: "mydomain.intra"      
    ingress.pomerium.io/path_regex: "true"
  name: example
spec:
  ingressClassName: pomerium
  rules:
  - host: example.localhost.pomerium.io
    http:
      paths:
      - backend:
          service:
            name: example
            port:
              name: http
        path: ^/(admin|superuser)/.*$
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - example.localhost.pomerium.io
    secretName: example-tls

As you can see Pomerium is a very versatile Ingress controller. For more examples fo to Pomerium’s page.