From 55dd017e620d8cb86fbdb625ab55fc5effc0af7e Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 17 Jul 2019 11:20:55 -0700 Subject: [PATCH] Deprecate auto detection of container user (#7930) There is no reliable way to handle fallbacks for MinIO deployments, due to various command line options and multiple locations which require access inside container. Parsing command line options is tricky to figure out which is the backend disk etc, we did try to fix this in implementations of check-user.go but it wasn't complete and introduced more bugs. This PR simplifies the entire approach to rather than running Docker container as non-root by default always, it allows users to opt-in. Such that they are aware that that is what they are planning to do. In-fact there are other ways docker containers can be run as regular users, without modifying our internal behavior and adding more complexities. --- .gitignore | 1 - Dockerfile | 4 +- Dockerfile.dev | 5 +- Dockerfile.release | 7 +- Makefile | 1 - dockerscripts/check-user.go | 135 ----------------------------- dockerscripts/docker-entrypoint.sh | 37 ++------ docs/docker/README.md | 16 ++-- 8 files changed, 21 insertions(+), 185 deletions(-) delete mode 100644 dockerscripts/check-user.go diff --git a/.gitignore b/.gitignore index 8279d7899..44a19a870 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,4 @@ prime/ stage/ .sia_temp/ config.json -dockerscripts/check-user dockerscripts/healthcheck \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5fca6197f..3248e59cd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,7 @@ RUN \ apk add --no-cache git && \ git clone https://github.com/minio/minio && cd minio && \ go install -v -ldflags "$(go run buildscripts/gen-ldflags.go)" && \ - cd dockerscripts; go build -tags kqueue -ldflags "-s -w" -o /usr/bin/healthcheck healthcheck.go && \ - go build -tags kqueue -ldflags "-s -w" -o /usr/bin/check-user check-user.go + cd dockerscripts; go build -tags kqueue -ldflags "-s -w" -o /usr/bin/healthcheck healthcheck.go FROM alpine:3.9 @@ -23,7 +22,6 @@ EXPOSE 9000 COPY --from=0 /go/bin/minio /usr/bin/minio COPY --from=0 /usr/bin/healthcheck /usr/bin/healthcheck -COPY --from=0 /usr/bin/check-user /usr/bin/check-user COPY dockerscripts/docker-entrypoint.sh /usr/bin/ RUN \ diff --git a/Dockerfile.dev b/Dockerfile.dev index 6e7de93b3..aadecd741 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -2,7 +2,7 @@ FROM alpine:3.9 LABEL maintainer="MinIO Inc " -COPY dockerscripts/docker-entrypoint.sh dockerscripts/healthcheck dockerscripts/check-user /usr/bin/ +COPY dockerscripts/docker-entrypoint.sh dockerscripts/healthcheck /usr/bin/ COPY minio /usr/bin/ ENV MINIO_UPDATE off @@ -14,8 +14,7 @@ RUN \ echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \ chmod +x /usr/bin/minio && \ chmod +x /usr/bin/docker-entrypoint.sh && \ - chmod +x /usr/bin/healthcheck && \ - chmod +x /usr/bin/check-user + chmod +x /usr/bin/healthcheck EXPOSE 9000 diff --git a/Dockerfile.release b/Dockerfile.release index 9f70ef4c0..09b8ce8b4 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -7,15 +7,13 @@ ENV GO111MODULE on RUN \ apk add --no-cache git && \ git clone https://github.com/minio/minio && cd minio/dockerscripts && \ - go build -tags kqueue -ldflags "-s -w" -o /usr/bin/healthcheck healthcheck.go && \ - go build -tags kqueue -ldflags "-s -w" -o /usr/bin/check-user check-user.go + go build -tags kqueue -ldflags "-s -w" -o /usr/bin/healthcheck healthcheck.go FROM alpine:3.9 LABEL maintainer="MinIO Inc " COPY --from=0 /usr/bin/healthcheck /usr/bin/healthcheck -COPY --from=0 /usr/bin/check-user /usr/bin/check-user COPY dockerscripts/docker-entrypoint.sh /usr/bin/ ENV MINIO_UPDATE off @@ -28,8 +26,7 @@ RUN \ curl https://dl.min.io/server/minio/release/linux-amd64/minio > /usr/bin/minio && \ chmod +x /usr/bin/minio && \ chmod +x /usr/bin/docker-entrypoint.sh && \ - chmod +x /usr/bin/healthcheck && \ - chmod +x /usr/bin/check-user + chmod +x /usr/bin/healthcheck EXPOSE 9000 diff --git a/Makefile b/Makefile index efdaa6167..1972c69ed 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,6 @@ build: checks @echo "Building minio binary to './minio'" @GO111MODULE=on GOFLAGS="" CGO_ENABLED=0 go build -tags kqueue --ldflags $(BUILD_LDFLAGS) -o $(PWD)/minio 1>/dev/null @GO111MODULE=on GOFLAGS="" CGO_ENABLED=0 go build -tags kqueue --ldflags $(BUILD_LDFLAGS) -o $(PWD)/dockerscripts/healthcheck $(PWD)/dockerscripts/healthcheck.go 1>/dev/null - @GO111MODULE=on GOFLAGS="" CGO_ENABLED=0 go build -tags kqueue --ldflags $(BUILD_LDFLAGS) -o $(PWD)/dockerscripts/check-user $(PWD)/dockerscripts/check-user.go 1>/dev/null docker: build @docker build -t $(TAG) . -f Dockerfile.dev diff --git a/dockerscripts/check-user.go b/dockerscripts/check-user.go deleted file mode 100644 index 8b915ad8d..000000000 --- a/dockerscripts/check-user.go +++ /dev/null @@ -1,135 +0,0 @@ -// +build ignore - -/* - * MinIO Cloud Storage, (C) 2019 MinIO, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package main - -import ( - "fmt" - "log" - "os" - "os/user" - "syscall" - - "github.com/minio/cli" - minio "github.com/minio/minio/cmd" -) - -var defaultUserGroup string - -func init() { - username := os.Getenv("MINIO_USERNAME") - groupname := os.Getenv("MINIO_GROUPNAME") - defaultUserGroup = username + ":" + groupname -} - -func getUserGroup(path string) (string, error) { - fi, err := os.Stat(minio.PathJoin(path, ".minio.sys")) - if err != nil { - // Fresh directory we should default to what was requested by user. - if os.IsNotExist(err) { - fi, err = os.Stat(path) - if err != nil { - return "", err - } - } else { - return "", err - } - } - stat, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - // Unable to figure out uid/gid, default to defaultUserGroup - return defaultUserGroup, nil - } - u, err := user.LookupId(fmt.Sprintf("%d", stat.Uid)) - if err != nil { - return fmt.Sprintf("%d:%d", stat.Uid, stat.Gid), nil - } - g, err := user.LookupGroupId(fmt.Sprintf("%d", stat.Gid)) - if err != nil { - return fmt.Sprintf("%d:%d", stat.Uid, stat.Gid), nil - } - return fmt.Sprintf("%s:%s", u.Username, g.Name), nil -} - -func main() { - app := cli.NewApp() - app.Flags = append(minio.ServerFlags, minio.GlobalFlags...) - app.Action = func(ctx *cli.Context) { - // Fetch address option - serverAddr := ctx.GlobalString("address") - if serverAddr == "" || serverAddr == ":9000" { - serverAddr = ctx.String("address") - } - if ctx.Args().First() == "help" { - cli.ShowCommandHelpAndExit(ctx, "check-user", 1) - } - if ctx.Args().First() != "minio" { - cli.ShowCommandHelpAndExit(ctx, "check-user", 1) - } - args := cli.Args(ctx.Args().Tail()) - if !args.Present() { - cli.ShowCommandHelpAndExit(ctx, "check-user", 1) - } - var ug string - var err error - switch args.First() { - case "gateway": - args = cli.Args(args.Tail()) - if args.First() != "nas" { - fmt.Println(defaultUserGroup) - return - } - args = cli.Args(args.Tail()) - if args.First() == "" { - fmt.Println("") - return - } - ug, err = getUserGroup(args.First()) - if err != nil { - log.Fatalln(err) - } - case "server": - var setArgs [][]string - setArgs, err = minio.GetAllSets(args.Tail()...) - if err != nil { - log.Fatalln(err) - } - var endpoints minio.EndpointList - _, endpoints, _, err = minio.CreateEndpoints(serverAddr, setArgs...) - if err != nil { - log.Fatalln(err) - } - for _, endpoint := range endpoints { - if !endpoint.IsLocal { - continue - } - ug, err = getUserGroup(endpoint.Path) - if err != nil { - log.Fatalln(err) - } - break - } - default: - cli.ShowCommandHelpAndExit(ctx, "check-user", 1) - } - fmt.Println(ug) - } - if err := app.Run(os.Args); err != nil { - log.Fatalln(err) - } -} diff --git a/dockerscripts/docker-entrypoint.sh b/dockerscripts/docker-entrypoint.sh index 39d38e19c..997771c4d 100755 --- a/dockerscripts/docker-entrypoint.sh +++ b/dockerscripts/docker-entrypoint.sh @@ -15,9 +15,6 @@ # limitations under the License. # -export MINIO_USERNAME=${MINIO_USERNAME:-"minio"} -export MINIO_GROUPNAME=${MINIO_GROUPNAME:-"minio"} - # If command starts with an option, prepend minio. if [ "${1}" != "minio" ]; then if [ -n "${1}" ]; then @@ -42,37 +39,21 @@ docker_secrets_env() { fi } -## Create UID/GID based on available environment variables. -docker_set_uid_gid() { - addgroup -S "$MINIO_GROUPNAME" >/dev/null 2>&1 && \ - adduser -S -G "$MINIO_GROUPNAME" "$MINIO_USERNAME" >/dev/null 2>&1 -} - -# su-exec to requested user, if user cannot be requested -# existing user is used automatically. +# su-exec to requested user, if service cannot run exec will fail. docker_switch_user() { - owner=$(check-user "$@") - if [ "${owner}" != "${MINIO_USERNAME}:${MINIO_GROUPNAME}" ]; then - ## Print the message only if we are not using non-default username:groupname. - if [ "${MINIO_USERNAME}:${MINIO_GROUPNAME}" != "minio:minio" ]; then - echo "Requested username/group ${MINIO_USERNAME}:${MINIO_GROUPNAME} cannot be used" - echo "Found existing data with user ${owner}, we will continue and use ${owner} instead." - return - fi + if [ -z "${MINIO_USERNAME}" ] || [ -z "${MINIO_GROUPNAME}" ]; then + addgroup -S "$MINIO_GROUPNAME" >/dev/null 2>&1 && \ + adduser -S -G "$MINIO_GROUPNAME" "$MINIO_USERNAME" >/dev/null 2>&1 + + exec su-exec "${MINIO_USERNAME}:${MINIO_GROUPNAME}" "$@" + else + # fallback + exec "$@" fi - # check if su-exec is allowed, if yes proceed proceed. - if su-exec "${owner}" "/bin/ls" >/dev/null 2>&1; then - exec su-exec "${owner}" "$@" - fi - # fallback - exec "$@" } ## Set access env from secrets if necessary. docker_secrets_env -## User Input UID and GID -docker_set_uid_gid - ## Switch to user if applicable. docker_switch_user "$@" diff --git a/docs/docker/README.md b/docs/docker/README.md index 639963c46..da1d5a877 100644 --- a/docs/docker/README.md +++ b/docs/docker/README.md @@ -58,20 +58,19 @@ docker run -p 9000:9000 --name minio1 \ minio/minio server /data ``` -### Run MinIO Docker as non root user -MinIO server runs as non-root within the container by default. However, this is applicable only if you're deploying new MinIO instance (not upgrading from older releases). Deployments upgrading from older MinIO deployments, will continue to run as the user previously used if any. +### Run MinIO Docker as regular user +MinIO server doesn't run as a regular user by default in docker containers. To run MinIO container as regular user use environment variables `MINIO_USERNAME` and `MINIO_GROUPNAME`. -By default `minio` is username and groupname. Use environment variables `MINIO_USERNAME` and `MINIO_GROUPNAME` to override these default values. +> NOTE: If you are upgrading from existing deployments, you need to make sure this user has write access to previous persistent volumes. MinIO will not migrate the content automatically. #### GNU/Linux and macOS ```sh docker run -p 9000:9000 --name minio1 \ -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \ -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \ - -e "MINIO_USERNAME=custom" \ - -e "MINIO_GROUPNAME=custom" \ + -e "MINIO_USERNAME=minio-user" \ + -e "MINIO_GROUPNAME=minio-user" \ -v /mnt/data:/data \ - -v /mnt/config:/root/.minio \ minio/minio server /data ``` @@ -80,10 +79,9 @@ docker run -p 9000:9000 --name minio1 \ docker run -p 9000:9000 --name minio1 \ -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \ -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \ - -e "MINIO_USERNAME=custom" \ - -e "MINIO_GROUPNAME=custom" \ + -e "MINIO_USERNAME=minio-user" \ + -e "MINIO_GROUPNAME=minio-user" \ -v D:\data:/data \ - -v D:\minio\config:/root/.minio \ minio/minio server /data ```