diff options
-rw-r--r-- | app/diagnostics.go | 1 | ||||
-rw-r--r-- | app/file.go | 29 | ||||
-rw-r--r-- | model/config.go | 6 | ||||
-rw-r--r-- | model/config_test.go | 9 | ||||
-rw-r--r-- | webapp/components/admin_console/storage_settings.jsx | 23 | ||||
-rwxr-xr-x | webapp/i18n/en.json | 3 |
6 files changed, 65 insertions, 6 deletions
diff --git a/app/diagnostics.go b/app/diagnostics.go index f12681d01..983ce8077 100644 --- a/app/diagnostics.go +++ b/app/diagnostics.go @@ -275,6 +275,7 @@ func trackConfig() { "enable_public_links": utils.Cfg.FileSettings.EnablePublicLink, "driver_name": utils.Cfg.FileSettings.DriverName, "amazon_s3_ssl": *utils.Cfg.FileSettings.AmazonS3SSL, + "amazon_s3_sse": *utils.Cfg.FileSettings.AmazonS3SSE, "amazon_s3_signv2": *utils.Cfg.FileSettings.AmazonS3SignV2, "max_file_size": *utils.Cfg.FileSettings.MaxFileSize, "enable_file_attachments": *utils.Cfg.FileSettings.EnableFileAttachments, diff --git a/app/file.go b/app/file.go index 74f70ec16..03d898acd 100644 --- a/app/file.go +++ b/app/file.go @@ -115,6 +115,7 @@ func MoveFile(oldPath, newPath string) *model.AppError { secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey secure := *utils.Cfg.FileSettings.AmazonS3SSL signV2 := *utils.Cfg.FileSettings.AmazonS3SignV2 + encrypt := *utils.Cfg.FileSettings.AmazonS3SSE region := utils.Cfg.FileSettings.AmazonS3Region s3Clnt, err := s3New(endpoint, accessKey, secretKey, secure, signV2, region) if err != nil { @@ -123,7 +124,7 @@ func MoveFile(oldPath, newPath string) *model.AppError { bucket := utils.Cfg.FileSettings.AmazonS3Bucket source := s3.NewSourceInfo(bucket, oldPath, nil) - destination, err := s3.NewDestinationInfo(bucket, newPath, nil, nil) + destination, err := s3.NewDestinationInfo(bucket, newPath, nil, CopyMetadata(encrypt)) if err != nil { return model.NewLocAppError("moveFile", "api.file.write_file.s3.app_error", nil, err.Error()) } @@ -155,6 +156,7 @@ func WriteFile(f []byte, path string) *model.AppError { secretKey := utils.Cfg.FileSettings.AmazonS3SecretAccessKey secure := *utils.Cfg.FileSettings.AmazonS3SSL signV2 := *utils.Cfg.FileSettings.AmazonS3SignV2 + encrypt := *utils.Cfg.FileSettings.AmazonS3SSE region := utils.Cfg.FileSettings.AmazonS3Region s3Clnt, err := s3New(endpoint, accessKey, secretKey, secure, signV2, region) if err != nil { @@ -163,12 +165,12 @@ func WriteFile(f []byte, path string) *model.AppError { bucket := utils.Cfg.FileSettings.AmazonS3Bucket ext := filepath.Ext(path) - + metaData := S3Metadata(encrypt, "binary/octet-stream") if model.IsFileExtImage(ext) { - _, err = s3Clnt.PutObject(bucket, path, bytes.NewReader(f), model.GetImageMimeType(ext)) - } else { - _, err = s3Clnt.PutObject(bucket, path, bytes.NewReader(f), "binary/octet-stream") + metaData = S3Metadata(encrypt, model.GetImageMimeType(ext)) } + + _, err = s3Clnt.PutObjectWithMetadata(bucket, path, bytes.NewReader(f), metaData, nil) if err != nil { return model.NewLocAppError("WriteFile", "api.file.write_file.s3.app_error", nil, err.Error()) } @@ -633,3 +635,20 @@ func GetFileInfo(fileId string) (*model.FileInfo, *model.AppError) { return result.Data.(*model.FileInfo), nil } } + +func S3Metadata(encrypt bool, contentType string) map[string][]string { + metaData := make(map[string][]string) + if contentType != "" { + metaData["Content-Type"] = []string{"contentType"} + } + if encrypt { + metaData["x-amz-server-side-encryption"] = []string{"AES256"} + } + return metaData +} + +func CopyMetadata(encrypt bool) map[string]string { + metaData := make(map[string]string) + metaData["x-amz-server-side-encryption"] = "AES256" + return metaData +} diff --git a/model/config.go b/model/config.go index 55fe8490b..1717d61a0 100644 --- a/model/config.go +++ b/model/config.go @@ -262,6 +262,7 @@ type FileSettings struct { AmazonS3Endpoint string AmazonS3SSL *bool AmazonS3SignV2 *bool + AmazonS3SSE *bool } type EmailSettings struct { @@ -551,6 +552,11 @@ func (o *Config) SetDefaults() { // Signature v2 is not enabled by default. } + if o.FileSettings.AmazonS3SSE == nil { + o.FileSettings.AmazonS3SSE = new(bool) + *o.FileSettings.AmazonS3SSE = false // Not Encrypted by default. + } + if o.FileSettings.EnableFileAttachments == nil { o.FileSettings.EnableFileAttachments = new(bool) *o.FileSettings.EnableFileAttachments = true diff --git a/model/config_test.go b/model/config_test.go index 1a944710f..f10e2d0cd 100644 --- a/model/config_test.go +++ b/model/config_test.go @@ -24,3 +24,12 @@ func TestConfigDefaultEmailNotificationContentsType(t *testing.T) { t.Fatal("EmailSettings.EmailNotificationContentsType should default to 'full'") } } + +func TestConfigDefaultFileSettingsS3SSE(t *testing.T) { + c1 := Config{} + c1.SetDefaults() + + if *c1.FileSettings.AmazonS3SSE != false { + t.Fatal("FileSettings.AmazonS3SSE should default to false") + } +} diff --git a/webapp/components/admin_console/storage_settings.jsx b/webapp/components/admin_console/storage_settings.jsx index 4e0d9d19b..89a56c04b 100644 --- a/webapp/components/admin_console/storage_settings.jsx +++ b/webapp/components/admin_console/storage_settings.jsx @@ -36,6 +36,7 @@ export default class StorageSettings extends AdminSettings { config.FileSettings.AmazonS3Bucket = this.state.amazonS3Bucket; config.FileSettings.AmazonS3Endpoint = this.state.amazonS3Endpoint; config.FileSettings.AmazonS3SSL = this.state.amazonS3SSL; + config.FileSettings.AmazonS3SSE = this.state.amazonS3SSE; return config; } @@ -52,7 +53,8 @@ export default class StorageSettings extends AdminSettings { amazonS3SecretAccessKey: config.FileSettings.AmazonS3SecretAccessKey, amazonS3Bucket: config.FileSettings.AmazonS3Bucket, amazonS3Endpoint: config.FileSettings.AmazonS3Endpoint, - amazonS3SSL: config.FileSettings.AmazonS3SSL + amazonS3SSL: config.FileSettings.AmazonS3SSL, + amazonS3SSE: config.FileSettings.AmazonS3SSE }; } @@ -253,6 +255,25 @@ export default class StorageSettings extends AdminSettings { disabled={this.state.driverName !== DRIVER_S3} /> <BooleanSetting + id='AmazonSSE' + label={ + <FormattedMessage + id='admin.image.AmazonSSETitle' + defaultMessage='Enable Server-Side Encryption for Amazon S3:' + /> + } + placeholder={Utils.localizeMessage('admin.image.AmazonSSEExample', 'Ex "false"')} + helpText={ + <FormattedMessage + id='admin.image.AmazonSSEDescription' + defaultMessage='When true, encrypt files in Amazon S3 using server-side encryption with Amazon S3-managed keys. See <a href="https://about.mattermost.com/default-server-side-encryption" target="_blank">documentation</a> to learn more.' + /> + } + value={this.state.AmazonSSE} + onChange={this.handleChange} + disabled={this.state.driverName !== DRIVER_S3} + /> + <BooleanSetting id='enableFileAttachments' label={ <FormattedMessage diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 509499c1d..6f87e540b 100755 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -466,6 +466,9 @@ "admin.image.amazonS3SSLDescription": "When false, allow insecure connections to Amazon S3. Defaults to secure connections only.", "admin.image.amazonS3SSLExample": "E.g.: \"true\"", "admin.image.amazonS3SSLTitle": "Enable Secure Amazon S3 Connections:", + "admin.image.amazonS3SSEDescription": "When true, encrypt files in Amazon S3 using server-side encryption with Amazon S3-managed keys. See <a href=\"https://about.mattermost.com/default-server-side-encryption\">documentation</a> to learn more.", + "admin.image.amazonS3SSEExample": "E.g.: \"false\"", + "admin.image.amazonS3SSETitle": "Enable Server-Side Encryption for Amazon S3:", "admin.image.amazonS3SecretDescription": "Obtain this credential from your Amazon EC2 administrator.", "admin.image.amazonS3SecretExample": "E.g.: \"jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY\"", "admin.image.amazonS3SecretTitle": "Amazon S3 Secret Access Key:", |