Skip to content

Commit 1a4127f

Browse files
committed
fix: add tests for Minio credentials
1 parent 197612e commit 1a4127f

File tree

4 files changed

+149
-27
lines changed

4 files changed

+149
-27
lines changed

modules/storage/minio.go

+30-27
Original file line numberDiff line numberDiff line change
@@ -96,34 +96,8 @@ func NewMinioStorage(ctx context.Context, cfg *setting.Storage) (ObjectStorage,
9696
return nil, fmt.Errorf("invalid minio bucket lookup type: %s", config.BucketLookUpType)
9797
}
9898

99-
// By default, use the static credentials
100-
creds := credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, "")
101-
102-
// If the Access Key ID is empty, configure a credentials chain for S3 access
103-
if config.AccessKeyID == "" {
104-
chain := []credentials.Provider{
105-
// configure based upon MINIO_ prefixed environment variables
106-
&credentials.EnvMinio{},
107-
// configure based upon AWS_ prefixed environment variables
108-
&credentials.EnvAWS{},
109-
// read credentials from MINIO_SHARED_CREDENTIALS_FILE
110-
// environment variable, or default json config files
111-
&credentials.FileMinioClient{},
112-
// read credentials from AWS_SHARED_CREDENTIALS_FILE
113-
// environment variable, or default credentials file
114-
&credentials.FileAWSCredentials{},
115-
// read IAM role from EC2 metadata endpoint if available
116-
&credentials.IAM{
117-
Client: &http.Client{
118-
Transport: http.DefaultTransport,
119-
},
120-
},
121-
}
122-
creds = credentials.NewChainCredentials(chain)
123-
}
124-
12599
minioClient, err := minio.New(config.Endpoint, &minio.Options{
126-
Creds: creds,
100+
Creds: buildMinioCredentials(config, credentials.DefaultIAMRoleEndpoint),
127101
Secure: config.UseSSL,
128102
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify}},
129103
Region: config.Location,
@@ -190,6 +164,35 @@ func (m *MinioStorage) buildMinioDirPrefix(p string) string {
190164
return p
191165
}
192166

167+
func buildMinioCredentials(config setting.MinioStorageConfig, iamEndpoint string) *credentials.Credentials {
168+
// If static credentials are provided, use those
169+
if config.AccessKeyID != "" {
170+
return credentials.NewStaticV4(config.AccessKeyID, config.SecretAccessKey, "")
171+
}
172+
173+
// Otherwise, fallback to a credentials chain for S3 access
174+
chain := []credentials.Provider{
175+
// configure based upon MINIO_ prefixed environment variables
176+
&credentials.EnvMinio{},
177+
// configure based upon AWS_ prefixed environment variables
178+
&credentials.EnvAWS{},
179+
// read credentials from MINIO_SHARED_CREDENTIALS_FILE
180+
// environment variable, or default json config files
181+
&credentials.FileMinioClient{},
182+
// read credentials from AWS_SHARED_CREDENTIALS_FILE
183+
// environment variable, or default credentials file
184+
&credentials.FileAWSCredentials{},
185+
// read IAM role from EC2 metadata endpoint if available
186+
&credentials.IAM{
187+
Endpoint: iamEndpoint,
188+
Client: &http.Client{
189+
Transport: http.DefaultTransport,
190+
},
191+
},
192+
}
193+
return credentials.NewChainCredentials(chain)
194+
}
195+
193196
// Open opens a file
194197
func (m *MinioStorage) Open(path string) (Object, error) {
195198
opts := minio.GetObjectOptions{}

modules/storage/minio_test.go

+104
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package storage
66
import (
77
"context"
88
"net/http"
9+
"net/http/httptest"
910
"os"
1011
"testing"
1112

@@ -92,3 +93,106 @@ func TestS3StorageBadRequest(t *testing.T) {
9293
_, err := NewStorage(setting.MinioStorageType, cfg)
9394
assert.ErrorContains(t, err, message)
9495
}
96+
97+
func TestMinioCredentials(t *testing.T) {
98+
const (
99+
ExpectedAccessKey = "ExampleAccessKeyID"
100+
ExpectedSecretAccessKey = "ExampleSecretAccessKeyID"
101+
// Use a FakeEndpoint for IAM credentials to avoid logging any
102+
// potential real IAM credentials when running in EC2.
103+
FakeEndpoint = "http://localhost"
104+
)
105+
106+
t.Run("Static Credentials", func(t *testing.T) {
107+
cfg := setting.MinioStorageConfig{
108+
AccessKeyID: ExpectedAccessKey,
109+
SecretAccessKey: ExpectedSecretAccessKey,
110+
}
111+
creds := buildMinioCredentials(cfg, FakeEndpoint)
112+
v, err := creds.Get()
113+
114+
assert.NoError(t, err)
115+
assert.Equal(t, ExpectedAccessKey, v.AccessKeyID)
116+
assert.Equal(t, ExpectedSecretAccessKey, v.SecretAccessKey)
117+
})
118+
119+
t.Run("Chain", func(t *testing.T) {
120+
cfg := setting.MinioStorageConfig{}
121+
122+
t.Run("EnvMinio", func(t *testing.T) {
123+
t.Setenv("MINIO_ACCESS_KEY", ExpectedAccessKey+"Minio")
124+
t.Setenv("MINIO_SECRET_KEY", ExpectedSecretAccessKey+"Minio")
125+
126+
creds := buildMinioCredentials(cfg, FakeEndpoint)
127+
v, err := creds.Get()
128+
129+
assert.NoError(t, err)
130+
assert.Equal(t, ExpectedAccessKey+"Minio", v.AccessKeyID)
131+
assert.Equal(t, ExpectedSecretAccessKey+"Minio", v.SecretAccessKey)
132+
})
133+
134+
t.Run("EnvAWS", func(t *testing.T) {
135+
t.Setenv("AWS_ACCESS_KEY", ExpectedAccessKey+"AWS")
136+
t.Setenv("AWS_SECRET_KEY", ExpectedSecretAccessKey+"AWS")
137+
138+
creds := buildMinioCredentials(cfg, FakeEndpoint)
139+
v, err := creds.Get()
140+
141+
assert.NoError(t, err)
142+
assert.Equal(t, ExpectedAccessKey+"AWS", v.AccessKeyID)
143+
assert.Equal(t, ExpectedSecretAccessKey+"AWS", v.SecretAccessKey)
144+
})
145+
146+
t.Run("FileMinio", func(t *testing.T) {
147+
t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/minio.json")
148+
// prevent loading any actual credentials files from the user
149+
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/fake")
150+
151+
creds := buildMinioCredentials(cfg, FakeEndpoint)
152+
v, err := creds.Get()
153+
154+
assert.NoError(t, err)
155+
assert.Equal(t, ExpectedAccessKey+"MinioFile", v.AccessKeyID)
156+
assert.Equal(t, ExpectedSecretAccessKey+"MinioFile", v.SecretAccessKey)
157+
})
158+
159+
t.Run("FileAWS", func(t *testing.T) {
160+
// prevent loading any actual credentials files from the user
161+
t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/fake.json")
162+
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/aws_credentials")
163+
164+
creds := buildMinioCredentials(cfg, FakeEndpoint)
165+
v, err := creds.Get()
166+
167+
assert.NoError(t, err)
168+
assert.Equal(t, ExpectedAccessKey+"AWSFile", v.AccessKeyID)
169+
assert.Equal(t, ExpectedSecretAccessKey+"AWSFile", v.SecretAccessKey)
170+
})
171+
172+
t.Run("IAM", func(t *testing.T) {
173+
// prevent loading any actual credentials files from the user
174+
t.Setenv("MINIO_SHARED_CREDENTIALS_FILE", "testdata/fake.json")
175+
t.Setenv("AWS_SHARED_CREDENTIALS_FILE", "testdata/fake")
176+
177+
// Spawn a server to emulate the EC2 Instance Metadata
178+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
179+
// The client will actually make 3 requests here,
180+
// first will be to get the IMDSv2 token, second to
181+
// get the role, and third for the actual
182+
// credentials. However, we can return credentials
183+
// every request since we're not emulating a full
184+
// IMDSv2 flow.
185+
w.Write([]byte(`{"Code":"Success","AccessKeyId":"ExampleAccessKeyIDIAM","SecretAccessKey":"ExampleSecretAccessKeyIDIAM"}`))
186+
}))
187+
defer server.Close()
188+
189+
// Use the provided EC2 Instance Metadata server
190+
creds := buildMinioCredentials(cfg, server.URL)
191+
v, err := creds.Get()
192+
193+
assert.NoError(t, err)
194+
assert.Equal(t, ExpectedAccessKey+"IAM", v.AccessKeyID)
195+
assert.Equal(t, ExpectedSecretAccessKey+"IAM", v.SecretAccessKey)
196+
})
197+
})
198+
}
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[default]
2+
aws_access_key_id=ExampleAccessKeyIDAWSFile
3+
aws_secret_access_key=ExampleSecretAccessKeyIDAWSFile

modules/storage/testdata/minio.json

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "10",
3+
"aliases": {
4+
"s3": {
5+
"url": "https://s3.amazonaws.com",
6+
"accessKey": "ExampleAccessKeyIDMinioFile",
7+
"secretKey": "ExampleSecretAccessKeyIDMinioFile",
8+
"api": "S3v4",
9+
"path": "dns"
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)