Search code examples
kubernetesdockerfileopenshiftkubernetes-helmpersistent-volumes

OpenShift: Accessing mounted file-system as non-root


I am trying to run Chart Museum as a non-root user in OpenShift. Here is a snapshot of my YAML.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: chart-museum
  namespace: demo
spec:
  selector:
    matchLabels:
      app: chart-museum
  replicas: 1
  template:
    metadata:
      labels:
        app: chart-museum
    spec:
      volumes:
        - name: pvc-charts
          persistentVolumeClaim:
            claimName: pvc-charts      
      containers:
        - name: chart-museum
          securityContext:
            fsGroup: 1000
          image: chartmuseum/chartmuseum:latest
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: chart-museum
          volumeMounts:
            - name: pvc-charts
              mountPath: "/charts"

As you can see, I have set spec.containers.securityContext.fsGroup to 1000 which is same as the user ID in the Chart Museum Dockerfile as shown below.

FROM alpine:3.10.3
RUN apk add --no-cache cifs-utils ca-certificates \
    && adduser -D -u 1000 chartmuseum
COPY bin/linux/amd64/chartmuseum /chartmuseum
USER 1000
ENTRYPOINT ["/chartmuseum"]

And, yet, when I try to upload a chart, I get a permission denied message for /charts. How do I get around this issue?


Solution

  • This is how I solved the issue.

    1. Download the binary curl -LO https://s3.amazonaws.com/chartmuseum/release/latest/bin/linux/amd64/chartmuseum.
    2. Change permissions chmod +xr chartmuseum
    3. Create a new Dockerfile as shown below. Basically, use the user name instead of ID for chown commands so that the binary and the storage location are owned by chartmuseum user and not root.
    FROM alpine:3.10.3
    RUN apk add --no-cache cifs-utils ca-certificates \
        && adduser -D -u 1000 chartmuseum
    COPY chartmuseum /chartmuseum
    RUN chown chartmuseum:chartmuseum /chartmuseum
    RUN chown chartmuseum:chartmuseum /charts
    USER chartmuseum
    ENTRYPOINT ["/chartmuseum"]
    
    1. Build and push the resulting Docker image to e.g. somerepo/chartmuseum:0.0.0.
    2. Use the k8s manifest as shown below. Edit the namespace as required. Note, creation of PersistentVolumeClaim is not covered here.
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: chart-museum
      namespace: demo
    data:
      DEBUG: 'true'
      STORAGE: local
      STORAGE_LOCAL_ROOTDIR: "/charts"
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: chart-museum
      namespace: demo
    spec:
      selector:
        matchLabels:
          app: chart-museum
      replicas: 1
      template:
        metadata:
          labels:
            app: chart-museum
        spec:
          volumes:
            - name: pvc-charts
              persistentVolumeClaim:
                  claimName: pvc-charts
          containers:
            - name: chart-museum
              image: somerepo/chartmuseum:0.0.0
              imagePullPolicy: Always
              ports:
                - containerPort: 8080
              envFrom:
                - configMapRef:
                    name: chart-museum
              volumeMounts:
                - mountPath: "/charts"
                  name: pvc-charts
              resources:
                limits:
                  memory: "128Mi"
                  cpu: "500m"
          imagePullSecrets:
            - name: us.icr.io.secret
    ---              
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: chart-museum
      name: chart-museum
      namespace: demo
    spec:
      type: ClusterIP
      ports:
        - name: 8080-tcp
          port: 8080
          protocol: TCP
          targetPort: 8080
      selector:
        app: chart-museum
    ---
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      labels:
        app: chart-museum
      name: chart-museum
      namespace: demo
    spec:
      port:
        targetPort: 8080-tcp
      tls:
        insecureEdgeTerminationPolicy: Redirect
        termination: edge
      to:
        kind: Service
        name: chart-museum
    

    The manifest creates a ConfigMap object and uses a PersistentVolumeClaim to 'replicate' the command to run Chart Museum locally (as described at https://chartmuseum.com/)

     docker run --rm -it \
      -p 8080:8080 \
      -v $(pwd)/charts:/charts \
      -e DEBUG=true \
      -e STORAGE=local \
      -e STORAGE_LOCAL_ROOTDIR=/charts \
      chartmuseum/chartmuseum:latest
    

    The Service and Route in the manifest expose the repo to the external world.

    1. After the objects are created, enter the HOST/PORT value in oc get route/chart-museum -n demo with https in address bar and hit enter. You should see a welcome page for Chart Museum. This means the installation is successful.