Skip to content

Commit f4701f0

Browse files
Erog38Fiery-Fenix
authored andcommitted
fix: make ACLs optional for AWS S3 buckets (open-telemetry#39354)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description Fixes a problem where ACLs have become required on configuration of the AWS S3 exporter. AWS explicitly recommends to disable ACLs on buckets https://docs.aws.amazon.com/AmazonS3/latest/userguide/ensure-object-ownership.html <!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes open-telemetry#39346 <!--Describe what testing was performed and which tests were added.--> #### Testing Added test to ensure configuration of the exporter worked as expected when ACL values were set. Updated existing config tests to ensure no ACL is set by default. <!--Describe the documentation added.--> #### Documentation Updated README.md to show ACLs are optional and off by default. Additionally added myself as a codeowner as I'm willing to take on partial ownership here. <!--Please delete paragraphs that you did not use before submitting.-->
1 parent e7727ea commit f4701f0

File tree

10 files changed

+115
-38
lines changed

10 files changed

+115
-38
lines changed

.chloggen/fix_optional-acls.yaml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: bug_fix
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: awss3exporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "Fixes an issue where the AWS S3 Exporter was forcing an ACL to be set, leading to unexpected behavior in S3 bucket permissions"
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [39346]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext: "Current behavior of the AWS S3 Exporter is to set the ACL to 'private' by default, this removes that behavior and sets no ACL if not specified."
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: ["user"]

.github/CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ exporter/alibabacloudlogserviceexporter/ @open-telemetry
4242
exporter/awscloudwatchlogsexporter/ @open-telemetry/collector-contrib-approvers @boostchicken @rapphil
4343
exporter/awsemfexporter/ @open-telemetry/collector-contrib-approvers @Aneurysm9 @mxiamxia
4444
exporter/awskinesisexporter/ @open-telemetry/collector-contrib-approvers @Aneurysm9 @MovieStoreGuy
45-
exporter/awss3exporter/ @open-telemetry/collector-contrib-approvers @atoulme @pdelewski
45+
exporter/awss3exporter/ @open-telemetry/collector-contrib-approvers @atoulme @pdelewski @Erog38
4646
exporter/awsxrayexporter/ @open-telemetry/collector-contrib-approvers @wangzlei @srprash
4747
exporter/azureblobexporter/ @open-telemetry/collector-contrib-approvers @hgaol @MovieStoreGuy
4848
exporter/azuredataexplorerexporter/ @open-telemetry/collector-contrib-approvers @ag-ramachandran

exporter/awss3exporter/README.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
| Stability | [alpha]: traces, metrics, logs |
77
| Distributions | [contrib] |
88
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fawss3%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fawss3) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fawss3%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fawss3) |
9-
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@atoulme](https://www.github.com/atoulme), [@pdelewski](https://www.github.com/pdelewski) |
9+
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@atoulme](https://www.github.com/atoulme), [@pdelewski](https://www.github.com/pdelewski), [@Erog38](https://www.github.com/Erog38) |
1010

1111
[alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha
1212
[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
@@ -19,25 +19,25 @@ This exporter targets to support proto/json format.
1919

2020
The following exporter configuration parameters are supported.
2121

22-
| Name | Description | Default |
23-
|:--------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------|-------------|
24-
| `region` | AWS region. | "us-east-1" |
25-
| `s3_bucket` | S3 bucket | |
26-
| `s3_prefix` | prefix for the S3 key (root directory inside bucket). | |
22+
| Name | Description | Default |
23+
|:--------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|
24+
| `region` | AWS region. | "us-east-1" |
25+
| `s3_bucket` | S3 bucket | |
26+
| `s3_prefix` | prefix for the S3 key (root directory inside bucket). | |
2727
| `s3_partition_format` | filepath formatting for the partition; See [strftime](https://www.man7.org/linux/man-pages/man3/strftime.3.html) for format specification. | "year=%Y/month=%m/day=%d/hour=%H/minute=%M" |
28-
| `role_arn` | the Role ARN to be assumed | |
29-
| `file_prefix` | file prefix defined by user | |
30-
| `marshaler` | marshaler used to produce output data | `otlp_json` |
31-
| `encoding` | Encoding extension to use to marshal data. Overrides the `marshaler` configuration option if set. | |
32-
| `encoding_file_extension` | file format extension suffix when using the `encoding` configuration option. May be left empty for no suffix to be appended. | |
33-
| `endpoint` | (REST API endpoint) overrides the endpoint used by the exporter instead of constructing it from `region` and `s3_bucket` | |
34-
| `storage_class` | [S3 storageclass](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html) | STANDARD |
35-
| `acl` | [S3 Object Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl) | private |
36-
| `s3_force_path_style` | [set this to `true` to force the request to use path-style addressing](http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html) | false |
37-
| `disable_ssl` | set this to `true` to disable SSL when sending requests | false |
38-
| `compression` | should the file be compressed | none |
39-
| `sending_queue` | [exporters common queuing](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md) | disabled |
40-
| `timeout` | [exporters common timeout](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md) | 5s |
28+
| `role_arn` | the Role ARN to be assumed | |
29+
| `file_prefix` | file prefix defined by user | |
30+
| `marshaler` | marshaler used to produce output data | `otlp_json` |
31+
| `encoding` | Encoding extension to use to marshal data. Overrides the `marshaler` configuration option if set. | |
32+
| `encoding_file_extension` | file format extension suffix when using the `encoding` configuration option. May be left empty for no suffix to be appended. | |
33+
| `endpoint` | (REST API endpoint) overrides the endpoint used by the exporter instead of constructing it from `region` and `s3_bucket` | |
34+
| `storage_class` | [S3 storageclass](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html) | STANDARD |
35+
| `acl` | [S3 Object Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl) | none (does not set by default) |
36+
| `s3_force_path_style` | [set this to `true` to force the request to use path-style addressing](http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html) | false |
37+
| `disable_ssl` | set this to `true` to disable SSL when sending requests | false |
38+
| `compression` | should the file be compressed | none |
39+
| `sending_queue` | [exporters common queuing](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md) | disabled |
40+
| `timeout` | [exporters common timeout](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md) | 5s |
4141

4242

4343
### Marshaler

exporter/awss3exporter/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func (c *Config) Validate() error {
9595
errs = multierr.Append(errs, errors.New("invalid StorageClass"))
9696
}
9797

98-
if !validACLs[c.S3Uploader.ACL] {
98+
if c.S3Uploader.ACL != "" && !validACLs[c.S3Uploader.ACL] {
9999
errs = multierr.Append(errs, errors.New("invalid ACL"))
100100
}
101101

exporter/awss3exporter/config_test.go

+35-9
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ func TestLoadConfig(t *testing.T) {
4646
S3Bucket: "foo",
4747
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
4848
StorageClass: "STANDARD",
49-
ACL: "private",
5049
},
5150
MarshalerName: "otlp_json",
5251
}, e,
@@ -88,7 +87,6 @@ func TestConfig(t *testing.T) {
8887
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
8988
Endpoint: "http://endpoint.com",
9089
StorageClass: "STANDARD",
91-
ACL: "private",
9290
},
9391
MarshalerName: "otlp_json",
9492
}, e,
@@ -121,7 +119,6 @@ func TestConfigS3StorageClass(t *testing.T) {
121119
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
122120
Endpoint: "http://endpoint.com",
123121
StorageClass: "STANDARD_IA",
124-
ACL: "private",
125122
},
126123
QueueSettings: queueCfg,
127124
TimeoutSettings: timeoutCfg,
@@ -156,7 +153,41 @@ func TestConfigS3ACL(t *testing.T) {
156153
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
157154
Endpoint: "http://endpoint.com",
158155
StorageClass: "STANDARD_IA",
159-
ACL: "private",
156+
},
157+
QueueSettings: queueCfg,
158+
TimeoutSettings: timeoutCfg,
159+
MarshalerName: "otlp_json",
160+
}, e,
161+
)
162+
}
163+
164+
func TestConfigS3ACLDefined(t *testing.T) {
165+
factories, err := otelcoltest.NopFactories()
166+
assert.NoError(t, err)
167+
168+
factory := NewFactory()
169+
factories.Exporters[factory.Type()] = factory
170+
// https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/33594
171+
cfg, err := otelcoltest.LoadConfigAndValidate(
172+
filepath.Join("testdata", "config-s3_canned-acl.yaml"), factories)
173+
174+
require.NoError(t, err)
175+
require.NotNil(t, cfg)
176+
177+
e := cfg.Exporters[component.MustNewID("awss3")].(*Config)
178+
queueCfg := exporterhelper.NewDefaultQueueConfig()
179+
queueCfg.Enabled = false
180+
timeoutCfg := exporterhelper.NewDefaultTimeoutConfig()
181+
182+
assert.Equal(t, &Config{
183+
S3Uploader: S3UploaderConfig{
184+
Region: "us-east-1",
185+
S3Bucket: "foo",
186+
S3Prefix: "bar",
187+
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
188+
Endpoint: "http://endpoint.com",
189+
StorageClass: "STANDARD",
190+
ACL: "bucket-owner-full-control",
160191
},
161192
QueueSettings: queueCfg,
162193
TimeoutSettings: timeoutCfg,
@@ -195,7 +226,6 @@ func TestConfigForS3CompatibleSystems(t *testing.T) {
195226
S3ForcePathStyle: true,
196227
DisableSSL: true,
197228
StorageClass: "STANDARD",
198-
ACL: "private",
199229
},
200230
MarshalerName: "otlp_json",
201231
}, e,
@@ -309,7 +339,6 @@ func TestMarshallerName(t *testing.T) {
309339
S3Bucket: "foo",
310340
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
311341
StorageClass: "STANDARD",
312-
ACL: "private",
313342
},
314343
MarshalerName: "sumo_ic",
315344
}, e,
@@ -325,7 +354,6 @@ func TestMarshallerName(t *testing.T) {
325354
S3Bucket: "bar",
326355
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
327356
StorageClass: "STANDARD",
328-
ACL: "private",
329357
},
330358
MarshalerName: "otlp_proto",
331359
}, e,
@@ -359,7 +387,6 @@ func TestCompressionName(t *testing.T) {
359387
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
360388
Compression: "gzip",
361389
StorageClass: "STANDARD",
362-
ACL: "private",
363390
},
364391
MarshalerName: "otlp_json",
365392
}, e,
@@ -376,7 +403,6 @@ func TestCompressionName(t *testing.T) {
376403
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
377404
Compression: "none",
378405
StorageClass: "STANDARD",
379-
ACL: "private",
380406
},
381407
MarshalerName: "otlp_proto",
382408
}, e,

exporter/awss3exporter/factory.go

-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ func createDefaultConfig() component.Config {
3737
Region: "us-east-1",
3838
S3PartitionFormat: "year=%Y/month=%m/day=%d/hour=%H/minute=%M",
3939
StorageClass: "STANDARD",
40-
ACL: "private",
4140
},
4241
MarshalerName: "otlp_json",
4342
}

exporter/awss3exporter/internal/upload/writer.go

+21-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type Manager interface {
2020
Upload(ctx context.Context, data []byte) error
2121
}
2222

23+
type ManagerOpt func(Manager)
24+
2325
type s3manager struct {
2426
bucket string
2527
builder *PartitionKeyBuilder
@@ -30,14 +32,20 @@ type s3manager struct {
3032

3133
var _ Manager = (*s3manager)(nil)
3234

33-
func NewS3Manager(bucket string, builder *PartitionKeyBuilder, service *s3.Client, storageClass s3types.StorageClass, acl s3types.ObjectCannedACL) Manager {
34-
return &s3manager{
35+
func NewS3Manager(bucket string, builder *PartitionKeyBuilder, service *s3.Client, storageClass s3types.StorageClass, opts ...ManagerOpt) Manager {
36+
manager := &s3manager{
3537
bucket: bucket,
3638
builder: builder,
3739
uploader: manager.NewUploader(service),
3840
storageClass: storageClass,
39-
acl: acl,
4041
}
42+
for _, opt := range opts {
43+
if opt != nil {
44+
opt(manager)
45+
}
46+
}
47+
48+
return manager
4149
}
4250

4351
func (sw *s3manager) Upload(ctx context.Context, data []byte) error {
@@ -87,3 +95,13 @@ func (sw *s3manager) contentBuffer(raw []byte) (*bytes.Buffer, error) {
8795
return bytes.NewBuffer(raw), nil
8896
}
8997
}
98+
99+
func WithACL(acl s3types.ObjectCannedACL) func(Manager) {
100+
return func(m Manager) {
101+
s3m, ok := m.(*s3manager)
102+
if !ok {
103+
return
104+
}
105+
s3m.acl = acl
106+
}
107+
}

exporter/awss3exporter/internal/upload/writer_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/aws/aws-sdk-go-v2/aws"
1616
"github.com/aws/aws-sdk-go-v2/service/s3"
17+
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
1718
"github.com/stretchr/testify/assert"
1819
"github.com/tilinna/clock"
1920
"go.opentelemetry.io/collector/config/configcompression"
@@ -27,7 +28,7 @@ func TestNewS3Manager(t *testing.T) {
2728
&PartitionKeyBuilder{},
2829
s3.New(s3.Options{}),
2930
"STANDARD",
30-
"private",
31+
WithACL(s3types.ObjectCannedACLPrivate),
3132
)
3233

3334
assert.NotNil(t, sm, "Must have a valid client returned")
@@ -155,7 +156,7 @@ func TestS3ManagerUpload(t *testing.T) {
155156
Region: "local",
156157
}),
157158
"STANDARD_IA",
158-
"private",
159+
WithACL(s3types.ObjectCannedACLPrivate),
159160
)
160161

161162
// Using a mocked virtual clock to fix the timestamp used

exporter/awss3exporter/metadata.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ status:
66
alpha: [traces, metrics, logs]
77
distributions: [contrib]
88
codeowners:
9-
active: [atoulme, pdelewski]
9+
active: [atoulme, pdelewski, Erog38]
1010

1111
tests:
1212
expect_consumer_error: true

exporter/awss3exporter/s3_writer.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ func newUploadManager(
6060
})
6161
}
6262

63+
var managerOpts []upload.ManagerOpt
64+
if conf.S3Uploader.ACL != "" {
65+
managerOpts = append(managerOpts,
66+
upload.WithACL(s3types.ObjectCannedACL(conf.S3Uploader.ACL)))
67+
}
68+
6369
return upload.NewS3Manager(
6470
conf.S3Uploader.S3Bucket,
6571
&upload.PartitionKeyBuilder{
@@ -72,6 +78,6 @@ func newUploadManager(
7278
},
7379
s3.NewFromConfig(cfg, s3Opts...),
7480
s3types.StorageClass(conf.S3Uploader.StorageClass),
75-
s3types.ObjectCannedACL(conf.S3Uploader.ACL),
81+
managerOpts...,
7682
), nil
7783
}

0 commit comments

Comments
 (0)