Search code examples
dockerdockerfilefile-permissions

Setup different user permissions on files copied in Dockerfile


I have this Dockerfile setup:

FROM node:14.5-buster-slim AS base
WORKDIR /app


FROM base AS production
ENV NODE_ENV=production

RUN chown -R node:node /app
RUN chmod 755 /app
USER node
... other copies
COPY ./scripts/startup-production.sh ./
COPY ./scripts/healthz.sh ./

CMD ["./startup-production.sh"]

The problem I'm facing is that I can't execute ./healthz.sh because it's only executable by the node user. When I commented out the two RUN and the USER commands, I could execute the file just fine. But I want to enforce the executable permissions only to the node for security reasons.

I need the ./healthz.sh to be externally executable by Kubernetes' liveness & rediness probes.

How can I make it so? Folder restructuring or stuff like that are fine with me.


Solution

  • In most cases, you probably want your code to be owned by root, but to be world-readable, and for scripts be world-executable. The Dockerfile COPY directive will copy in a file with its existing permissions from the host system (hidden in the list of bullet points at the end is a note that a file "is copied individually along with its metadata"). So the easiest way to approach this is to make sure the script has the right permissions on the host system:

    # mode 0755 is readable and executable by everyone but only writable by owner
    chmod 0755 healthz.sh
    git commit -am 'make healthz script executable'
    

    Then you can just COPY it in, without any special setup.

    # Do not RUN chown or chmod; just
    WORKDIR /app
    COPY ./scripts/healthz.sh .
    
    # Then when launching the container, specify
    USER node
    CMD ["./startup-production.sh"]
    

    You should be able to verify this locally by running your container and manually invoking the health-check script

    docker run -d --name app the-image
    # possibly with a `docker exec -u` option to specify a different user
    docker exec app /app/healthz.sh && echo OK
    

    The important thing to check is that the file is world-executable. You can also double-check this by looking at the built container

    docker run --rm the-image ls -l /app/healthz.sh
    

    That should print out one line, starting with a permission string -rwxr-xr-x; the last three r-x are the important part. If you can't get the permissions right another way, you can also fix them up in your image build

    COPY ./scripts/healthz.sh .
    # If you can't make the permissions on the original file right:
    RUN chmod 0755 *.sh