mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
feat: Encrypt s3zip file index (#16179)
This commit is contained in:
parent
12fd6678ee
commit
ebe395788b
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user