diff --git a/cmd/api-errors.go b/cmd/api-errors.go index f73f6cb36..06c3c22ea 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -381,6 +381,13 @@ func (e errorCodeMap) ToAPIErrWithErr(errCode APIErrorCode, err error) APIError if err != nil { apiErr.Description = fmt.Sprintf("%s (%s)", apiErr.Description, err) } + if globalServerRegion != "" { + switch errCode { + case ErrAuthorizationHeaderMalformed: + apiErr.Description = fmt.Sprintf("The authorization header is malformed; the region is wrong; expecting '%s'.", globalServerRegion) + return apiErr + } + } return apiErr } @@ -2116,6 +2123,13 @@ func toAPIError(ctx context.Context, err error) APIError { Description: e.Message, HTTPStatusCode: e.StatusCode, } + if globalIsGateway && strings.Contains(e.Message, "KMS is not configured") { + apiErr = APIError{ + Code: "NotImplemented", + Description: e.Message, + HTTPStatusCode: http.StatusNotImplemented, + } + } case *googleapi.Error: apiErr = APIError{ Code: "XGCSInternalError", diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index e72a1c831..266f28180 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -876,6 +876,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) return } + vars := mux.Vars(r) dstBucket := vars["bucket"] dstObject, err := unescapePath(vars["object"]) @@ -1395,9 +1396,18 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req return } - if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) - return + if _, ok := crypto.IsRequested(r.Header); ok { + if globalIsGateway { + if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } else { + if !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } } vars := mux.Vars(r) @@ -1698,9 +1708,18 @@ func (api objectAPIHandlers) PutObjectExtractHandler(w http.ResponseWriter, r *h return } - if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) - return + if _, ok := crypto.IsRequested(r.Header); ok { + if globalIsGateway { + if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } else { + if !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } } vars := mux.Vars(r) @@ -1978,9 +1997,18 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r return } - if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) - return + if _, ok := crypto.IsRequested(r.Header); ok { + if globalIsGateway { + if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } else { + if !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } } vars := mux.Vars(r) @@ -2429,10 +2457,20 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http return } - if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { - writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) - return + if _, ok := crypto.IsRequested(r.Header); ok { + if globalIsGateway { + if crypto.SSEC.IsRequested(r.Header) && !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } else { + if !objectAPI.IsEncryptionSupported() { + writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) + return + } + } } + vars := mux.Vars(r) bucket := vars["bucket"] object, err := unescapePath(vars["object"]) diff --git a/docs/gateway/s3.md b/docs/gateway/s3.md index 1b66632ce..0a906e9e7 100644 --- a/docs/gateway/s3.md +++ b/docs/gateway/s3.md @@ -67,22 +67,28 @@ As a prerequisite to run MinIO S3 gateway on an AWS S3 compatible service, you n ## Run MinIO Gateway with double-encryption MinIO gateway to S3 supports encryption of data at rest. Three types of encryption modes are supported -- encryption can be set to ``pass-through`` to backend +- encryption can be set to ``pass-through`` to backend only for SSE-S3, SSE-C is not allowed passthrough. - ``single encryption`` (at the gateway) -- ``double encryption`` (single encryption at gateway and pass through to backend). +- ``double encryption`` (single encryption at gateway and pass through to backend) This can be specified by setting MINIO_GATEWAY_SSE environment variable. If MINIO_GATEWAY_SSE and KMS are not setup, all encryption headers are passed through to the backend. If KMS environment variables are set up, ``single encryption`` is automatically performed at the gateway and encrypted object is saved at the backend. To specify ``double encryption``, MINIO_GATEWAY_SSE environment variable needs to be set to "s3" for sse-s3 and "c" for sse-c encryption. More than one encryption option can be set, delimited by ";". Objects are encrypted at the gateway and the gateway also does a pass-through to backend. Note that in the case of SSE-C encryption, gateway derives a unique SSE-C key for pass through from the SSE-C client key using a key derivation function (KDF). + +```sh +curl -sSL --tlsv1.2 \ + -O 'https://raw.githubusercontent.com/minio/kes/master/root.key' \ + -O 'https://raw.githubusercontent.com/minio/kes/master/root.cert' +``` + ```sh export MINIO_GATEWAY_SSE="s3;c" -export MINIO_KMS_VAULT_APPROLE_ID=9b56cc08-8258-45d5-24a3-679876769126 -export MINIO_KMS_VAULT_APPROLE_SECRET=4e30c52f-13e4-a6f5-0763-d50e8cb4321f -export MINIO_KMS_VAULT_ENDPOINT=https://vault-endpoint-ip:8200 -export MINIO_KMS_VAULT_KEY_NAME=my-minio-key -export MINIO_KMS_VAULT_AUTH_TYPE=approle +export MINIO_KMS_KES_ENDPOINT=https://play.min.io:7373 +export MINIO_KMS_KES_KEY_FILE=root.key +export MINIO_KMS_KES_CERT_FILE=root.cert +export MINIO_KMS_KES_KEY_NAME=my-minio-key minio gateway s3 ``` diff --git a/pkg/net/url.go b/pkg/net/url.go index 315a954a8..c52261245 100644 --- a/pkg/net/url.go +++ b/pkg/net/url.go @@ -186,6 +186,12 @@ func IsNetworkOrHostDown(err error, expectTimeouts bool) bool { case strings.Contains(err.Error(), "connection timed out"): // If err is a net.Dial timeout. return true + case strings.Contains(err.Error(), "connection reset by peer"): + // IF err is a peer reset on a socket. + return true + case strings.Contains(err.Error(), "broken pipe"): + // IF err is a broken pipe on a socket. + return true case strings.Contains(strings.ToLower(err.Error()), "503 service unavailable"): // Denial errors return true