Skip to content

Commit 2f84ddd

Browse files
committed
Add support for STS endpoint in the Bucket API
Signed-off-by: Matheus Pimenta <[email protected]>
1 parent 58b4e6d commit 2f84ddd

File tree

6 files changed

+107
-2
lines changed

6 files changed

+107
-2
lines changed

Diff for: api/v1beta2/bucket_types.go

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ type BucketSpec struct {
6666
// +required
6767
Endpoint string `json:"endpoint"`
6868

69+
// STSEndpoint is the HTTP/S endpoint of the Security Token Service from
70+
// where temporary credentials will automatically be fetched in the
71+
// absence of a Secret reference.
72+
//
73+
// This field is only supported for the `generic` and `aws` providers.
74+
// +optional
75+
STSEndpoint string `json:"stsEndpoint,omitempty"`
76+
6977
// Insecure allows connecting to a non-TLS HTTP Endpoint.
7078
// +optional
7179
Insecure bool `json:"insecure,omitempty"`

Diff for: config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,15 @@ spec:
420420
required:
421421
- name
422422
type: object
423+
stsEndpoint:
424+
description: |-
425+
STSEndpoint is the HTTP/S endpoint of the Security Token Service from
426+
where temporary credentials will automatically be fetched in the
427+
absence of a Secret reference.
428+
429+
430+
This field is only supported for the `generic` and `aws` providers.
431+
type: string
423432
suspend:
424433
description: |-
425434
Suspend tells the controller to suspend the reconciliation of this

Diff for: docs/api/v1beta2/source.md

+30
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,21 @@ string
114114
</tr>
115115
<tr>
116116
<td>
117+
<code>stsEndpoint</code><br>
118+
<em>
119+
string
120+
</em>
121+
</td>
122+
<td>
123+
<em>(Optional)</em>
124+
<p>STSEndpoint is the HTTP/S endpoint of the Security Token Service from
125+
where temporary credentials will automatically be fetched in the
126+
absence of a Secret reference.</p>
127+
<p>This field is only supported for the <code>generic</code> and <code>aws</code> providers.</p>
128+
</td>
129+
</tr>
130+
<tr>
131+
<td>
117132
<code>insecure</code><br>
118133
<em>
119134
bool
@@ -1480,6 +1495,21 @@ string
14801495
</tr>
14811496
<tr>
14821497
<td>
1498+
<code>stsEndpoint</code><br>
1499+
<em>
1500+
string
1501+
</em>
1502+
</td>
1503+
<td>
1504+
<em>(Optional)</em>
1505+
<p>STSEndpoint is the HTTP/S endpoint of the Security Token Service from
1506+
where temporary credentials will automatically be fetched in the
1507+
absence of a Secret reference.</p>
1508+
<p>This field is only supported for the <code>generic</code> and <code>aws</code> providers.</p>
1509+
</td>
1510+
</tr>
1511+
<tr>
1512+
<td>
14831513
<code>insecure</code><br>
14841514
<em>
14851515
bool

Diff for: docs/spec/v1beta2/buckets.md

+8
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,14 @@ HTTP endpoint requires enabling [`.spec.insecure`](#insecure).
749749
Some endpoints require the specification of a [`.spec.region`](#region),
750750
see [Provider](#provider) for more (provider specific) examples.
751751

752+
### STS Endpoint
753+
754+
`.spec.stsEndpoint` is an optional field that specifies the HTTP/S endpoint
755+
of the Security Token Service from where temporary credentials will automatically
756+
be fetched in the absence of a Secret reference.
757+
758+
This field is only supported for the `generic` and `aws` providers.
759+
752760
### Bucket name
753761

754762
`.spec.bucketName` is a required field that specifies which object storage

Diff for: pkg/minio/minio.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ func NewClient(bucket *sourcev1.Bucket, opts ...Option) (*MinioClient, error) {
9999
if accessKey != "" && secretKey != "" {
100100
minioOpts.Creds = credentials.NewStaticV4(accessKey, secretKey, "")
101101
}
102-
} else if bucket.Spec.Provider == sourcev1.AmazonBucketProvider {
103-
minioOpts.Creds = credentials.NewIAM("")
102+
} else if bucket.Spec.Provider == sourcev1.AmazonBucketProvider || bucket.Spec.STSEndpoint != "" {
103+
minioOpts.Creds = credentials.NewIAM(bucket.Spec.STSEndpoint)
104104
}
105105

106106
var transportOpts []func(*http.Transport)

Diff for: pkg/minio/minio_test.go

+50
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"crypto/tls"
2222
"crypto/x509"
23+
"encoding/json"
2324
"errors"
2425
"fmt"
2526
"log"
@@ -35,6 +36,7 @@ import (
3536
"github.com/elazarl/goproxy"
3637
"github.com/google/uuid"
3738
miniov7 "github.com/minio/minio-go/v7"
39+
"github.com/minio/minio-go/v7/pkg/credentials"
3840
"github.com/ory/dockertest/v3"
3941
"github.com/ory/dockertest/v3/docker"
4042
"gotest.tools/assert"
@@ -244,6 +246,54 @@ func TestFGetObject(t *testing.T) {
244246
assert.NilError(t, err)
245247
}
246248

249+
func TestFGetObjectWithSTSEndpoint(t *testing.T) {
250+
// start a mock STS server
251+
stsListener, err := net.Listen("tcp", ":0")
252+
assert.NilError(t, err, "could not start STS listener")
253+
defer stsListener.Close()
254+
stsAddr := stsListener.Addr().String()
255+
stsHandler := http.NewServeMux()
256+
stsHandler.HandleFunc("PUT "+credentials.TokenPath, func(w http.ResponseWriter, r *http.Request) {
257+
_, err := w.Write([]byte("mock-token"))
258+
assert.NilError(t, err)
259+
})
260+
stsHandler.HandleFunc("GET "+credentials.DefaultIAMSecurityCredsPath, func(w http.ResponseWriter, r *http.Request) {
261+
_, err := w.Write([]byte("mock-role"))
262+
assert.NilError(t, err)
263+
})
264+
roleCredsRetrieved := false
265+
stsHandler.HandleFunc("GET "+credentials.DefaultIAMSecurityCredsPath+"mock-role", func(w http.ResponseWriter, r *http.Request) {
266+
token := r.Header.Get(credentials.TokenRequestHeader)
267+
assert.Equal(t, token, "mock-token")
268+
err := json.NewEncoder(w).Encode(map[string]any{
269+
"Code": "Success",
270+
"AccessKeyID": testMinioRootUser,
271+
"SecretAccessKey": testMinioRootPassword,
272+
})
273+
assert.NilError(t, err)
274+
roleCredsRetrieved = true
275+
})
276+
stsServer := &http.Server{
277+
Addr: stsAddr,
278+
Handler: stsHandler,
279+
}
280+
go stsServer.Serve(stsListener)
281+
defer stsServer.Shutdown(context.Background())
282+
283+
// test FGetObject with STS endpoint
284+
bucket := bucketStub(bucket, testMinioAddress)
285+
bucket.Spec.STSEndpoint = fmt.Sprintf("http://%s", stsAddr)
286+
minioClient, err := NewClient(bucket, WithTLSConfig(testTLSConfig))
287+
assert.NilError(t, err)
288+
assert.Assert(t, minioClient != nil)
289+
ctx := context.Background()
290+
tempDir := t.TempDir()
291+
path := filepath.Join(tempDir, sourceignore.IgnoreFile)
292+
_, err = minioClient.FGetObject(ctx, bucketName, objectName, path)
293+
assert.NilError(t, err)
294+
assert.Assert(t, roleCredsRetrieved)
295+
}
296+
247297
func TestNewClientAndFGetObjectWithProxy(t *testing.T) {
248298
// start proxy
249299
proxyListener, err := net.Listen("tcp", ":0")

0 commit comments

Comments
 (0)