| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * 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 cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2019-11-05 22:18:26 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2019-12-05 07:32:37 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/gorilla/mux" | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/config" | 
					
						
							| 
									
										
										
										
											2019-12-05 07:32:37 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/config/cache" | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/config/etcd" | 
					
						
							|  |  |  | 	xldap "github.com/minio/minio/cmd/config/identity/ldap" | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/config/identity/openid" | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/config/policy/opa" | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/config/storageclass" | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/crypto" | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	"github.com/minio/minio/cmd/logger" | 
					
						
							| 
									
										
										
										
											2019-11-19 18:03:18 +08:00
										 |  |  | 	iampolicy "github.com/minio/minio/pkg/iam/policy" | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/madmin" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | func validateAdminReqConfigKV(ctx context.Context, w http.ResponseWriter, r *http.Request) ObjectLayer { | 
					
						
							|  |  |  | 	// Get current object layer instance.
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	objectAPI := newObjectLayerWithoutSafeModeFn() | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL) | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Validate request signature.
 | 
					
						
							| 
									
										
										
										
											2019-11-19 18:03:18 +08:00
										 |  |  | 	_, adminAPIErr := checkAdminRequestAuthType(ctx, r, iampolicy.ConfigUpdateAdminAction, "") | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	if adminAPIErr != ErrNone { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(adminAPIErr), r.URL) | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return objectAPI | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | // DelConfigKVHandler - DELETE /minio/admin/v2/del-config-kv
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) DelConfigKVHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "DelConfigKVHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Deny if WORM is enabled
 | 
					
						
							|  |  |  | 	if globalWORMEnabled { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { | 
					
						
							|  |  |  | 		// More than maxConfigSize bytes were available
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	password := globalActiveCred.SecretKey | 
					
						
							|  |  |  | 	kvBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		logger.LogIf(ctx, err, logger.Application) | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	cfg, err := readServerConfig(ctx, objectAPI) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 	if err = cfg.DelFrom(bytes.NewReader(kvBytes)); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-21 20:24:51 +08:00
										 |  |  | 	if err = saveServerConfig(ctx, objectAPI, cfg); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetConfigKVHandler - PUT /minio/admin/v2/set-config-kv
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) SetConfigKVHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "SetConfigKVHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Deny if WORM is enabled
 | 
					
						
							|  |  |  | 	if globalWORMEnabled { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { | 
					
						
							|  |  |  | 		// More than maxConfigSize bytes were available
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	password := globalActiveCred.SecretKey | 
					
						
							|  |  |  | 	kvBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		logger.LogIf(ctx, err, logger.Application) | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	cfg, err := readServerConfig(ctx, objectAPI) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 08:13:07 +08:00
										 |  |  | 	if _, err = cfg.ReadFrom(bytes.NewReader(kvBytes)); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if err = validateConfig(cfg); err != nil { | 
					
						
							|  |  |  | 		writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Update the actual server config on disk.
 | 
					
						
							| 
									
										
										
										
											2019-11-21 20:24:51 +08:00
										 |  |  | 	if err = saveServerConfig(ctx, objectAPI, cfg); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Write to the config input KV to history.
 | 
					
						
							|  |  |  | 	if err = saveServerConfigHistory(ctx, objectAPI, kvBytes); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Make sure to write backend is encrypted
 | 
					
						
							| 
									
										
										
										
											2019-11-12 10:42:10 +08:00
										 |  |  | 	if globalConfigEncrypted { | 
					
						
							|  |  |  | 		saveConfig(context.Background(), objectAPI, backendEncryptedFile, backendEncryptedMigrationComplete) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-27 02:08:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseHeadersOnly(w) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GetConfigKVHandler - GET /minio/admin/v2/get-config-kv?key={key}
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) GetConfigKVHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "GetConfigKVHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-12 04:01:21 +08:00
										 |  |  | 	cfg := globalServerConfig | 
					
						
							|  |  |  | 	if globalSafeMode { | 
					
						
							|  |  |  | 		var err error | 
					
						
							|  |  |  | 		cfg, err = getValidConfig(objectAPI) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	vars := mux.Vars(r) | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 	var buf = &bytes.Buffer{} | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 	cw := config.NewConfigWriteTo(cfg, vars["key"]) | 
					
						
							|  |  |  | 	if _, err := cw.WriteTo(buf); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	password := globalActiveCred.SecretKey | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 	econfigData, err := madmin.EncryptData(password, buf.Bytes()) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, econfigData) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ClearConfigHistoryKVHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "ClearConfigHistoryKVHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	restoreID := vars["restoreId"] | 
					
						
							|  |  |  | 	if restoreID == "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if restoreID == "all" { | 
					
						
							| 
									
										
										
										
											2019-11-05 22:18:26 +08:00
										 |  |  | 		chEntries, err := listServerConfigHistory(ctx, objectAPI, false, -1) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for _, chEntry := range chEntries { | 
					
						
							|  |  |  | 			if err = delServerConfigHistory(ctx, objectAPI, chEntry.RestoreID); err != nil { | 
					
						
							|  |  |  | 				writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if err := delServerConfigHistory(ctx, objectAPI, restoreID); err != nil { | 
					
						
							|  |  |  | 			writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RestoreConfigHistoryKVHandler - restores a config with KV settings for the given KV id.
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) RestoreConfigHistoryKVHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "RestoreConfigHistoryKVHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	restoreID := vars["restoreId"] | 
					
						
							|  |  |  | 	if restoreID == "" { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kvBytes, err := readServerConfigHistory(ctx, objectAPI, restoreID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cfg, err := readServerConfig(ctx, objectAPI) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 	if _, err = cfg.ReadFrom(bytes.NewReader(kvBytes)); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err = validateConfig(cfg); err != nil { | 
					
						
							|  |  |  | 		writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-21 20:24:51 +08:00
										 |  |  | 	if err = saveServerConfig(ctx, objectAPI, cfg); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	delServerConfigHistory(ctx, objectAPI, restoreID) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListConfigHistoryKVHandler - lists all the KV ids.
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) ListConfigHistoryKVHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "ListConfigHistoryKVHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 22:18:26 +08:00
										 |  |  | 	vars := mux.Vars(r) | 
					
						
							|  |  |  | 	count, err := strconv.Atoi(vars["count"]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	chEntries, err := listServerConfigHistory(ctx, objectAPI, true, count) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	data, err := json.Marshal(chEntries) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 22:18:26 +08:00
										 |  |  | 	password := globalActiveCred.SecretKey | 
					
						
							|  |  |  | 	econfigData, err := madmin.EncryptData(password, data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, econfigData) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // HelpConfigKVHandler - GET /minio/admin/v2/help-config-kv?subSys={subSys}&key={key}
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) HelpConfigKVHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "HelpConfigKVHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vars := mux.Vars(r) | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	subSys := vars["subSys"] | 
					
						
							|  |  |  | 	key := vars["key"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 	_, envOnly := r.URL.Query()["env"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rd, err := GetHelp(subSys, key, envOnly) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | 	json.NewEncoder(w).Encode(rd) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	w.(http.Flusher).Flush() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | // SetConfigHandler - PUT /minio/admin/v2/config
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "SetConfigHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Deny if WORM is enabled
 | 
					
						
							|  |  |  | 	if globalWORMEnabled { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if r.ContentLength > maxEConfigJSONSize || r.ContentLength == -1 { | 
					
						
							|  |  |  | 		// More than maxConfigSize bytes were available
 | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigTooLarge), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	password := globalActiveCred.SecretKey | 
					
						
							| 
									
										
										
										
											2019-11-27 02:08:25 +08:00
										 |  |  | 	kvBytes, err := madmin.DecryptData(password, io.LimitReader(r.Body, r.ContentLength)) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		logger.LogIf(ctx, err, logger.Application) | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 02:08:25 +08:00
										 |  |  | 	cfg := newServerConfig() | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 	if _, err = cfg.ReadFrom(bytes.NewReader(kvBytes)); err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-27 02:08:25 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err = validateConfig(cfg); err != nil { | 
					
						
							|  |  |  | 		writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 02:08:25 +08:00
										 |  |  | 	// Update the actual server config on disk.
 | 
					
						
							| 
									
										
										
										
											2019-11-21 20:24:51 +08:00
										 |  |  | 	if err = saveServerConfig(ctx, objectAPI, cfg); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-27 02:08:25 +08:00
										 |  |  | 	// Write to the config input KV to history.
 | 
					
						
							|  |  |  | 	if err = saveServerConfigHistory(ctx, objectAPI, kvBytes); err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 	// Make sure to write backend is encrypted
 | 
					
						
							| 
									
										
										
										
											2019-11-12 10:42:10 +08:00
										 |  |  | 	if globalConfigEncrypted { | 
					
						
							|  |  |  | 		saveConfig(context.Background(), objectAPI, backendEncryptedFile, backendEncryptedMigrationComplete) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	writeSuccessResponseHeadersOnly(w) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 15:04:39 +08:00
										 |  |  | // GetConfigHandler - GET /minio/admin/v2/config
 | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | // Get config.json of this minio setup.
 | 
					
						
							|  |  |  | func (a adminAPIHandlers) GetConfigHandler(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 	ctx := newContext(r, w, "GetConfigHandler") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 14:39:09 +08:00
										 |  |  | 	objectAPI := validateAdminReqConfigKV(ctx, w, r) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if objectAPI == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 	cfg, err := readServerConfig(ctx, objectAPI) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-05 07:32:37 +08:00
										 |  |  | 	var s strings.Builder | 
					
						
							|  |  |  | 	hkvs := config.HelpSubSysMap[""] | 
					
						
							| 
									
										
										
										
											2019-12-21 06:47:14 +08:00
										 |  |  | 	var count int | 
					
						
							|  |  |  | 	for _, hkv := range hkvs { | 
					
						
							|  |  |  | 		count += len(cfg[hkv.Key]) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-05 07:32:37 +08:00
										 |  |  | 	for _, hkv := range hkvs { | 
					
						
							|  |  |  | 		v := cfg[hkv.Key] | 
					
						
							|  |  |  | 		for target, kv := range v { | 
					
						
							|  |  |  | 			off := kv.Get(config.Enable) == config.EnableOff | 
					
						
							|  |  |  | 			switch hkv.Key { | 
					
						
							|  |  |  | 			case config.EtcdSubSys: | 
					
						
							|  |  |  | 				off = !etcd.Enabled(kv) | 
					
						
							|  |  |  | 			case config.CacheSubSys: | 
					
						
							|  |  |  | 				off = !cache.Enabled(kv) | 
					
						
							|  |  |  | 			case config.StorageClassSubSys: | 
					
						
							|  |  |  | 				off = !storageclass.Enabled(kv) | 
					
						
							|  |  |  | 			case config.KmsVaultSubSys: | 
					
						
							| 
									
										
										
										
											2019-12-14 04:57:11 +08:00
										 |  |  | 				off = !crypto.EnabledVault(kv) | 
					
						
							|  |  |  | 			case config.KmsKesSubSys: | 
					
						
							|  |  |  | 				off = !crypto.EnabledKes(kv) | 
					
						
							| 
									
										
										
										
											2019-12-05 07:32:37 +08:00
										 |  |  | 			case config.PolicyOPASubSys: | 
					
						
							|  |  |  | 				off = !opa.Enabled(kv) | 
					
						
							|  |  |  | 			case config.IdentityOpenIDSubSys: | 
					
						
							|  |  |  | 				off = !openid.Enabled(kv) | 
					
						
							|  |  |  | 			case config.IdentityLDAPSubSys: | 
					
						
							|  |  |  | 				off = !xldap.Enabled(kv) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if off { | 
					
						
							|  |  |  | 				s.WriteString(config.KvComment) | 
					
						
							|  |  |  | 				s.WriteString(config.KvSpaceSeparator) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.WriteString(hkv.Key) | 
					
						
							|  |  |  | 			if target != config.Default { | 
					
						
							|  |  |  | 				s.WriteString(config.SubSystemSeparator) | 
					
						
							|  |  |  | 				s.WriteString(target) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.WriteString(config.KvSpaceSeparator) | 
					
						
							|  |  |  | 			s.WriteString(kv.String()) | 
					
						
							| 
									
										
										
										
											2019-12-21 06:47:14 +08:00
										 |  |  | 			count-- | 
					
						
							|  |  |  | 			if count > 0 { | 
					
						
							|  |  |  | 				s.WriteString(config.KvNewline) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-12-05 07:32:37 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-11-28 01:36:08 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	password := globalActiveCred.SecretKey | 
					
						
							| 
									
										
										
										
											2019-12-05 07:32:37 +08:00
										 |  |  | 	econfigData, err := madmin.EncryptData(password, []byte(s.String())) | 
					
						
							| 
									
										
										
										
											2019-10-23 13:59:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeSuccessResponseJSON(w, econfigData) | 
					
						
							|  |  |  | } |