diff --git a/Dockerfile b/Dockerfile index aeda44a3c..566472407 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,8 +17,7 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \ MINIO_SECRET_KEY_FILE=secret_key \ MINIO_ROOT_USER_FILE=access_key \ MINIO_ROOT_PASSWORD_FILE=secret_key \ - MINIO_KMS_MASTER_KEY_FILE=kms_master_key \ - MINIO_SSE_MASTER_KEY_FILE=sse_master_key \ + MINIO_KMS_SECRET_KEY_FILE=kms_master_key \ MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" EXPOSE 9000 diff --git a/Dockerfile.cicd b/Dockerfile.cicd index 10312fe58..15b3ad416 100644 --- a/Dockerfile.cicd +++ b/Dockerfile.cicd @@ -19,8 +19,7 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \ MINIO_SECRET_KEY_FILE=secret_key \ MINIO_ROOT_USER_FILE=access_key \ MINIO_ROOT_PASSWORD_FILE=secret_key \ - MINIO_KMS_MASTER_KEY_FILE=kms_master_key \ - MINIO_SSE_MASTER_KEY_FILE=sse_master_key \ + MINIO_KMS_SECRET_KEY_FILE=kms_master_key \ MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" EXPOSE 9000 diff --git a/Dockerfile.dev b/Dockerfile.dev index 1ec4fe57a..752b80d44 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -12,8 +12,7 @@ ENV MINIO_UPDATE=off \ MINIO_SECRET_KEY_FILE=secret_key \ MINIO_ROOT_USER_FILE=access_key \ MINIO_ROOT_PASSWORD_FILE=secret_key \ - MINIO_KMS_MASTER_KEY_FILE=kms_master_key \ - MINIO_SSE_MASTER_KEY_FILE=sse_master_key + MINIO_KMS_SECRET_KEY_FILE=kms_master_key RUN microdnf update --nodocs RUN microdnf install curl ca-certificates shadow-utils util-linux --nodocs diff --git a/Dockerfile.release b/Dockerfile.release index 4ef41b7e7..679fbd40d 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -16,8 +16,7 @@ ENV MINIO_ACCESS_KEY_FILE=access_key \ MINIO_SECRET_KEY_FILE=secret_key \ MINIO_ROOT_USER_FILE=access_key \ MINIO_ROOT_PASSWORD_FILE=secret_key \ - MINIO_KMS_MASTER_KEY_FILE=kms_master_key \ - MINIO_SSE_MASTER_KEY_FILE=sse_master_key \ + MINIO_KMS_SECRET_KEY_FILE=kms_master_key \ MINIO_UPDATE_MINISIGN_PUBKEY="RWTx5Zr1tiHQLwG9keckT0c45M3AGeHD6IvimQHpyRywVWGbP1aVSGav" COPY dockerscripts/verify-minio.sh /usr/bin/verify-minio.sh diff --git a/cmd/admin-handlers-config-kv.go b/cmd/admin-handlers-config-kv.go index ca4691cd9..9e3a106d4 100644 --- a/cmd/admin-handlers-config-kv.go +++ b/cmd/admin-handlers-config-kv.go @@ -33,7 +33,6 @@ import ( "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" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" iampolicy "github.com/minio/minio/pkg/iam/policy" @@ -154,11 +153,6 @@ func (a adminAPIHandlers) SetConfigKVHandler(w http.ResponseWriter, r *http.Requ return } - // Make sure to write backend is encrypted - if globalConfigEncrypted { - saveConfig(GlobalContext, objectAPI, backendEncryptedFile, backendEncryptedMigrationComplete) - } - if dynamic { // Apply dynamic values. if err := applyDynamicConfig(GlobalContext, objectAPI, cfg); err != nil { @@ -411,11 +405,6 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques return } - // Make sure to write backend is encrypted - if globalConfigEncrypted { - saveConfig(GlobalContext, objectAPI, backendEncryptedFile, backendEncryptedMigrationComplete) - } - writeSuccessResponseHeadersOnly(w) } @@ -454,10 +443,6 @@ func (a adminAPIHandlers) GetConfigHandler(w http.ResponseWriter, r *http.Reques off = !cache.Enabled(kv) case config.StorageClassSubSys: off = !storageclass.Enabled(kv) - case config.KmsVaultSubSys: - off = !crypto.EnabledVault(kv) - case config.KmsKesSubSys: - off = !crypto.EnabledKes(kv) case config.PolicyOPASubSys: off = !opa.Enabled(kv) case config.IdentityOpenIDSubSys: diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index f9fcf1109..3fe5a37a1 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -1756,32 +1756,32 @@ func fetchKMSStatus() madmin.KMS { } if len(stat.Endpoints) == 0 { kmsStat.Status = stat.Name + return kmsStat + } + if err := checkConnection(stat.Endpoints[0], 15*time.Second); err != nil { + kmsStat.Status = string(madmin.ItemOffline) + return kmsStat + } + kmsStat.Status = string(madmin.ItemOnline) + + kmsContext := kms.Context{"MinIO admin API": "ServerInfoHandler"} // Context for a test key operation + // 1. Generate a new key using the KMS. + key, err := GlobalKMS.GenerateKey("", kmsContext) + if err != nil { + kmsStat.Encrypt = fmt.Sprintf("Encryption failed: %v", err) } else { - if err := checkConnection(stat.Endpoints[0], 15*time.Second); err != nil { - kmsStat.Status = string(madmin.ItemOffline) - } else { - kmsStat.Status = string(madmin.ItemOnline) + kmsStat.Encrypt = "success" + } - kmsContext := kms.Context{"MinIO admin API": "ServerInfoHandler"} // Context for a test key operation - // 1. Generate a new key using the KMS. - key, err := GlobalKMS.GenerateKey("", kmsContext) - if err != nil { - kmsStat.Encrypt = fmt.Sprintf("Encryption failed: %v", err) - } else { - kmsStat.Encrypt = "success" - } - - // 2. Verify that we can indeed decrypt the (encrypted) key - decryptedKey, err := GlobalKMS.DecryptKey(key.KeyID, key.Ciphertext, kmsContext) - switch { - case err != nil: - kmsStat.Decrypt = fmt.Sprintf("Decryption failed: %v", err) - case subtle.ConstantTimeCompare(key.Plaintext, decryptedKey) != 1: - kmsStat.Decrypt = "Decryption failed: decrypted key does not match generated key" - default: - kmsStat.Decrypt = "success" - } - } + // 2. Verify that we can indeed decrypt the (encrypted) key + decryptedKey, err := GlobalKMS.DecryptKey(key.KeyID, key.Ciphertext, kmsContext) + switch { + case err != nil: + kmsStat.Decrypt = fmt.Sprintf("Decryption failed: %v", err) + case subtle.ConstantTimeCompare(key.Plaintext, decryptedKey) != 1: + kmsStat.Decrypt = "Decryption failed: decrypted key does not match generated key" + default: + kmsStat.Decrypt = "success" } return kmsStat } diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 17d7a88cc..e9ef54085 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -204,7 +204,6 @@ const ( ErrInvalidSSECustomerParameters ErrIncompatibleEncryptionMethod ErrKMSNotConfigured - ErrKMSAuthFailure ErrNoAccessKey ErrInvalidToken @@ -1079,11 +1078,6 @@ var errorCodes = errorCodeMap{ Description: "Server side encryption specified but KMS is not configured", HTTPStatusCode: http.StatusBadRequest, }, - ErrKMSAuthFailure: { - Code: "InvalidArgument", - Description: "Server side encryption specified but KMS authorization failed", - HTTPStatusCode: http.StatusBadRequest, - }, ErrNoAccessKey: { Code: "AccessDenied", Description: "No AWSAccessKey was presented", @@ -1837,8 +1831,6 @@ func toAPIErrorCode(ctx context.Context, err error) (apiErr APIErrorCode) { apiErr = ErrIncompatibleEncryptionMethod case errKMSNotConfigured: apiErr = ErrKMSNotConfigured - case crypto.ErrKMSAuthLogin: - apiErr = ErrKMSAuthFailure case context.Canceled, context.DeadlineExceeded: apiErr = ErrOperationTimedOut case errDiskNotFound: diff --git a/cmd/apierrorcode_string.go b/cmd/apierrorcode_string.go index 4004c7148..3db466687 100644 --- a/cmd/apierrorcode_string.go +++ b/cmd/apierrorcode_string.go @@ -137,157 +137,156 @@ func _() { _ = x[ErrInvalidSSECustomerParameters-126] _ = x[ErrIncompatibleEncryptionMethod-127] _ = x[ErrKMSNotConfigured-128] - _ = x[ErrKMSAuthFailure-129] - _ = x[ErrNoAccessKey-130] - _ = x[ErrInvalidToken-131] - _ = x[ErrEventNotification-132] - _ = x[ErrARNNotification-133] - _ = x[ErrRegionNotification-134] - _ = x[ErrOverlappingFilterNotification-135] - _ = x[ErrFilterNameInvalid-136] - _ = x[ErrFilterNamePrefix-137] - _ = x[ErrFilterNameSuffix-138] - _ = x[ErrFilterValueInvalid-139] - _ = x[ErrOverlappingConfigs-140] - _ = x[ErrUnsupportedNotification-141] - _ = x[ErrContentSHA256Mismatch-142] - _ = x[ErrReadQuorum-143] - _ = x[ErrWriteQuorum-144] - _ = x[ErrParentIsObject-145] - _ = x[ErrStorageFull-146] - _ = x[ErrRequestBodyParse-147] - _ = x[ErrObjectExistsAsDirectory-148] - _ = x[ErrInvalidObjectName-149] - _ = x[ErrInvalidObjectNamePrefixSlash-150] - _ = x[ErrInvalidResourceName-151] - _ = x[ErrServerNotInitialized-152] - _ = x[ErrOperationTimedOut-153] - _ = x[ErrClientDisconnected-154] - _ = x[ErrOperationMaxedOut-155] - _ = x[ErrInvalidRequest-156] - _ = x[ErrInvalidStorageClass-157] - _ = x[ErrBackendDown-158] - _ = x[ErrMalformedJSON-159] - _ = x[ErrAdminNoSuchUser-160] - _ = x[ErrAdminNoSuchGroup-161] - _ = x[ErrAdminGroupNotEmpty-162] - _ = x[ErrAdminNoSuchPolicy-163] - _ = x[ErrAdminInvalidArgument-164] - _ = x[ErrAdminInvalidAccessKey-165] - _ = x[ErrAdminInvalidSecretKey-166] - _ = x[ErrAdminConfigNoQuorum-167] - _ = x[ErrAdminConfigTooLarge-168] - _ = x[ErrAdminConfigBadJSON-169] - _ = x[ErrAdminConfigDuplicateKeys-170] - _ = x[ErrAdminCredentialsMismatch-171] - _ = x[ErrInsecureClientRequest-172] - _ = x[ErrObjectTampered-173] - _ = x[ErrAdminBucketQuotaExceeded-174] - _ = x[ErrAdminNoSuchQuotaConfiguration-175] - _ = x[ErrHealNotImplemented-176] - _ = x[ErrHealNoSuchProcess-177] - _ = x[ErrHealInvalidClientToken-178] - _ = x[ErrHealMissingBucket-179] - _ = x[ErrHealAlreadyRunning-180] - _ = x[ErrHealOverlappingPaths-181] - _ = x[ErrIncorrectContinuationToken-182] - _ = x[ErrEmptyRequestBody-183] - _ = x[ErrUnsupportedFunction-184] - _ = x[ErrInvalidExpressionType-185] - _ = x[ErrBusy-186] - _ = x[ErrUnauthorizedAccess-187] - _ = x[ErrExpressionTooLong-188] - _ = x[ErrIllegalSQLFunctionArgument-189] - _ = x[ErrInvalidKeyPath-190] - _ = x[ErrInvalidCompressionFormat-191] - _ = x[ErrInvalidFileHeaderInfo-192] - _ = x[ErrInvalidJSONType-193] - _ = x[ErrInvalidQuoteFields-194] - _ = x[ErrInvalidRequestParameter-195] - _ = x[ErrInvalidDataType-196] - _ = x[ErrInvalidTextEncoding-197] - _ = x[ErrInvalidDataSource-198] - _ = x[ErrInvalidTableAlias-199] - _ = x[ErrMissingRequiredParameter-200] - _ = x[ErrObjectSerializationConflict-201] - _ = x[ErrUnsupportedSQLOperation-202] - _ = x[ErrUnsupportedSQLStructure-203] - _ = x[ErrUnsupportedSyntax-204] - _ = x[ErrUnsupportedRangeHeader-205] - _ = x[ErrLexerInvalidChar-206] - _ = x[ErrLexerInvalidOperator-207] - _ = x[ErrLexerInvalidLiteral-208] - _ = x[ErrLexerInvalidIONLiteral-209] - _ = x[ErrParseExpectedDatePart-210] - _ = x[ErrParseExpectedKeyword-211] - _ = x[ErrParseExpectedTokenType-212] - _ = x[ErrParseExpected2TokenTypes-213] - _ = x[ErrParseExpectedNumber-214] - _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-215] - _ = x[ErrParseExpectedTypeName-216] - _ = x[ErrParseExpectedWhenClause-217] - _ = x[ErrParseUnsupportedToken-218] - _ = x[ErrParseUnsupportedLiteralsGroupBy-219] - _ = x[ErrParseExpectedMember-220] - _ = x[ErrParseUnsupportedSelect-221] - _ = x[ErrParseUnsupportedCase-222] - _ = x[ErrParseUnsupportedCaseClause-223] - _ = x[ErrParseUnsupportedAlias-224] - _ = x[ErrParseUnsupportedSyntax-225] - _ = x[ErrParseUnknownOperator-226] - _ = x[ErrParseMissingIdentAfterAt-227] - _ = x[ErrParseUnexpectedOperator-228] - _ = x[ErrParseUnexpectedTerm-229] - _ = x[ErrParseUnexpectedToken-230] - _ = x[ErrParseUnexpectedKeyword-231] - _ = x[ErrParseExpectedExpression-232] - _ = x[ErrParseExpectedLeftParenAfterCast-233] - _ = x[ErrParseExpectedLeftParenValueConstructor-234] - _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-235] - _ = x[ErrParseExpectedArgumentDelimiter-236] - _ = x[ErrParseCastArity-237] - _ = x[ErrParseInvalidTypeParam-238] - _ = x[ErrParseEmptySelect-239] - _ = x[ErrParseSelectMissingFrom-240] - _ = x[ErrParseExpectedIdentForGroupName-241] - _ = x[ErrParseExpectedIdentForAlias-242] - _ = x[ErrParseUnsupportedCallWithStar-243] - _ = x[ErrParseNonUnaryAgregateFunctionCall-244] - _ = x[ErrParseMalformedJoin-245] - _ = x[ErrParseExpectedIdentForAt-246] - _ = x[ErrParseAsteriskIsNotAloneInSelectList-247] - _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-248] - _ = x[ErrParseInvalidContextForWildcardInSelectList-249] - _ = x[ErrIncorrectSQLFunctionArgumentType-250] - _ = x[ErrValueParseFailure-251] - _ = x[ErrEvaluatorInvalidArguments-252] - _ = x[ErrIntegerOverflow-253] - _ = x[ErrLikeInvalidInputs-254] - _ = x[ErrCastFailed-255] - _ = x[ErrInvalidCast-256] - _ = x[ErrEvaluatorInvalidTimestampFormatPattern-257] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-258] - _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-259] - _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-260] - _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-261] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-262] - _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-263] - _ = x[ErrEvaluatorBindingDoesNotExist-264] - _ = x[ErrMissingHeaders-265] - _ = x[ErrInvalidColumnIndex-266] - _ = x[ErrAdminConfigNotificationTargetsFailed-267] - _ = x[ErrAdminProfilerNotEnabled-268] - _ = x[ErrInvalidDecompressedSize-269] - _ = x[ErrAddUserInvalidArgument-270] - _ = x[ErrAdminAccountNotEligible-271] - _ = x[ErrAccountNotEligible-272] - _ = x[ErrAdminServiceAccountNotFound-273] - _ = x[ErrPostPolicyConditionInvalidFormat-274] + _ = x[ErrNoAccessKey-129] + _ = x[ErrInvalidToken-130] + _ = x[ErrEventNotification-131] + _ = x[ErrARNNotification-132] + _ = x[ErrRegionNotification-133] + _ = x[ErrOverlappingFilterNotification-134] + _ = x[ErrFilterNameInvalid-135] + _ = x[ErrFilterNamePrefix-136] + _ = x[ErrFilterNameSuffix-137] + _ = x[ErrFilterValueInvalid-138] + _ = x[ErrOverlappingConfigs-139] + _ = x[ErrUnsupportedNotification-140] + _ = x[ErrContentSHA256Mismatch-141] + _ = x[ErrReadQuorum-142] + _ = x[ErrWriteQuorum-143] + _ = x[ErrParentIsObject-144] + _ = x[ErrStorageFull-145] + _ = x[ErrRequestBodyParse-146] + _ = x[ErrObjectExistsAsDirectory-147] + _ = x[ErrInvalidObjectName-148] + _ = x[ErrInvalidObjectNamePrefixSlash-149] + _ = x[ErrInvalidResourceName-150] + _ = x[ErrServerNotInitialized-151] + _ = x[ErrOperationTimedOut-152] + _ = x[ErrClientDisconnected-153] + _ = x[ErrOperationMaxedOut-154] + _ = x[ErrInvalidRequest-155] + _ = x[ErrInvalidStorageClass-156] + _ = x[ErrBackendDown-157] + _ = x[ErrMalformedJSON-158] + _ = x[ErrAdminNoSuchUser-159] + _ = x[ErrAdminNoSuchGroup-160] + _ = x[ErrAdminGroupNotEmpty-161] + _ = x[ErrAdminNoSuchPolicy-162] + _ = x[ErrAdminInvalidArgument-163] + _ = x[ErrAdminInvalidAccessKey-164] + _ = x[ErrAdminInvalidSecretKey-165] + _ = x[ErrAdminConfigNoQuorum-166] + _ = x[ErrAdminConfigTooLarge-167] + _ = x[ErrAdminConfigBadJSON-168] + _ = x[ErrAdminConfigDuplicateKeys-169] + _ = x[ErrAdminCredentialsMismatch-170] + _ = x[ErrInsecureClientRequest-171] + _ = x[ErrObjectTampered-172] + _ = x[ErrAdminBucketQuotaExceeded-173] + _ = x[ErrAdminNoSuchQuotaConfiguration-174] + _ = x[ErrHealNotImplemented-175] + _ = x[ErrHealNoSuchProcess-176] + _ = x[ErrHealInvalidClientToken-177] + _ = x[ErrHealMissingBucket-178] + _ = x[ErrHealAlreadyRunning-179] + _ = x[ErrHealOverlappingPaths-180] + _ = x[ErrIncorrectContinuationToken-181] + _ = x[ErrEmptyRequestBody-182] + _ = x[ErrUnsupportedFunction-183] + _ = x[ErrInvalidExpressionType-184] + _ = x[ErrBusy-185] + _ = x[ErrUnauthorizedAccess-186] + _ = x[ErrExpressionTooLong-187] + _ = x[ErrIllegalSQLFunctionArgument-188] + _ = x[ErrInvalidKeyPath-189] + _ = x[ErrInvalidCompressionFormat-190] + _ = x[ErrInvalidFileHeaderInfo-191] + _ = x[ErrInvalidJSONType-192] + _ = x[ErrInvalidQuoteFields-193] + _ = x[ErrInvalidRequestParameter-194] + _ = x[ErrInvalidDataType-195] + _ = x[ErrInvalidTextEncoding-196] + _ = x[ErrInvalidDataSource-197] + _ = x[ErrInvalidTableAlias-198] + _ = x[ErrMissingRequiredParameter-199] + _ = x[ErrObjectSerializationConflict-200] + _ = x[ErrUnsupportedSQLOperation-201] + _ = x[ErrUnsupportedSQLStructure-202] + _ = x[ErrUnsupportedSyntax-203] + _ = x[ErrUnsupportedRangeHeader-204] + _ = x[ErrLexerInvalidChar-205] + _ = x[ErrLexerInvalidOperator-206] + _ = x[ErrLexerInvalidLiteral-207] + _ = x[ErrLexerInvalidIONLiteral-208] + _ = x[ErrParseExpectedDatePart-209] + _ = x[ErrParseExpectedKeyword-210] + _ = x[ErrParseExpectedTokenType-211] + _ = x[ErrParseExpected2TokenTypes-212] + _ = x[ErrParseExpectedNumber-213] + _ = x[ErrParseExpectedRightParenBuiltinFunctionCall-214] + _ = x[ErrParseExpectedTypeName-215] + _ = x[ErrParseExpectedWhenClause-216] + _ = x[ErrParseUnsupportedToken-217] + _ = x[ErrParseUnsupportedLiteralsGroupBy-218] + _ = x[ErrParseExpectedMember-219] + _ = x[ErrParseUnsupportedSelect-220] + _ = x[ErrParseUnsupportedCase-221] + _ = x[ErrParseUnsupportedCaseClause-222] + _ = x[ErrParseUnsupportedAlias-223] + _ = x[ErrParseUnsupportedSyntax-224] + _ = x[ErrParseUnknownOperator-225] + _ = x[ErrParseMissingIdentAfterAt-226] + _ = x[ErrParseUnexpectedOperator-227] + _ = x[ErrParseUnexpectedTerm-228] + _ = x[ErrParseUnexpectedToken-229] + _ = x[ErrParseUnexpectedKeyword-230] + _ = x[ErrParseExpectedExpression-231] + _ = x[ErrParseExpectedLeftParenAfterCast-232] + _ = x[ErrParseExpectedLeftParenValueConstructor-233] + _ = x[ErrParseExpectedLeftParenBuiltinFunctionCall-234] + _ = x[ErrParseExpectedArgumentDelimiter-235] + _ = x[ErrParseCastArity-236] + _ = x[ErrParseInvalidTypeParam-237] + _ = x[ErrParseEmptySelect-238] + _ = x[ErrParseSelectMissingFrom-239] + _ = x[ErrParseExpectedIdentForGroupName-240] + _ = x[ErrParseExpectedIdentForAlias-241] + _ = x[ErrParseUnsupportedCallWithStar-242] + _ = x[ErrParseNonUnaryAgregateFunctionCall-243] + _ = x[ErrParseMalformedJoin-244] + _ = x[ErrParseExpectedIdentForAt-245] + _ = x[ErrParseAsteriskIsNotAloneInSelectList-246] + _ = x[ErrParseCannotMixSqbAndWildcardInSelectList-247] + _ = x[ErrParseInvalidContextForWildcardInSelectList-248] + _ = x[ErrIncorrectSQLFunctionArgumentType-249] + _ = x[ErrValueParseFailure-250] + _ = x[ErrEvaluatorInvalidArguments-251] + _ = x[ErrIntegerOverflow-252] + _ = x[ErrLikeInvalidInputs-253] + _ = x[ErrCastFailed-254] + _ = x[ErrInvalidCast-255] + _ = x[ErrEvaluatorInvalidTimestampFormatPattern-256] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbolForParsing-257] + _ = x[ErrEvaluatorTimestampFormatPatternDuplicateFields-258] + _ = x[ErrEvaluatorTimestampFormatPatternHourClockAmPmMismatch-259] + _ = x[ErrEvaluatorUnterminatedTimestampFormatPatternToken-260] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternToken-261] + _ = x[ErrEvaluatorInvalidTimestampFormatPatternSymbol-262] + _ = x[ErrEvaluatorBindingDoesNotExist-263] + _ = x[ErrMissingHeaders-264] + _ = x[ErrInvalidColumnIndex-265] + _ = x[ErrAdminConfigNotificationTargetsFailed-266] + _ = x[ErrAdminProfilerNotEnabled-267] + _ = x[ErrInvalidDecompressedSize-268] + _ = x[ErrAddUserInvalidArgument-269] + _ = x[ErrAdminAccountNotEligible-270] + _ = x[ErrAccountNotEligible-271] + _ = x[ErrAdminServiceAccountNotFound-272] + _ = x[ErrPostPolicyConditionInvalidFormat-273] } -const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledMalformedPolicyMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedCredentialRegionMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataMaximumExpiresSlowDownInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectiveInvalidEncryptionMethodInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredKMSAuthFailureNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchReadQuorumWriteQuorumParentIsObjectStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameServerNotInitializedOperationTimedOutClientDisconnectedOperationMaxedOutInvalidRequestInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchGroupAdminGroupNotEmptyAdminNoSuchPolicyAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminConfigDuplicateKeysAdminCredentialsMismatchInsecureClientRequestObjectTamperedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormat" +const _APIErrorCode_name = "NoneAccessDeniedBadDigestEntityTooSmallEntityTooLargePolicyTooLargeIncompleteBodyInternalErrorInvalidAccessKeyIDInvalidBucketNameInvalidDigestInvalidRangeInvalidRangePartNumberInvalidCopyPartRangeInvalidCopyPartRangeSourceInvalidMaxKeysInvalidEncodingMethodInvalidMaxUploadsInvalidMaxPartsInvalidPartNumberMarkerInvalidPartNumberInvalidRequestBodyInvalidCopySourceInvalidMetadataDirectiveInvalidCopyDestInvalidPolicyDocumentInvalidObjectStateMalformedXMLMissingContentLengthMissingContentMD5MissingRequestBodyErrorMissingSecurityHeaderNoSuchBucketNoSuchBucketPolicyNoSuchBucketLifecycleNoSuchLifecycleConfigurationNoSuchBucketSSEConfigNoSuchCORSConfigurationNoSuchWebsiteConfigurationReplicationConfigurationNotFoundErrorRemoteDestinationNotFoundErrorReplicationDestinationMissingLockRemoteTargetNotFoundErrorReplicationRemoteConnectionErrorBucketRemoteIdenticalToSourceBucketRemoteAlreadyExistsBucketRemoteLabelInUseBucketRemoteArnTypeInvalidBucketRemoteArnInvalidBucketRemoteRemoveDisallowedRemoteTargetNotVersionedErrorReplicationSourceNotVersionedErrorReplicationNeedsVersioningErrorReplicationBucketNeedsVersioningErrorObjectRestoreAlreadyInProgressNoSuchKeyNoSuchUploadInvalidVersionIDNoSuchVersionNotImplementedPreconditionFailedRequestTimeTooSkewedSignatureDoesNotMatchMethodNotAllowedInvalidPartInvalidPartOrderAuthorizationHeaderMalformedMalformedPOSTRequestPOSTFileRequiredSignatureVersionNotSupportedBucketNotEmptyAllAccessDisabledMalformedPolicyMissingFieldsMissingCredTagCredMalformedInvalidRegionInvalidServiceS3InvalidServiceSTSInvalidRequestVersionMissingSignTagMissingSignHeadersTagMalformedDateMalformedPresignedDateMalformedCredentialDateMalformedCredentialRegionMalformedExpiresNegativeExpiresAuthHeaderEmptyExpiredPresignRequestRequestNotReadyYetUnsignedHeadersMissingDateHeaderInvalidQuerySignatureAlgoInvalidQueryParamsBucketAlreadyOwnedByYouInvalidDurationBucketAlreadyExistsMetadataTooLargeUnsupportedMetadataMaximumExpiresSlowDownInvalidPrefixMarkerBadRequestKeyTooLongErrorInvalidBucketObjectLockConfigurationObjectLockConfigurationNotFoundObjectLockConfigurationNotAllowedNoSuchObjectLockConfigurationObjectLockedInvalidRetentionDatePastObjectLockRetainDateUnknownWORMModeDirectiveBucketTaggingNotFoundObjectLockInvalidHeadersInvalidTagDirectiveInvalidEncryptionMethodInsecureSSECustomerRequestSSEMultipartEncryptedSSEEncryptedObjectInvalidEncryptionParametersInvalidSSECustomerAlgorithmInvalidSSECustomerKeyMissingSSECustomerKeyMissingSSECustomerKeyMD5SSECustomerKeyMD5MismatchInvalidSSECustomerParametersIncompatibleEncryptionMethodKMSNotConfiguredNoAccessKeyInvalidTokenEventNotificationARNNotificationRegionNotificationOverlappingFilterNotificationFilterNameInvalidFilterNamePrefixFilterNameSuffixFilterValueInvalidOverlappingConfigsUnsupportedNotificationContentSHA256MismatchReadQuorumWriteQuorumParentIsObjectStorageFullRequestBodyParseObjectExistsAsDirectoryInvalidObjectNameInvalidObjectNamePrefixSlashInvalidResourceNameServerNotInitializedOperationTimedOutClientDisconnectedOperationMaxedOutInvalidRequestInvalidStorageClassBackendDownMalformedJSONAdminNoSuchUserAdminNoSuchGroupAdminGroupNotEmptyAdminNoSuchPolicyAdminInvalidArgumentAdminInvalidAccessKeyAdminInvalidSecretKeyAdminConfigNoQuorumAdminConfigTooLargeAdminConfigBadJSONAdminConfigDuplicateKeysAdminCredentialsMismatchInsecureClientRequestObjectTamperedAdminBucketQuotaExceededAdminNoSuchQuotaConfigurationHealNotImplementedHealNoSuchProcessHealInvalidClientTokenHealMissingBucketHealAlreadyRunningHealOverlappingPathsIncorrectContinuationTokenEmptyRequestBodyUnsupportedFunctionInvalidExpressionTypeBusyUnauthorizedAccessExpressionTooLongIllegalSQLFunctionArgumentInvalidKeyPathInvalidCompressionFormatInvalidFileHeaderInfoInvalidJSONTypeInvalidQuoteFieldsInvalidRequestParameterInvalidDataTypeInvalidTextEncodingInvalidDataSourceInvalidTableAliasMissingRequiredParameterObjectSerializationConflictUnsupportedSQLOperationUnsupportedSQLStructureUnsupportedSyntaxUnsupportedRangeHeaderLexerInvalidCharLexerInvalidOperatorLexerInvalidLiteralLexerInvalidIONLiteralParseExpectedDatePartParseExpectedKeywordParseExpectedTokenTypeParseExpected2TokenTypesParseExpectedNumberParseExpectedRightParenBuiltinFunctionCallParseExpectedTypeNameParseExpectedWhenClauseParseUnsupportedTokenParseUnsupportedLiteralsGroupByParseExpectedMemberParseUnsupportedSelectParseUnsupportedCaseParseUnsupportedCaseClauseParseUnsupportedAliasParseUnsupportedSyntaxParseUnknownOperatorParseMissingIdentAfterAtParseUnexpectedOperatorParseUnexpectedTermParseUnexpectedTokenParseUnexpectedKeywordParseExpectedExpressionParseExpectedLeftParenAfterCastParseExpectedLeftParenValueConstructorParseExpectedLeftParenBuiltinFunctionCallParseExpectedArgumentDelimiterParseCastArityParseInvalidTypeParamParseEmptySelectParseSelectMissingFromParseExpectedIdentForGroupNameParseExpectedIdentForAliasParseUnsupportedCallWithStarParseNonUnaryAgregateFunctionCallParseMalformedJoinParseExpectedIdentForAtParseAsteriskIsNotAloneInSelectListParseCannotMixSqbAndWildcardInSelectListParseInvalidContextForWildcardInSelectListIncorrectSQLFunctionArgumentTypeValueParseFailureEvaluatorInvalidArgumentsIntegerOverflowLikeInvalidInputsCastFailedInvalidCastEvaluatorInvalidTimestampFormatPatternEvaluatorInvalidTimestampFormatPatternSymbolForParsingEvaluatorTimestampFormatPatternDuplicateFieldsEvaluatorTimestampFormatPatternHourClockAmPmMismatchEvaluatorUnterminatedTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternTokenEvaluatorInvalidTimestampFormatPatternSymbolEvaluatorBindingDoesNotExistMissingHeadersInvalidColumnIndexAdminConfigNotificationTargetsFailedAdminProfilerNotEnabledInvalidDecompressedSizeAddUserInvalidArgumentAdminAccountNotEligibleAccountNotEligibleAdminServiceAccountNotFoundPostPolicyConditionInvalidFormat" -var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 142, 154, 176, 196, 222, 236, 257, 274, 289, 312, 329, 347, 364, 388, 403, 424, 442, 454, 474, 491, 514, 535, 547, 565, 586, 614, 635, 658, 684, 721, 751, 784, 809, 841, 870, 895, 917, 943, 965, 993, 1022, 1056, 1087, 1124, 1154, 1163, 1175, 1191, 1204, 1218, 1236, 1256, 1277, 1293, 1304, 1320, 1348, 1368, 1384, 1412, 1426, 1443, 1458, 1471, 1485, 1498, 1511, 1527, 1544, 1565, 1579, 1600, 1613, 1635, 1658, 1683, 1699, 1714, 1729, 1750, 1768, 1783, 1800, 1825, 1843, 1866, 1881, 1900, 1916, 1935, 1949, 1957, 1976, 1986, 2001, 2037, 2068, 2101, 2130, 2142, 2162, 2186, 2210, 2231, 2255, 2274, 2297, 2323, 2344, 2362, 2389, 2416, 2437, 2458, 2482, 2507, 2535, 2563, 2579, 2593, 2604, 2616, 2633, 2648, 2666, 2695, 2712, 2728, 2744, 2762, 2780, 2803, 2824, 2834, 2845, 2859, 2870, 2886, 2909, 2926, 2954, 2973, 2993, 3010, 3028, 3045, 3059, 3078, 3089, 3102, 3117, 3133, 3151, 3168, 3188, 3209, 3230, 3249, 3268, 3286, 3310, 3334, 3355, 3369, 3393, 3422, 3440, 3457, 3479, 3496, 3514, 3534, 3560, 3576, 3595, 3616, 3620, 3638, 3655, 3681, 3695, 3719, 3740, 3755, 3773, 3796, 3811, 3830, 3847, 3864, 3888, 3915, 3938, 3961, 3978, 4000, 4016, 4036, 4055, 4077, 4098, 4118, 4140, 4164, 4183, 4225, 4246, 4269, 4290, 4321, 4340, 4362, 4382, 4408, 4429, 4451, 4471, 4495, 4518, 4537, 4557, 4579, 4602, 4633, 4671, 4712, 4742, 4756, 4777, 4793, 4815, 4845, 4871, 4899, 4932, 4950, 4973, 5008, 5048, 5090, 5122, 5139, 5164, 5179, 5196, 5206, 5217, 5255, 5309, 5355, 5407, 5455, 5498, 5542, 5570, 5584, 5602, 5638, 5661, 5684, 5706, 5729, 5747, 5774, 5806} +var _APIErrorCode_index = [...]uint16{0, 4, 16, 25, 39, 53, 67, 81, 94, 112, 129, 142, 154, 176, 196, 222, 236, 257, 274, 289, 312, 329, 347, 364, 388, 403, 424, 442, 454, 474, 491, 514, 535, 547, 565, 586, 614, 635, 658, 684, 721, 751, 784, 809, 841, 870, 895, 917, 943, 965, 993, 1022, 1056, 1087, 1124, 1154, 1163, 1175, 1191, 1204, 1218, 1236, 1256, 1277, 1293, 1304, 1320, 1348, 1368, 1384, 1412, 1426, 1443, 1458, 1471, 1485, 1498, 1511, 1527, 1544, 1565, 1579, 1600, 1613, 1635, 1658, 1683, 1699, 1714, 1729, 1750, 1768, 1783, 1800, 1825, 1843, 1866, 1881, 1900, 1916, 1935, 1949, 1957, 1976, 1986, 2001, 2037, 2068, 2101, 2130, 2142, 2162, 2186, 2210, 2231, 2255, 2274, 2297, 2323, 2344, 2362, 2389, 2416, 2437, 2458, 2482, 2507, 2535, 2563, 2579, 2590, 2602, 2619, 2634, 2652, 2681, 2698, 2714, 2730, 2748, 2766, 2789, 2810, 2820, 2831, 2845, 2856, 2872, 2895, 2912, 2940, 2959, 2979, 2996, 3014, 3031, 3045, 3064, 3075, 3088, 3103, 3119, 3137, 3154, 3174, 3195, 3216, 3235, 3254, 3272, 3296, 3320, 3341, 3355, 3379, 3408, 3426, 3443, 3465, 3482, 3500, 3520, 3546, 3562, 3581, 3602, 3606, 3624, 3641, 3667, 3681, 3705, 3726, 3741, 3759, 3782, 3797, 3816, 3833, 3850, 3874, 3901, 3924, 3947, 3964, 3986, 4002, 4022, 4041, 4063, 4084, 4104, 4126, 4150, 4169, 4211, 4232, 4255, 4276, 4307, 4326, 4348, 4368, 4394, 4415, 4437, 4457, 4481, 4504, 4523, 4543, 4565, 4588, 4619, 4657, 4698, 4728, 4742, 4763, 4779, 4801, 4831, 4857, 4885, 4918, 4936, 4959, 4994, 5034, 5076, 5108, 5125, 5150, 5165, 5182, 5192, 5203, 5241, 5295, 5341, 5393, 5441, 5484, 5528, 5556, 5570, 5588, 5624, 5647, 5670, 5692, 5715, 5733, 5760, 5792} func (i APIErrorCode) String() string { if i < 0 || i >= APIErrorCode(len(_APIErrorCode_index)-1) { diff --git a/cmd/common-main.go b/cmd/common-main.go index 4b55a3685..e41d0dae0 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -18,8 +18,10 @@ package cmd import ( "context" + "crypto/tls" "crypto/x509" "encoding/gob" + "encoding/hex" "errors" "fmt" "math/rand" @@ -37,6 +39,7 @@ import ( "github.com/minio/cli" "github.com/minio/minio-go/v7/pkg/set" "github.com/minio/minio/cmd/config" + "github.com/minio/minio/cmd/crypto" xhttp "github.com/minio/minio/cmd/http" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" @@ -44,6 +47,7 @@ import ( "github.com/minio/minio/pkg/console" "github.com/minio/minio/pkg/env" "github.com/minio/minio/pkg/handlers" + "github.com/minio/minio/pkg/kms" ) // serverDebugLog will enable debug printing @@ -316,7 +320,6 @@ func handleCommonEnvVars() { "Unable to validate credentials inherited from the shell environment") } globalActiveCred = cred - globalConfigEncrypted = true } if env.IsSet(config.EnvRootUser) || env.IsSet(config.EnvRootPassword) { @@ -326,29 +329,58 @@ func handleCommonEnvVars() { "Unable to validate credentials inherited from the shell environment") } globalActiveCred = cred - globalConfigEncrypted = true } - if env.IsSet(config.EnvAccessKeyOld) && env.IsSet(config.EnvSecretKeyOld) { - oldCred, err := auth.CreateCredentials(env.Get(config.EnvAccessKeyOld, ""), env.Get(config.EnvSecretKeyOld, "")) - if err != nil { - logger.Fatal(config.ErrInvalidCredentials(err), - "Unable to validate the old credentials inherited from the shell environment") - } - globalOldCred = oldCred - os.Unsetenv(config.EnvAccessKeyOld) - os.Unsetenv(config.EnvSecretKeyOld) + if env.IsSet(config.EnvKMSSecretKey) && env.IsSet(config.EnvKESEndpoint) { + logger.Fatal(errors.New("ambigious KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", config.EnvKMSSecretKey, config.EnvKESEndpoint)) } - - if env.IsSet(config.EnvRootUserOld) && env.IsSet(config.EnvRootPasswordOld) { - oldCred, err := auth.CreateCredentials(env.Get(config.EnvRootUserOld, ""), env.Get(config.EnvRootPasswordOld, "")) + switch { + case env.IsSet(config.EnvKMSSecretKey) && env.IsSet(config.EnvKESEndpoint): + logger.Fatal(errors.New("ambigious KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", config.EnvKMSSecretKey, config.EnvKESEndpoint)) + case env.IsSet(config.EnvKMSMasterKey) && env.IsSet(config.EnvKESEndpoint): + logger.Fatal(errors.New("ambigious KMS configuration"), fmt.Sprintf("The environment contains %q as well as %q", config.EnvKMSMasterKey, config.EnvKESEndpoint)) + } + if env.IsSet(config.EnvKMSSecretKey) { + KMS, err := kms.Parse(env.Get(config.EnvKMSSecretKey, "")) if err != nil { - logger.Fatal(config.ErrInvalidCredentials(err), - "Unable to validate the old credentials inherited from the shell environment") + logger.Fatal(err, "Unable to parse the KMS secret key inherited from the shell environment") } - globalOldCred = oldCred - os.Unsetenv(config.EnvRootUserOld) - os.Unsetenv(config.EnvRootPasswordOld) + GlobalKMS = KMS + } else if env.IsSet(config.EnvKMSMasterKey) { + logger.LogIf(GlobalContext, errors.New("legacy KMS configuration"), fmt.Sprintf("The environment variable %q is deprecated and will be removed in the future", config.EnvKMSMasterKey)) + + v := strings.SplitN(env.Get(config.EnvKMSMasterKey, ""), ":", 2) + if len(v) != 2 { + logger.Fatal(errors.New("invalid "+config.EnvKMSMasterKey), "Unable to parse the KMS secret key inherited from the shell environment") + } + secretKey, err := hex.DecodeString(v[1]) + if err != nil { + logger.Fatal(err, "Unable to parse the KMS secret key inherited from the shell environment") + } + KMS, err := kms.New(v[0], secretKey) + if err != nil { + logger.Fatal(err, "Unable to parse the KMS secret key inherited from the shell environment") + } + GlobalKMS = KMS + } + if env.IsSet(config.EnvKESEndpoint) { + kesEndpoints, err := crypto.ParseKESEndpoints(env.Get(config.EnvKESEndpoint, "")) + if err != nil { + logger.Fatal(err, "Unable to parse the KES endpoints inherited from the shell environment") + } + KMS, err := crypto.NewKes(crypto.KesConfig{ + Enabled: true, + Endpoint: kesEndpoints, + DefaultKeyID: env.Get(config.EnvKESKeyName, ""), + CertFile: env.Get(config.EnvKESClientCert, ""), + KeyFile: env.Get(config.EnvKESClientKey, ""), + CAPath: env.Get(config.EnvKESServerCA, globalCertsCADir.Get()), + Transport: newCustomHTTPTransportWithHTTP2(&tls.Config{RootCAs: globalRootCAs}, defaultDialTimeout)(), + }) + if err != nil { + logger.Fatal(err, "Unable to initialize a connection to KES as specified by the shell environment") + } + GlobalKMS = KMS } } diff --git a/cmd/config-current.go b/cmd/config-current.go index 7207fe254..92bbb01b8 100644 --- a/cmd/config-current.go +++ b/cmd/config-current.go @@ -18,7 +18,7 @@ package cmd import ( "context" - "crypto/tls" + "errors" "fmt" "strings" "sync" @@ -41,6 +41,7 @@ import ( "github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger/target/http" "github.com/minio/minio/pkg/env" + "github.com/minio/minio/pkg/kms" "github.com/minio/minio/pkg/madmin" ) @@ -55,8 +56,6 @@ func initHelp() { config.RegionSubSys: config.DefaultRegionKVS, config.APISubSys: api.DefaultKVS, config.CredentialsSubSys: config.DefaultCredentialKVS, - config.KmsVaultSubSys: crypto.DefaultVaultKVS, - config.KmsKesSubSys: crypto.DefaultKesKVS, config.LoggerWebhookSubSys: logger.DefaultKVS, config.AuditWebhookSubSys: logger.DefaultAuditKVS, config.HealSubSys: heal.DefaultKVS, @@ -204,8 +203,6 @@ func initHelp() { config.IdentityOpenIDSubSys: openid.Help, config.IdentityLDAPSubSys: xldap.Help, config.PolicyOPASubSys: opa.Help, - config.KmsVaultSubSys: crypto.HelpVault, - config.KmsKesSubSys: crypto.HelpKes, config.LoggerWebhookSubSys: logger.Help, config.AuditWebhookSubSys: logger.HelpAudit, config.NotifyAMQPSubSys: notify.HelpAMQP, @@ -295,27 +292,6 @@ func validateConfig(s config.Config, setDriveCounts []int) error { etcdClnt.Close() } } - { - kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get(), newCustomHTTPTransportWithHTTP2( - &tls.Config{ - RootCAs: globalRootCAs, - }, defaultDialTimeout)()) - if err != nil { - return err - } - - // Set env to enable master key validation. - // this is needed only for KMS. - env.SetEnvOn() - - if _, err = crypto.NewKMS(kmsCfg); err != nil { - return err - } - - // Disable merging env values for the rest. - env.SetEnvOff() - } - if _, err := openid.LookupConfig(s[config.IdentityOpenIDSubSys][config.Default], NewGatewayHTTPTransport(), xhttp.DrainBody); err != nil { return err @@ -467,33 +443,17 @@ func lookupConfigs(s config.Config, setDriveCounts []int) { } if globalCacheConfig.Enabled { - if cacheEncKey := env.Get(cache.EnvCacheEncryptionMasterKey, ""); cacheEncKey != "" { - globalCacheKMS, err = crypto.ParseMasterKey(cacheEncKey) + if cacheEncKey := env.Get(cache.EnvCacheEncryptionKey, ""); cacheEncKey != "" { + globalCacheKMS, err = kms.Parse(cacheEncKey) if err != nil { logger.LogIf(ctx, fmt.Errorf("Unable to setup encryption cache: %w", err)) } } } - kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get(), newCustomHTTPTransportWithHTTP2( - &tls.Config{ - RootCAs: globalRootCAs, - }, defaultDialTimeout)()) - if err != nil { - logger.LogIf(ctx, fmt.Errorf("Unable to setup KMS config: %w", err)) - } - - GlobalKMS, err = crypto.NewKMS(kmsCfg) - if err != nil { - logger.LogIf(ctx, fmt.Errorf("Unable to setup KMS with current KMS config: %w", err)) - } - globalAutoEncryption = kmsCfg.AutoEncryption // Enable auto-encryption if enabled - - if kmsCfg.Vault.Enabled { - const deprecationWarning = `Native Hashicorp Vault support is deprecated and will be removed on 2021-10-01. Please migrate to KES + Hashicorp Vault: https://github.com/minio/kes/wiki/Hashicorp-Vault-Keystore -Note that native Hashicorp Vault and KES + Hashicorp Vault are not compatible. -If you need help to migrate smoothly visit: https://min.io/pricing` - logger.LogIf(ctx, fmt.Errorf(deprecationWarning)) + globalAutoEncryption = crypto.LookupAutoEncryption() // Enable auto-encryption if enabled + if globalAutoEncryption && GlobalKMS == nil { + logger.Fatal(errors.New("no KMS configured"), "MINIO_KMS_AUTO_ENCRYPTION requires a valid KMS configuration") } globalOpenIDConfig, err = openid.LookupConfig(s[config.IdentityOpenIDSubSys][config.Default], diff --git a/cmd/config-encrypted.go b/cmd/config-encrypted.go index 083b85358..5cb64d070 100644 --- a/cmd/config-encrypted.go +++ b/cmd/config-encrypted.go @@ -20,57 +20,32 @@ import ( "bytes" "context" "fmt" + "path" "time" "unicode/utf8" "github.com/minio/minio/cmd/config" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" + "github.com/minio/minio/pkg/kms" "github.com/minio/minio/pkg/madmin" etcd "go.etcd.io/etcd/clientv3" ) func handleEncryptedConfigBackend(objAPI ObjectLayer) error { - encrypted, err := checkBackendEncrypted(objAPI) if err != nil { return fmt.Errorf("Unable to encrypt config %w", err) } - - if encrypted { - // backend is encrypted, but credentials are not specified - // we shall fail right here. if not proceed forward. - if !globalConfigEncrypted || !globalActiveCred.IsValid() { - return config.ErrMissingCredentialsBackendEncrypted(nil) - } - } else { - // backend is not yet encrypted, check if encryption of - // backend is requested if not return nil and proceed - // forward. - if !globalConfigEncrypted { - return nil - } - if !globalActiveCred.IsValid() { - return config.ErrMissingCredentialsBackendEncrypted(nil) - } - } - - // Migrate IAM configuration - if err = migrateConfigPrefixToEncrypted(objAPI, globalOldCred, encrypted); err != nil { + if err = migrateConfigPrefixToEncrypted(objAPI, encrypted); err != nil { return fmt.Errorf("Unable to migrate all config at .minio.sys/config/: %w", err) } - return nil } -const ( - backendEncryptedFile = "backend-encrypted" -) +const backendEncryptedFile = "backend-encrypted" -var ( - backendEncryptedMigrationIncomplete = []byte("incomplete") - backendEncryptedMigrationComplete = []byte("encrypted") -) +var backendEncryptedMigrationComplete = []byte("encrypted") func checkBackendEtcdEncrypted(ctx context.Context, client *etcd.Client) (bool, error) { data, err := readKeyEtcd(ctx, client, backendEncryptedFile) @@ -112,38 +87,15 @@ func migrateIAMConfigsEtcdToEncrypted(ctx context.Context, client *etcd.Client) } if encrypted { - // backend is encrypted, but credentials are not specified - // we shall fail right here. if not proceed forward. - if !globalConfigEncrypted || !globalActiveCred.IsValid() { - return config.ErrMissingCredentialsBackendEncrypted(nil) + if GlobalKMS != nil { + stat, err := GlobalKMS.Stat() + if err != nil { + return err + } + logger.Info("Attempting to re-encrypt config, IAM users and policies on MinIO with %q (%s)", stat.DefaultKey, stat.Name) + } else { + logger.Info("Attempting to migrate encrypted config, IAM users and policies on MinIO to a plaintext format. To encrypt all MinIO config data a KMS is needed") } - } else { - // backend is not yet encrypted, check if encryption of - // backend is requested if not return nil and proceed - // forward. - if !globalConfigEncrypted { - return nil - } - if !globalActiveCred.IsValid() { - return errInvalidArgument - } - } - - if encrypted { - // No key rotation requested, and backend is - // already encrypted. We proceed without migration. - if !globalOldCred.IsValid() { - return nil - } - - // No real reason to rotate if old and new creds are same. - if globalOldCred.Equal(globalActiveCred) { - return nil - } - - logger.Info("Attempting rotation of encrypted IAM users and policies on etcd with newly supplied credentials") - } else { - logger.Info("Attempting encryption of all IAM users and policies on etcd") } listCtx, cancel := context.WithTimeout(ctx, 1*time.Minute) @@ -154,134 +106,89 @@ func migrateIAMConfigsEtcdToEncrypted(ctx context.Context, client *etcd.Client) return err } - if err = saveKeyEtcd(ctx, client, backendEncryptedFile, backendEncryptedMigrationIncomplete); err != nil { - return err - } - for _, kv := range r.Kvs { - var ( - cdata []byte - cencdata []byte - ) - cdata, err = readKeyEtcd(ctx, client, string(kv.Key)) - if err != nil { - switch err { - case errConfigNotFound: - // Perhaps not present or someone deleted it. - continue - } - return err + data, err := readKeyEtcd(ctx, client, string(kv.Key)) + if err == errConfigNotFound { // Perhaps not present or someone deleted it. + continue } - - var data []byte - // Is rotating of creds requested? - if globalOldCred.IsValid() { - data, err = decryptData(cdata, globalOldCred, globalActiveCred) - if err != nil { - if err == madmin.ErrMaliciousData { - return config.ErrInvalidRotatingCredentialsBackendEncrypted(nil) - } - return err - } - } else { - data = cdata + if err != nil { + return err } if !utf8.Valid(data) { - _, err = decryptData(data, globalActiveCred) - if err == nil { - // Config is already encrypted with right keys - continue + data, err = decryptData(data, globalActiveCred) + if err != nil { + return fmt.Errorf("Decrypting config failed %w, possibly credentials are incorrect", err) } - return fmt.Errorf("Decrypting config failed %w, possibly credentials are incorrect", err) } - cencdata, err = madmin.EncryptData(globalActiveCred.String(), data) - if err != nil { - return err + if GlobalKMS != nil { + data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: string(kv.Key), + }) + if err != nil { + return err + } } - if err = saveKeyEtcd(ctx, client, string(kv.Key), cencdata); err != nil { + if err = saveKeyEtcd(ctx, client, string(kv.Key), data); err != nil { return err } } - if encrypted && globalActiveCred.IsValid() && globalOldCred.IsValid() { - logger.Info("Rotation complete, please make sure to unset MINIO_ROOT_USER_OLD and MINIO_ROOT_PASSWORD_OLD envs") + if encrypted { + if GlobalKMS != nil { + logger.Info("Migration of encrypted config data completed. All config data is now encrypted with the KMS") + } else { + logger.Info("Migration of encrypted config data completed. All config data is now stored in plaintext") + } } - - return saveKeyEtcd(ctx, client, backendEncryptedFile, backendEncryptedMigrationComplete) + return deleteKeyEtcd(ctx, client, backendEncryptedFile) } -func migrateConfigPrefixToEncrypted(objAPI ObjectLayer, activeCredOld auth.Credentials, encrypted bool) error { - if encrypted { - // No key rotation requested, and backend is - // already encrypted. We proceed without migration. - if !activeCredOld.IsValid() { - return nil - } - - // No real reason to rotate if old and new creds are same. - if activeCredOld.Equal(globalActiveCred) { - return nil - } - logger.Info("Attempting rotation of encrypted config, IAM users and policies on MinIO with newly supplied credentials") - } else { - logger.Info("Attempting encryption of all config, IAM users and policies on MinIO backend") +func migrateConfigPrefixToEncrypted(objAPI ObjectLayer, encrypted bool) error { + if !encrypted { + return nil } - - err := saveConfig(GlobalContext, objAPI, backendEncryptedFile, backendEncryptedMigrationIncomplete) - if err != nil { - return err + if encrypted { + if GlobalKMS != nil { + stat, err := GlobalKMS.Stat() + if err != nil { + return err + } + logger.Info("Attempting to re-encrypt config, IAM users and policies on MinIO with %q (%s)", stat.DefaultKey, stat.Name) + } else { + logger.Info("Attempting to migrate encrypted config, IAM users and policies on MinIO to a plaintext format. To encrypt all MinIO config data a KMS is needed") + } } var marker string for { - res, err := objAPI.ListObjects(GlobalContext, minioMetaBucket, - minioConfigPrefix, marker, "", maxObjectList) + res, err := objAPI.ListObjects(GlobalContext, minioMetaBucket, minioConfigPrefix, marker, "", maxObjectList) if err != nil { return err } for _, obj := range res.Objects { - var ( - cdata []byte - cencdata []byte - ) - - cdata, err = readConfig(GlobalContext, objAPI, obj.Name) + data, err := readConfig(GlobalContext, objAPI, obj.Name) if err != nil { return err } - var data []byte - // Is rotating of creds requested? - if activeCredOld.IsValid() { - data, err = decryptData(cdata, activeCredOld, globalActiveCred) - if err != nil { - if err == madmin.ErrMaliciousData { - return config.ErrInvalidRotatingCredentialsBackendEncrypted(nil) - } - return err - } - } else { - data = cdata - } - if !utf8.Valid(data) { - _, err = decryptData(data, globalActiveCred) - if err == nil { - // Config is already encrypted with right keys - continue + data, err = decryptData(data, globalActiveCred) + if err != nil { + return fmt.Errorf("Decrypting config failed %w, possibly credentials are incorrect", err) } - return fmt.Errorf("Decrypting config failed %w, possibly credentials are incorrect", err) } - - cencdata, err = madmin.EncryptData(globalActiveCred.String(), data) - if err != nil { - return err + if GlobalKMS != nil { + data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{ + obj.Bucket: path.Join(obj.Bucket, obj.Name), + }) + if err != nil { + return err + } } - - if err = saveConfig(GlobalContext, objAPI, obj.Name, cencdata); err != nil { + if err = saveConfig(GlobalContext, objAPI, obj.Name, data); err != nil { return err } } @@ -289,13 +196,14 @@ func migrateConfigPrefixToEncrypted(objAPI ObjectLayer, activeCredOld auth.Crede if !res.IsTruncated { break } - marker = res.NextMarker } - - if encrypted && globalActiveCred.IsValid() && activeCredOld.IsValid() { - logger.Info("Rotation complete, please make sure to unset MINIO_ROOT_USER_OLD and MINIO_ROOT_PASSWORD_OLD envs") + if encrypted { + if GlobalKMS != nil { + logger.Info("Migration of encrypted config data completed. All config data is now encrypted with the KMS") + } else { + logger.Info("Migration of encrypted config data completed. All config data is now stored in plaintext") + } } - - return saveConfig(GlobalContext, objAPI, backendEncryptedFile, backendEncryptedMigrationComplete) + return deleteConfig(GlobalContext, globalObjectAPI, backendEncryptedFile) } diff --git a/cmd/config-migrate.go b/cmd/config-migrate.go index f9ecbf9ec..dcc22fc11 100644 --- a/cmd/config-migrate.go +++ b/cmd/config-migrate.go @@ -34,11 +34,11 @@ import ( "github.com/minio/minio/cmd/config/notify" "github.com/minio/minio/cmd/config/policy/opa" "github.com/minio/minio/cmd/config/storageclass" - "github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event/target" + "github.com/minio/minio/pkg/kms" "github.com/minio/minio/pkg/madmin" xnet "github.com/minio/minio/pkg/net" "github.com/minio/minio/pkg/quick" @@ -2412,7 +2412,6 @@ func migrateV27ToV28() error { } srvConfig.Version = "28" - srvConfig.KMS = crypto.KMSConfig{} if err = quick.SaveConfig(srvConfig, configFile, globalEtcdClient); err != nil { return fmt.Errorf("Failed to migrate config from ‘27’ to ‘28’. %w", err) } @@ -2507,13 +2506,28 @@ func checkConfigVersion(objAPI ObjectLayer, configFile string, version string) ( return false, nil, err } - if globalConfigEncrypted && !utf8.Valid(data) { - data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) - if err != nil { - if err == madmin.ErrMaliciousData { - return false, nil, config.ErrInvalidCredentialsBackendEncrypted(nil) + if !utf8.Valid(data) { + if GlobalKMS != nil { + data, err = config.DecryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, configFile), + }) + if err != nil { + data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if err != nil { + if err == madmin.ErrMaliciousData { + return false, nil, config.ErrInvalidCredentialsBackendEncrypted(nil) + } + return false, nil, err + } + } + } else { + data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if err != nil { + if err == madmin.ErrMaliciousData { + return false, nil, config.ErrInvalidCredentialsBackendEncrypted(nil) + } + return false, nil, err } - return false, nil, err } } @@ -2546,8 +2560,6 @@ func migrateV27ToV28MinioSys(objAPI ObjectLayer) error { } cfg.Version = "28" - cfg.KMS = crypto.KMSConfig{} - if err = saveServerConfig(GlobalContext, objAPI, cfg); err != nil { return fmt.Errorf("Failed to migrate config from ‘27’ to ‘28’. %w", err) } @@ -2739,7 +2751,6 @@ func migrateMinioSysConfigToKV(objAPI ObjectLayer) error { logger.SetLoggerHTTPAudit(newCfg, k, auditArgs) } - crypto.SetKMSConfig(newCfg, cfg.KMS) xldap.SetIdentityLDAP(newCfg, cfg.LDAPServerConfig) openid.SetIdentityOpenID(newCfg, cfg.OpenID) opa.SetPolicyOPAConfig(newCfg, cfg.Policy.OPA) diff --git a/cmd/config-versions.go b/cmd/config-versions.go index 60849554e..065d01e4f 100644 --- a/cmd/config-versions.go +++ b/cmd/config-versions.go @@ -27,7 +27,6 @@ import ( "github.com/minio/minio/cmd/config/notify" "github.com/minio/minio/cmd/config/policy/opa" "github.com/minio/minio/cmd/config/storageclass" - "github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/event/target" @@ -713,9 +712,6 @@ type serverConfigV28 struct { // Cache configuration Cache cache.Config `json:"cache"` - // KMS configuration - KMS crypto.KMSConfig `json:"kms"` - // Notification queue configuration. Notify notifierV3 `json:"notify"` @@ -742,9 +738,6 @@ type serverConfigV30 struct { // Cache configuration Cache cache.Config `json:"cache"` - // KMS configuration - KMS crypto.KMSConfig `json:"kms"` - // Notification queue configuration. Notify notifierV3 `json:"notify"` @@ -770,9 +763,6 @@ type serverConfigV31 struct { // Cache configuration Cache cache.Config `json:"cache"` - // KMS configuration - KMS crypto.KMSConfig `json:"kms"` - // Notification queue configuration. Notify notifierV3 `json:"notify"` @@ -809,9 +799,6 @@ type serverConfigV32 struct { // Cache configuration Cache cache.Config `json:"cache"` - // KMS configuration - KMS crypto.KMSConfig `json:"kms"` - // Notification queue configuration. Notify notify.Config `json:"notify"` @@ -850,9 +837,6 @@ type serverConfigV33 struct { // Cache configuration Cache cache.Config `json:"cache"` - // KMS configuration - KMS crypto.KMSConfig `json:"kms"` - // Notification queue configuration. Notify notify.Config `json:"notify"` diff --git a/cmd/config.go b/cmd/config.go index abed9b95a..a3ffdda9e 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -17,7 +17,6 @@ package cmd import ( - "bytes" "context" "encoding/json" "path" @@ -27,6 +26,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/minio/minio/cmd/config" + "github.com/minio/minio/pkg/kms" "github.com/minio/minio/pkg/madmin" ) @@ -64,8 +64,10 @@ func listServerConfigHistory(ctx context.Context, objAPI ObjectLayer, withData b if err != nil { return nil, err } - if globalConfigEncrypted && !utf8.Valid(data) { - data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if GlobalKMS != nil { + data, err = config.DecryptBytes(GlobalKMS, data, kms.Context{ + obj.Bucket: path.Join(obj.Bucket, obj.Name), + }) if err != nil { return nil, err } @@ -103,10 +105,11 @@ func readServerConfigHistory(ctx context.Context, objAPI ObjectLayer, uuidKV str return nil, err } - if globalConfigEncrypted && !utf8.Valid(data) { - data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if GlobalKMS != nil { + data, err = config.DecryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, historyFile), + }) } - return data, err } @@ -114,39 +117,39 @@ func saveServerConfigHistory(ctx context.Context, objAPI ObjectLayer, kv []byte) uuidKV := mustGetUUID() + kvPrefix historyFile := pathJoin(minioConfigHistoryPrefix, uuidKV) - var err error - if globalConfigEncrypted { - kv, err = madmin.EncryptData(globalActiveCred.String(), kv) + if GlobalKMS != nil { + var err error + kv, err = config.EncryptBytes(GlobalKMS, kv, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, historyFile), + }) if err != nil { return err } } - - // Save the new config KV settings into the history path. return saveConfig(ctx, objAPI, historyFile, kv) } -func saveServerConfig(ctx context.Context, objAPI ObjectLayer, config interface{}) error { - data, err := json.Marshal(config) +func saveServerConfig(ctx context.Context, objAPI ObjectLayer, cfg interface{}) error { + data, err := json.Marshal(cfg) if err != nil { return err } - if globalConfigEncrypted { - data, err = madmin.EncryptData(globalActiveCred.String(), data) + var configFile = path.Join(minioConfigPrefix, minioConfigFile) + if GlobalKMS != nil { + data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, configFile), + }) if err != nil { return err } } - - configFile := path.Join(minioConfigPrefix, minioConfigFile) - // Save the new config in the std config path return saveConfig(ctx, objAPI, configFile, data) } func readServerConfig(ctx context.Context, objAPI ObjectLayer) (config.Config, error) { configFile := path.Join(minioConfigPrefix, minioConfigFile) - configData, err := readConfig(ctx, objAPI, configFile) + data, err := readConfig(ctx, objAPI, configFile) if err != nil { // Config not found for some reason, allow things to continue // by initializing a new fresh config in safe mode. @@ -156,19 +159,18 @@ func readServerConfig(ctx context.Context, objAPI ObjectLayer) (config.Config, e return nil, err } - if globalConfigEncrypted && !utf8.Valid(configData) { - configData, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(configData)) + if GlobalKMS != nil && !utf8.Valid(data) { + data, err = config.DecryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, configFile), + }) if err != nil { - if err == madmin.ErrMaliciousData { - return nil, config.ErrInvalidCredentialsBackendEncrypted(nil) - } return nil, err } } var srvCfg = config.New() var json = jsoniter.ConfigCompatibleWithStandardLibrary - if err = json.Unmarshal(configData, &srvCfg); err != nil { + if err = json.Unmarshal(data, &srvCfg); err != nil { return nil, err } diff --git a/cmd/config/cache/lookup.go b/cmd/config/cache/lookup.go index 297bc90a4..f6e1e8830 100644 --- a/cmd/config/cache/lookup.go +++ b/cmd/config/cache/lookup.go @@ -48,7 +48,7 @@ const ( EnvCacheRange = "MINIO_CACHE_RANGE" EnvCacheCommit = "MINIO_CACHE_COMMIT" - EnvCacheEncryptionMasterKey = "MINIO_CACHE_ENCRYPTION_MASTER_KEY" + EnvCacheEncryptionKey = "MINIO_CACHE_ENCRYPTION_SECRET_KEY" DefaultExpiry = "90" DefaultQuota = "80" diff --git a/cmd/config/constants.go b/cmd/config/constants.go index 0551519eb..d76c8d0d8 100644 --- a/cmd/config/constants.go +++ b/cmd/config/constants.go @@ -23,24 +23,29 @@ const ( // Top level common ENVs const ( - EnvAccessKey = "MINIO_ACCESS_KEY" - EnvSecretKey = "MINIO_SECRET_KEY" - EnvRootUser = "MINIO_ROOT_USER" - EnvRootPassword = "MINIO_ROOT_PASSWORD" - EnvAccessKeyOld = "MINIO_ACCESS_KEY_OLD" - EnvSecretKeyOld = "MINIO_SECRET_KEY_OLD" - EnvRootUserOld = "MINIO_ROOT_USER_OLD" - EnvRootPasswordOld = "MINIO_ROOT_PASSWORD_OLD" - EnvBrowser = "MINIO_BROWSER" - EnvDomain = "MINIO_DOMAIN" - EnvRegionName = "MINIO_REGION_NAME" - EnvPublicIPs = "MINIO_PUBLIC_IPS" - EnvFSOSync = "MINIO_FS_OSYNC" - EnvArgs = "MINIO_ARGS" - EnvDNSWebhook = "MINIO_DNS_WEBHOOK_ENDPOINT" + EnvAccessKey = "MINIO_ACCESS_KEY" + EnvSecretKey = "MINIO_SECRET_KEY" + EnvRootUser = "MINIO_ROOT_USER" + EnvRootPassword = "MINIO_ROOT_PASSWORD" + + EnvBrowser = "MINIO_BROWSER" + EnvDomain = "MINIO_DOMAIN" + EnvRegionName = "MINIO_REGION_NAME" + EnvPublicIPs = "MINIO_PUBLIC_IPS" + EnvFSOSync = "MINIO_FS_OSYNC" + EnvArgs = "MINIO_ARGS" + EnvDNSWebhook = "MINIO_DNS_WEBHOOK_ENDPOINT" EnvUpdate = "MINIO_UPDATE" + EnvKMSMasterKey = "MINIO_KMS_MASTER_KEY" // legacy + EnvKMSSecretKey = "MINIO_KMS_SECRET_KEY" + EnvKESEndpoint = "MINIO_KMS_KES_ENDPOINT" + EnvKESKeyName = "MINIO_KMS_KES_KEY_NAME" + EnvKESClientKey = "MINIO_KMS_KES_KEY_FILE" + EnvKESClientCert = "MINIO_KMS_KES_CERT_FILE" + EnvKESServerCA = "MINIO_KMS_KES_CAPATH" + EnvEndpoints = "MINIO_ENDPOINTS" // legacy EnvWorm = "MINIO_WORM" // legacy EnvRegion = "MINIO_REGION" // legacy diff --git a/cmd/config/crypto.go b/cmd/config/crypto.go index a7d97d279..9087ecfc6 100644 --- a/cmd/config/crypto.go +++ b/cmd/config/crypto.go @@ -28,6 +28,30 @@ import ( "github.com/secure-io/sio-go/sioutil" ) +// EncryptBytes encrypts the plaintext with a key managed by KMS. +// The context is bound to the returned ciphertext. +// +// The same context must be provided when decrypting the +// ciphertext. +func EncryptBytes(KMS kms.KMS, plaintext []byte, context kms.Context) ([]byte, error) { + ciphertext, err := Encrypt(KMS, bytes.NewReader(plaintext), context) + if err != nil { + return nil, err + } + return io.ReadAll(ciphertext) +} + +// DecryptBytes decrypts the ciphertext using a key managed by the KMS. +// The same context that have been used during encryption must be +// provided. +func DecryptBytes(KMS kms.KMS, ciphertext []byte, context kms.Context) ([]byte, error) { + plaintext, err := Decrypt(KMS, bytes.NewReader(ciphertext), context) + if err != nil { + return nil, err + } + return io.ReadAll(plaintext) +} + // Encrypt encrypts the plaintext with a key managed by KMS. // The context is bound to the returned ciphertext. // diff --git a/cmd/crypto/config.go b/cmd/crypto/config.go index 6c27a00d1..1328c0edb 100644 --- a/cmd/crypto/config.go +++ b/cmd/crypto/config.go @@ -15,12 +15,7 @@ package crypto import ( - "errors" "math/rand" - "net/http" - "os" - "reflect" - "strconv" "strings" "github.com/minio/minio/cmd/config" @@ -29,101 +24,7 @@ import ( xnet "github.com/minio/minio/pkg/net" ) -// KMSConfig has the KMS config for hashicorp vault -type KMSConfig struct { - AutoEncryption bool `json:"-"` - Vault VaultConfig `json:"vault"` - Kes KesConfig `json:"kes"` -} - -// KMS Vault constants. const ( - KMSVaultEndpoint = "endpoint" - KMSVaultCAPath = "capath" - KMSVaultKeyName = "key_name" - KMSVaultKeyVersion = "key_version" - KMSVaultNamespace = "namespace" - KMSVaultAuthType = "auth_type" - KMSVaultAppRoleID = "auth_approle_id" - KMSVaultAppRoleSecret = "auth_approle_secret" -) - -// KMS kes constants. -const ( - KMSKesEndpoint = "endpoint" - KMSKesKeyFile = "key_file" - KMSKesCertFile = "cert_file" - KMSKesCAPath = "capath" - KMSKesKeyName = "key_name" -) - -// DefaultKVS - default KV crypto config -var ( - DefaultVaultKVS = config.KVS{ - config.KV{ - Key: KMSVaultEndpoint, - Value: "", - }, - config.KV{ - Key: KMSVaultKeyName, - Value: "", - }, - config.KV{ - Key: KMSVaultAuthType, - Value: "approle", - }, - config.KV{ - Key: KMSVaultAppRoleID, - Value: "", - }, - config.KV{ - Key: KMSVaultAppRoleSecret, - Value: "", - }, - config.KV{ - Key: KMSVaultCAPath, - Value: "", - }, - config.KV{ - Key: KMSVaultKeyVersion, - Value: "", - }, - config.KV{ - Key: KMSVaultNamespace, - Value: "", - }, - } - - DefaultKesKVS = config.KVS{ - config.KV{ - Key: KMSKesEndpoint, - Value: "", - }, - config.KV{ - Key: KMSKesKeyName, - Value: "", - }, - config.KV{ - Key: KMSKesCertFile, - Value: "", - }, - config.KV{ - Key: KMSKesKeyFile, - Value: "", - }, - config.KV{ - Key: KMSKesCAPath, - Value: "", - }, - } -) - -const ( - // EnvKMSMasterKey is the environment variable used to specify - // a KMS master key used to protect SSE-S3 per-object keys. - // Valid values must be of the from: "KEY_ID:32_BYTE_HEX_VALUE". - EnvKMSMasterKey = "MINIO_KMS_MASTER_KEY" - // EnvKMSAutoEncryption is the environment variable used to en/disable // SSE-S3 auto-encryption. SSE-S3 auto-encryption, if enabled, // requires a valid KMS configuration and turns any non-SSE-C @@ -132,301 +33,49 @@ const ( EnvKMSAutoEncryption = "MINIO_KMS_AUTO_ENCRYPTION" ) -const ( - // EnvKMSVaultEndpoint is the environment variable used to specify - // the vault HTTPS endpoint. - EnvKMSVaultEndpoint = "MINIO_KMS_VAULT_ENDPOINT" - - // EnvKMSVaultAuthType is the environment variable used to specify - // the authentication type for vault. - EnvKMSVaultAuthType = "MINIO_KMS_VAULT_AUTH_TYPE" - - // EnvKMSVaultAppRoleID is the environment variable used to specify - // the vault AppRole ID. - EnvKMSVaultAppRoleID = "MINIO_KMS_VAULT_APPROLE_ID" - - // EnvKMSVaultAppSecretID is the environment variable used to specify - // the vault AppRole secret corresponding to the AppRole ID. - EnvKMSVaultAppSecretID = "MINIO_KMS_VAULT_APPROLE_SECRET" - - // EnvKMSVaultKeyVersion is the environment variable used to specify - // the vault key version. - EnvKMSVaultKeyVersion = "MINIO_KMS_VAULT_KEY_VERSION" - - // EnvKMSVaultKeyName is the environment variable used to specify - // the vault named key-ring. In the S3 context it's referred as - // customer master key ID (CMK-ID). - EnvKMSVaultKeyName = "MINIO_KMS_VAULT_KEY_NAME" - - // EnvKMSVaultCAPath is the environment variable used to specify the - // path to a directory of PEM-encoded CA cert files. These CA cert - // files are used to authenticate MinIO to Vault over mTLS. - EnvKMSVaultCAPath = "MINIO_KMS_VAULT_CAPATH" - - // EnvKMSVaultNamespace is the environment variable used to specify - // vault namespace. The vault namespace is used if the enterprise - // version of Hashicorp Vault is used. - EnvKMSVaultNamespace = "MINIO_KMS_VAULT_NAMESPACE" -) - -const ( - // EnvKMSKesEndpoint is the environment variable used to specify - // one or multiple KES server HTTPS endpoints. The individual - // endpoints should be separated by ','. - EnvKMSKesEndpoint = "MINIO_KMS_KES_ENDPOINT" - - // EnvKMSKesKeyFile is the environment variable used to specify - // the TLS private key used by MinIO to authenticate to the kes - // server HTTPS via mTLS. - EnvKMSKesKeyFile = "MINIO_KMS_KES_KEY_FILE" - - // EnvKMSKesCertFile is the environment variable used to specify - // the TLS certificate used by MinIO to authenticate to the kes - // server HTTPS via mTLS. - EnvKMSKesCertFile = "MINIO_KMS_KES_CERT_FILE" - - // EnvKMSKesCAPath is the environment variable used to specify - // the TLS root certificates used by MinIO to verify the certificate - // presented by to the kes server when establishing a TLS connection. - EnvKMSKesCAPath = "MINIO_KMS_KES_CA_PATH" - - // EnvKMSKesKeyName is the environment variable used to specify - // the (default) key at the kes server. In the S3 context it's - // referred as customer master key ID (CMK-ID). - EnvKMSKesKeyName = "MINIO_KMS_KES_KEY_NAME" -) - -var defaultVaultCfg = VaultConfig{ - Auth: VaultAuth{ - Type: "approle", - }, -} - -var defaultKesCfg = KesConfig{} - -// EnabledVault returns true if HashiCorp Vault is enabled. -func EnabledVault(kvs config.KVS) bool { - endpoint := kvs.Get(KMSVaultEndpoint) - return endpoint != "" -} - -// EnabledKes returns true if kes as KMS is enabled. -func EnabledKes(kvs config.KVS) bool { - endpoint := kvs.Get(KMSKesEndpoint) - return endpoint != "" -} - -// LookupKesConfig lookup kes server configuration. -func LookupKesConfig(kvs config.KVS) (KesConfig, error) { - kesCfg := KesConfig{} - - endpointStr := env.Get(EnvKMSKesEndpoint, kvs.Get(KMSKesEndpoint)) - var endpoints []string +// ParseKESEndpoints parses the given endpoint string and +// returns a list of valid endpoint URLs. The order of the +// returned endpoints is randomized. +func ParseKESEndpoints(endpointStr string) ([]string, error) { + var rawEndpoints []string for _, endpoint := range strings.Split(endpointStr, ",") { if strings.TrimSpace(endpoint) == "" { continue } if !ellipses.HasEllipses(endpoint) { - endpoints = append(endpoints, endpoint) + rawEndpoints = append(rawEndpoints, endpoint) continue } pattern, err := ellipses.FindEllipsesPatterns(endpoint) if err != nil { - return kesCfg, err + return nil, Errorf("Invalid KES endpoint %q: %v", endpointStr, err) } for _, p := range pattern { - endpoints = append(endpoints, p.Expand()...) + rawEndpoints = append(rawEndpoints, p.Expand()...) } } - if len(endpoints) == 0 { - return kesCfg, nil + if len(rawEndpoints) == 0 { + return nil, Errorf("Invalid KES endpoint %q", endpointStr) } - randNum := rand.Intn(len(endpoints) + 1) // We add 1 b/c len(endpoints) may be 0: See: rand.Intn docs - kesCfg.Endpoint = make([]string, len(endpoints)) - for i, endpoint := range endpoints { + var ( + randNum = rand.Intn(len(rawEndpoints)) + endpoints = make([]string, len(rawEndpoints)) + ) + for i, endpoint := range rawEndpoints { endpoint, err := xnet.ParseHTTPURL(endpoint) if err != nil { - return kesCfg, err + return nil, Errorf("Invalid KES endpoint %q: %v", endpointStr, err) } - kesCfg.Endpoint[(randNum+i)%len(endpoints)] = endpoint.String() + endpoints[(randNum+i)%len(rawEndpoints)] = endpoint.String() } - kesCfg.KeyFile = env.Get(EnvKMSKesKeyFile, kvs.Get(KMSKesKeyFile)) - kesCfg.CertFile = env.Get(EnvKMSKesCertFile, kvs.Get(KMSKesCertFile)) - kesCfg.CAPath = env.Get(EnvKMSKesCAPath, kvs.Get(KMSKesCAPath)) - kesCfg.DefaultKeyID = env.Get(EnvKMSKesKeyName, kvs.Get(KMSKesKeyName)) - - if reflect.DeepEqual(kesCfg, defaultKesCfg) { - return kesCfg, nil - } - - // Verify all the proper settings. - if err := kesCfg.Verify(); err != nil { - return kesCfg, err - } - kesCfg.Enabled = true - return kesCfg, nil + return endpoints, nil } -func lookupAutoEncryption() (bool, error) { - autoBool, err := config.ParseBool(env.Get(EnvAutoEncryptionLegacy, config.EnableOff)) - if err != nil { - return false, err - } - if !autoBool { - autoBool, err = config.ParseBool(env.Get(EnvKMSAutoEncryption, config.EnableOff)) - if err != nil { - return false, err - } - } - return autoBool, nil -} - -// LookupConfig lookup vault or kes config, returns KMSConfig -// to configure KMS object for object encryption -func LookupConfig(c config.Config, defaultRootCAsDir string, transport *http.Transport) (KMSConfig, error) { - vcfg, err := LookupVaultConfig(c[config.KmsVaultSubSys][config.Default]) - if err != nil { - return KMSConfig{}, err - } - kesCfg, err := LookupKesConfig(c[config.KmsKesSubSys][config.Default]) - if err != nil { - return KMSConfig{}, err - } - kesCfg.Transport = transport - if kesCfg.Enabled && kesCfg.CAPath == "" { - kesCfg.CAPath = defaultRootCAsDir - } - autoEncrypt, err := lookupAutoEncryption() - if err != nil { - return KMSConfig{}, err - } - kmsCfg := KMSConfig{ - AutoEncryption: autoEncrypt, - Vault: vcfg, - Kes: kesCfg, - } - return kmsCfg, nil -} - -// LookupVaultConfig extracts the KMS configuration provided by environment -// variables and merge them with the provided KMS configuration. The -// merging follows the following rules: -// -// 1. A valid value provided as environment variable is higher prioritized -// than the provided configuration and overwrites the value from the -// configuration file. -// -// 2. A value specified as environment variable never changes the configuration -// file. So it is never made a persistent setting. -// -// It sets the global KMS configuration according to the merged configuration -// on succes. -func LookupVaultConfig(kvs config.KVS) (VaultConfig, error) { - if err := config.CheckValidKeys(config.KmsVaultSubSys, kvs, DefaultVaultKVS); err != nil { - return VaultConfig{}, err - } - - vcfg, err := lookupConfigLegacy(kvs) - if err != nil { - return vcfg, err - } - - if vcfg.Enabled { - return vcfg, nil - } - - vcfg = VaultConfig{ - Auth: VaultAuth{ - Type: "approle", - }, - } - - endpointStr := env.Get(EnvKMSVaultEndpoint, kvs.Get(KMSVaultEndpoint)) - if endpointStr != "" { - // Lookup Hashicorp-Vault configuration & overwrite config entry if ENV var is present - endpoint, err := xnet.ParseHTTPURL(endpointStr) - if err != nil { - return vcfg, err - } - endpointStr = endpoint.String() - } - - vcfg.Endpoint = endpointStr - vcfg.CAPath = env.Get(EnvKMSVaultCAPath, kvs.Get(KMSVaultCAPath)) - vcfg.Auth.Type = env.Get(EnvKMSVaultAuthType, kvs.Get(KMSVaultAuthType)) - if vcfg.Auth.Type == "" { - vcfg.Auth.Type = "approle" - } - - vcfg.Auth.AppRole.ID = env.Get(EnvKMSVaultAppRoleID, kvs.Get(KMSVaultAppRoleID)) - vcfg.Auth.AppRole.Secret = env.Get(EnvKMSVaultAppSecretID, kvs.Get(KMSVaultAppRoleSecret)) - vcfg.Key.Name = env.Get(EnvKMSVaultKeyName, kvs.Get(KMSVaultKeyName)) - vcfg.Namespace = env.Get(EnvKMSVaultNamespace, kvs.Get(KMSVaultNamespace)) - if keyVersion := env.Get(EnvKMSVaultKeyVersion, kvs.Get(KMSVaultKeyVersion)); keyVersion != "" { - vcfg.Key.Version, err = strconv.Atoi(keyVersion) - if err != nil { - return vcfg, Errorf("Unable to parse VaultKeyVersion value (`%s`)", keyVersion) - } - } - - if reflect.DeepEqual(vcfg, defaultVaultCfg) { - return vcfg, nil - } - - // Verify all the proper settings. - if err = vcfg.Verify(); err != nil { - return vcfg, err - } - - vcfg.Enabled = true - return vcfg, nil -} - -// NewKMS - initialize a new KMS. -func NewKMS(cfg KMSConfig) (kms KMS, err error) { - // Lookup KMS master kes - only available through ENV. - if masterKeyLegacy := env.Get(EnvKMSMasterKeyLegacy, ""); len(masterKeyLegacy) != 0 { - if cfg.Vault.Enabled { // Vault and KMS master key provided - return kms, errors.New("Ambiguous KMS configuration: vault configuration and a master key are provided at the same time") - } - if cfg.Kes.Enabled { - return kms, errors.New("Ambiguous KMS configuration: kes configuration and a master key are provided at the same time") - } - kms, err = ParseMasterKey(masterKeyLegacy) - if err != nil { - return kms, err - } - } else if masterKey := env.Get(EnvKMSMasterKey, ""); len(masterKey) != 0 { - if cfg.Vault.Enabled { // Vault and KMS master key provided - return kms, errors.New("Ambiguous KMS configuration: vault configuration and a master key are provided at the same time") - } - if cfg.Kes.Enabled { - return kms, errors.New("Ambiguous KMS configuration: kes configuration and a master key are provided at the same time") - } - kms, err = ParseMasterKey(masterKey) - if err != nil { - return kms, err - } - } else if cfg.Vault.Enabled && cfg.Kes.Enabled { - return kms, errors.New("Ambiguous KMS configuration: vault configuration and kes configuration are provided at the same time") - } else if cfg.Vault.Enabled { - if v, ok := os.LookupEnv("MINIO_KMS_VAULT_DEPRECATION"); !ok || v != "off" { // TODO(aead): Remove once Vault support has been removed - return kms, errors.New("Hashicorp Vault is deprecated and will be removed Oct. 2021. To temporarily enable Hashicorp Vault support, set MINIO_KMS_VAULT_DEPRECATION=off") - } - kms, err = NewVault(cfg.Vault) - if err != nil { - return kms, err - } - } else if cfg.Kes.Enabled { - kms, err = NewKes(cfg.Kes) - if err != nil { - return kms, err - } - } - - if cfg.AutoEncryption && kms == nil { - return kms, errors.New("Invalid KMS configuration: auto-encryption is enabled but no valid KMS configuration is present") - } - return kms, nil +// LookupAutoEncryption returns true if and only if +// the MINIO_KMS_AUTO_ENCRYPTION env. variable is +// set to "on". +func LookupAutoEncryption() bool { + auto, _ := config.ParseBool(env.Get(EnvKMSAutoEncryption, config.EnableOff)) + return auto } diff --git a/cmd/crypto/help.go b/cmd/crypto/help.go index 8fa3c654d..4ceffbcbd 100644 --- a/cmd/crypto/help.go +++ b/cmd/crypto/help.go @@ -15,95 +15,3 @@ */ package crypto - -import "github.com/minio/minio/cmd/config" - -// Help template for KMS vault -var ( - HelpVault = config.HelpKVS{ - config.HelpKV{ - Key: KMSVaultEndpoint, - Description: `API endpoint e.g. "http://vault-endpoint-ip:8200"`, - Type: "url", - }, - config.HelpKV{ - Key: KMSVaultKeyName, - Description: `unique transit key name - e.g. "my-minio-key"`, - Type: "string", - }, - config.HelpKV{ - Key: KMSVaultAuthType, - Description: `supported auth type(s) ["approle"], defaults to "approle"`, - Type: "string", - }, - config.HelpKV{ - Key: KMSVaultAppRoleID, - Description: `unique role ID for approle`, - Type: "string", - }, - config.HelpKV{ - Key: KMSVaultAppRoleSecret, - Description: `unique secret ID for approle`, - Type: "string", - }, - config.HelpKV{ - Key: KMSVaultNamespace, - Description: `optional KMS namespace e.g. "customer1"`, - Optional: true, - Type: "string", - }, - config.HelpKV{ - Key: KMSVaultKeyVersion, - Description: `optional key version number`, - Optional: true, - Type: "number", - }, - config.HelpKV{ - Key: KMSVaultCAPath, - Description: `optional path to PEM-encoded CA certs e.g. "/home/user/custom-certs"`, - Optional: true, - Type: "path", - }, - config.HelpKV{ - Key: config.Comment, - Description: config.DefaultComment, - Optional: true, - Type: "sentence", - }, - } - - HelpKes = config.HelpKVS{ - config.HelpKV{ - Key: KMSKesEndpoint, - Description: `API endpoint - e.g. "https://kes-endpoint:7373"`, - Type: "url", - }, - config.HelpKV{ - Key: KMSKesKeyName, - Description: `unique key name - e.g. "my-minio-key"`, - Type: "string", - }, - config.HelpKV{ - Key: KMSKesCertFile, - Description: `path to client certificate for TLS auth - e.g. /etc/keys/public.crt`, - Type: "path", - }, - config.HelpKV{ - Key: KMSKesKeyFile, - Description: `path to client private key for TLS auth - e.g. /etc/keys/private.key`, - Type: "path", - }, - config.HelpKV{ - Key: KMSKesCAPath, - Description: `path to PEM-encoded cert(s) to verify kes server cert - e.g. /etc/keys/CAs`, - Optional: true, - Type: "path", - }, - config.HelpKV{ - Key: config.Comment, - Description: config.DefaultComment, - Optional: true, - Type: "sentence", - }, - } -) diff --git a/cmd/crypto/key.go b/cmd/crypto/key.go index 035880984..0adf36f25 100644 --- a/cmd/crypto/key.go +++ b/cmd/crypto/key.go @@ -41,6 +41,9 @@ func GenerateKey(extKey []byte, random io.Reader) (key ObjectKey) { if random == nil { random = rand.Reader } + if len(extKey) != 32 { // safety check + logger.CriticalIf(context.Background(), errors.New("crypto: invalid key length")) + } var nonce [32]byte if _, err := io.ReadFull(random, nonce[:]); err != nil { logger.CriticalIf(context.Background(), errOutOfEntropy) @@ -77,6 +80,9 @@ type SealedKey struct { // key is also cryptographically bound to the object's path (bucket/object) and the // domain (SSE-C or SSE-S3). func (key ObjectKey) Seal(extKey []byte, iv [32]byte, domain, bucket, object string) SealedKey { + if len(extKey) != 32 { + logger.CriticalIf(context.Background(), errors.New("crypto: invalid key length")) + } var ( sealingKey [32]byte encryptedKey bytes.Buffer diff --git a/cmd/crypto/kms.go b/cmd/crypto/kms.go index c66b44502..e6b1aae01 100644 --- a/cmd/crypto/kms.go +++ b/cmd/crypto/kms.go @@ -15,17 +15,7 @@ package crypto import ( - "bytes" - "context" - "crypto/hmac" - "crypto/rand" - "crypto/sha256" - "errors" - "io" - - "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/kms" - "github.com/minio/sio" ) // Context is a list of key-value pairs cryptographically @@ -37,73 +27,3 @@ type Context = kms.Context // data key generation and unsealing of KMS-generated // data keys. type KMS = kms.KMS - -type masterKeyKMS struct { - keyID string - masterKey [32]byte -} - -// NewMasterKey returns a basic KMS implementation from a single 256 bit master key. -// -// The KMS accepts any keyID but binds the keyID and context cryptographically -// to the generated keys. -func NewMasterKey(keyID string, key [32]byte) KMS { return &masterKeyKMS{keyID: keyID, masterKey: key} } - -func (m *masterKeyKMS) Stat() (kms.Status, error) { - return kms.Status{ - Name: "MasterKey", - DefaultKey: m.keyID, - }, nil -} - -func (m *masterKeyKMS) CreateKey(keyID string) error { - return errors.New("crypto: creating keys is not supported by a static master key") -} - -func (m *masterKeyKMS) GenerateKey(keyID string, ctx Context) (kms.DEK, error) { - if keyID == "" { - keyID = m.keyID - } - - var key [32]byte - if _, err := io.ReadFull(rand.Reader, key[:]); err != nil { - logger.CriticalIf(context.Background(), errOutOfEntropy) - } - - var ( - buffer bytes.Buffer - derivedKey = m.deriveKey(keyID, ctx) - ) - if n, err := sio.Encrypt(&buffer, bytes.NewReader(key[:]), sio.Config{Key: derivedKey[:]}); err != nil || n != 64 { - logger.CriticalIf(context.Background(), errors.New("KMS: unable to encrypt data key")) - } - return kms.DEK{ - KeyID: m.keyID, - Plaintext: key[:], - Ciphertext: buffer.Bytes(), - }, nil -} - -func (m *masterKeyKMS) DecryptKey(keyID string, sealedKey []byte, ctx Context) ([]byte, error) { - var derivedKey = m.deriveKey(keyID, ctx) - - var key [32]byte - out, err := sio.DecryptBuffer(key[:0], sealedKey, sio.Config{Key: derivedKey[:]}) - if err != nil || len(out) != 32 { - return nil, err // TODO(aead): upgrade sio to use sio.Error - } - return key[:], nil -} - -func (m *masterKeyKMS) deriveKey(keyID string, context Context) (key [32]byte) { - if context == nil { - context = Context{} - } - ctxBytes, _ := context.MarshalText() - - mac := hmac.New(sha256.New, m.masterKey[:]) - mac.Write([]byte(keyID)) - mac.Write(ctxBytes) - mac.Sum(key[:0]) - return key -} diff --git a/cmd/crypto/kms_test.go b/cmd/crypto/kms_test.go deleted file mode 100644 index 65829770c..000000000 --- a/cmd/crypto/kms_test.go +++ /dev/null @@ -1,104 +0,0 @@ -// MinIO Cloud Storage, (C) 2015, 2016, 2017, 2018 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 crypto - -import ( - "bytes" - "fmt" - "path" - "testing" -) - -var masterKeyKMSTests = []struct { - GenKeyID, UnsealKeyID string - GenContext, UnsealContext Context - - ShouldFail bool -}{ - {GenKeyID: "", UnsealKeyID: "", GenContext: Context{}, UnsealContext: nil, ShouldFail: false}, // 0 - {GenKeyID: "ac47be7f", UnsealKeyID: "ac47be7f", GenContext: Context{}, UnsealContext: Context{}, ShouldFail: false}, // 1 - {GenKeyID: "ac47be7f", UnsealKeyID: "ac47be7f", GenContext: Context{"bucket": "object"}, UnsealContext: Context{"bucket": "object"}, ShouldFail: false}, // 2 - {GenKeyID: "", UnsealKeyID: "", GenContext: Context{"bucket": path.Join("bucket", "object")}, UnsealContext: Context{"bucket": path.Join("bucket", "object")}, ShouldFail: false}, // 3 - {GenKeyID: "", UnsealKeyID: "", GenContext: Context{"a": "a", "0": "0", "b": "b"}, UnsealContext: Context{"b": "b", "a": "a", "0": "0"}, ShouldFail: false}, // 4 - - {GenKeyID: "ac47be7f", UnsealKeyID: "ac47be7e", GenContext: Context{}, UnsealContext: Context{}, ShouldFail: true}, // 5 - {GenKeyID: "ac47be7f", UnsealKeyID: "ac47be7f", GenContext: Context{"bucket": "object"}, UnsealContext: Context{"Bucket": "object"}, ShouldFail: true}, // 6 - {GenKeyID: "", UnsealKeyID: "", GenContext: Context{"bucket": path.Join("bucket", "Object")}, UnsealContext: Context{"bucket": path.Join("bucket", "object")}, ShouldFail: true}, // 7 - {GenKeyID: "", UnsealKeyID: "", GenContext: Context{"a": "a", "0": "1", "b": "b"}, UnsealContext: Context{"b": "b", "a": "a", "0": "0"}, ShouldFail: true}, // 8 -} - -func TestMasterKeyKMS(t *testing.T) { - for i, test := range masterKeyKMSTests { - kms := NewMasterKey(test.GenKeyID, [32]byte{}) - - key, err := kms.GenerateKey(test.GenKeyID, test.GenContext) - if err != nil { - t.Errorf("Test %d: KMS failed to generate key: %v", i, err) - } - unsealedKey, err := kms.DecryptKey(test.UnsealKeyID, key.Ciphertext, test.UnsealContext) - if err != nil && !test.ShouldFail { - t.Errorf("Test %d: KMS failed to unseal the generated key: %v", i, err) - } - if err == nil && test.ShouldFail { - t.Errorf("Test %d: KMS unsealed the generated key successfully but should have failed", i) - } - if !test.ShouldFail && !bytes.Equal(key.Plaintext, unsealedKey[:]) { - t.Errorf("Test %d: The generated and unsealed key differ", i) - } - } -} - -var contextMarshalTextTests = []struct { - Context Context - ExpectedJSON string -}{ - 0: {Context: Context{}, ExpectedJSON: "{}"}, - 1: {Context: Context{"a": "b"}, ExpectedJSON: `{"a":"b"}`}, - 2: {Context: Context{"a": "b", "c": "d"}, ExpectedJSON: `{"a":"b","c":"d"}`}, - 3: {Context: Context{"c": "d", "a": "b"}, ExpectedJSON: `{"a":"b","c":"d"}`}, - 4: {Context: Context{"0": "1", "-": "2", ".": "#"}, ExpectedJSON: `{"-":"2",".":"#","0":"1"}`}, - // rfc 8259 escapes - 5: {Context: Context{"0": "1", "key\\": "val\tue\r\n", "\"": "\""}, ExpectedJSON: `{"\"":"\"","0":"1","key\\":"val\tue\r\n"}`}, - // html sensitive escapes - 6: {Context: Context{"a": "<>&"}, ExpectedJSON: `{"a":"\u003c\u003e\u0026"}`}, -} - -func TestContextMarshalText(t *testing.T) { - for i, test := range contextMarshalTextTests { - text, err := test.Context.MarshalText() - if err != nil { - t.Fatalf("Test %d: Failed to encode context: %v", i, err) - } - if string(text) != test.ExpectedJSON { - t.Errorf("Test %d: JSON representation differ - got: '%s' want: '%s'", i, string(text), test.ExpectedJSON) - } - } -} - -func BenchmarkContext(b *testing.B) { - tests := []Context{{}, {"bucket": "warp-benchmark-bucket"}, {"0": "1", "-": "2", ".": "#"}, {"34trg": "dfioutr89", "ikjfdghkjf": "jkedfhgfjkhg", "sdfhsdjkh": "if88889", "asddsirfh804": "kjfdshgdfuhgfg78-45604586#$%<>&"}} - for _, test := range tests { - b.Run(fmt.Sprintf("%d-elems", len(test)), func(b *testing.B) { - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := test.MarshalText() - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/cmd/crypto/legacy.go b/cmd/crypto/legacy.go deleted file mode 100644 index a074e160b..000000000 --- a/cmd/crypto/legacy.go +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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 crypto - -import ( - "reflect" - "strconv" - - "github.com/minio/minio/cmd/config" - "github.com/minio/minio/pkg/env" - xnet "github.com/minio/minio/pkg/net" -) - -const ( - // EnvKMSMasterKeyLegacy is the environment variable used to specify - // a KMS master key used to protect SSE-S3 per-object keys. - // Valid values must be of the from: "KEY_ID:32_BYTE_HEX_VALUE". - EnvKMSMasterKeyLegacy = "MINIO_SSE_MASTER_KEY" - - // EnvAutoEncryptionLegacy is the environment variable used to en/disable - // SSE-S3 auto-encryption. SSE-S3 auto-encryption, if enabled, - // requires a valid KMS configuration and turns any non-SSE-C - // request into an SSE-S3 request. - // If present EnvAutoEncryption must be either "on" or "off". - EnvAutoEncryptionLegacy = "MINIO_SSE_AUTO_ENCRYPTION" -) - -const ( - // EnvLegacyVaultEndpoint is the environment variable used to specify - // the vault HTTPS endpoint. - EnvLegacyVaultEndpoint = "MINIO_SSE_VAULT_ENDPOINT" - - // EnvLegacyVaultAuthType is the environment variable used to specify - // the authentication type for vault. - EnvLegacyVaultAuthType = "MINIO_SSE_VAULT_AUTH_TYPE" - - // EnvLegacyVaultAppRoleID is the environment variable used to specify - // the vault AppRole ID. - EnvLegacyVaultAppRoleID = "MINIO_SSE_VAULT_APPROLE_ID" - - // EnvLegacyVaultAppSecretID is the environment variable used to specify - // the vault AppRole secret corresponding to the AppRole ID. - EnvLegacyVaultAppSecretID = "MINIO_SSE_VAULT_APPROLE_SECRET" - - // EnvLegacyVaultKeyVersion is the environment variable used to specify - // the vault key version. - EnvLegacyVaultKeyVersion = "MINIO_SSE_VAULT_KEY_VERSION" - - // EnvLegacyVaultKeyName is the environment variable used to specify - // the vault named key-ring. In the S3 context it's referred as - // customer master key ID (CMK-ID). - EnvLegacyVaultKeyName = "MINIO_SSE_VAULT_KEY_NAME" - - // EnvLegacyVaultCAPath is the environment variable used to specify the - // path to a directory of PEM-encoded CA cert files. These CA cert - // files are used to authenticate MinIO to Vault over mTLS. - EnvLegacyVaultCAPath = "MINIO_SSE_VAULT_CAPATH" - - // EnvLegacyVaultNamespace is the environment variable used to specify - // vault namespace. The vault namespace is used if the enterprise - // version of Hashicorp Vault is used. - EnvLegacyVaultNamespace = "MINIO_SSE_VAULT_NAMESPACE" -) - -// SetKMSConfig helper to migrate from older KMSConfig to new KV. -func SetKMSConfig(s config.Config, cfg KMSConfig) { - if cfg.Vault.Endpoint == "" { - return - } - s[config.KmsVaultSubSys][config.Default] = config.KVS{ - config.KV{ - Key: KMSVaultEndpoint, - Value: cfg.Vault.Endpoint, - }, - config.KV{ - Key: KMSVaultCAPath, - Value: cfg.Vault.CAPath, - }, - config.KV{ - Key: KMSVaultAuthType, - Value: func() string { - if cfg.Vault.Auth.Type != "" { - return cfg.Vault.Auth.Type - } - return "approle" - }(), - }, - config.KV{ - Key: KMSVaultAppRoleID, - Value: cfg.Vault.Auth.AppRole.ID, - }, - config.KV{ - Key: KMSVaultAppRoleSecret, - Value: cfg.Vault.Auth.AppRole.Secret, - }, - config.KV{ - Key: KMSVaultKeyName, - Value: cfg.Vault.Key.Name, - }, - config.KV{ - Key: KMSVaultKeyVersion, - Value: strconv.Itoa(cfg.Vault.Key.Version), - }, - config.KV{ - Key: KMSVaultNamespace, - Value: cfg.Vault.Namespace, - }, - } -} - -// lookupConfigLegacy extracts the KMS configuration provided by legacy -// environment variables and merge them with the provided KMS configuration. -// The merging follows the following rules: -// -// 1. A valid value provided as environment variable has higher priority -// than the provided configuration and overwrites the value from the -// configuration file. -// -// 2. A value specified as environment variable never changes the configuration -// file. So it is never made a persistent setting. -// -// It sets the global KMS configuration according to the merged configuration -// on success. -func lookupConfigLegacy(kvs config.KVS) (VaultConfig, error) { - vcfg := VaultConfig{ - Auth: VaultAuth{ - Type: "approle", - }, - } - - endpointStr := env.Get(EnvLegacyVaultEndpoint, "") - if endpointStr != "" { - // Lookup Hashicorp-Vault configuration & overwrite config entry if ENV var is present - endpoint, err := xnet.ParseHTTPURL(endpointStr) - if err != nil { - return vcfg, err - } - endpointStr = endpoint.String() - } - - var err error - vcfg.Endpoint = endpointStr - vcfg.CAPath = env.Get(EnvLegacyVaultCAPath, "") - vcfg.Auth.Type = env.Get(EnvLegacyVaultAuthType, "") - if vcfg.Auth.Type == "" { - vcfg.Auth.Type = "approle" - } - vcfg.Auth.AppRole.ID = env.Get(EnvLegacyVaultAppRoleID, "") - vcfg.Auth.AppRole.Secret = env.Get(EnvLegacyVaultAppSecretID, "") - vcfg.Key.Name = env.Get(EnvLegacyVaultKeyName, "") - vcfg.Namespace = env.Get(EnvLegacyVaultNamespace, "") - if keyVersion := env.Get(EnvLegacyVaultKeyVersion, ""); keyVersion != "" { - vcfg.Key.Version, err = strconv.Atoi(keyVersion) - if err != nil { - return vcfg, Errorf("Invalid ENV variable: Unable to parse %s value (`%s`)", - EnvLegacyVaultKeyVersion, keyVersion) - } - } - - if reflect.DeepEqual(vcfg, defaultVaultCfg) { - return vcfg, nil - } - - if err = vcfg.Verify(); err != nil { - return vcfg, err - } - - vcfg.Enabled = true - return vcfg, nil -} diff --git a/cmd/crypto/parse.go b/cmd/crypto/parse.go deleted file mode 100644 index 5930d82d3..000000000 --- a/cmd/crypto/parse.go +++ /dev/null @@ -1,41 +0,0 @@ -// MinIO Cloud Storage, (C) 2017-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 crypto - -import ( - "encoding/hex" - "strings" -) - -// ParseMasterKey parses the value of the environment variable -// `EnvKMSMasterKey` and returns a key-ID and a master-key KMS on success. -func ParseMasterKey(envArg string) (KMS, error) { - values := strings.SplitN(envArg, ":", 2) - if len(values) != 2 { - return nil, Errorf("Invalid KMS master key: %s does not contain a ':'", envArg) - } - var ( - keyID = values[0] - hexKey = values[1] - ) - if len(hexKey) != 64 { // 2 hex bytes = 1 byte - return nil, Errorf("Invalid KMS master key: %s not a 32 bytes long HEX value", hexKey) - } - var masterKey [32]byte - if _, err := hex.Decode(masterKey[:], []byte(hexKey)); err != nil { - return nil, Errorf("Invalid KMS master key: %v", err) - } - return NewMasterKey(keyID, masterKey), nil -} diff --git a/cmd/crypto/parse_test.go b/cmd/crypto/parse_test.go deleted file mode 100644 index cd096ed83..000000000 --- a/cmd/crypto/parse_test.go +++ /dev/null @@ -1,62 +0,0 @@ -// 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 crypto - -import "testing" - -func TestParseMasterKey(t *testing.T) { - tests := []struct { - envValue string - expectedKeyID string - success bool - }{ - { - envValue: "invalid-value", - success: false, - }, - { - envValue: "too:many:colons", - success: false, - }, - { - envValue: "myminio-key:not-a-hex", - success: false, - }, - { - envValue: "my-minio-key:6368616e676520746869732070617373776f726420746f206120736563726574", - expectedKeyID: "my-minio-key", - success: true, - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.envValue, func(t *testing.T) { - kms, err := ParseMasterKey(tt.envValue) - if tt.success && err != nil { - t.Error(err) - } - if !tt.success && err == nil { - t.Error("Unexpected failure") - } - if kms != nil { - stat, _ := kms.Stat() - if err == nil && stat.DefaultKey != tt.expectedKeyID { - t.Errorf("Expected keyID %s, got %s", tt.expectedKeyID, stat.DefaultKey) - } - } - }) - } -} diff --git a/cmd/crypto/sse_test.go b/cmd/crypto/sse_test.go index ae28653ad..d6887ddf1 100644 --- a/cmd/crypto/sse_test.go +++ b/cmd/crypto/sse_test.go @@ -182,45 +182,3 @@ func TestSSECopyUnsealObjectKey(t *testing.T) { } } } - -var s3UnsealObjectKeyTests = []struct { - KMS KMS - Bucket, Object string - Metadata map[string]string - - ExpectedErr error -}{ - { // 0 - Valid KMS key-ID and valid metadata entries for bucket/object - KMS: NewMasterKey("my-minio-key", [32]byte{}), - Bucket: "bucket", - Object: "object", - Metadata: map[string]string{ - "X-Minio-Internal-Server-Side-Encryption-Iv": "hhVY0LKR1YtZbzAKxTWUfZt5enDfYX6Fxz1ma8Kiudc=", - "X-Minio-Internal-Server-Side-Encryption-S3-Sealed-Key": "IAAfALhsOeD5AE3s5Zgq3DZ5VFGsOa3B0ksVC86veDcaj+fXv2U0VadhPaOKYr9Emd5ssOsO0uIhIIrKiOy9rA==", - "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Sealed-Key": "IAAfAMRS2iw45FsfiF3QXajSYVWj1lxMpQm6DxDGPtADCX6fJQQ4atHBtfpgqJFyeQmIHsm0FBI+UlHw1Lv4ug==", - "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Key-Id": "test-key-1", - "X-Minio-Internal-Server-Side-Encryption-Seal-Algorithm": "DAREv2-HMAC-SHA256", - }, - ExpectedErr: nil, - }, - { // 1 - Valid KMS key-ID for invalid metadata entries for bucket/object - KMS: NewMasterKey("my-minio-key", [32]byte{}), - Bucket: "bucket", - Object: "object", - Metadata: map[string]string{ - "X-Minio-Internal-Server-Side-Encryption-Iv": "hhVY0LKR1YtZbzAKxTWUfZt5enDfYX6Fxz1ma8Kiudc=", - "X-Minio-Internal-Server-Side-Encryption-S3-Sealed-Key": "IAAfALhsOeD5AE3s5Zgq3DZ5VFGsOa3B0ksVC86veDcaj+fXv2U0VadhPaOKYr9Emd5ssOsO0uIhIIrKiOy9rA==", - "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Sealed-Key": "IAAfAMRS2iw45FsfiF3QXajSYVWj1lxMpQm6DxDGPtADCX6fJQQ4atHBtfpgqJFyeQmIHsm0FBI+UlHw1Lv4ug==", - "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Key-Id": "test-key-1", - }, - ExpectedErr: errMissingInternalSealAlgorithm, - }, -} - -func TestS3UnsealObjectKey(t *testing.T) { - for i, test := range s3UnsealObjectKeyTests { - if _, err := S3.UnsealObjectKey(test.KMS, test.Metadata, test.Bucket, test.Object); err != test.ExpectedErr { - t.Errorf("Test %d: got: %v - want: %v", i, err, test.ExpectedErr) - } - } -} diff --git a/cmd/crypto/vault.go b/cmd/crypto/vault.go deleted file mode 100644 index d16f691d3..000000000 --- a/cmd/crypto/vault.go +++ /dev/null @@ -1,289 +0,0 @@ -// MinIO Cloud Storage, (C) 2015, 2016, 2017, 2018 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 crypto - -import ( - "encoding/base64" - "errors" - "fmt" - "strings" - "time" - - vault "github.com/hashicorp/vault/api" - "github.com/minio/minio/pkg/kms" -) - -var ( - //ErrKMSAuthLogin is raised when there is a failure authenticating to KMS - ErrKMSAuthLogin = Errorf("Vault service did not return auth info") -) - -// VaultKey represents vault encryption key-ring. -type VaultKey struct { - Name string `json:"name"` // The name of the encryption key-ring - Version int `json:"version"` // The key version -} - -// VaultAuth represents vault authentication type. -// Currently the only supported authentication type is AppRole. -type VaultAuth struct { - Type string `json:"type"` // The authentication type - AppRole VaultAppRole `json:"approle"` // The AppRole authentication credentials -} - -// VaultAppRole represents vault AppRole authentication credentials -type VaultAppRole struct { - ID string `json:"id"` // The AppRole access ID - Secret string `json:"secret"` // The AppRole secret -} - -// VaultConfig represents vault configuration. -type VaultConfig struct { - Enabled bool `json:"-"` - Endpoint string `json:"endpoint"` // The vault API endpoint as URL - CAPath string `json:"-"` // The path to PEM-encoded certificate files used for mTLS. Currently not used in config file. - Auth VaultAuth `json:"auth"` // The vault authentication configuration - Key VaultKey `json:"key-id"` // The named key used for key-generation / decryption. - Namespace string `json:"-"` // The vault namespace of enterprise vault instances -} - -// vaultService represents a connection to a vault KMS. -type vaultService struct { - config *VaultConfig - client *vault.Client - secret *vault.Secret - leaseDuration time.Duration -} - -var _ KMS = (*vaultService)(nil) // compiler check that *vaultService implements KMS - -// Verify returns a nil error if the vault configuration -// is valid. A valid configuration is either empty or -// contains valid non-default values. -func (v *VaultConfig) Verify() (err error) { - switch { - case v.Endpoint == "": - err = Errorf("crypto: missing hashicorp vault endpoint") - case strings.ToLower(v.Auth.Type) != "approle": - err = Errorf("crypto: invalid hashicorp vault authentication type: %s is not supported", v.Auth.Type) - case v.Auth.AppRole.ID == "": - err = Errorf("crypto: missing hashicorp vault AppRole ID") - case v.Auth.AppRole.Secret == "": - err = Errorf("crypto: missing hashicorp vault AppSecret ID") - case v.Key.Name == "": - err = Errorf("crypto: missing hashicorp vault key name") - case v.Key.Version < 0: - err = Errorf("crypto: invalid hashicorp vault key version: The key version must not be negative") - } - return -} - -// NewVault initializes Hashicorp Vault KMS by authenticating -// to Vault with the credentials in config and gets a client -// token for future api calls. -func NewVault(config VaultConfig) (KMS, error) { - if !config.Enabled { - return nil, nil - } - if err := config.Verify(); err != nil { - return nil, err - } - - vaultCfg := vault.Config{Address: config.Endpoint} - if err := vaultCfg.ConfigureTLS(&vault.TLSConfig{CAPath: config.CAPath}); err != nil { - return nil, err - } - client, err := vault.NewClient(&vaultCfg) - if err != nil { - return nil, Errorf("crypto: client error %w", err) - } - if config.Namespace != "" { - client.SetNamespace(config.Namespace) - } - v := &vaultService{client: client, config: &config} - if err := v.authenticate(); err != nil { - return nil, err - } - v.renewToken() - return v, nil -} - -// renewToken starts a new go-routine which renews -// the vault authentication token periodically and re-authenticates -// if the token renewal fails -func (v *vaultService) renewToken() { - retryDelay := v.leaseDuration / 2 - go func() { - for { - if v.secret == nil { - if err := v.authenticate(); err != nil { - time.Sleep(retryDelay) - continue - } - } - s, err := v.client.Auth().Token().RenewSelf(int(v.leaseDuration)) - if err != nil || s == nil { - v.secret = nil - time.Sleep(retryDelay) - continue - } - if ok, err := s.TokenIsRenewable(); !ok || err != nil { - v.secret = nil - continue - } - ttl, err := s.TokenTTL() - if err != nil { - v.secret = nil - continue - } - v.secret = s - retryDelay = ttl / 2 - time.Sleep(retryDelay) - } - }() -} - -// authenticate logs the app to vault, and starts the auto renewer -// before secret expires -func (v *vaultService) authenticate() (err error) { - payload := map[string]interface{}{ - "role_id": v.config.Auth.AppRole.ID, - "secret_id": v.config.Auth.AppRole.Secret, - } - var tokenID string - var ttl time.Duration - var secret *vault.Secret - secret, err = v.client.Logical().Write("auth/approle/login", payload) - if err != nil { - err = Errorf("crypto: client error %w", err) - return - } - if secret == nil { - err = ErrKMSAuthLogin - return - } - - tokenID, err = secret.TokenID() - if err != nil { - err = ErrKMSAuthLogin - return - } - ttl, err = secret.TokenTTL() - if err != nil { - err = ErrKMSAuthLogin - return - } - v.client.SetToken(tokenID) - v.secret = secret - v.leaseDuration = ttl - return -} - -// Info returns some information about the Vault, -// configuration - like the endpoints or authentication -// method. -func (v *vaultService) Stat() (kms.Status, error) { - return kms.Status{ - Endpoints: []string{v.config.Endpoint}, - Name: "Hashicorp Vault", - DefaultKey: v.config.Key.Name, - }, nil -} - -// CreateKey is a stub that exists such that the Vault -// client implements the KMS interface. It always returns -// a not-implemented error. -// -// Creating keys requires a KES instance between MinIO and Vault. -func (v *vaultService) CreateKey(keyID string) error { - // Creating new keys requires KES. - return errors.New("crypto: creating keys is not supported by Vault") -} - -// GenerateKey returns a new plaintext key, generated by the KMS, -// and a sealed version of this plaintext key encrypted using the -// named key referenced by keyID. It also binds the generated key -// cryptographically to the provided context. -func (v *vaultService) GenerateKey(keyID string, ctx Context) (kms.DEK, error) { - if keyID == "" { - keyID = v.config.Key.Name - } - context, err := ctx.MarshalText() - if err != nil { - return kms.DEK{}, err - } - - payload := map[string]interface{}{ - "context": base64.StdEncoding.EncodeToString(context), - } - s, err := v.client.Logical().Write(fmt.Sprintf("/transit/datakey/plaintext/%s", keyID), payload) - if err != nil { - return kms.DEK{}, Errorf("crypto: client error %w", err) - } - sealKey, ok := s.Data["ciphertext"].(string) - if !ok { - return kms.DEK{}, Errorf("crypto: incorrect 'ciphertext' key type %v", s.Data["ciphertext"]) - } - - plainKeyB64, ok := s.Data["plaintext"].(string) - if !ok { - return kms.DEK{}, Errorf("crypto: incorrect 'plaintext' key type %v", s.Data["plaintext"]) - } - - plainKey, err := base64.StdEncoding.DecodeString(plainKeyB64) - if err != nil { - return kms.DEK{}, Errorf("crypto: invalid base64 key %w", err) - } - return kms.DEK{ - KeyID: keyID, - Plaintext: plainKey, - Ciphertext: []byte(sealKey), - }, nil -} - -// UnsealKey returns the decrypted sealedKey as plaintext key. -// Therefore it sends the sealedKey to the KMS which decrypts -// it using the named key referenced by keyID and responses with -// the plaintext key. -// -// The context must be same context as the one provided while -// generating the plaintext key / sealedKey. -func (v *vaultService) DecryptKey(keyID string, sealedKey []byte, ctx Context) ([]byte, error) { - context, err := ctx.MarshalText() - if err != nil { - return nil, err - } - - payload := map[string]interface{}{ - "ciphertext": string(sealedKey), - "context": base64.StdEncoding.EncodeToString(context), - } - - s, err := v.client.Logical().Write(fmt.Sprintf("/transit/decrypt/%s", keyID), payload) - if err != nil { - return nil, Errorf("crypto: client error %w", err) - } - - base64Key, ok := s.Data["plaintext"].(string) - if !ok { - return nil, Errorf("crypto: incorrect 'plaintext' key type %v", s.Data["plaintext"]) - } - - plainKey, err := base64.StdEncoding.DecodeString(base64Key) - if err != nil { - return nil, Errorf("crypto: invalid base64 key %w", err) - } - return plainKey, nil -} diff --git a/cmd/crypto/vault_test.go b/cmd/crypto/vault_test.go deleted file mode 100644 index c83cb8f3a..000000000 --- a/cmd/crypto/vault_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// 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 crypto - -import ( - "testing" -) - -var verifyVaultConfigTests = []struct { - Config VaultConfig - ShouldFail bool -}{ - { - ShouldFail: true, - Config: VaultConfig{ - Endpoint: "https://127.0.0.1:8080", - Enabled: true, - }, - }, - { - ShouldFail: true, // 1 - Config: VaultConfig{ - Enabled: true, - Endpoint: "https://127.0.0.1:8080", - Auth: VaultAuth{Type: "unsupported"}, - }, - }, - { - ShouldFail: true, // 2 - Config: VaultConfig{ - Enabled: true, - Endpoint: "https://127.0.0.1:8080", - Auth: VaultAuth{ - Type: "approle", - AppRole: VaultAppRole{}, - }, - }, - }, - { - ShouldFail: true, // 3 - Config: VaultConfig{ - Enabled: true, - Endpoint: "https://127.0.0.1:8080", - Auth: VaultAuth{ - Type: "approle", - AppRole: VaultAppRole{ID: "123456"}, - }, - }, - }, - { - ShouldFail: true, // 4 - Config: VaultConfig{ - Enabled: true, - Endpoint: "https://127.0.0.1:8080", - Auth: VaultAuth{ - Type: "approle", - AppRole: VaultAppRole{ID: "123456", Secret: "abcdef"}, - }, - }, - }, - { - ShouldFail: true, // 5 - Config: VaultConfig{ - Enabled: true, - Endpoint: "https://127.0.0.1:8080", - Auth: VaultAuth{ - Type: "approle", - AppRole: VaultAppRole{ID: "123456", Secret: "abcdef"}, - }, - Key: VaultKey{Name: "default-key", Version: -1}, - }, - }, -} - -func TestVerifyVaultConfig(t *testing.T) { - for _, test := range verifyVaultConfigTests { - test := test - t.Run(test.Config.Endpoint, func(t *testing.T) { - err := test.Config.Verify() - if test.ShouldFail && err == nil { - t.Errorf("Verify should fail but returned 'err == nil'") - } - if !test.ShouldFail && err != nil { - t.Errorf("Verify should succeed but returned err: %s", err) - } - }) - } -} diff --git a/cmd/encryption-v1_test.go b/cmd/encryption-v1_test.go index 91a6a8cfb..edb3df230 100644 --- a/cmd/encryption-v1_test.go +++ b/cmd/encryption-v1_test.go @@ -19,14 +19,10 @@ package cmd import ( "bytes" "encoding/base64" - "encoding/json" - "fmt" "net/http" - "os" "testing" humanize "github.com/dustin/go-humanize" - "github.com/klauspost/compress/zstd" "github.com/minio/minio-go/v7/pkg/encrypt" "github.com/minio/minio/cmd/crypto" xhttp "github.com/minio/minio/cmd/http" @@ -619,7 +615,6 @@ func TestGetDefaultOpts(t *testing.T) { if err == nil { if opts.ServerSideEncryption == nil && test.encryptionType != "" { t.Errorf("Case %d: expected opts to be of %v encryption type", i, test.encryptionType) - } if opts.ServerSideEncryption != nil && test.encryptionType != opts.ServerSideEncryption.Type() { t.Errorf("Case %d: expected opts to have encryption type %v but was %v ", i, test.encryptionType, opts.ServerSideEncryption.Type()) @@ -627,89 +622,3 @@ func TestGetDefaultOpts(t *testing.T) { } } } -func Test_decryptObjectInfo(t *testing.T) { - var testSet []struct { - Bucket string - Name string - UserDef map[string]string - } - file, err := os.Open("testdata/decryptObjectInfo.json.zst") - if err != nil { - t.Fatal(err) - } - defer file.Close() - dec, err := zstd.NewReader(file) - if err != nil { - t.Fatal(err) - } - defer dec.Close() - js := json.NewDecoder(dec) - err = js.Decode(&testSet) - if err != nil { - t.Fatal(err) - } - - os.Setenv("MINIO_KMS_MASTER_KEY", "my-minio-key:6368616e676520746869732070617373776f726420746f206120736563726574") - defer os.Setenv("MINIO_KMS_MASTER_KEY", "") - GlobalKMS, err = crypto.NewKMS(crypto.KMSConfig{}) - if err != nil { - t.Fatal(err) - } - - var dst [32]byte - for i := range testSet { - t.Run(fmt.Sprint("case-", i), func(t *testing.T) { - test := &testSet[i] - _, err := decryptObjectInfo(dst[:], test.Bucket, test.Name, test.UserDef) - if err != nil { - t.Fatal(err) - } - }) - } -} - -func Benchmark_decryptObjectInfo(b *testing.B) { - var testSet []struct { - Bucket string - Name string - UserDef map[string]string - } - file, err := os.Open("testdata/decryptObjectInfo.json.zst") - if err != nil { - b.Fatal(err) - } - defer file.Close() - dec, err := zstd.NewReader(file) - if err != nil { - b.Fatal(err) - } - defer dec.Close() - js := json.NewDecoder(dec) - err = js.Decode(&testSet) - if err != nil { - b.Fatal(err) - } - - os.Setenv("MINIO_KMS_MASTER_KEY", "my-minio-key:6368616e676520746869732070617373776f726420746f206120736563726574") - defer os.Setenv("MINIO_KMS_MASTER_KEY", "") - GlobalKMS, err = crypto.NewKMS(crypto.KMSConfig{}) - if err != nil { - b.Fatal(err) - } - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(testSet))) - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - var dst [32]byte - for i := range testSet { - test := &testSet[i] - _, err := decryptObjectInfo(dst[:], test.Bucket, test.Name, test.UserDef) - if err != nil { - b.Fatal(err) - } - } - } - }) -} diff --git a/cmd/iam-etcd-store.go b/cmd/iam-etcd-store.go index ebd8b81ea..9d853fc9e 100644 --- a/cmd/iam-etcd-store.go +++ b/cmd/iam-etcd-store.go @@ -29,9 +29,11 @@ import ( jwtgo "github.com/dgrijalva/jwt-go" "github.com/minio/minio-go/v7/pkg/set" + "github.com/minio/minio/cmd/config" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" iampolicy "github.com/minio/minio/pkg/iam/policy" + "github.com/minio/minio/pkg/kms" "github.com/minio/minio/pkg/madmin" etcd "go.etcd.io/etcd/clientv3" "go.etcd.io/etcd/mvcc/mvccpb" @@ -85,38 +87,51 @@ func (ies *IAMEtcdStore) runlock() { ies.RUnlock() } -func (ies *IAMEtcdStore) saveIAMConfig(ctx context.Context, item interface{}, path string, opts ...options) error { +func (ies *IAMEtcdStore) saveIAMConfig(ctx context.Context, item interface{}, itemPath string, opts ...options) error { data, err := json.Marshal(item) if err != nil { return err } - if globalConfigEncrypted { - data, err = madmin.EncryptData(globalActiveCred.String(), data) + if GlobalKMS != nil { + data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, itemPath), + }) if err != nil { return err } } - return saveKeyEtcd(ctx, ies.client, path, data, opts...) + return saveKeyEtcd(ctx, ies.client, itemPath, data, opts...) } -func getIAMConfig(item interface{}, value []byte) error { - conf := value +func getIAMConfig(item interface{}, data []byte, itemPath string) error { var err error - if globalConfigEncrypted && !utf8.Valid(value) { - conf, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(conf)) - if err != nil { - return err + if !utf8.Valid(data) { + if GlobalKMS != nil { + data, err = config.DecryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, itemPath), + }) + if err != nil { + data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if err != nil { + return err + } + } + } else { + data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if err != nil { + return err + } } } - return json.Unmarshal(conf, item) + return json.Unmarshal(data, item) } func (ies *IAMEtcdStore) loadIAMConfig(ctx context.Context, item interface{}, path string) error { - pdata, err := readKeyEtcd(ctx, ies.client, path) + data, err := readKeyEtcd(ctx, ies.client, path) if err != nil { return err } - return getIAMConfig(item, pdata) + return getIAMConfig(item, data, path) } func (ies *IAMEtcdStore) deleteIAMConfig(ctx context.Context, path string) error { @@ -265,7 +280,7 @@ func (ies *IAMEtcdStore) loadPolicyDoc(ctx context.Context, policy string, m map func (ies *IAMEtcdStore) getPolicyDoc(ctx context.Context, kvs *mvccpb.KeyValue, m map[string]iampolicy.Policy) error { var p iampolicy.Policy - err := getIAMConfig(&p, kvs.Value) + err := getIAMConfig(&p, kvs.Value, string(kvs.Key)) if err != nil { if err == errConfigNotFound { return errNoSuchPolicy @@ -298,7 +313,7 @@ func (ies *IAMEtcdStore) loadPolicyDocs(ctx context.Context, m map[string]iampol func (ies *IAMEtcdStore) getUser(ctx context.Context, userkv *mvccpb.KeyValue, userType IAMUserType, m map[string]auth.Credentials, basePrefix string) error { var u UserIdentity - err := getIAMConfig(&u, userkv.Value) + err := getIAMConfig(&u, userkv.Value, string(userkv.Key)) if err != nil { if err == errConfigNotFound { return errNoSuchUser @@ -436,7 +451,7 @@ func (ies *IAMEtcdStore) loadMappedPolicy(ctx context.Context, name string, user func getMappedPolicy(ctx context.Context, kv *mvccpb.KeyValue, userType IAMUserType, isGroup bool, m map[string]MappedPolicy, basePrefix string) error { var p MappedPolicy - err := getIAMConfig(&p, kv.Value) + err := getIAMConfig(&p, kv.Value, string(kv.Key)) if err != nil { if err == errConfigNotFound { return errNoSuchPolicy diff --git a/cmd/iam-object-store.go b/cmd/iam-object-store.go index 897f2a102..8b0cd0ef1 100644 --- a/cmd/iam-object-store.go +++ b/cmd/iam-object-store.go @@ -27,11 +27,11 @@ import ( "time" "unicode/utf8" - jwtgo "github.com/dgrijalva/jwt-go" - + "github.com/minio/minio/cmd/config" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" iampolicy "github.com/minio/minio/pkg/iam/policy" + "github.com/minio/minio/pkg/kms" "github.com/minio/minio/pkg/madmin" ) @@ -204,29 +204,43 @@ func (iamOS *IAMObjectStore) migrateBackendFormat(ctx context.Context) error { return iamOS.migrateToV1(ctx) } -func (iamOS *IAMObjectStore) saveIAMConfig(ctx context.Context, item interface{}, path string, opts ...options) error { +func (iamOS *IAMObjectStore) saveIAMConfig(ctx context.Context, item interface{}, objPath string, opts ...options) error { data, err := json.Marshal(item) if err != nil { return err } - if globalConfigEncrypted { - data, err = madmin.EncryptData(globalActiveCred.String(), data) + if GlobalKMS != nil { + data, err = config.EncryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, objPath), + }) if err != nil { return err } } - return saveConfig(ctx, iamOS.objAPI, path, data) + return saveConfig(ctx, iamOS.objAPI, objPath, data) } -func (iamOS *IAMObjectStore) loadIAMConfig(ctx context.Context, item interface{}, path string) error { - data, err := readConfig(ctx, iamOS.objAPI, path) +func (iamOS *IAMObjectStore) loadIAMConfig(ctx context.Context, item interface{}, objPath string) error { + data, err := readConfig(ctx, iamOS.objAPI, objPath) if err != nil { return err } - if globalConfigEncrypted && !utf8.Valid(data) { - data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) - if err != nil { - return err + if !utf8.Valid(data) { + if GlobalKMS != nil { + data, err = config.DecryptBytes(GlobalKMS, data, kms.Context{ + minioMetaBucket: path.Join(minioMetaBucket, objPath), + }) + if err != nil { + data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if err != nil { + return err + } + } + } else { + data, err = madmin.DecryptData(globalActiveCred.String(), bytes.NewReader(data)) + if err != nil { + return err + } } } return json.Unmarshal(data, item) @@ -280,26 +294,6 @@ func (iamOS *IAMObjectStore) loadUser(ctx context.Context, user string, userType return nil } - // If this is a service account, rotate the session key if needed - if globalOldCred.IsValid() && u.Credentials.IsServiceAccount() { - if !globalOldCred.Equal(globalActiveCred) { - m := jwtgo.MapClaims{} - stsTokenCallback := func(t *jwtgo.Token) (interface{}, error) { - return []byte(globalOldCred.SecretKey), nil - } - if _, err := jwtgo.ParseWithClaims(u.Credentials.SessionToken, m, stsTokenCallback); err == nil { - jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, jwtgo.MapClaims(m)) - if token, err := jwt.SignedString([]byte(globalActiveCred.SecretKey)); err == nil { - u.Credentials.SessionToken = token - err := iamOS.saveIAMConfig(ctx, &u, getUserIdentityPath(user, userType)) - if err != nil { - return err - } - } - } - } - } - if u.Credentials.AccessKey == "" { u.Credentials.AccessKey = user } diff --git a/cmd/object_api_suite_test.go b/cmd/object_api_suite_test.go index 21cefebbe..df209078d 100644 --- a/cmd/object_api_suite_test.go +++ b/cmd/object_api_suite_test.go @@ -21,12 +21,11 @@ import ( "context" "io" "math/rand" - "os" "strconv" "testing" "github.com/dustin/go-humanize" - "github.com/minio/minio/cmd/crypto" + "github.com/minio/minio/pkg/kms" ) // Return pointer to testOneByteReadEOF{} @@ -518,10 +517,8 @@ func enableCompression(t *testing.T, encrypt bool) { globalCompressConfigMu.Unlock() if encrypt { globalAutoEncryption = encrypt - os.Setenv("MINIO_KMS_MASTER_KEY", "my-minio-key:6368616e676520746869732070617373776f726420746f206120736563726574") - defer os.Setenv("MINIO_KMS_MASTER_KEY", "") var err error - GlobalKMS, err = crypto.NewKMS(crypto.KMSConfig{}) + GlobalKMS, err = kms.Parse("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=") if err != nil { t.Fatal(err) } @@ -535,10 +532,8 @@ func enableEncrytion(t *testing.T) { globalCompressConfigMu.Unlock() globalAutoEncryption = true - os.Setenv("MINIO_KMS_MASTER_KEY", "my-minio-key:6368616e676520746869732070617373776f726420746f206120736563726574") - defer os.Setenv("MINIO_KMS_MASTER_KEY", "") var err error - GlobalKMS, err = crypto.NewKMS(crypto.KMSConfig{}) + GlobalKMS, err = kms.Parse("my-minio-key:5lF+0pJM0OWwlQrvK2S/I7W9mO4a6rJJI7wzj7v09cw=") if err != nil { t.Fatal(err) } diff --git a/cmd/test-utils_test.go b/cmd/test-utils_test.go index b7faaaa1e..24c606406 100644 --- a/cmd/test-utils_test.go +++ b/cmd/test-utils_test.go @@ -81,12 +81,9 @@ func TestMain(m *testing.M) { // disable ENVs which interfere with tests. for _, env := range []string{ - crypto.EnvAutoEncryptionLegacy, crypto.EnvKMSAutoEncryption, config.EnvAccessKey, - config.EnvAccessKeyOld, config.EnvSecretKey, - config.EnvSecretKeyOld, } { os.Unsetenv(env) } diff --git a/dockerscripts/docker-entrypoint.sh b/dockerscripts/docker-entrypoint.sh index 29a54e5cc..46bb7adb5 100755 --- a/dockerscripts/docker-entrypoint.sh +++ b/dockerscripts/docker-entrypoint.sh @@ -73,26 +73,26 @@ docker_secrets_env() { ## Set KMS_MASTER_KEY from docker secrets if provided docker_kms_encryption_env() { - if [ -f "$MINIO_KMS_MASTER_KEY_FILE" ]; then - KMS_MASTER_KEY_FILE="$MINIO_KMS_MASTER_KEY_FILE" + if [ -f "$MINIO_KMS_SECRET_KEY_FILE" ]; then + KMS_SECRET_KEY_FILE="$MINIO_KMS_SECRET_KEY_FILE" else - KMS_MASTER_KEY_FILE="/run/secrets/$MINIO_KMS_MASTER_KEY_FILE" + KMS_SECRET_KEY_FILE="/run/secrets/$MINIO_KMS_SECRET_KEY_FILE" fi - if [ -f "$KMS_MASTER_KEY_FILE" ]; then - MINIO_KMS_MASTER_KEY="$(cat "$KMS_MASTER_KEY_FILE")" - export MINIO_KMS_MASTER_KEY + if [ -f "$KMS_SECRET_KEY_FILE" ]; then + MINIO_KMS_SECRET_KEY="$(cat "$KMS_SECRET_KEY_FILE")" + export MINIO_KMS_SECRET_KEY fi } ## Legacy ## Set SSE_MASTER_KEY from docker secrets if provided docker_sse_encryption_env() { - SSE_MASTER_KEY_FILE="/run/secrets/$MINIO_SSE_MASTER_KEY_FILE" + KMS_SECRET_KEY_FILE="/run/secrets/$MINIO_KMS_MASTER_KEY_FILE" - if [ -f "$SSE_MASTER_KEY_FILE" ]; then - MINIO_SSE_MASTER_KEY="$(cat "$SSE_MASTER_KEY_FILE")" - export MINIO_SSE_MASTER_KEY + if [ -f "$KMS_SECRET_KEY_FILE" ]; then + MINIO_KMS_SECRET_KEY="$(cat "$KMS_SECRET_KEY_FILE")" + export MINIO_KMS_SECRET_KEY fi } diff --git a/go.mod b/go.mod index c4f0048cd..f4d2f64f8 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,6 @@ require ( github.com/google/uuid v1.1.2 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 - github.com/hashicorp/vault/api v1.0.4 github.com/jcmturner/gokrb5/v8 v8.4.2 github.com/json-iterator/go v1.1.10 github.com/klauspost/compress v1.11.12 @@ -77,15 +76,14 @@ require ( github.com/tidwall/gjson v1.6.8 github.com/tidwall/sjson v1.0.4 github.com/tinylib/msgp v1.1.3 - github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 // indirect github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a github.com/willf/bitset v1.1.11 // indirect github.com/willf/bloom v2.0.3+incompatible github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c go.etcd.io/etcd v0.0.0-20201125193152-8a03d2e9614b go.uber.org/zap v1.13.0 - golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 - golang.org/x/net v0.0.0-20201216054612-986b41b23924 + golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 golang.org/x/tools v0.1.0 // indirect google.golang.org/api v0.5.0 diff --git a/go.sum b/go.sum index 23e3d1c29..ac2668a5a 100644 --- a/go.sum +++ b/go.sum @@ -149,8 +149,6 @@ github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g= -github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-ldap/ldap/v3 v3.2.4 h1:PFavAq2xTgzo/loE8qNXcQaofAaqIpI4WgaLdv+1l3E= github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -162,7 +160,6 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -239,13 +236,9 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= @@ -255,31 +248,20 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= -github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE= -github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8= -github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= @@ -287,12 +269,6 @@ github.com/hashicorp/raft v1.2.0 h1:mHzHIrF0S91d3A7RPBvuqkgB4d/7oFJZyvf1Q4m7GA0= github.com/hashicorp/raft v1.2.0/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU= -github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= -github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8= -github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -410,19 +386,14 @@ github.com/minio/simdjson-go v0.2.1/go.mod h1:JPUSkRykfSPS+AhO0YPA1h0l5vY7NqrF4z github.com/minio/sio v0.2.1 h1:NjzKiIMSMcHediVQR0AFVx2tp7Wxh9tKPfDI3kH7aHQ= github.com/minio/sio v0.2.1/go.mod h1:8b0yPp2avGThviy/+OCJBI6OMpvxoUuiLvE6F1lebhw= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mmcloughlin/avo v0.0.0-20201105074841-5d2f697d268f/go.mod h1:6aKT4zZIrpGqB3RpFU14ByCSSyKY6LfJz4J/JJChHfI= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -543,9 +514,6 @@ github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/secure-io/sio-go v0.3.1 h1:dNvY9awjabXTYGsTF1PiCySl9Ltofk9GA3VdWlo7rRc= @@ -598,8 +566,6 @@ github.com/tinylib/msgp v1.1.3 h1:3giwAkmtaEDLSV0MdO1lDLuPgklgPzmk8H9+So2BVfA= github.com/tinylib/msgp v1.1.3/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -657,8 +623,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA= +golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -697,8 +664,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY= -golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -720,11 +687,9 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -756,13 +721,11 @@ golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXR golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -800,19 +763,16 @@ google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO50 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -827,7 +787,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -850,8 +809,6 @@ gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuv gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= diff --git a/pkg/fips/fips.go b/pkg/fips/fips.go index 54b941bac..1d2571ceb 100644 --- a/pkg/fips/fips.go +++ b/pkg/fips/fips.go @@ -1,3 +1,5 @@ +// +build fips + // MinIO Cloud Storage, (C) 2021 MinIO, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,8 +14,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -//+build fips - package fips import ( @@ -37,6 +37,6 @@ func cipherSuitesTLS() []uint16 { } } -func ellipticCurvesTLS() []tls.Curve { +func ellipticCurvesTLS() []tls.CurveID { return []tls.CurveID{tls.CurveP256} } diff --git a/pkg/kms/single-key.go b/pkg/kms/single-key.go index 47ee0f7be..bbbd5201b 100644 --- a/pkg/kms/single-key.go +++ b/pkg/kms/single-key.go @@ -52,7 +52,7 @@ func Parse(s string) (KMS, error) { } // New returns a single-key KMS that derives new DEKs from the -// given key. +// given key. The given key must always be 32 bytes. func New(keyID string, key []byte) (KMS, error) { if len(key) != 32 { return nil, errors.New("kms: invalid key length " + strconv.Itoa(len(key))) diff --git a/pkg/madmin/encrypt.go b/pkg/madmin/encrypt.go index ef2937ab9..08942479a 100644 --- a/pkg/madmin/encrypt.go +++ b/pkg/madmin/encrypt.go @@ -1,5 +1,5 @@ /* - * MinIO Cloud Storage, (C) 2018 MinIO, Inc. + * MinIO Cloud Storage, (C) 2018-2021 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,21 +19,18 @@ package madmin import ( "bytes" + "crypto/sha256" "errors" "io" "io/ioutil" "github.com/minio/minio/pkg/argon2" + "github.com/minio/minio/pkg/fips" "github.com/secure-io/sio-go" "github.com/secure-io/sio-go/sioutil" + "golang.org/x/crypto/pbkdf2" ) -var idKey func([]byte, []byte, []byte, []byte, uint32) []byte - -func init() { - idKey = argon2.NewIDKey(1, 64*1024, 4) -} - // EncryptData encrypts the data with an unique key // derived from password using the Argon2id PBKDF. // @@ -43,24 +40,35 @@ func init() { func EncryptData(password string, data []byte) ([]byte, error) { salt := sioutil.MustRandom(32) - // Derive an unique 256 bit key from the password and the random salt. - key := idKey([]byte(password), salt, nil, nil, 32) - var ( id byte err error stream *sio.Stream ) - if useAES() { // Only use AES-GCM if we can use an optimized implementation - id = aesGcm + if fips.Enabled() { + key := pbkdf2.Key([]byte(password), salt, pbkdf2Cost, 32, sha256.New) stream, err = sio.AES_256_GCM.Stream(key) + if err != nil { + return nil, err + } + id = pbkdf2AESGCM } else { - id = c20p1305 - stream, err = sio.ChaCha20Poly1305.Stream(key) - } - if err != nil { - return nil, err + key := argon2.IDKey([]byte(password), salt, argon2idTime, argon2idMemory, argon2idThreads, 32) + if sioutil.NativeAES() { + stream, err = sio.AES_256_GCM.Stream(key) + if err != nil { + return nil, err + } + id = argon2idAESGCM + } else { + stream, err = sio.ChaCha20Poly1305.Stream(key) + if err != nil { + return nil, err + } + id = argon2idChaCHa20Poly1305 + } } + nonce := sioutil.MustRandom(stream.NonceSize()) // ciphertext = salt || AEAD ID | nonce | encrypted data @@ -110,33 +118,43 @@ func DecryptData(password string, data io.Reader) ([]byte, error) { return nil, err } - key := idKey([]byte(password), salt[:], nil, nil, 32) var ( err error stream *sio.Stream ) - switch id[0] { - case aesGcm: + switch { + case id[0] == argon2idAESGCM: + key := argon2.IDKey([]byte(password), salt[:], argon2idTime, argon2idMemory, argon2idThreads, 32) stream, err = sio.AES_256_GCM.Stream(key) - case c20p1305: + case id[0] == argon2idChaCHa20Poly1305: + key := argon2.IDKey([]byte(password), salt[:], argon2idTime, argon2idMemory, argon2idThreads, 32) stream, err = sio.ChaCha20Poly1305.Stream(key) + case id[0] == pbkdf2AESGCM: + key := pbkdf2.Key([]byte(password), salt[:], pbkdf2Cost, 32, sha256.New) + stream, err = sio.AES_256_GCM.Stream(key) default: - err = errors.New("madmin: invalid AEAD algorithm ID") + err = errors.New("madmin: invalid encryption algorithm ID") } if err != nil { return nil, err } - enBytes, err := ioutil.ReadAll(stream.DecryptReader(data, nonce[:], nil)) + plaintext, err := ioutil.ReadAll(stream.DecryptReader(data, nonce[:], nil)) if err != nil { - if err == sio.NotAuthentic { - return enBytes, ErrMaliciousData - } + return nil, err } - return enBytes, err + return plaintext, err } const ( - aesGcm = 0x00 - c20p1305 = 0x01 + argon2idAESGCM = 0x00 + argon2idChaCHa20Poly1305 = 0x01 + pbkdf2AESGCM = 0x02 +) + +const ( + argon2idTime = 1 + argon2idMemory = 64 * 1024 + argon2idThreads = 4 + pbkdf2Cost = 8192 ) diff --git a/pkg/madmin/encrypt_fips.go b/pkg/madmin/encrypt_fips.go deleted file mode 100644 index 0971c223e..000000000 --- a/pkg/madmin/encrypt_fips.go +++ /dev/null @@ -1,22 +0,0 @@ -// MinIO Cloud Storage, (C) 2021 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. - -// +build fips - -package madmin - -// useAES always returns true since AES is the only -// option out of AES-GCM and ChaCha20-Poly1305 that -// is approved by the NIST. -func useAES() bool { return true } diff --git a/pkg/madmin/encrypt_nofips.go b/pkg/madmin/encrypt_nofips.go deleted file mode 100644 index 4d618b0b4..000000000 --- a/pkg/madmin/encrypt_nofips.go +++ /dev/null @@ -1,24 +0,0 @@ -// MinIO Cloud Storage, (C) 2021 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. - -// +build !fips - -package madmin - -import "github.com/secure-io/sio-go/sioutil" - -// useAES returns true if the executing CPU provides -// AES-GCM hardware instructions and an optimized -// assembler implementation is available. -func useAES() bool { return sioutil.NativeAES() }