Add support for customizable user (#7569)

This commit is contained in:
Harshavardhana
2019-06-10 07:57:42 -07:00
committed by Nitish Tiwari
parent 1008c2c069
commit 91ceae23d0
13 changed files with 244 additions and 31 deletions

136
dockerscripts/check-user.go Normal file
View File

@@ -0,0 +1,136 @@
// +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/exec"
"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) {
cmd := exec.Command("chown", "-R", defaultUserGroup, path)
if err = cmd.Run(); err != nil {
return "", err
}
return defaultUserGroup, nil
}
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

@@ -1,6 +1,6 @@
#!/bin/sh
#
# MinIO Cloud Storage, (C) 2017 MinIO, Inc.
# 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.
@@ -15,6 +15,9 @@
# 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
@@ -24,20 +27,47 @@ fi
## Look for docker secrets in default documented location.
docker_secrets_env() {
local ACCESS_KEY_FILE="/run/secrets/$MINIO_ACCESS_KEY_FILE"
local SECRET_KEY_FILE="/run/secrets/$MINIO_SECRET_KEY_FILE"
ACCESS_KEY_FILE="/run/secrets/$MINIO_ACCESS_KEY_FILE"
SECRET_KEY_FILE="/run/secrets/$MINIO_SECRET_KEY_FILE"
if [ -f $ACCESS_KEY_FILE -a -f $SECRET_KEY_FILE ]; then
if [ -f $ACCESS_KEY_FILE ]; then
export MINIO_ACCESS_KEY="$(cat "$ACCESS_KEY_FILE")"
if [ -f "$ACCESS_KEY_FILE" ] && [ -f "$SECRET_KEY_FILE" ]; then
if [ -f "$ACCESS_KEY_FILE" ]; then
MINIO_ACCESS_KEY="$(cat "$ACCESS_KEY_FILE")"
export MINIO_ACCESS_KEY
fi
if [ -f $SECRET_KEY_FILE ]; then
export MINIO_SECRET_KEY="$(cat "$SECRET_KEY_FILE")"
if [ -f "$SECRET_KEY_FILE" ]; then
MINIO_SECRET_KEY="$(cat "$SECRET_KEY_FILE")"
export MINIO_SECRET_KEY
fi
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.
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
fi
exec su-exec "${owner}" "$@"
}
## Set access env from secrets if necessary.
docker_secrets_env
exec "$@"
## User Input UID and GID
docker_set_uid_gid
## Switch to user if applicable.
docker_switch_user "$@"

View File

@@ -1,3 +1,5 @@
// +build ignore
/*
* MinIO Cloud Storage, (C) 2019 MinIO, Inc.
*
@@ -36,7 +38,7 @@ const (
initGraceTime = 300
healthPath = "/minio/health/live"
timeout = time.Duration(30 * time.Second)
minioProcess = "minio"
tcp = "tcp"
)
// returns container boot time by finding
@@ -66,9 +68,16 @@ func findEndpoint() (string, error) {
// split netstat output in rows
scanner := bufio.NewScanner(stdout)
scanner.Split(bufio.ScanLines)
// loop over the rows to find MinIO process
// MinIO works on TCP and it is supposed to be
// the only process listening on a port inside
// container. So we take the first row of netstat
// output (that has tcp) and assume that is the
// MinIO server port.
// Since MinIO is running as non-root user, we can
// no longer depend on the PID/Program name column
// of netstat output
for scanner.Scan() {
if strings.Contains(scanner.Text(), minioProcess) {
if strings.Contains(scanner.Text(), tcp) {
line := scanner.Text()
newLine := strings.Replace(line, ":::", "127.0.0.1:", 1)
fields := strings.Fields(newLine)