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
-
Install Kubectl and set the context to the cluster you'll be working with.
-
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.
-
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
-
Install Pomerium to your cluster:
kubectl apply -f https://raw.githubusercontent.com/pomerium/ingress-controller/main/deployment.yamlDefine a Secret with your IdP configuration. See Pomerium's Identity Providers pages for more information specific to your IdP:
apiVersion: v1kind: Secretmetadata:name: idpnamespace: pomeriumtype: OpaquestringData:client_id: ${IDP_PROVIDED_CLIENT_ID}client_secret: ${IDP_PROVIDED_CLIENT_SECRET}Add the secret to the cluster with
kubectl apply -f
. -
Define the global settings for Pomerium:
apiVersion: ingress.pomerium.io/v1kind: Pomeriummetadata:name: globalnamespace: pomeriumspec:secrets: pomerium/bootstrapauthenticate:url: https://authenticate.example.comidentityProvider:provider: ${YOUR_IdP}secret: pomerium/idp# certificates:# - pomerium/pomerium-proxy-tlsReplace
${YOUR_IdP}
with your identity provider. Apply withkubectl -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.15.3/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.
-
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/v1kind: Issuermetadata:name: letsencrypt-stagingnamespace: pomeriumspec:acme:# The ACME server URLserver: https://acme-staging-v02.api.letsencrypt.org/directory# Email address used for ACME registrationemail: user@example.com# Name of a secret used to store the ACME account private keyprivateKeySecretRef:name: letsencrypt-staging# Enable the HTTP-01 challenge providersolvers:- http01:ingress:ingressClassName: pomeriumYou 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 -
Create a production issuer and deploy it. As with the staging issuer, update this example with your own email address:
apiVersion: cert-manager.io/v1kind: Issuermetadata:name: letsencrypt-prodnamespace: pomeriumspec:acme:# The ACME server URLserver: https://acme-v02.api.letsencrypt.org/directory# Email address used for ACME registrationemail: user@example.com# Name of a secret used to store the ACME account private keyprivateKeySecretRef:name: letsencrypt-prod# Enable the HTTP-01 challenge providersolvers:- http01:ingress:ingressClassName: pomeriumkubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/pomerium-production-issuer.yaml -
You can confirm on the status of the issuers after you create them:
kubectl describe issuer -n pomerium letsencrypt-stagingkubectl describe issuer -n pomerium letsencrypt-prodYou should see the issuer listed with a registered account.
-
Define a certificate for the Pomerium Proxy service. This should be the only certificate you need to manually define:
apiVersion: cert-manager.io/v1kind: Certificatemetadata:name: pomerium-proxy-tlsnamespace: pomeriumspec:dnsNames:- 'authenticate.example.com'issuerRef:kind: Issuername: letsencrypt-stagingsecretName: pomerium-proxy-tlsAdjust 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 withkubectl -f
. -
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.
-
Define the kuard deployment and associated service:
apiVersion: apps/v1kind: Deploymentmetadata:name: kuardspec:selector:matchLabels:app: kuardreplicas: 1template:metadata:labels:app: kuardspec:containers:- image: gcr.io/kuar-demo/kuard-amd64:1imagePullPolicy: Alwaysname: kuardports:- containerPort: 8080apiVersion: v1kind: Servicemetadata:name: kuardspec:ports:- port: 80targetPort: 8080protocol: TCPselector:app: kuardYou 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.yamlkubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/service.yaml -
Create a new Ingress manifest (
example-ingress.yaml
) for our test service:apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: kuardannotations:cert-manager.io/issuer: letsencrypt-stagingingress.pomerium.io/policy: '[{"allow":{"and":[{"domain":{"is":"example.com"}}]}}]'spec:ingressClassName: pomeriumrules:- host: kuard.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: kuardport:number: 80tls:- hosts:- kuard.example.comsecretName: kuard.example.com-tlsAgain, change the references to
example.com
to match your domain space. -
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
.