Skip to content

Commit 79a01e9

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

File tree

4 files changed

+147
-27
lines changed

4 files changed

+147
-27
lines changed

Diff for: 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{}

Diff for: modules/storage/minio_test.go

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

1213
"code.gitea.io/gitea/modules/setting"
1314

1415
"github.com/minio/minio-go/v7"
16+
"github.com/minio/minio-go/v7/pkg/credentials"
1517
"github.com/stretchr/testify/assert"
1618
)
1719

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

Diff for: modules/storage/testdata/aws_credentials

+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

Diff for: 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)