fix: allow S3 gateway passthrough for SSE-S3 header (#12020)

only in case of S3 gateway we have a case where we
need to allow for SSE-S3 headers as passthrough,

If SSE-C headers are passed then they are rejected
if KMS is not configured.
This commit is contained in:
Harshavardhana 2021-04-08 16:40:38 -07:00 committed by GitHub
parent 16ce7fb70c
commit 0e4794ea50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 19 deletions

View File

@ -381,6 +381,13 @@ func (e errorCodeMap) ToAPIErrWithErr(errCode APIErrorCode, err error) APIError
if err != nil { if err != nil {
apiErr.Description = fmt.Sprintf("%s (%s)", apiErr.Description, err) 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 return apiErr
} }
@ -2116,6 +2123,13 @@ func toAPIError(ctx context.Context, err error) APIError {
Description: e.Message, Description: e.Message,
HTTPStatusCode: e.StatusCode, 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: case *googleapi.Error:
apiErr = APIError{ apiErr = APIError{
Code: "XGCSInternalError", Code: "XGCSInternalError",

View File

@ -876,6 +876,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return return
} }
vars := mux.Vars(r) vars := mux.Vars(r)
dstBucket := vars["bucket"] dstBucket := vars["bucket"]
dstObject, err := unescapePath(vars["object"]) dstObject, err := unescapePath(vars["object"])
@ -1395,10 +1396,19 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
return return
} }
if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { 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)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return return
} }
} else {
if !objectAPI.IsEncryptionSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
}
}
vars := mux.Vars(r) vars := mux.Vars(r)
bucket := vars["bucket"] bucket := vars["bucket"]
@ -1698,10 +1708,19 @@ func (api objectAPIHandlers) PutObjectExtractHandler(w http.ResponseWriter, r *h
return return
} }
if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { 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)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return return
} }
} else {
if !objectAPI.IsEncryptionSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
}
}
vars := mux.Vars(r) vars := mux.Vars(r)
bucket := vars["bucket"] bucket := vars["bucket"]
@ -1978,10 +1997,19 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
return return
} }
if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { 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)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return return
} }
} else {
if !objectAPI.IsEncryptionSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
}
}
vars := mux.Vars(r) vars := mux.Vars(r)
bucket := vars["bucket"] bucket := vars["bucket"]
@ -2429,10 +2457,20 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
return return
} }
if _, ok := crypto.IsRequested(r.Header); !objectAPI.IsEncryptionSupported() && ok { 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)) writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return return
} }
} else {
if !objectAPI.IsEncryptionSupported() {
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL, guessIsBrowserReq(r))
return
}
}
}
vars := mux.Vars(r) vars := mux.Vars(r)
bucket := vars["bucket"] bucket := vars["bucket"]
object, err := unescapePath(vars["object"]) object, err := unescapePath(vars["object"])

View File

@ -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 ## Run MinIO Gateway with double-encryption
MinIO gateway to S3 supports encryption of data at rest. Three types of encryption modes are supported 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) - ``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. 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 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). 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 ```sh
export MINIO_GATEWAY_SSE="s3;c" export MINIO_GATEWAY_SSE="s3;c"
export MINIO_KMS_VAULT_APPROLE_ID=9b56cc08-8258-45d5-24a3-679876769126 export MINIO_KMS_KES_ENDPOINT=https://play.min.io:7373
export MINIO_KMS_VAULT_APPROLE_SECRET=4e30c52f-13e4-a6f5-0763-d50e8cb4321f export MINIO_KMS_KES_KEY_FILE=root.key
export MINIO_KMS_VAULT_ENDPOINT=https://vault-endpoint-ip:8200 export MINIO_KMS_KES_CERT_FILE=root.cert
export MINIO_KMS_VAULT_KEY_NAME=my-minio-key export MINIO_KMS_KES_KEY_NAME=my-minio-key
export MINIO_KMS_VAULT_AUTH_TYPE=approle
minio gateway s3 minio gateway s3
``` ```

View File

@ -186,6 +186,12 @@ func IsNetworkOrHostDown(err error, expectTimeouts bool) bool {
case strings.Contains(err.Error(), "connection timed out"): case strings.Contains(err.Error(), "connection timed out"):
// If err is a net.Dial timeout. // If err is a net.Dial timeout.
return true 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"): case strings.Contains(strings.ToLower(err.Error()), "503 service unavailable"):
// Denial errors // Denial errors
return true return true