DiUS / pact_broker-docker

'Dockerised' pact broker
http://pact.io
MIT License
76 stars 102 forks source link

[do not merge] Start pactbroker as non-root on kubernetes #84

Closed patvong closed 5 years ago

patvong commented 5 years ago

Description

We have pactbroker running on our kubernets cluster currently as root using the image https://hub.docker.com/r/dius/pact-broker/dockerfile. Our k8s admin want to enforce a security context configuration to have the pods all running as non-root.

Since the Docker pact_broker-docker image is based off phusion/passenger-ruby24:1.0.0 which runs CMD ["/sbin/my_init"] which requires a root user for many things. To workaround many issues (requiring root), I had to modify the Dockerfile to be able to run as non-root with user app:

I tested this docker image with the k8s manifest configuration as follow:

pactbroker.yml

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: pact-broker
  name: pact-broker
  namespace: default
spec:
  ports:
  - name: "8080"
    port: 8080
    targetPort: 8080
  selector:
    io.kompose.service: pact-broker
  type: LoadBalancer

---

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: pact-broker
  name: pact-broker
  namespace: default
spec:
  replicas: 1
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        io.kompose.service: pact-broker
    spec:
      containers:
      - env:
        - name: PACT_BROKER_DATABASE_USERNAME
          value: postgres
        - name: PACT_BROKER_DATABASE_PASSWORD
          value: postgres
        - name: PACT_BROKER_DATABASE_HOST
          value: postgres
        - name: PACT_BROKER_DATABASE_NAME
          value: postgres
        - name: PACT_BROKER_PUBLIC_HEARTBEAT
          value: "true"
        # load docker image locally
        imagePullPolicy: Never
        image: my-pact-broker:latest
        name: pact-broker
        securityContext:
          runAsNonRoot: true
          runAsUser: 9999
        ports:
        - containerPort: 8080
        resources: {}
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 30
          timeoutSeconds: 10
        readinessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 30
          timeoutSeconds: 10
      restartPolicy: Always

postgres.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: postgres-claim0
  name: postgres-claim0
  namespace: default
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 100Mi

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: postgres
  name: postgres
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      creationTimestamp: null
      labels:
        io.kompose.service: postgres
    spec:
      containers:
      - env:
        - name: POSTGRES_PASSWORD
          value: postgres
        - name: POSTGRES_USER
          value: postgres
        image: postgres:9.6-alpine
        name: postgres
        resources: {}
        volumeMounts:
        - mountPath: /var/lib/postgresql/data
          name: postgres-claim0
      restartPolicy: Always
      volumes:
      - name: postgres-claim0
        persistentVolumeClaim:
          claimName: postgres-claim0

---
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: postgres
  name: postgres
  namespace: default
spec:
  clusterIP: None
  ports:
  - name: headless
    port: 55555
    targetPort: 0
  selector:
    io.kompose.service: postgres

Running in kubernetes

$ kubectl apply -f pactbroker.yml
$ kubectl apply -f postgres.yml
$ kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
pact-broker-ff9cf89fb-hmshw   1/1     Running   3          3h
postgres-57477d7cfc-j8pxn     1/1     Running   0          4d

$ kubectl logs pact-broker-ff9cf89fb-hmshw
*** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
*** Running /etc/my_init.d/30_presetup_nginx.sh...
*** Booting runit daemon...
*** Runit started as PID 8
ok: run: /etc/service/nginx-log-forwarder: (pid 14) 0s
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1
2019/03/11 20:45:41 [warn] 13#13: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1
[ N 2019-03-11 20:45:41.1556 16/T1 age/Wat/WatchdogMain.cpp:1366 ]: Starting Passenger watchdog...
[ N 2019-03-11 20:45:41.1752 19/T1 age/Cor/CoreMain.cpp:1339 ]: Starting Passenger core...
[ N 2019-03-11 20:45:41.1753 19/T1 age/Cor/CoreMain.cpp:256 ]: Passenger core running in multi-application mode.
[ N 2019-03-11 20:45:41.1871 19/T1 age/Cor/CoreMain.cpp:1014 ]: Passenger core online, PID 19
[ N 2019-03-11 20:45:43.7963 19/T5 age/Cor/SecurityUpdateChecker.h:519 ]: Security update check: no update found (next check in 24 hours)
App 53 output:  [passenger_native_support.so] trying to compile for the current user (app) and Ruby interpreter...
App 53 output:
App 53 output:      (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)
App 53 output:
App 53 output:      Compilation successful. The logs are here:
App 53 output:      /tmp/passenger_native_support-fkxkl3.log
App 53 output:  [passenger_native_support.so] successfully loaded.

$ curl localhost:8080
{"_links":{"self":{"href":"http://localhost:8080","title":"Index","templated":false},"pb:publish-pact":{"href":"http://localhost:8080/pacts/provider/{provider}/consumer/{consumer}/version/{consumerApplicationVersion}","title":"Publish a pact","templated":true},"pb:latest-pact-versions":{"href":"http://localhost:8080/pacts/latest","title":"Latest pact versions","templated":false},"pb:tagged-pact-versions":{"href":"http://localhost:8080/pacts/provider/{provider}/consumer/{consumer}/tag/{tag}","title":"All versions of a pact for a given consumer, provider and consumer version tag","templated":false},"pb:pacticipants":{"href":"http://localhost:8080/pacticipants","title":"Pacticipants","templated":false},"pb:latest-provider-pacts":{"href":"http://localhost:8080/pacts/provider/{provider}/latest","title":"Latest pacts by provider","templated":true},"pb:latest-provider-pacts-with-tag":{"href":"http://localhost:8080/pacts/provider/{provider}/latest/{tag}","title":"Latest pacts for provider with the specified tag","templated":true},"pb:provider-pacts-with-tag":{"href":"http://localhost:8080/pacts/provider/{provider}/tag/{tag}","title":"All pact versions for the provider with the specified consumer version tag","templated":true},"pb:provider-pacts":{"href":"http://localhost:8080/pacts/provider/{provider}","title":"All pact versions for the specified provider","templated":true},"pb:latest-version":{"href":"http://localhost:8080/pacticipants/{pacticipant}/latest-version","title":"Latest pacticipant version","templated":true},"pb:latest-tagged-version":{"href":"http://localhost:8080/pacticipants/{pacticipant}/latest-version/{tag}","title":"Latest pacticipant version with the specified tag","templated":true},"pb:webhooks":{"href":"http://localhost:8080/webhooks","title":"Webhooks","templated":false},"pb:integrations":{"href":"http://localhost:8080/integrations","title":"Integrations","templated":false},"beta:pending-provider-pacts":{"href":"http://localhost:8080/pacts/provider/{provider}/pending","title":"Pending pact versions for the specified provider","templated":true},"curies":[{"name":"pb","href":"http://localhost:8080/doc/{rel}?context=index","templated":true},{"name":"beta","href":"http://localhost:8080/doc/{rel}?context=index","templated":true}]}}
bethesque commented 5 years ago

I can't accept this PR to master as it will break all our existing users. I could accept it to a branch, and then see if we can tag builds from that branch differently in dockerhub.

patvong commented 5 years ago

I can't accept this PR to master as it will break all our existing users. I could accept it to a branch, and then see if we can tag builds from that branch differently in dockerhub.

Sure, PR to another branch makes total sense. There's the Travis CI build as well that would need to be modified as the test scripts try to reach to the 80 port instead of 8080.

bethesque commented 5 years ago

Can you update the travis tests please @patvong? I'll do a manual merge of this into a different branch when that's passing.

bethesque commented 5 years ago

Ping me when it's done, because I won't get any notifications that there are new commits or that it's passing.

mcon-gr commented 5 years ago

Also had a go trying to get this working on k8s - hit the same problem: from what I can see the only breaking change should be the exposed port, is that not something that could be done in a major version release?

bethesque commented 5 years ago

I'm not going to break the current docker image, but I will put this on a branch, and release a version with a different tag. Just waiting for those tests @patvong

patvong commented 5 years ago

Closing this PR, please refer to https://github.com/DiUS/pact_broker-docker/pull/87