Building a local copy of pomerium into the ingest-controller

As you'd expect, the pomerium ingest-controller (IC) for k8s has some local code, some pomerium interface code, and depends on pomerium. If you want to try something with the pomerium library code, you need to arrange for a local version of it to end up in your IC container image.

Checkouts

% git clone https://git@github.com/pomerium/ingress-controller.git
ingress-controller% grep "pomerium v" go.mod 
    github.com/pomerium/pomerium v0.20.1-0.20230526203421-d315e683357a
ingress-controller% git clone https://git@github.com/pomerium/pomerium.git pomerium-src

I want pomerium source inside the IC directory for ease of docker building, but it needs a separate name from the ingress-controller/pomerium/ that's already there.

The grep call above says that this IC version depends on a pomerium-src revision (not just v0.20.1, which took me a while to figure out!)

ingress-controller/pomerium-src% git checkout d315e683357a

go.mod link

go.mod tells the IC build to use a version of pomerium from github. Insert this in go.mod (before the first require block, but maybe that doesn't matter):

replace github.com/pomerium/pomerium => ./pomerium-src

Incorporate pomerium-src's dependencies

Edit ingress-controller's Dockerfile, so the build can incorporate pomerium-src/go.mod.

diff --git a/Dockerfile b/Dockerfile
index 9805497..3044a97 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,10 +12,15 @@ COPY Makefile Makefile

 RUN mkdir -p pomerium/envoy/bin
 RUN make envoy
+
+COPY pomerium-src/go.mod pomerium-src/go.sum pomerium-src/
 RUN go mod download

 COPY Makefile ./Makefile

This docker (actually podman) build takes me 2m45s. I believe the following is a safe speedup. It does some dependency downloads before the source code copy, which caches better. New rebuild time is 2m0s:

diff --git a/Dockerfile b/Dockerfile
index 9805497..a9212d2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,6 +16,9 @@ RUN go mod download

 COPY Makefile ./Makefile

+# this pulls a bunch of deps that we don't want to repeat in 'make build-go'
+RUN make controller-gen
+
 # download ui dependencies from core module
 RUN mkdir -p internal
 RUN make internal/ui

Build the docker image with all the local edits

So far, this is building to ingress-controller/bin/*, but we want to affect the build in a docker image.

ingress-controller% export TAG=bang5:5000/pomerium_ic_local
ingress-controller% docker build -t ${TAG} . && docker push ${TAG}

Output includes this:

Successfully tagged bang5:5000/pomerium_ic_local:latest
031715bd3fa0da34f7cfdfc26eb020643bf1a9904ad8af228837c2bdcaef39cc

GCR error

You may see this:

       [3/3] STEP 1/5: FROM gcr.io/distroless/base:debug-nonroot@sha256:de8fb012fc630b7cdea6861442a0185213b574c71e246ddc97e9eb1d047048e7
    Trying to pull gcr.io/distroless/base@sha256:de8fb012fc630b7cdea6861442a0185213b574c71e246ddc97e9eb1d047048e7...
        Error: creating build container: initializing source docker://gcr.io/distroless/base@sha256:de8fb012fc630b7cdea6861442a0185213b574c71e246ddc97e9eb1d047048e7: getting username and password: 1 error occurred:
        * error getting credentials - err: docker-credential-gcloud resolves to executable in current directory (./docker-credential-gcloud), out: ``

Something from the user setup is breaking this (how?). I used a different account on another computer to work around it.

Use the local docker image in a k8s setup

I run ingress-controller/deployment.yaml with some kustomize patches, so I deploy the new docker image like this:

My existing deployment configs:

upstream% cp .../ingress-controller/deplyment.yaml pomerium-ingress-controller.yaml

My existing upstream/kustomzation.yaml:

bases:
  - pomerium-ingress-controller.yaml
  - cert-manager-v1.12.0.yaml
patchesStrategicMerge:
  - "patch.yaml"
etc

My upstream/patch.yaml, with the local image:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pomerium
  namespace: pomerium
spec:
  template:
    spec:
      containers:
        - name: pomerium
          image: bang5:5000/pomerium_ic_local:latest
          imagePullPolicy: Always

Apply changes (abridged):

kubectl kustomize upstream | kubectl apply -f -

Test the result

Edit this:

--- a/pomerium/ctrl/run.go
+++ b/pomerium/ctrl/run.go
@@ -75,6 +75,7 @@ func (r *Runner) Run(ctx context.Context) error {
        }

        log.FromContext(ctx).V(1).Info("got bootstrap config, starting pomerium...", "cfg", r.src.GetConfig())
+       log.Log.Error(nil, "hello IC world")

        return pomerium_cmd.Run(ctx, r.src)
 }

And this:

diff --git a/pomerium-src/authorize/internal/store/store.go b/pomerium-src/authorize/internal/store/store.go
index f9f9e08d..3dcac141 100644
--- a/pomerium-src/authorize/internal/store/store.go
+++ b/pomerium-src/authorize/internal/store/store.go
@@ -31,6 +31,8 @@ type Store struct {

 // New creates a new Store.
 func New() *Store {
+       ctx := context.TODO()
+       log.Error(ctx).Err(nil).Msg("hello pom world")
        return &Store{
                Store: inmem.New(),
        }

Rebuild

ingress-controller% docker build -t ${TAG} . && docker push ${TAG}

Also, my docker is podman, so I added "build --network=host" for a speedup.

Redeploy to k8s:

% kubectl rollout restart -n pomerium deploy/pomerium

Use tab-complete (or a app.name selector) to describe the right pod:

% kubectl describe -n pomerium pod/pomerium-79954677c-qzhpj

    Image:         bang5:5000/pomerium_ic_local:latest
    Image ID:      bang5:5000/pomerium_ic_local@sha256:0edbab12576bc68054b4f900f96318c04df4fcb9c1f588f2e4c2454cbe3b8a08

Not sure why this 0edb id doesn't match the 'successfully tagged' 0317 one above.

However, we still have great success!

% kubectl logs -n pomerium deploy/pomerium | grep hello

{"level":"error","ts":"2023-07-17T01:32:27Z","msg":"hello IC world"}
{"level":"error","time":"2023-07-17T01:32:27Z","message":"hello pom world"}