1

I'm trying to run a pgAdmin container (the one I'm using comes from here) in an OpenShift cluster where I don't have admin privileges and the admin does not want to allow containers to run as root for security reasons.

The error I'm currently receiving looks like this:

I created a Dockerfile that creates that directory ahead of time based on the image linked above and I get this error:

Is there any way to run pgAdmin within OpenShift? I want to be able to let DB admins log into the instance of pgAdmin and configure the DB from there, without having to use the OpenShift CLI and port forwarding. When I use that method the port-forwarding connection drops very frequently.

Edit1:

Is there a way that I should edit the Dockerfile and entrypoint.sh file found on pgAdmin's github?

Edit2:

It looks like this is a bug with pgAdmin... :/

https://www.postgresql.org/message-id/15470-c84b4e5cc424169d%40postgresql.org

The Dude
  • 21
  • 1
  • 3

4 Answers4

3

To work around these errors, you need to add a writable volume to the container and set pgadmin's configuration to use that directory.

Permission Denied: '/var/lib/pgadmin'
Permission Denied: '/var/log/pgadmin'

The OpenShift/Kubernetes YAML example below demonstrates this by supplying a custom /pgadmin4/config_local.py as documented here. This allows you to run the image as a container with regular privileges.

Note the configuration files base directory (/var/lib/pgadmin/data) still needs to be underneath the mount point (/var/lib/pgadmin/), as pgadmin's initialization code tries to create/change ownership of that directory which is not allowed on mount point directories inside the container.

apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: Secret
  metadata:
    labels:
      app: pgadmin-app
    name: pgadmin
  type: Opaque
  stringData:
    username: admin
    password: DEFAULT_PASSWORD
- apiVersion: v1
  kind: ServiceAccount
  metadata:
    annotations:
      serviceaccounts.openshift.io/oauth-redirectreference.pgadmin: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"pgadmin"}}'
    labels:
      app: pgadmin-app
    name: pgadmin
- apiVersion: v1
  kind: ConfigMap
  metadata:
    labels:
      app: pgadmin-app
    name: pgadmin
  data:
    config_local.py: |-
      import os
      _BASEDIR = '/var/lib/pgadmin/data'
      LOG_FILE = os.path.join(_BASEDIR, 'logfile')
      SQLITE_PATH = os.path.join(_BASEDIR, 'sqlite.db')
      STORAGE_DIR = os.path.join(_BASEDIR, 'storage')
      SESSION_DB_PATH = os.path.join(_BASEDIR, 'sessions')
    servers.json: |-
      {
        "Servers": {
          "1": {
            "Name": "postgresql",
            "Group": "Servers",
            "Host": "postgresql",
            "Port": 5432,
            "MaintenanceDB": "postgres",
            "Username": "dbuser",
            "SSLMode": "prefer",
            "SSLCompression": 0,
            "Timeout": 0,
            "UseSSHTunnel": 0,
            "TunnelPort": "22",
            "TunnelAuthentication": 0
          }
        }
      }
- apiVersion: apps.openshift.io/v1
  kind: DeploymentConfig
  metadata:
    name: pgadmin
    labels:
      app: pgadmin-app
  spec:
    replicas: 1
    selector:
      app: pgadmin-app
      deploymentconfig: pgadmin
    template:
      metadata:
        labels:
          app: pgadmin-app
          deploymentconfig: pgadmin
        name: pgadmin
      spec:
        serviceAccountName: pgadmin
        containers:
        - env:
          - name: PGADMIN_DEFAULT_EMAIL
            valueFrom:
              secretKeyRef:
                key: username
                name: pgadmin
          - name: PGADMIN_DEFAULT_PASSWORD
            valueFrom:
              secretKeyRef:
                key: password
                name: pgadmin
          - name: PGADMIN_LISTEN_PORT
            value: "5050"
          - name: PGADMIN_LISTEN_ADDRESS
            value: 0.0.0.0
          image: docker.io/dpage/pgadmin4:4
          livenessProbe:
            failureThreshold: 3
            initialDelaySeconds: 30
            httpGet:
              path: /misc/ping
              port: 5050
              scheme: HTTP
            periodSeconds: 60
            successThreshold: 1
            timeoutSeconds: 1
          name: pgadmin
          ports:
            - containerPort: 5050
              protocol: TCP
          readinessProbe:
            failureThreshold: 10
            initialDelaySeconds: 3
            httpGet:
              path: /misc/ping
              port: 5050
              scheme: HTTP
            periodSeconds: 5
            successThreshold: 1
            timeoutSeconds: 1
          volumeMounts:
          - mountPath: /pgadmin4/config_local.py
            name: pgadmin-config
            subPath: config_local.py
          - mountPath: /pgadmin4/servers.json
            name: pgadmin-config
            subPath: servers.json
          - mountPath: /var/lib/pgadmin
            name: pgadmin-data
        - image: docker.io/openshift/oauth-proxy:latest
          name: pgadmin-oauth-proxy
          ports:
          - containerPort: 5051
            protocol: TCP
          args:
          - --http-address=:5051
          - --https-address=
          - --openshift-service-account=pgadmin
          - --upstream=http://localhost:5050
          - --cookie-secret=bdna987REWQ1234
        volumes:
        - name: pgadmin-config
          configMap:
            name: pgadmin
            defaultMode: 0664
        - name: pgadmin-data
          emptyDir: {}
- apiVersion: v1
  kind: Service
  metadata:
    name: pgadmin-oauth-proxy
    labels:
      app: pgadmin-app
  spec:
    ports:
      - name: 80-tcp
        protocol: TCP
        port: 80
        targetPort: 5051
    selector:
      app: pgadmin-app
      deploymentconfig: pgadmin
- apiVersion: route.openshift.io/v1
  kind: Route
  metadata:
    labels:
      app: pgadmin-app
    name: pgadmin
  spec:
    port:
      targetPort: 80-tcp
    tls:
      insecureEdgeTerminationPolicy: Redirect
      termination: edge
    to:
      kind: Service
      name: pgadmin-oauth-proxy
jwmullally
  • 456
  • 4
  • 4
  • I see [Murtuza Z has already answered this here](https://stackoverflow.com/a/54265788/363836), but I will leave this example here for anyone who wants to know how this is done. – jwmullally Aug 14 '19 at 14:42
2

Openshift by default doesn't allow to run containers with root privilege, you can add Security Context Constraints (SCC) to the user anyuid for the project where you are deploying the container.

Adding a SCC for the project:

$ oc adm policy add-scc-to-user anyuid system:serviceaccount:<your-project>:default

scc "anyuid" added to: ["system:serviceaccount:data-base-administration:default"]
$ oc get scc
NAME               PRIV      CAPS      SELINUX     RUNASUSER          FSGROUP     SUPGROUP    PRIORITY   READONLYROOTFS   VOLUMES
anyuid             false     []        MustRunAs   RunAsAny           RunAsAny    RunAsAny    10         false            [configMap downwardAPI emptyDir persistentVolumeClaim projected secret]

PGAdmin deployed:

$ oc describe pod pgadmin4-4-fjv4h
Name:               pgadmin4-4-fjv4h
Namespace:          data-base-administration
Priority:           0
PriorityClassName:  <none>
Node:               host/IP
Start Time:         Mon, 18 Feb 2019 23:22:30 -0400
Labels:             app=pgadmin4
                    deployment=pgadmin4-4
                    deploymentconfig=pgadmin4
Annotations:        openshift.io/deployment-config.latest-version=4
                    openshift.io/deployment-config.name=pgadmin4
                    openshift.io/deployment.name=pgadmin4-4
                    openshift.io/generated-by=OpenShiftWebConsole
                    openshift.io/scc=anyuid
Status:             Running
IP:                 IP
Controlled By:      ReplicationController/pgadmin4-4
Containers:
  pgadmin4:
    Container ID:   docker://ID
    Image:          dpage/pgadmin4@sha256:SHA
    Image ID:       docker-pullable://docker.io/dpage/pgadmin4@sha256:SHA
    Ports:          80/TCP, 443/TCP
    Host Ports:     0/TCP, 0/TCP
    State:          Running
      Started:      Mon, 18 Feb 2019 23:22:37 -0400
    Ready:          True
    Restart Count:  0
    Environment:
      PGADMIN_DEFAULT_EMAIL:     secret
      PGADMIN_DEFAULT_PASSWORD:  secret
    Mounts:
      /var/lib/pgadmin from pgadmin4-1 (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-74b75 (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  pgadmin4-1:
    Type:    EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:
  default-token-74b75:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-74b75
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  node-role.kubernetes.io/compute=true
Tolerations:     <none>
Events:
  Type    Reason     Age   From                             Message
  ----    ------     ----  ----                             -------
  Normal  Scheduled  51m   default-scheduler                Successfully assigned data-base-administration/pgadmin4-4-fjv4h to host
  Normal  Pulling    51m   kubelet, host  pulling image "dpage/pgadmin4@sha256:SHA"
  Normal  Pulled     51m   kubelet, host  Successfully pulled image "dpage/pgadmin4@sha256:SHA"
  Normal  Created    51m   kubelet, host  Created container
  Normal  Started    51m   kubelet, host  Started container

deploy-image-openshift pgadmin-deployed-ocp

Fulvio
  • 925
  • 2
  • 13
  • 21
1

I have already replied to similar issue for local installation OSError: [Errno 13] Permission denied: '/var/lib/pgadmin'

For docker image, you can map the /pgadmin4/config_local.py using environment variables, Check Mapped Files and Directories section on the https://hub.docker.com/r/dpage/pgadmin4/

Murtuza Z
  • 5,639
  • 1
  • 28
  • 52
0

This might work if you create a pgadmin user via the Dockerfile, and give it permission to write to /var/log/pgadmin.

You can create a user in the Dockerfile using the RUN command; something like this:

# Create pgadmin user
ENV_HOME=/pgadmin
RUN mkdir -p ${HOME} && \
mkdir -p ${HOME}/pgadmin && \
useradd -u 1001 -r -g 0 -G pgadmin -d ${HOME} -s /bin/bash \
-c "Default Application User" pgadmin

# Set user home and permissions with group 0 and writeable.
RUN chmod -R 700 ${HOME} && chown -R 1001:0 ${HOME}

# Create the log folder and set permissions
RUN mkdir /var/log/pgadmin && \
chmod 0600 /var/log/pgadmin && \
chown 1001:0 /var/log/pgadmin

# Run as 1001 (pgadmin)
USER 1001

Adjust your pgadmin install so it runs as 1001, and I think you should be set.

Ciaodown
  • 529
  • 5
  • 15
  • I still get that error when my Dockerfile is created `FROM: dpage/pgadmin4` – The Dude Jan 22 '19 at 22:10
  • Okay, I'm now no longer getting that error because I did `chmod 0777 /var/log/pgadmin` and I'm only receiving the error `Starting gunicorn 19.8.1` and `Can't connect to ('::', 80)` – The Dude Jan 23 '19 at 00:38
  • I'm not sure if this will help since it may be a bug, but you might want to try enabling `PGADMIN_ENABLE_TLS` to see if you can get it working over 443. Also, I noticed that the Github account maps 80:8080 and 443:8443 in the `docker run` command, but the documentation (https://www.pgadmin.org/docs/pgadmin4/dev/container_deployment.html?highlight=container) maps 80:80 and 443:443, which is weird since you're getting and error connecting to port 80, but the run command is trying to map your host 80 to the container's 8080. – Ciaodown Jan 23 '19 at 13:48
  • 1
    As it turns out, it is [a bug](https://www.postgresql.org/message-id/15470-c84b4e5cc424169d%40postgresql.org) and pgAdmin can only be run as root. I showed the cluster admin this, and he said he would create a service account that can run apps as `anyuid`. Unfortunately, that seems to be the fix. Should I answer my own question? I'm new to Stack Overflow. – The Dude Jan 24 '19 at 01:20
  • I'm not sure what the correct thing is, but I'd probably just answer your own question, since you did. – Ciaodown Jan 24 '19 at 15:20