Pomerium Ingress

This tutorial covers installing the Pomerium Ingress Controller and securing it with cert-manager. Pomerium is an identity-aware proxy that can also provide a custom ingress controller for your Kubernetes services.

Prerequisites

  1. Install Kubectl and set the context to the cluster you'll be working with.

  2. Pomerium connects to an identity provider (IdP) to authenticate users. See one of their guides to learn how to set up your IdP of choice to provide oauth2 validation.

  3. This tutorial assumes you have a domain space reserved for this cluster (such as *.example.com). You will need access to DNS for this domain to assign A and CNAME records as needed.

Install The Pomerium Ingress Controller

  1. Install Pomerium to your cluster:

    kubectl apply -f https://raw.githubusercontent.com/pomerium/ingress-controller/main/deployment.yaml

    Define a Secret with your IdP configuration. See Pomerium's Identity Providers pages for more information specific to your IdP:

    apiVersion: v1
    kind: Secret
    metadata:
    name: idp
    namespace: pomerium
    type: Opaque
    stringData:
    client_id: ${IDP_PROVIDED_CLIENT_ID}
    client_secret: ${IDP_PROVIDED_CLIENT_SECRET}

    Add the secret to the cluster with kubectl apply -f.

  2. Define the global settings for Pomerium:

    apiVersion: ingress.pomerium.io/v1
    kind: Pomerium
    metadata:
    name: global
    namespace: pomerium
    spec:
    secrets: pomerium/bootstrap
    authenticate:
    url: https://authenticate.example.com
    identityProvider:
    provider: ${YOUR_IdP}
    secret: pomerium/idp
    # certificates:
    # - pomerium/pomerium-proxy-tls

    Replace ${YOUR_IdP} with your identity provider. Apply with kubectl -f.

    Note that the last two lines are commented out. They reference a TLS certificate we will create further in the process.

Install cert-manager

Install cert-manager using any of the methods documented in the Installation section of the cert-manager docs. The simplest method is to download and apply the provided manifest:

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml

Configure Let's Encrypt Issuer

For communication between the Ingresses and the internet, we'll want to use certificates signed by a trusted certificate authority like Let's Encrypt. This example creates two Let's Encrypt issuers, one for staging and one for production.

The Let's Encrypt production issuer has strict rate limits. Before your configuration is finalized you may have to recreate services several times, hitting those limits. It's easy to confuse rate limiting with errors in configuration or operation while building your stack.

Because of this, we will start with the Let's Encrypt staging issuer. Once your configuration is all but finalized, we will switch to a production issuer. Both of these issuers are configured to use the HTTP01 challenge provider.

  1. The following YAML defines a staging certificate issuer. You must update the email address to your own. The email field is required by Let's Encrypt and used to notify you of certificate expiration and updates.

    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
    name: letsencrypt-staging
    namespace: pomerium
    spec:
    acme:
    # The ACME server URL
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: user@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
    name: letsencrypt-staging
    # Enable the HTTP-01 challenge provider
    solvers:
    - http01:
    ingress:
    class: pomerium

    You can download and edit the example and apply it with kubectl apply -f, or edit, and apply the custom resource in one command:

    kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/pomerium-staging-issuer.yaml
  2. Create a production issuer and deploy it. As with the staging issuer, update this example with your own email address:

    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
    name: letsencrypt-prod
    namespace: pomerium
    spec:
    acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: user@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
    name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    solvers:
    - http01:
    ingress:
    class: pomerium
    kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/pomerium-production-issuer.yaml
  3. You can confirm on the status of the issuers after you create them:

    kubectl describe issuer -n pomerium letsencrypt-staging
    kubectl describe issuer -n pomerium letsencrypt-prod

    You should see the issuer listed with a registered account.

  4. Define a certificate for the Pomerium Proxy service. This should be the only certificate you need to manually define:

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    name: pomerium-proxy-tls
    namespace: pomerium
    spec:
    dnsNames:
    - 'authenticate.example.com'
    issuerRef:
    kind: Issuer
    name: letsencrypt-staging
    secretName: pomerium-proxy-tls

    Adjust the dnsNames value to match your domain space. The subdomain (authenticate in our example) must match the domain used for the callback URL in your IdP configuration. Add the certificate with kubectl -f.

  5. Uncomment the last two lines of the Pomerium global configuration that reference your newly created certificate, and re-apply to the cluster.

Pomerium should now be installed and running in your cluster. You can verify by going to https://authenticate.example.com in your browser. Use kubectl describe pomerium to review the status of the Pomerium deployment and see recent events.

Define a Test Service

To test our new Ingress Controller, we will add the kuard app to our cluster and define an Ingress for it.

  1. Define the kuard deployment and associated service:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: kuard
    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
    spec:
    ports:
    - port: 80
    targetPort: 8080
    protocol: TCP
    selector:
    app: kuard

    You can download and reference these files locally, or you can reference them from the GitHub source repository for this documentation.

    To install the example service from the tutorial files straight from GitHub:

    kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/deployment.yaml
    kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/service.yaml
  2. Create a new Ingress manifest (example-ingress.yaml) for our test service:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: kuard
    annotations:
    cert-manager.io/issuer: letsencrypt-staging
    ingress.pomerium.io/policy: '[{"allow":{"and":[{"domain":{"is":"example.com"}}]}}]'
    spec:
    ingressClassName: pomerium
    rules:
    - host: kuard.example.com
    http:
    paths:
    - path: /
    pathType: Prefix
    backend:
    service:
    name: kuard
    port:
    number: 80
    tls:
    - hosts:
    - kuard.example.com
    secretName: kuard.example.com-tls

    Again, change the references to example.com to match your domain space.

  3. Apply the Ingress manifest to the cluster:

    kubectl apply -f example-ingress.yaml

The Pomerium Ingress Controller will use cert-manager to automatically provision a certificate from the letsencrypt-staging issuer for the route to kuard.example.com.

Once you've configured all your application services correctly in the cluster, adjust the issuer for your Ingresses (including the Authenticate service) to use letsencrypt-prod.