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.
This commit is contained in:
Harshavardhana 2019-07-17 11:20:55 -07:00 committed by kannappanr
parent 12353caf35
commit 55dd017e62
8 changed files with 21 additions and 185 deletions

1
.gitignore vendored
View File

@ -22,5 +22,4 @@ prime/
stage/ stage/
.sia_temp/ .sia_temp/
config.json config.json
dockerscripts/check-user
dockerscripts/healthcheck dockerscripts/healthcheck

View File

@ -10,8 +10,7 @@ RUN \
apk add --no-cache git && \ apk add --no-cache git && \
git clone https://github.com/minio/minio && cd minio && \ git clone https://github.com/minio/minio && cd minio && \
go install -v -ldflags "$(go run buildscripts/gen-ldflags.go)" && \ 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 && \ 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
FROM alpine:3.9 FROM alpine:3.9
@ -23,7 +22,6 @@ EXPOSE 9000
COPY --from=0 /go/bin/minio /usr/bin/minio COPY --from=0 /go/bin/minio /usr/bin/minio
COPY --from=0 /usr/bin/healthcheck /usr/bin/healthcheck 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/ COPY dockerscripts/docker-entrypoint.sh /usr/bin/
RUN \ RUN \

View File

@ -2,7 +2,7 @@ FROM alpine:3.9
LABEL maintainer="MinIO Inc <dev@min.io>" LABEL maintainer="MinIO Inc <dev@min.io>"
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/ COPY minio /usr/bin/
ENV MINIO_UPDATE off ENV MINIO_UPDATE off
@ -14,8 +14,7 @@ RUN \
echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \ echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \
chmod +x /usr/bin/minio && \ chmod +x /usr/bin/minio && \
chmod +x /usr/bin/docker-entrypoint.sh && \ chmod +x /usr/bin/docker-entrypoint.sh && \
chmod +x /usr/bin/healthcheck && \ chmod +x /usr/bin/healthcheck
chmod +x /usr/bin/check-user
EXPOSE 9000 EXPOSE 9000

View File

@ -7,15 +7,13 @@ ENV GO111MODULE on
RUN \ RUN \
apk add --no-cache git && \ apk add --no-cache git && \
git clone https://github.com/minio/minio && cd minio/dockerscripts && \ 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/healthcheck healthcheck.go
go build -tags kqueue -ldflags "-s -w" -o /usr/bin/check-user check-user.go
FROM alpine:3.9 FROM alpine:3.9
LABEL maintainer="MinIO Inc <dev@min.io>" LABEL maintainer="MinIO Inc <dev@min.io>"
COPY --from=0 /usr/bin/healthcheck /usr/bin/healthcheck 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/ COPY dockerscripts/docker-entrypoint.sh /usr/bin/
ENV MINIO_UPDATE off ENV MINIO_UPDATE off
@ -28,8 +26,7 @@ RUN \
curl https://dl.min.io/server/minio/release/linux-amd64/minio > /usr/bin/minio && \ curl https://dl.min.io/server/minio/release/linux-amd64/minio > /usr/bin/minio && \
chmod +x /usr/bin/minio && \ chmod +x /usr/bin/minio && \
chmod +x /usr/bin/docker-entrypoint.sh && \ chmod +x /usr/bin/docker-entrypoint.sh && \
chmod +x /usr/bin/healthcheck && \ chmod +x /usr/bin/healthcheck
chmod +x /usr/bin/check-user
EXPOSE 9000 EXPOSE 9000

View File

@ -73,7 +73,6 @@ build: checks
@echo "Building minio binary to './minio'" @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)/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/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
@docker build -t $(TAG) . -f Dockerfile.dev @docker build -t $(TAG) . -f Dockerfile.dev

View File

@ -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)
}
}

View File

@ -15,9 +15,6 @@
# limitations under the License. # 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 command starts with an option, prepend minio.
if [ "${1}" != "minio" ]; then if [ "${1}" != "minio" ]; then
if [ -n "${1}" ]; then if [ -n "${1}" ]; then
@ -42,37 +39,21 @@ docker_secrets_env() {
fi fi
} }
## Create UID/GID based on available environment variables. # su-exec to requested user, if service cannot run exec will fail.
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.
docker_switch_user() { docker_switch_user() {
owner=$(check-user "$@") if [ -z "${MINIO_USERNAME}" ] || [ -z "${MINIO_GROUPNAME}" ]; then
if [ "${owner}" != "${MINIO_USERNAME}:${MINIO_GROUPNAME}" ]; then addgroup -S "$MINIO_GROUPNAME" >/dev/null 2>&1 && \
## Print the message only if we are not using non-default username:groupname. adduser -S -G "$MINIO_GROUPNAME" "$MINIO_USERNAME" >/dev/null 2>&1
if [ "${MINIO_USERNAME}:${MINIO_GROUPNAME}" != "minio:minio" ]; then
echo "Requested username/group ${MINIO_USERNAME}:${MINIO_GROUPNAME} cannot be used" exec su-exec "${MINIO_USERNAME}:${MINIO_GROUPNAME}" "$@"
echo "Found existing data with user ${owner}, we will continue and use ${owner} instead." else
return # fallback
fi exec "$@"
fi 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. ## Set access env from secrets if necessary.
docker_secrets_env docker_secrets_env
## User Input UID and GID
docker_set_uid_gid
## Switch to user if applicable. ## Switch to user if applicable.
docker_switch_user "$@" docker_switch_user "$@"

View File

@ -58,20 +58,19 @@ docker run -p 9000:9000 --name minio1 \
minio/minio server /data minio/minio server /data
``` ```
### Run MinIO Docker as non root user ### Run MinIO Docker as regular 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. 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 #### GNU/Linux and macOS
```sh ```sh
docker run -p 9000:9000 --name minio1 \ docker run -p 9000:9000 --name minio1 \
-e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \ -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \
-e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \ -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
-e "MINIO_USERNAME=custom" \ -e "MINIO_USERNAME=minio-user" \
-e "MINIO_GROUPNAME=custom" \ -e "MINIO_GROUPNAME=minio-user" \
-v /mnt/data:/data \ -v /mnt/data:/data \
-v /mnt/config:/root/.minio \
minio/minio server /data minio/minio server /data
``` ```
@ -80,10 +79,9 @@ docker run -p 9000:9000 --name minio1 \
docker run -p 9000:9000 --name minio1 \ docker run -p 9000:9000 --name minio1 \
-e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \ -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \
-e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \ -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
-e "MINIO_USERNAME=custom" \ -e "MINIO_USERNAME=minio-user" \
-e "MINIO_GROUPNAME=custom" \ -e "MINIO_GROUPNAME=minio-user" \
-v D:\data:/data \ -v D:\data:/data \
-v D:\minio\config:/root/.minio \
minio/minio server /data minio/minio server /data
``` ```