feat: Encrypt s3zip file index (#16179)

This commit is contained in:
Klaus Post 2022-12-07 23:56:07 +01:00 committed by GitHub
parent 12fd6678ee
commit ebe395788b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 8 deletions

View File

@ -1083,6 +1083,44 @@ func (o *ObjectInfo) metadataDecrypter() objectMetaDecryptFn {
} }
} }
// metadataEncryptFn provides an encryption function for metadata.
// Will return nil, nil if unencrypted.
func (o *ObjectInfo) metadataEncryptFn(headers http.Header) (objectMetaEncryptFn, error) {
kind, _ := crypto.IsEncrypted(o.UserDefined)
switch kind {
case crypto.SSEC:
if crypto.SSECopy.IsRequested(headers) {
key, err := crypto.SSECopy.ParseHTTP(headers)
if err != nil {
return nil, err
}
objectEncryptionKey, err := decryptObjectMeta(key[:], o.Bucket, o.Name, o.UserDefined)
if err != nil {
return nil, err
}
if len(objectEncryptionKey) == 32 {
var key crypto.ObjectKey
copy(key[:], objectEncryptionKey)
return metadataEncrypter(key), nil
}
return nil, errors.New("metadataEncryptFn: unexpected key size")
}
case crypto.S3, crypto.S3KMS:
objectEncryptionKey, err := decryptObjectMeta(nil, o.Bucket, o.Name, o.UserDefined)
if err != nil {
return nil, err
}
if len(objectEncryptionKey) == 32 {
var key crypto.ObjectKey
copy(key[:], objectEncryptionKey)
return metadataEncrypter(key), nil
}
return nil, errors.New("metadataEncryptFn: unexpected key size")
}
return nil, nil
}
// decryptChecksums will attempt to decode checksums and return it/them if set. // decryptChecksums will attempt to decode checksums and return it/them if set.
func (o *ObjectInfo) decryptChecksums() map[string]string { func (o *ObjectInfo) decryptChecksums() map[string]string {
data := o.Checksum data := o.Checksum

View File

@ -26,6 +26,7 @@ import (
"github.com/minio/madmin-go/v2" "github.com/minio/madmin-go/v2"
"github.com/minio/minio/internal/bucket/replication" "github.com/minio/minio/internal/bucket/replication"
"github.com/minio/minio/internal/hash" "github.com/minio/minio/internal/hash"
"github.com/minio/minio/internal/logger"
) )
// BackendType - represents different backend types. // BackendType - represents different backend types.
@ -181,8 +182,9 @@ type ObjectInfo struct {
Checksum []byte Checksum []byte
} }
// ArchiveInfo returns any saved zip archive meta information // ArchiveInfo returns any saved zip archive meta information.
func (o ObjectInfo) ArchiveInfo() []byte { // It will be decrypted if needed.
func (o *ObjectInfo) ArchiveInfo() []byte {
if len(o.UserDefined) == 0 { if len(o.UserDefined) == 0 {
return nil return nil
} }
@ -190,11 +192,20 @@ func (o ObjectInfo) ArchiveInfo() []byte {
if !ok { if !ok {
return nil return nil
} }
return []byte(z) data := []byte(z)
if v, ok := o.UserDefined[archiveTypeMetadataKey]; ok && v == archiveTypeEnc {
decrypted, err := o.metadataDecrypter()(archiveTypeEnc, data)
if err != nil {
logger.LogIf(GlobalContext, err)
return nil
}
data = decrypted
}
return data
} }
// Clone - Returns a cloned copy of current objectInfo // Clone - Returns a cloned copy of current objectInfo
func (o ObjectInfo) Clone() (cinfo ObjectInfo) { func (o *ObjectInfo) Clone() (cinfo ObjectInfo) {
cinfo = ObjectInfo{ cinfo = ObjectInfo{
Bucket: o.Bucket, Bucket: o.Bucket,
Name: o.Name, Name: o.Name,

View File

@ -676,6 +676,11 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite
} }
} }
opts.EncryptFn, err = objInfo.metadataEncryptFn(r.Header)
if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
return
}
if r.Header.Get(xMinIOExtract) == "true" && strings.HasSuffix(object, archiveExt) { if r.Header.Get(xMinIOExtract) == "true" && strings.HasSuffix(object, archiveExt) {
opts := ObjectOptions{VersionID: objInfo.VersionID, MTime: objInfo.ModTime} opts := ObjectOptions{VersionID: objInfo.VersionID, MTime: objInfo.ModTime}
if _, err := updateObjectMetadataWithZipInfo(ctx, objectAPI, bucket, object, opts); err != nil { if _, err := updateObjectMetadataWithZipInfo(ctx, objectAPI, bucket, object, opts); err != nil {

View File

@ -38,6 +38,7 @@ import (
const ( const (
archiveType = "zip" archiveType = "zip"
archiveTypeEnc = "zip-enc"
archiveExt = "." + archiveType // ".zip" archiveExt = "." + archiveType // ".zip"
archiveSeparator = "/" archiveSeparator = "/"
archivePattern = archiveExt + archiveSeparator // ".zip/" archivePattern = archiveExt + archiveSeparator // ".zip/"
@ -152,6 +153,12 @@ func (api objectAPIHandlers) getObjectInArchiveFileHandler(ctx context.Context,
zipInfo := zipObjInfo.ArchiveInfo() zipInfo := zipObjInfo.ArchiveInfo()
if len(zipInfo) == 0 { if len(zipInfo) == 0 {
opts.EncryptFn, err = zipObjInfo.metadataEncryptFn(r.Header)
if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
return
}
zipInfo, err = updateObjectMetadataWithZipInfo(ctx, objectAPI, bucket, zipPath, opts) zipInfo, err = updateObjectMetadataWithZipInfo(ctx, objectAPI, bucket, zipPath, opts)
} }
if err != nil { if err != nil {
@ -451,6 +458,11 @@ func (api objectAPIHandlers) headObjectInArchiveFileHandler(ctx context.Context,
zipInfo := zipObjInfo.ArchiveInfo() zipInfo := zipObjInfo.ArchiveInfo()
if len(zipInfo) == 0 { if len(zipInfo) == 0 {
opts.EncryptFn, err = zipObjInfo.metadataEncryptFn(r.Header)
if err != nil {
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
return
}
zipInfo, err = updateObjectMetadataWithZipInfo(ctx, objectAPI, bucket, zipPath, opts) zipInfo, err = updateObjectMetadataWithZipInfo(ctx, objectAPI, bucket, zipPath, opts)
} }
if err != nil { if err != nil {
@ -491,7 +503,8 @@ func (api objectAPIHandlers) headObjectInArchiveFileHandler(ctx context.Context,
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
// Update the passed zip object metadata with the zip contents info, file name, modtime, size, etc.. // Update the passed zip object metadata with the zip contents info, file name, modtime, size, etc.
// The returned zip index will de decrypted.
func updateObjectMetadataWithZipInfo(ctx context.Context, objectAPI ObjectLayer, bucket, object string, opts ObjectOptions) ([]byte, error) { func updateObjectMetadataWithZipInfo(ctx context.Context, objectAPI ObjectLayer, bucket, object string, opts ObjectOptions) ([]byte, error) {
files, srcInfo, err := getFilesListFromZIPObject(ctx, objectAPI, bucket, object, opts) files, srcInfo, err := getFilesListFromZIPObject(ctx, objectAPI, bucket, object, opts)
if err != nil { if err != nil {
@ -502,14 +515,18 @@ func updateObjectMetadataWithZipInfo(ctx context.Context, objectAPI ObjectLayer,
if err != nil { if err != nil {
return nil, err return nil, err
} }
at := archiveType
srcInfo.UserDefined[archiveTypeMetadataKey] = archiveType
zipInfoStr := string(zipInfo) zipInfoStr := string(zipInfo)
if opts.EncryptFn != nil {
at = archiveTypeEnc
zipInfoStr = string(opts.EncryptFn(archiveTypeEnc, zipInfo))
}
srcInfo.UserDefined[archiveTypeMetadataKey] = at
popts := ObjectOptions{ popts := ObjectOptions{
MTime: srcInfo.ModTime, MTime: srcInfo.ModTime,
VersionID: srcInfo.VersionID, VersionID: srcInfo.VersionID,
EvalMetadataFn: func(oi *ObjectInfo) error { EvalMetadataFn: func(oi *ObjectInfo) error {
oi.UserDefined[archiveTypeMetadataKey] = archiveType oi.UserDefined[archiveTypeMetadataKey] = at
oi.UserDefined[archiveInfoMetadataKey] = zipInfoStr oi.UserDefined[archiveInfoMetadataKey] = zipInfoStr
return nil return nil
}, },