From 7f0788395845c750f54ed0af2a7e58cdd554b32e Mon Sep 17 00:00:00 2001 From: Ramon de Klein Date: Thu, 10 Oct 2024 20:14:37 +0200 Subject: [PATCH 1/3] add `credentials.NewSTSWebIdentityWithPolicy` method The `NewSTSWebIdentityWithPolicy` allows fetching credentials that are narrowed down to the specified policy. This is useful when a client requires less rights then it actually has. The returned credentials will have the intersection of the requested policy and the assigned policies. --- pkg/credentials/sts_web_identity.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/pkg/credentials/sts_web_identity.go b/pkg/credentials/sts_web_identity.go index 596d951525..185be0c239 100644 --- a/pkg/credentials/sts_web_identity.go +++ b/pkg/credentials/sts_web_identity.go @@ -85,6 +85,9 @@ type STSWebIdentity struct { // assuming. RoleARN string + // Policy is the policy where the credentials should be limited too. + Policy string + // roleSessionName is the identifier for the assumed role session. roleSessionName string } @@ -92,6 +95,20 @@ type STSWebIdentity struct { // NewSTSWebIdentity returns a pointer to a new // Credentials object wrapping the STSWebIdentity. func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { + return newSTSWebIdentity(stsEndpoint, "", getWebIDTokenExpiry) +} + +// NewSTSWebIdentityWithPolicy returns a pointer to a new +// Credentials object wrapping the STSWebIdentity that is +// scoped to the specified policy +func NewSTSWebIdentityWithPolicy(stsEndpoint, policy string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { + if policy == "" { + return nil, errors.New("policy cannot be empty") + } + return newSTSWebIdentity(stsEndpoint, policy, getWebIDTokenExpiry) +} + +func newSTSWebIdentity(stsEndpoint, policy string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { if stsEndpoint == "" { return nil, errors.New("STS endpoint cannot be empty") } @@ -103,11 +120,12 @@ func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdent Transport: http.DefaultTransport, }, STSEndpoint: stsEndpoint, + Policy: policy, GetWebIDTokenExpiry: getWebIDTokenExpiry, }), nil } -func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string, +func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string, policy string, getWebIDTokenExpiry func() (*WebIdentityToken, error), ) (AssumeRoleWithWebIdentityResponse, error) { idToken, err := getWebIDTokenExpiry() @@ -133,6 +151,9 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSession if idToken.Expiry > 0 { v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry)) } + if policy != "" { + v.Set("Policy", policy) + } v.Set("Version", STSVersion) u, err := url.Parse(endpoint) @@ -183,7 +204,7 @@ func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSession // Retrieve retrieves credentials from the MinIO service. // Error will be returned if the request fails. func (m *STSWebIdentity) Retrieve() (Value, error) { - a, err := getWebIdentityCredentials(m.Client, m.STSEndpoint, m.RoleARN, m.roleSessionName, m.GetWebIDTokenExpiry) + a, err := getWebIdentityCredentials(m.Client, m.STSEndpoint, m.RoleARN, m.roleSessionName, m.Policy, m.GetWebIDTokenExpiry) if err != nil { return Value{}, err } From 305b6c44b711d3ec20f6807257355adcd584b7b8 Mon Sep 17 00:00:00 2001 From: Ramon de Klein Date: Thu, 10 Oct 2024 20:25:28 +0200 Subject: [PATCH 2/3] convert to options pattern --- pkg/credentials/sts_web_identity.go | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/pkg/credentials/sts_web_identity.go b/pkg/credentials/sts_web_identity.go index 185be0c239..da801863cc 100644 --- a/pkg/credentials/sts_web_identity.go +++ b/pkg/credentials/sts_web_identity.go @@ -94,35 +94,32 @@ type STSWebIdentity struct { // NewSTSWebIdentity returns a pointer to a new // Credentials object wrapping the STSWebIdentity. -func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { - return newSTSWebIdentity(stsEndpoint, "", getWebIDTokenExpiry) -} - -// NewSTSWebIdentityWithPolicy returns a pointer to a new -// Credentials object wrapping the STSWebIdentity that is -// scoped to the specified policy -func NewSTSWebIdentityWithPolicy(stsEndpoint, policy string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { - if policy == "" { - return nil, errors.New("policy cannot be empty") - } - return newSTSWebIdentity(stsEndpoint, policy, getWebIDTokenExpiry) -} - -func newSTSWebIdentity(stsEndpoint, policy string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { +func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error), opts ...func(*STSWebIdentity)) (*Credentials, error) { if stsEndpoint == "" { return nil, errors.New("STS endpoint cannot be empty") } if getWebIDTokenExpiry == nil { return nil, errors.New("Web ID token and expiry retrieval function should be defined") } - return New(&STSWebIdentity{ + i := &STSWebIdentity{ Client: &http.Client{ Transport: http.DefaultTransport, }, STSEndpoint: stsEndpoint, - Policy: policy, GetWebIDTokenExpiry: getWebIDTokenExpiry, - }), nil + } + for _, o := range opts { + o(i) + } + return New(i), nil +} + +// WithPolicy option will enforce that the returned credentials +// will be scoped down to the specified policy +func WithPolicy(policy string) func(*STSWebIdentity) { + return func(i *STSWebIdentity) { + i.Policy = policy + } } func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string, policy string, From fd9d19cb917e5c1de5221dc229d1e9c8f469fd5f Mon Sep 17 00:00:00 2001 From: Ramon de Klein Date: Thu, 10 Oct 2024 20:37:55 +0200 Subject: [PATCH 3/3] add `credentials.NewKubernetesIdentity` --- pkg/credentials/sts_web_identity.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/credentials/sts_web_identity.go b/pkg/credentials/sts_web_identity.go index da801863cc..f1c76c78ea 100644 --- a/pkg/credentials/sts_web_identity.go +++ b/pkg/credentials/sts_web_identity.go @@ -25,6 +25,7 @@ import ( "io" "net/http" "net/url" + "os" "strconv" "strings" "time" @@ -114,6 +115,21 @@ func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdent return New(i), nil } +// NewKubernetesIdentity returns a pointer to a new +// Credentials object using the Kubernetes service account +func NewKubernetesIdentity(stsEndpoint string, opts ...func(*STSWebIdentity)) (*Credentials, error) { + return NewSTSWebIdentity(stsEndpoint, func() (*WebIdentityToken, error) { + token, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token") + if err != nil { + return nil, err + } + + return &WebIdentityToken{ + Token: string(token), + }, nil + }, opts...) +} + // WithPolicy option will enforce that the returned credentials // will be scoped down to the specified policy func WithPolicy(policy string) func(*STSWebIdentity) {