diff options
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/pkg/credentials')
20 files changed, 2662 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/assume_role.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/assume_role.go new file mode 100644 index 0000000..800c4a2 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/assume_role.go | |||
| @@ -0,0 +1,242 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2020 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "bytes" | ||
| 22 | "crypto/sha256" | ||
| 23 | "encoding/hex" | ||
| 24 | "encoding/xml" | ||
| 25 | "errors" | ||
| 26 | "io" | ||
| 27 | "net/http" | ||
| 28 | "net/url" | ||
| 29 | "strconv" | ||
| 30 | "strings" | ||
| 31 | "time" | ||
| 32 | |||
| 33 | "github.com/minio/minio-go/v7/pkg/signer" | ||
| 34 | ) | ||
| 35 | |||
| 36 | // AssumeRoleResponse contains the result of successful AssumeRole request. | ||
| 37 | type AssumeRoleResponse struct { | ||
| 38 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleResponse" json:"-"` | ||
| 39 | |||
| 40 | Result AssumeRoleResult `xml:"AssumeRoleResult"` | ||
| 41 | ResponseMetadata struct { | ||
| 42 | RequestID string `xml:"RequestId,omitempty"` | ||
| 43 | } `xml:"ResponseMetadata,omitempty"` | ||
| 44 | } | ||
| 45 | |||
| 46 | // AssumeRoleResult - Contains the response to a successful AssumeRole | ||
| 47 | // request, including temporary credentials that can be used to make | ||
| 48 | // MinIO API requests. | ||
| 49 | type AssumeRoleResult struct { | ||
| 50 | // The identifiers for the temporary security credentials that the operation | ||
| 51 | // returns. | ||
| 52 | AssumedRoleUser AssumedRoleUser `xml:",omitempty"` | ||
| 53 | |||
| 54 | // The temporary security credentials, which include an access key ID, a secret | ||
| 55 | // access key, and a security (or session) token. | ||
| 56 | // | ||
| 57 | // Note: The size of the security token that STS APIs return is not fixed. We | ||
| 58 | // strongly recommend that you make no assumptions about the maximum size. As | ||
| 59 | // of this writing, the typical size is less than 4096 bytes, but that can vary. | ||
| 60 | // Also, future updates to AWS might require larger sizes. | ||
| 61 | Credentials struct { | ||
| 62 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
| 63 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
| 64 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
| 65 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
| 66 | } `xml:",omitempty"` | ||
| 67 | |||
| 68 | // A percentage value that indicates the size of the policy in packed form. | ||
| 69 | // The service rejects any policy with a packed size greater than 100 percent, | ||
| 70 | // which means the policy exceeded the allowed space. | ||
| 71 | PackedPolicySize int `xml:",omitempty"` | ||
| 72 | } | ||
| 73 | |||
| 74 | // A STSAssumeRole retrieves credentials from MinIO service, and keeps track if | ||
| 75 | // those credentials are expired. | ||
| 76 | type STSAssumeRole struct { | ||
| 77 | Expiry | ||
| 78 | |||
| 79 | // Required http Client to use when connecting to MinIO STS service. | ||
| 80 | Client *http.Client | ||
| 81 | |||
| 82 | // STS endpoint to fetch STS credentials. | ||
| 83 | STSEndpoint string | ||
| 84 | |||
| 85 | // various options for this request. | ||
| 86 | Options STSAssumeRoleOptions | ||
| 87 | } | ||
| 88 | |||
| 89 | // STSAssumeRoleOptions collection of various input options | ||
| 90 | // to obtain AssumeRole credentials. | ||
| 91 | type STSAssumeRoleOptions struct { | ||
| 92 | // Mandatory inputs. | ||
| 93 | AccessKey string | ||
| 94 | SecretKey string | ||
| 95 | |||
| 96 | SessionToken string // Optional if the first request is made with temporary credentials. | ||
| 97 | Policy string // Optional to assign a policy to the assumed role | ||
| 98 | |||
| 99 | Location string // Optional commonly needed with AWS STS. | ||
| 100 | DurationSeconds int // Optional defaults to 1 hour. | ||
| 101 | |||
| 102 | // Optional only valid if using with AWS STS | ||
| 103 | RoleARN string | ||
| 104 | RoleSessionName string | ||
| 105 | ExternalID string | ||
| 106 | } | ||
| 107 | |||
| 108 | // NewSTSAssumeRole returns a pointer to a new | ||
| 109 | // Credentials object wrapping the STSAssumeRole. | ||
| 110 | func NewSTSAssumeRole(stsEndpoint string, opts STSAssumeRoleOptions) (*Credentials, error) { | ||
| 111 | if stsEndpoint == "" { | ||
| 112 | return nil, errors.New("STS endpoint cannot be empty") | ||
| 113 | } | ||
| 114 | if opts.AccessKey == "" || opts.SecretKey == "" { | ||
| 115 | return nil, errors.New("AssumeRole credentials access/secretkey is mandatory") | ||
| 116 | } | ||
| 117 | return New(&STSAssumeRole{ | ||
| 118 | Client: &http.Client{ | ||
| 119 | Transport: http.DefaultTransport, | ||
| 120 | }, | ||
| 121 | STSEndpoint: stsEndpoint, | ||
| 122 | Options: opts, | ||
| 123 | }), nil | ||
| 124 | } | ||
| 125 | |||
| 126 | const defaultDurationSeconds = 3600 | ||
| 127 | |||
| 128 | // closeResponse close non nil response with any response Body. | ||
| 129 | // convenient wrapper to drain any remaining data on response body. | ||
| 130 | // | ||
| 131 | // Subsequently this allows golang http RoundTripper | ||
| 132 | // to re-use the same connection for future requests. | ||
| 133 | func closeResponse(resp *http.Response) { | ||
| 134 | // Callers should close resp.Body when done reading from it. | ||
| 135 | // If resp.Body is not closed, the Client's underlying RoundTripper | ||
| 136 | // (typically Transport) may not be able to re-use a persistent TCP | ||
| 137 | // connection to the server for a subsequent "keep-alive" request. | ||
| 138 | if resp != nil && resp.Body != nil { | ||
| 139 | // Drain any remaining Body and then close the connection. | ||
| 140 | // Without this closing connection would disallow re-using | ||
| 141 | // the same connection for future uses. | ||
| 142 | // - http://stackoverflow.com/a/17961593/4465767 | ||
| 143 | io.Copy(io.Discard, resp.Body) | ||
| 144 | resp.Body.Close() | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | func getAssumeRoleCredentials(clnt *http.Client, endpoint string, opts STSAssumeRoleOptions) (AssumeRoleResponse, error) { | ||
| 149 | v := url.Values{} | ||
| 150 | v.Set("Action", "AssumeRole") | ||
| 151 | v.Set("Version", STSVersion) | ||
| 152 | if opts.RoleARN != "" { | ||
| 153 | v.Set("RoleArn", opts.RoleARN) | ||
| 154 | } | ||
| 155 | if opts.RoleSessionName != "" { | ||
| 156 | v.Set("RoleSessionName", opts.RoleSessionName) | ||
| 157 | } | ||
| 158 | if opts.DurationSeconds > defaultDurationSeconds { | ||
| 159 | v.Set("DurationSeconds", strconv.Itoa(opts.DurationSeconds)) | ||
| 160 | } else { | ||
| 161 | v.Set("DurationSeconds", strconv.Itoa(defaultDurationSeconds)) | ||
| 162 | } | ||
| 163 | if opts.Policy != "" { | ||
| 164 | v.Set("Policy", opts.Policy) | ||
| 165 | } | ||
| 166 | if opts.ExternalID != "" { | ||
| 167 | v.Set("ExternalId", opts.ExternalID) | ||
| 168 | } | ||
| 169 | |||
| 170 | u, err := url.Parse(endpoint) | ||
| 171 | if err != nil { | ||
| 172 | return AssumeRoleResponse{}, err | ||
| 173 | } | ||
| 174 | u.Path = "/" | ||
| 175 | |||
| 176 | postBody := strings.NewReader(v.Encode()) | ||
| 177 | hash := sha256.New() | ||
| 178 | if _, err = io.Copy(hash, postBody); err != nil { | ||
| 179 | return AssumeRoleResponse{}, err | ||
| 180 | } | ||
| 181 | postBody.Seek(0, 0) | ||
| 182 | |||
| 183 | req, err := http.NewRequest(http.MethodPost, u.String(), postBody) | ||
| 184 | if err != nil { | ||
| 185 | return AssumeRoleResponse{}, err | ||
| 186 | } | ||
| 187 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
| 188 | req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(hash.Sum(nil))) | ||
| 189 | if opts.SessionToken != "" { | ||
| 190 | req.Header.Set("X-Amz-Security-Token", opts.SessionToken) | ||
| 191 | } | ||
| 192 | req = signer.SignV4STS(*req, opts.AccessKey, opts.SecretKey, opts.Location) | ||
| 193 | |||
| 194 | resp, err := clnt.Do(req) | ||
| 195 | if err != nil { | ||
| 196 | return AssumeRoleResponse{}, err | ||
| 197 | } | ||
| 198 | defer closeResponse(resp) | ||
| 199 | if resp.StatusCode != http.StatusOK { | ||
| 200 | var errResp ErrorResponse | ||
| 201 | buf, err := io.ReadAll(resp.Body) | ||
| 202 | if err != nil { | ||
| 203 | return AssumeRoleResponse{}, err | ||
| 204 | } | ||
| 205 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
| 206 | if err != nil { | ||
| 207 | var s3Err Error | ||
| 208 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
| 209 | return AssumeRoleResponse{}, err | ||
| 210 | } | ||
| 211 | errResp.RequestID = s3Err.RequestID | ||
| 212 | errResp.STSError.Code = s3Err.Code | ||
| 213 | errResp.STSError.Message = s3Err.Message | ||
| 214 | } | ||
| 215 | return AssumeRoleResponse{}, errResp | ||
| 216 | } | ||
| 217 | |||
| 218 | a := AssumeRoleResponse{} | ||
| 219 | if _, err = xmlDecodeAndBody(resp.Body, &a); err != nil { | ||
| 220 | return AssumeRoleResponse{}, err | ||
| 221 | } | ||
| 222 | return a, nil | ||
| 223 | } | ||
| 224 | |||
| 225 | // Retrieve retrieves credentials from the MinIO service. | ||
| 226 | // Error will be returned if the request fails. | ||
| 227 | func (m *STSAssumeRole) Retrieve() (Value, error) { | ||
| 228 | a, err := getAssumeRoleCredentials(m.Client, m.STSEndpoint, m.Options) | ||
| 229 | if err != nil { | ||
| 230 | return Value{}, err | ||
| 231 | } | ||
| 232 | |||
| 233 | // Expiry window is set to 10secs. | ||
| 234 | m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
| 235 | |||
| 236 | return Value{ | ||
| 237 | AccessKeyID: a.Result.Credentials.AccessKey, | ||
| 238 | SecretAccessKey: a.Result.Credentials.SecretKey, | ||
| 239 | SessionToken: a.Result.Credentials.SessionToken, | ||
| 240 | SignerType: SignatureV4, | ||
| 241 | }, nil | ||
| 242 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/chain.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/chain.go new file mode 100644 index 0000000..ddccfb1 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/chain.go | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | // A Chain will search for a provider which returns credentials | ||
| 21 | // and cache that provider until Retrieve is called again. | ||
| 22 | // | ||
| 23 | // The Chain provides a way of chaining multiple providers together | ||
| 24 | // which will pick the first available using priority order of the | ||
| 25 | // Providers in the list. | ||
| 26 | // | ||
| 27 | // If none of the Providers retrieve valid credentials Value, ChainProvider's | ||
| 28 | // Retrieve() will return the no credentials value. | ||
| 29 | // | ||
| 30 | // If a Provider is found which returns valid credentials Value ChainProvider | ||
| 31 | // will cache that Provider for all calls to IsExpired(), until Retrieve is | ||
| 32 | // called again after IsExpired() is true. | ||
| 33 | // | ||
| 34 | // creds := credentials.NewChainCredentials( | ||
| 35 | // []credentials.Provider{ | ||
| 36 | // &credentials.EnvAWSS3{}, | ||
| 37 | // &credentials.EnvMinio{}, | ||
| 38 | // }) | ||
| 39 | // | ||
| 40 | // // Usage of ChainCredentials. | ||
| 41 | // mc, err := minio.NewWithCredentials(endpoint, creds, secure, "us-east-1") | ||
| 42 | // if err != nil { | ||
| 43 | // log.Fatalln(err) | ||
| 44 | // } | ||
| 45 | type Chain struct { | ||
| 46 | Providers []Provider | ||
| 47 | curr Provider | ||
| 48 | } | ||
| 49 | |||
| 50 | // NewChainCredentials returns a pointer to a new Credentials object | ||
| 51 | // wrapping a chain of providers. | ||
| 52 | func NewChainCredentials(providers []Provider) *Credentials { | ||
| 53 | return New(&Chain{ | ||
| 54 | Providers: append([]Provider{}, providers...), | ||
| 55 | }) | ||
| 56 | } | ||
| 57 | |||
| 58 | // Retrieve returns the credentials value, returns no credentials(anonymous) | ||
| 59 | // if no credentials provider returned any value. | ||
| 60 | // | ||
| 61 | // If a provider is found with credentials, it will be cached and any calls | ||
| 62 | // to IsExpired() will return the expired state of the cached provider. | ||
| 63 | func (c *Chain) Retrieve() (Value, error) { | ||
| 64 | for _, p := range c.Providers { | ||
| 65 | creds, _ := p.Retrieve() | ||
| 66 | // Always prioritize non-anonymous providers, if any. | ||
| 67 | if creds.AccessKeyID == "" && creds.SecretAccessKey == "" { | ||
| 68 | continue | ||
| 69 | } | ||
| 70 | c.curr = p | ||
| 71 | return creds, nil | ||
| 72 | } | ||
| 73 | // At this point we have exhausted all the providers and | ||
| 74 | // are left without any credentials return anonymous. | ||
| 75 | return Value{ | ||
| 76 | SignerType: SignatureAnonymous, | ||
| 77 | }, nil | ||
| 78 | } | ||
| 79 | |||
| 80 | // IsExpired will returned the expired state of the currently cached provider | ||
| 81 | // if there is one. If there is no current provider, true will be returned. | ||
| 82 | func (c *Chain) IsExpired() bool { | ||
| 83 | if c.curr != nil { | ||
| 84 | return c.curr.IsExpired() | ||
| 85 | } | ||
| 86 | |||
| 87 | return true | ||
| 88 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/config.json.sample b/vendor/github.com/minio/minio-go/v7/pkg/credentials/config.json.sample new file mode 100644 index 0000000..d793c9e --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/config.json.sample | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | { | ||
| 2 | "version": "8", | ||
| 3 | "hosts": { | ||
| 4 | "play": { | ||
| 5 | "url": "https://play.min.io", | ||
| 6 | "accessKey": "Q3AM3UQ867SPQQA43P2F", | ||
| 7 | "secretKey": "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG", | ||
| 8 | "api": "S3v2" | ||
| 9 | }, | ||
| 10 | "s3": { | ||
| 11 | "url": "https://s3.amazonaws.com", | ||
| 12 | "accessKey": "accessKey", | ||
| 13 | "secretKey": "secret", | ||
| 14 | "api": "S3v4" | ||
| 15 | } | ||
| 16 | } | ||
| 17 | } \ No newline at end of file | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.go new file mode 100644 index 0000000..af61049 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.go | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "sync" | ||
| 22 | "time" | ||
| 23 | ) | ||
| 24 | |||
| 25 | const ( | ||
| 26 | // STSVersion sts version string | ||
| 27 | STSVersion = "2011-06-15" | ||
| 28 | |||
| 29 | // How much duration to slash from the given expiration duration | ||
| 30 | defaultExpiryWindow = 0.8 | ||
| 31 | ) | ||
| 32 | |||
| 33 | // A Value is the AWS credentials value for individual credential fields. | ||
| 34 | type Value struct { | ||
| 35 | // AWS Access key ID | ||
| 36 | AccessKeyID string | ||
| 37 | |||
| 38 | // AWS Secret Access Key | ||
| 39 | SecretAccessKey string | ||
| 40 | |||
| 41 | // AWS Session Token | ||
| 42 | SessionToken string | ||
| 43 | |||
| 44 | // Signature Type. | ||
| 45 | SignerType SignatureType | ||
| 46 | } | ||
| 47 | |||
| 48 | // A Provider is the interface for any component which will provide credentials | ||
| 49 | // Value. A provider is required to manage its own Expired state, and what to | ||
| 50 | // be expired means. | ||
| 51 | type Provider interface { | ||
| 52 | // Retrieve returns nil if it successfully retrieved the value. | ||
| 53 | // Error is returned if the value were not obtainable, or empty. | ||
| 54 | Retrieve() (Value, error) | ||
| 55 | |||
| 56 | // IsExpired returns if the credentials are no longer valid, and need | ||
| 57 | // to be retrieved. | ||
| 58 | IsExpired() bool | ||
| 59 | } | ||
| 60 | |||
| 61 | // A Expiry provides shared expiration logic to be used by credentials | ||
| 62 | // providers to implement expiry functionality. | ||
| 63 | // | ||
| 64 | // The best method to use this struct is as an anonymous field within the | ||
| 65 | // provider's struct. | ||
| 66 | // | ||
| 67 | // Example: | ||
| 68 | // | ||
| 69 | // type IAMCredentialProvider struct { | ||
| 70 | // Expiry | ||
| 71 | // ... | ||
| 72 | // } | ||
| 73 | type Expiry struct { | ||
| 74 | // The date/time when to expire on | ||
| 75 | expiration time.Time | ||
| 76 | |||
| 77 | // If set will be used by IsExpired to determine the current time. | ||
| 78 | // Defaults to time.Now if CurrentTime is not set. | ||
| 79 | CurrentTime func() time.Time | ||
| 80 | } | ||
| 81 | |||
| 82 | // SetExpiration sets the expiration IsExpired will check when called. | ||
| 83 | // | ||
| 84 | // If window is greater than 0 the expiration time will be reduced by the | ||
| 85 | // window value. | ||
| 86 | // | ||
| 87 | // Using a window is helpful to trigger credentials to expire sooner than | ||
| 88 | // the expiration time given to ensure no requests are made with expired | ||
| 89 | // tokens. | ||
| 90 | func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) { | ||
| 91 | if e.CurrentTime == nil { | ||
| 92 | e.CurrentTime = time.Now | ||
| 93 | } | ||
| 94 | cut := window | ||
| 95 | if cut < 0 { | ||
| 96 | expireIn := expiration.Sub(e.CurrentTime()) | ||
| 97 | cut = time.Duration(float64(expireIn) * (1 - defaultExpiryWindow)) | ||
| 98 | } | ||
| 99 | e.expiration = expiration.Add(-cut) | ||
| 100 | } | ||
| 101 | |||
| 102 | // IsExpired returns if the credentials are expired. | ||
| 103 | func (e *Expiry) IsExpired() bool { | ||
| 104 | if e.CurrentTime == nil { | ||
| 105 | e.CurrentTime = time.Now | ||
| 106 | } | ||
| 107 | return e.expiration.Before(e.CurrentTime()) | ||
| 108 | } | ||
| 109 | |||
| 110 | // Credentials - A container for synchronous safe retrieval of credentials Value. | ||
| 111 | // Credentials will cache the credentials value until they expire. Once the value | ||
| 112 | // expires the next Get will attempt to retrieve valid credentials. | ||
| 113 | // | ||
| 114 | // Credentials is safe to use across multiple goroutines and will manage the | ||
| 115 | // synchronous state so the Providers do not need to implement their own | ||
| 116 | // synchronization. | ||
| 117 | // | ||
| 118 | // The first Credentials.Get() will always call Provider.Retrieve() to get the | ||
| 119 | // first instance of the credentials Value. All calls to Get() after that | ||
| 120 | // will return the cached credentials Value until IsExpired() returns true. | ||
| 121 | type Credentials struct { | ||
| 122 | sync.Mutex | ||
| 123 | |||
| 124 | creds Value | ||
| 125 | forceRefresh bool | ||
| 126 | provider Provider | ||
| 127 | } | ||
| 128 | |||
| 129 | // New returns a pointer to a new Credentials with the provider set. | ||
| 130 | func New(provider Provider) *Credentials { | ||
| 131 | return &Credentials{ | ||
| 132 | provider: provider, | ||
| 133 | forceRefresh: true, | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | // Get returns the credentials value, or error if the credentials Value failed | ||
| 138 | // to be retrieved. | ||
| 139 | // | ||
| 140 | // Will return the cached credentials Value if it has not expired. If the | ||
| 141 | // credentials Value has expired the Provider's Retrieve() will be called | ||
| 142 | // to refresh the credentials. | ||
| 143 | // | ||
| 144 | // If Credentials.Expire() was called the credentials Value will be force | ||
| 145 | // expired, and the next call to Get() will cause them to be refreshed. | ||
| 146 | func (c *Credentials) Get() (Value, error) { | ||
| 147 | if c == nil { | ||
| 148 | return Value{}, nil | ||
| 149 | } | ||
| 150 | |||
| 151 | c.Lock() | ||
| 152 | defer c.Unlock() | ||
| 153 | |||
| 154 | if c.isExpired() { | ||
| 155 | creds, err := c.provider.Retrieve() | ||
| 156 | if err != nil { | ||
| 157 | return Value{}, err | ||
| 158 | } | ||
| 159 | c.creds = creds | ||
| 160 | c.forceRefresh = false | ||
| 161 | } | ||
| 162 | |||
| 163 | return c.creds, nil | ||
| 164 | } | ||
| 165 | |||
| 166 | // Expire expires the credentials and forces them to be retrieved on the | ||
| 167 | // next call to Get(). | ||
| 168 | // | ||
| 169 | // This will override the Provider's expired state, and force Credentials | ||
| 170 | // to call the Provider's Retrieve(). | ||
| 171 | func (c *Credentials) Expire() { | ||
| 172 | c.Lock() | ||
| 173 | defer c.Unlock() | ||
| 174 | |||
| 175 | c.forceRefresh = true | ||
| 176 | } | ||
| 177 | |||
| 178 | // IsExpired returns if the credentials are no longer valid, and need | ||
| 179 | // to be refreshed. | ||
| 180 | // | ||
| 181 | // If the Credentials were forced to be expired with Expire() this will | ||
| 182 | // reflect that override. | ||
| 183 | func (c *Credentials) IsExpired() bool { | ||
| 184 | c.Lock() | ||
| 185 | defer c.Unlock() | ||
| 186 | |||
| 187 | return c.isExpired() | ||
| 188 | } | ||
| 189 | |||
| 190 | // isExpired helper method wrapping the definition of expired credentials. | ||
| 191 | func (c *Credentials) isExpired() bool { | ||
| 192 | return c.forceRefresh || c.provider.IsExpired() | ||
| 193 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.json b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.json new file mode 100644 index 0000000..afbfad5 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.json | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | { | ||
| 2 | "Version": 1, | ||
| 3 | "SessionToken": "token", | ||
| 4 | "AccessKeyId": "accessKey", | ||
| 5 | "SecretAccessKey": "secret", | ||
| 6 | "Expiration": "9999-04-27T16:02:25.000Z" | ||
| 7 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.sample b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.sample new file mode 100644 index 0000000..e2dc1bf --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.sample | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | [default] | ||
| 2 | aws_access_key_id = accessKey | ||
| 3 | aws_secret_access_key = secret | ||
| 4 | aws_session_token = token | ||
| 5 | |||
| 6 | [no_token] | ||
| 7 | aws_access_key_id = accessKey | ||
| 8 | aws_secret_access_key = secret | ||
| 9 | |||
| 10 | [with_colon] | ||
| 11 | aws_access_key_id: accessKey | ||
| 12 | aws_secret_access_key: secret | ||
| 13 | |||
| 14 | [with_process] | ||
| 15 | credential_process = /bin/cat credentials.json | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/doc.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/doc.go new file mode 100644 index 0000000..fbfb105 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/doc.go | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | // Package credentials provides credential retrieval and management | ||
| 19 | // for S3 compatible object storage. | ||
| 20 | // | ||
| 21 | // By default the Credentials.Get() will cache the successful result of a | ||
| 22 | // Provider's Retrieve() until Provider.IsExpired() returns true. At which | ||
| 23 | // point Credentials will call Provider's Retrieve() to get new credential Value. | ||
| 24 | // | ||
| 25 | // The Provider is responsible for determining when credentials have expired. | ||
| 26 | // It is also important to note that Credentials will always call Retrieve the | ||
| 27 | // first time Credentials.Get() is called. | ||
| 28 | // | ||
| 29 | // Example of using the environment variable credentials. | ||
| 30 | // | ||
| 31 | // creds := NewFromEnv() | ||
| 32 | // // Retrieve the credentials value | ||
| 33 | // credValue, err := creds.Get() | ||
| 34 | // if err != nil { | ||
| 35 | // // handle error | ||
| 36 | // } | ||
| 37 | // | ||
| 38 | // Example of forcing credentials to expire and be refreshed on the next Get(). | ||
| 39 | // This may be helpful to proactively expire credentials and refresh them sooner | ||
| 40 | // than they would naturally expire on their own. | ||
| 41 | // | ||
| 42 | // creds := NewFromIAM("") | ||
| 43 | // creds.Expire() | ||
| 44 | // credsValue, err := creds.Get() | ||
| 45 | // // New credentials will be retrieved instead of from cache. | ||
| 46 | // | ||
| 47 | // # Custom Provider | ||
| 48 | // | ||
| 49 | // Each Provider built into this package also provides a helper method to generate | ||
| 50 | // a Credentials pointer setup with the provider. To use a custom Provider just | ||
| 51 | // create a type which satisfies the Provider interface and pass it to the | ||
| 52 | // NewCredentials method. | ||
| 53 | // | ||
| 54 | // type MyProvider struct{} | ||
| 55 | // func (m *MyProvider) Retrieve() (Value, error) {...} | ||
| 56 | // func (m *MyProvider) IsExpired() bool {...} | ||
| 57 | // | ||
| 58 | // creds := NewCredentials(&MyProvider{}) | ||
| 59 | // credValue, err := creds.Get() | ||
| 60 | package credentials | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_aws.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_aws.go new file mode 100644 index 0000000..b6e60d0 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_aws.go | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import "os" | ||
| 21 | |||
| 22 | // A EnvAWS retrieves credentials from the environment variables of the | ||
| 23 | // running process. EnvAWSironment credentials never expire. | ||
| 24 | // | ||
| 25 | // EnvAWSironment variables used: | ||
| 26 | // | ||
| 27 | // * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY. | ||
| 28 | // * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY. | ||
| 29 | // * Secret Token: AWS_SESSION_TOKEN. | ||
| 30 | type EnvAWS struct { | ||
| 31 | retrieved bool | ||
| 32 | } | ||
| 33 | |||
| 34 | // NewEnvAWS returns a pointer to a new Credentials object | ||
| 35 | // wrapping the environment variable provider. | ||
| 36 | func NewEnvAWS() *Credentials { | ||
| 37 | return New(&EnvAWS{}) | ||
| 38 | } | ||
| 39 | |||
| 40 | // Retrieve retrieves the keys from the environment. | ||
| 41 | func (e *EnvAWS) Retrieve() (Value, error) { | ||
| 42 | e.retrieved = false | ||
| 43 | |||
| 44 | id := os.Getenv("AWS_ACCESS_KEY_ID") | ||
| 45 | if id == "" { | ||
| 46 | id = os.Getenv("AWS_ACCESS_KEY") | ||
| 47 | } | ||
| 48 | |||
| 49 | secret := os.Getenv("AWS_SECRET_ACCESS_KEY") | ||
| 50 | if secret == "" { | ||
| 51 | secret = os.Getenv("AWS_SECRET_KEY") | ||
| 52 | } | ||
| 53 | |||
| 54 | signerType := SignatureV4 | ||
| 55 | if id == "" || secret == "" { | ||
| 56 | signerType = SignatureAnonymous | ||
| 57 | } | ||
| 58 | |||
| 59 | e.retrieved = true | ||
| 60 | return Value{ | ||
| 61 | AccessKeyID: id, | ||
| 62 | SecretAccessKey: secret, | ||
| 63 | SessionToken: os.Getenv("AWS_SESSION_TOKEN"), | ||
| 64 | SignerType: signerType, | ||
| 65 | }, nil | ||
| 66 | } | ||
| 67 | |||
| 68 | // IsExpired returns if the credentials have been retrieved. | ||
| 69 | func (e *EnvAWS) IsExpired() bool { | ||
| 70 | return !e.retrieved | ||
| 71 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_minio.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_minio.go new file mode 100644 index 0000000..5bfeab1 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/env_minio.go | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import "os" | ||
| 21 | |||
| 22 | // A EnvMinio retrieves credentials from the environment variables of the | ||
| 23 | // running process. EnvMinioironment credentials never expire. | ||
| 24 | // | ||
| 25 | // Environment variables used: | ||
| 26 | // | ||
| 27 | // * Access Key ID: MINIO_ACCESS_KEY. | ||
| 28 | // * Secret Access Key: MINIO_SECRET_KEY. | ||
| 29 | // * Access Key ID: MINIO_ROOT_USER. | ||
| 30 | // * Secret Access Key: MINIO_ROOT_PASSWORD. | ||
| 31 | type EnvMinio struct { | ||
| 32 | retrieved bool | ||
| 33 | } | ||
| 34 | |||
| 35 | // NewEnvMinio returns a pointer to a new Credentials object | ||
| 36 | // wrapping the environment variable provider. | ||
| 37 | func NewEnvMinio() *Credentials { | ||
| 38 | return New(&EnvMinio{}) | ||
| 39 | } | ||
| 40 | |||
| 41 | // Retrieve retrieves the keys from the environment. | ||
| 42 | func (e *EnvMinio) Retrieve() (Value, error) { | ||
| 43 | e.retrieved = false | ||
| 44 | |||
| 45 | id := os.Getenv("MINIO_ROOT_USER") | ||
| 46 | secret := os.Getenv("MINIO_ROOT_PASSWORD") | ||
| 47 | |||
| 48 | signerType := SignatureV4 | ||
| 49 | if id == "" || secret == "" { | ||
| 50 | id = os.Getenv("MINIO_ACCESS_KEY") | ||
| 51 | secret = os.Getenv("MINIO_SECRET_KEY") | ||
| 52 | if id == "" || secret == "" { | ||
| 53 | signerType = SignatureAnonymous | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | e.retrieved = true | ||
| 58 | return Value{ | ||
| 59 | AccessKeyID: id, | ||
| 60 | SecretAccessKey: secret, | ||
| 61 | SignerType: signerType, | ||
| 62 | }, nil | ||
| 63 | } | ||
| 64 | |||
| 65 | // IsExpired returns if the credentials have been retrieved. | ||
| 66 | func (e *EnvMinio) IsExpired() bool { | ||
| 67 | return !e.retrieved | ||
| 68 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/error_response.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/error_response.go new file mode 100644 index 0000000..07a9c2f --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/error_response.go | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2021 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "bytes" | ||
| 22 | "encoding/xml" | ||
| 23 | "fmt" | ||
| 24 | "io" | ||
| 25 | ) | ||
| 26 | |||
| 27 | // ErrorResponse - Is the typed error returned. | ||
| 28 | // ErrorResponse struct should be comparable since it is compared inside | ||
| 29 | // golang http API (https://github.com/golang/go/issues/29768) | ||
| 30 | type ErrorResponse struct { | ||
| 31 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ ErrorResponse" json:"-"` | ||
| 32 | STSError struct { | ||
| 33 | Type string `xml:"Type"` | ||
| 34 | Code string `xml:"Code"` | ||
| 35 | Message string `xml:"Message"` | ||
| 36 | } `xml:"Error"` | ||
| 37 | RequestID string `xml:"RequestId"` | ||
| 38 | } | ||
| 39 | |||
| 40 | // Error - Is the typed error returned by all API operations. | ||
| 41 | type Error struct { | ||
| 42 | XMLName xml.Name `xml:"Error" json:"-"` | ||
| 43 | Code string | ||
| 44 | Message string | ||
| 45 | BucketName string | ||
| 46 | Key string | ||
| 47 | Resource string | ||
| 48 | RequestID string `xml:"RequestId"` | ||
| 49 | HostID string `xml:"HostId"` | ||
| 50 | |||
| 51 | // Region where the bucket is located. This header is returned | ||
| 52 | // only in HEAD bucket and ListObjects response. | ||
| 53 | Region string | ||
| 54 | |||
| 55 | // Captures the server string returned in response header. | ||
| 56 | Server string | ||
| 57 | |||
| 58 | // Underlying HTTP status code for the returned error | ||
| 59 | StatusCode int `xml:"-" json:"-"` | ||
| 60 | } | ||
| 61 | |||
| 62 | // Error - Returns S3 error string. | ||
| 63 | func (e Error) Error() string { | ||
| 64 | if e.Message == "" { | ||
| 65 | return fmt.Sprintf("Error response code %s.", e.Code) | ||
| 66 | } | ||
| 67 | return e.Message | ||
| 68 | } | ||
| 69 | |||
| 70 | // Error - Returns STS error string. | ||
| 71 | func (e ErrorResponse) Error() string { | ||
| 72 | if e.STSError.Message == "" { | ||
| 73 | return fmt.Sprintf("Error response code %s.", e.STSError.Code) | ||
| 74 | } | ||
| 75 | return e.STSError.Message | ||
| 76 | } | ||
| 77 | |||
| 78 | // xmlDecoder provide decoded value in xml. | ||
| 79 | func xmlDecoder(body io.Reader, v interface{}) error { | ||
| 80 | d := xml.NewDecoder(body) | ||
| 81 | return d.Decode(v) | ||
| 82 | } | ||
| 83 | |||
| 84 | // xmlDecodeAndBody reads the whole body up to 1MB and | ||
| 85 | // tries to XML decode it into v. | ||
| 86 | // The body that was read and any error from reading or decoding is returned. | ||
| 87 | func xmlDecodeAndBody(bodyReader io.Reader, v interface{}) ([]byte, error) { | ||
| 88 | // read the whole body (up to 1MB) | ||
| 89 | const maxBodyLength = 1 << 20 | ||
| 90 | body, err := io.ReadAll(io.LimitReader(bodyReader, maxBodyLength)) | ||
| 91 | if err != nil { | ||
| 92 | return nil, err | ||
| 93 | } | ||
| 94 | return bytes.TrimSpace(body), xmlDecoder(bytes.NewReader(body), v) | ||
| 95 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go new file mode 100644 index 0000000..5b07376 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_aws_credentials.go | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "encoding/json" | ||
| 22 | "errors" | ||
| 23 | "os" | ||
| 24 | "os/exec" | ||
| 25 | "path/filepath" | ||
| 26 | "strings" | ||
| 27 | "time" | ||
| 28 | |||
| 29 | ini "gopkg.in/ini.v1" | ||
| 30 | ) | ||
| 31 | |||
| 32 | // A externalProcessCredentials stores the output of a credential_process | ||
| 33 | type externalProcessCredentials struct { | ||
| 34 | Version int | ||
| 35 | SessionToken string | ||
| 36 | AccessKeyID string `json:"AccessKeyId"` | ||
| 37 | SecretAccessKey string | ||
| 38 | Expiration time.Time | ||
| 39 | } | ||
| 40 | |||
| 41 | // A FileAWSCredentials retrieves credentials from the current user's home | ||
| 42 | // directory, and keeps track if those credentials are expired. | ||
| 43 | // | ||
| 44 | // Profile ini file example: $HOME/.aws/credentials | ||
| 45 | type FileAWSCredentials struct { | ||
| 46 | Expiry | ||
| 47 | |||
| 48 | // Path to the shared credentials file. | ||
| 49 | // | ||
| 50 | // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the | ||
| 51 | // env value is empty will default to current user's home directory. | ||
| 52 | // Linux/OSX: "$HOME/.aws/credentials" | ||
| 53 | // Windows: "%USERPROFILE%\.aws\credentials" | ||
| 54 | Filename string | ||
| 55 | |||
| 56 | // AWS Profile to extract credentials from the shared credentials file. If empty | ||
| 57 | // will default to environment variable "AWS_PROFILE" or "default" if | ||
| 58 | // environment variable is also not set. | ||
| 59 | Profile string | ||
| 60 | |||
| 61 | // retrieved states if the credentials have been successfully retrieved. | ||
| 62 | retrieved bool | ||
| 63 | } | ||
| 64 | |||
| 65 | // NewFileAWSCredentials returns a pointer to a new Credentials object | ||
| 66 | // wrapping the Profile file provider. | ||
| 67 | func NewFileAWSCredentials(filename, profile string) *Credentials { | ||
| 68 | return New(&FileAWSCredentials{ | ||
| 69 | Filename: filename, | ||
| 70 | Profile: profile, | ||
| 71 | }) | ||
| 72 | } | ||
| 73 | |||
| 74 | // Retrieve reads and extracts the shared credentials from the current | ||
| 75 | // users home directory. | ||
| 76 | func (p *FileAWSCredentials) Retrieve() (Value, error) { | ||
| 77 | if p.Filename == "" { | ||
| 78 | p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE") | ||
| 79 | if p.Filename == "" { | ||
| 80 | homeDir, err := os.UserHomeDir() | ||
| 81 | if err != nil { | ||
| 82 | return Value{}, err | ||
| 83 | } | ||
| 84 | p.Filename = filepath.Join(homeDir, ".aws", "credentials") | ||
| 85 | } | ||
| 86 | } | ||
| 87 | if p.Profile == "" { | ||
| 88 | p.Profile = os.Getenv("AWS_PROFILE") | ||
| 89 | if p.Profile == "" { | ||
| 90 | p.Profile = "default" | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | p.retrieved = false | ||
| 95 | |||
| 96 | iniProfile, err := loadProfile(p.Filename, p.Profile) | ||
| 97 | if err != nil { | ||
| 98 | return Value{}, err | ||
| 99 | } | ||
| 100 | |||
| 101 | // Default to empty string if not found. | ||
| 102 | id := iniProfile.Key("aws_access_key_id") | ||
| 103 | // Default to empty string if not found. | ||
| 104 | secret := iniProfile.Key("aws_secret_access_key") | ||
| 105 | // Default to empty string if not found. | ||
| 106 | token := iniProfile.Key("aws_session_token") | ||
| 107 | |||
| 108 | // If credential_process is defined, obtain credentials by executing | ||
| 109 | // the external process | ||
| 110 | credentialProcess := strings.TrimSpace(iniProfile.Key("credential_process").String()) | ||
| 111 | if credentialProcess != "" { | ||
| 112 | args := strings.Fields(credentialProcess) | ||
| 113 | if len(args) <= 1 { | ||
| 114 | return Value{}, errors.New("invalid credential process args") | ||
| 115 | } | ||
| 116 | cmd := exec.Command(args[0], args[1:]...) | ||
| 117 | out, err := cmd.Output() | ||
| 118 | if err != nil { | ||
| 119 | return Value{}, err | ||
| 120 | } | ||
| 121 | var externalProcessCredentials externalProcessCredentials | ||
| 122 | err = json.Unmarshal([]byte(out), &externalProcessCredentials) | ||
| 123 | if err != nil { | ||
| 124 | return Value{}, err | ||
| 125 | } | ||
| 126 | p.retrieved = true | ||
| 127 | p.SetExpiration(externalProcessCredentials.Expiration, DefaultExpiryWindow) | ||
| 128 | return Value{ | ||
| 129 | AccessKeyID: externalProcessCredentials.AccessKeyID, | ||
| 130 | SecretAccessKey: externalProcessCredentials.SecretAccessKey, | ||
| 131 | SessionToken: externalProcessCredentials.SessionToken, | ||
| 132 | SignerType: SignatureV4, | ||
| 133 | }, nil | ||
| 134 | } | ||
| 135 | p.retrieved = true | ||
| 136 | return Value{ | ||
| 137 | AccessKeyID: id.String(), | ||
| 138 | SecretAccessKey: secret.String(), | ||
| 139 | SessionToken: token.String(), | ||
| 140 | SignerType: SignatureV4, | ||
| 141 | }, nil | ||
| 142 | } | ||
| 143 | |||
| 144 | // loadProfiles loads from the file pointed to by shared credentials filename for profile. | ||
| 145 | // The credentials retrieved from the profile will be returned or error. Error will be | ||
| 146 | // returned if it fails to read from the file, or the data is invalid. | ||
| 147 | func loadProfile(filename, profile string) (*ini.Section, error) { | ||
| 148 | config, err := ini.Load(filename) | ||
| 149 | if err != nil { | ||
| 150 | return nil, err | ||
| 151 | } | ||
| 152 | iniProfile, err := config.GetSection(profile) | ||
| 153 | if err != nil { | ||
| 154 | return nil, err | ||
| 155 | } | ||
| 156 | return iniProfile, nil | ||
| 157 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go new file mode 100644 index 0000000..eb77767 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/file_minio_client.go | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "os" | ||
| 22 | "path/filepath" | ||
| 23 | "runtime" | ||
| 24 | |||
| 25 | jsoniter "github.com/json-iterator/go" | ||
| 26 | ) | ||
| 27 | |||
| 28 | // A FileMinioClient retrieves credentials from the current user's home | ||
| 29 | // directory, and keeps track if those credentials are expired. | ||
| 30 | // | ||
| 31 | // Configuration file example: $HOME/.mc/config.json | ||
| 32 | type FileMinioClient struct { | ||
| 33 | // Path to the shared credentials file. | ||
| 34 | // | ||
| 35 | // If empty will look for "MINIO_SHARED_CREDENTIALS_FILE" env variable. If the | ||
| 36 | // env value is empty will default to current user's home directory. | ||
| 37 | // Linux/OSX: "$HOME/.mc/config.json" | ||
| 38 | // Windows: "%USERALIAS%\mc\config.json" | ||
| 39 | Filename string | ||
| 40 | |||
| 41 | // MinIO Alias to extract credentials from the shared credentials file. If empty | ||
| 42 | // will default to environment variable "MINIO_ALIAS" or "default" if | ||
| 43 | // environment variable is also not set. | ||
| 44 | Alias string | ||
| 45 | |||
| 46 | // retrieved states if the credentials have been successfully retrieved. | ||
| 47 | retrieved bool | ||
| 48 | } | ||
| 49 | |||
| 50 | // NewFileMinioClient returns a pointer to a new Credentials object | ||
| 51 | // wrapping the Alias file provider. | ||
| 52 | func NewFileMinioClient(filename, alias string) *Credentials { | ||
| 53 | return New(&FileMinioClient{ | ||
| 54 | Filename: filename, | ||
| 55 | Alias: alias, | ||
| 56 | }) | ||
| 57 | } | ||
| 58 | |||
| 59 | // Retrieve reads and extracts the shared credentials from the current | ||
| 60 | // users home directory. | ||
| 61 | func (p *FileMinioClient) Retrieve() (Value, error) { | ||
| 62 | if p.Filename == "" { | ||
| 63 | if value, ok := os.LookupEnv("MINIO_SHARED_CREDENTIALS_FILE"); ok { | ||
| 64 | p.Filename = value | ||
| 65 | } else { | ||
| 66 | homeDir, err := os.UserHomeDir() | ||
| 67 | if err != nil { | ||
| 68 | return Value{}, err | ||
| 69 | } | ||
| 70 | p.Filename = filepath.Join(homeDir, ".mc", "config.json") | ||
| 71 | if runtime.GOOS == "windows" { | ||
| 72 | p.Filename = filepath.Join(homeDir, "mc", "config.json") | ||
| 73 | } | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | if p.Alias == "" { | ||
| 78 | p.Alias = os.Getenv("MINIO_ALIAS") | ||
| 79 | if p.Alias == "" { | ||
| 80 | p.Alias = "s3" | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | p.retrieved = false | ||
| 85 | |||
| 86 | hostCfg, err := loadAlias(p.Filename, p.Alias) | ||
| 87 | if err != nil { | ||
| 88 | return Value{}, err | ||
| 89 | } | ||
| 90 | |||
| 91 | p.retrieved = true | ||
| 92 | return Value{ | ||
| 93 | AccessKeyID: hostCfg.AccessKey, | ||
| 94 | SecretAccessKey: hostCfg.SecretKey, | ||
| 95 | SignerType: parseSignatureType(hostCfg.API), | ||
| 96 | }, nil | ||
| 97 | } | ||
| 98 | |||
| 99 | // IsExpired returns if the shared credentials have expired. | ||
| 100 | func (p *FileMinioClient) IsExpired() bool { | ||
| 101 | return !p.retrieved | ||
| 102 | } | ||
| 103 | |||
| 104 | // hostConfig configuration of a host. | ||
| 105 | type hostConfig struct { | ||
| 106 | URL string `json:"url"` | ||
| 107 | AccessKey string `json:"accessKey"` | ||
| 108 | SecretKey string `json:"secretKey"` | ||
| 109 | API string `json:"api"` | ||
| 110 | } | ||
| 111 | |||
| 112 | // config config version. | ||
| 113 | type config struct { | ||
| 114 | Version string `json:"version"` | ||
| 115 | Hosts map[string]hostConfig `json:"hosts"` | ||
| 116 | Aliases map[string]hostConfig `json:"aliases"` | ||
| 117 | } | ||
| 118 | |||
| 119 | // loadAliass loads from the file pointed to by shared credentials filename for alias. | ||
| 120 | // The credentials retrieved from the alias will be returned or error. Error will be | ||
| 121 | // returned if it fails to read from the file. | ||
| 122 | func loadAlias(filename, alias string) (hostConfig, error) { | ||
| 123 | cfg := &config{} | ||
| 124 | json := jsoniter.ConfigCompatibleWithStandardLibrary | ||
| 125 | |||
| 126 | configBytes, err := os.ReadFile(filename) | ||
| 127 | if err != nil { | ||
| 128 | return hostConfig{}, err | ||
| 129 | } | ||
| 130 | if err = json.Unmarshal(configBytes, cfg); err != nil { | ||
| 131 | return hostConfig{}, err | ||
| 132 | } | ||
| 133 | |||
| 134 | if cfg.Version == "10" { | ||
| 135 | return cfg.Aliases[alias], nil | ||
| 136 | } | ||
| 137 | |||
| 138 | return cfg.Hosts[alias], nil | ||
| 139 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/iam_aws.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/iam_aws.go new file mode 100644 index 0000000..c5153c4 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/iam_aws.go | |||
| @@ -0,0 +1,433 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "bufio" | ||
| 22 | "context" | ||
| 23 | "errors" | ||
| 24 | "fmt" | ||
| 25 | "io" | ||
| 26 | "net" | ||
| 27 | "net/http" | ||
| 28 | "net/url" | ||
| 29 | "os" | ||
| 30 | "path" | ||
| 31 | "strings" | ||
| 32 | "time" | ||
| 33 | |||
| 34 | jsoniter "github.com/json-iterator/go" | ||
| 35 | ) | ||
| 36 | |||
| 37 | // DefaultExpiryWindow - Default expiry window. | ||
| 38 | // ExpiryWindow will allow the credentials to trigger refreshing | ||
| 39 | // prior to the credentials actually expiring. This is beneficial | ||
| 40 | // so race conditions with expiring credentials do not cause | ||
| 41 | // request to fail unexpectedly due to ExpiredTokenException exceptions. | ||
| 42 | // DefaultExpiryWindow can be used as parameter to (*Expiry).SetExpiration. | ||
| 43 | // When used the tokens refresh will be triggered when 80% of the elapsed | ||
| 44 | // time until the actual expiration time is passed. | ||
| 45 | const DefaultExpiryWindow = -1 | ||
| 46 | |||
| 47 | // A IAM retrieves credentials from the EC2 service, and keeps track if | ||
| 48 | // those credentials are expired. | ||
| 49 | type IAM struct { | ||
| 50 | Expiry | ||
| 51 | |||
| 52 | // Required http Client to use when connecting to IAM metadata service. | ||
| 53 | Client *http.Client | ||
| 54 | |||
| 55 | // Custom endpoint to fetch IAM role credentials. | ||
| 56 | Endpoint string | ||
| 57 | |||
| 58 | // Region configurable custom region for STS | ||
| 59 | Region string | ||
| 60 | |||
| 61 | // Support for container authorization token https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html | ||
| 62 | Container struct { | ||
| 63 | AuthorizationToken string | ||
| 64 | CredentialsFullURI string | ||
| 65 | CredentialsRelativeURI string | ||
| 66 | } | ||
| 67 | |||
| 68 | // EKS based k8s RBAC authorization - https://docs.aws.amazon.com/eks/latest/userguide/pod-configuration.html | ||
| 69 | EKSIdentity struct { | ||
| 70 | TokenFile string | ||
| 71 | RoleARN string | ||
| 72 | RoleSessionName string | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | // IAM Roles for Amazon EC2 | ||
| 77 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
| 78 | const ( | ||
| 79 | DefaultIAMRoleEndpoint = "http://169.254.169.254" | ||
| 80 | DefaultECSRoleEndpoint = "http://169.254.170.2" | ||
| 81 | DefaultSTSRoleEndpoint = "https://sts.amazonaws.com" | ||
| 82 | DefaultIAMSecurityCredsPath = "/latest/meta-data/iam/security-credentials/" | ||
| 83 | TokenRequestTTLHeader = "X-aws-ec2-metadata-token-ttl-seconds" | ||
| 84 | TokenPath = "/latest/api/token" | ||
| 85 | TokenTTL = "21600" | ||
| 86 | TokenRequestHeader = "X-aws-ec2-metadata-token" | ||
| 87 | ) | ||
| 88 | |||
| 89 | // NewIAM returns a pointer to a new Credentials object wrapping the IAM. | ||
| 90 | func NewIAM(endpoint string) *Credentials { | ||
| 91 | return New(&IAM{ | ||
| 92 | Client: &http.Client{ | ||
| 93 | Transport: http.DefaultTransport, | ||
| 94 | }, | ||
| 95 | Endpoint: endpoint, | ||
| 96 | }) | ||
| 97 | } | ||
| 98 | |||
| 99 | // Retrieve retrieves credentials from the EC2 service. | ||
| 100 | // Error will be returned if the request fails, or unable to extract | ||
| 101 | // the desired | ||
| 102 | func (m *IAM) Retrieve() (Value, error) { | ||
| 103 | token := os.Getenv("AWS_CONTAINER_AUTHORIZATION_TOKEN") | ||
| 104 | if token == "" { | ||
| 105 | token = m.Container.AuthorizationToken | ||
| 106 | } | ||
| 107 | |||
| 108 | relativeURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI") | ||
| 109 | if relativeURI == "" { | ||
| 110 | relativeURI = m.Container.CredentialsRelativeURI | ||
| 111 | } | ||
| 112 | |||
| 113 | fullURI := os.Getenv("AWS_CONTAINER_CREDENTIALS_FULL_URI") | ||
| 114 | if fullURI == "" { | ||
| 115 | fullURI = m.Container.CredentialsFullURI | ||
| 116 | } | ||
| 117 | |||
| 118 | identityFile := os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE") | ||
| 119 | if identityFile == "" { | ||
| 120 | identityFile = m.EKSIdentity.TokenFile | ||
| 121 | } | ||
| 122 | |||
| 123 | roleArn := os.Getenv("AWS_ROLE_ARN") | ||
| 124 | if roleArn == "" { | ||
| 125 | roleArn = m.EKSIdentity.RoleARN | ||
| 126 | } | ||
| 127 | |||
| 128 | roleSessionName := os.Getenv("AWS_ROLE_SESSION_NAME") | ||
| 129 | if roleSessionName == "" { | ||
| 130 | roleSessionName = m.EKSIdentity.RoleSessionName | ||
| 131 | } | ||
| 132 | |||
| 133 | region := os.Getenv("AWS_REGION") | ||
| 134 | if region == "" { | ||
| 135 | region = m.Region | ||
| 136 | } | ||
| 137 | |||
| 138 | var roleCreds ec2RoleCredRespBody | ||
| 139 | var err error | ||
| 140 | |||
| 141 | endpoint := m.Endpoint | ||
| 142 | switch { | ||
| 143 | case identityFile != "": | ||
| 144 | if len(endpoint) == 0 { | ||
| 145 | if region != "" { | ||
| 146 | if strings.HasPrefix(region, "cn-") { | ||
| 147 | endpoint = "https://sts." + region + ".amazonaws.com.cn" | ||
| 148 | } else { | ||
| 149 | endpoint = "https://sts." + region + ".amazonaws.com" | ||
| 150 | } | ||
| 151 | } else { | ||
| 152 | endpoint = DefaultSTSRoleEndpoint | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | creds := &STSWebIdentity{ | ||
| 157 | Client: m.Client, | ||
| 158 | STSEndpoint: endpoint, | ||
| 159 | GetWebIDTokenExpiry: func() (*WebIdentityToken, error) { | ||
| 160 | token, err := os.ReadFile(identityFile) | ||
| 161 | if err != nil { | ||
| 162 | return nil, err | ||
| 163 | } | ||
| 164 | |||
| 165 | return &WebIdentityToken{Token: string(token)}, nil | ||
| 166 | }, | ||
| 167 | RoleARN: roleArn, | ||
| 168 | roleSessionName: roleSessionName, | ||
| 169 | } | ||
| 170 | |||
| 171 | stsWebIdentityCreds, err := creds.Retrieve() | ||
| 172 | if err == nil { | ||
| 173 | m.SetExpiration(creds.Expiration(), DefaultExpiryWindow) | ||
| 174 | } | ||
| 175 | return stsWebIdentityCreds, err | ||
| 176 | |||
| 177 | case relativeURI != "": | ||
| 178 | if len(endpoint) == 0 { | ||
| 179 | endpoint = fmt.Sprintf("%s%s", DefaultECSRoleEndpoint, relativeURI) | ||
| 180 | } | ||
| 181 | |||
| 182 | roleCreds, err = getEcsTaskCredentials(m.Client, endpoint, token) | ||
| 183 | |||
| 184 | case fullURI != "": | ||
| 185 | if len(endpoint) == 0 { | ||
| 186 | endpoint = fullURI | ||
| 187 | var ok bool | ||
| 188 | if ok, err = isLoopback(endpoint); !ok { | ||
| 189 | if err == nil { | ||
| 190 | err = fmt.Errorf("uri host is not a loopback address: %s", endpoint) | ||
| 191 | } | ||
| 192 | break | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | roleCreds, err = getEcsTaskCredentials(m.Client, endpoint, token) | ||
| 197 | |||
| 198 | default: | ||
| 199 | roleCreds, err = getCredentials(m.Client, endpoint) | ||
| 200 | } | ||
| 201 | |||
| 202 | if err != nil { | ||
| 203 | return Value{}, err | ||
| 204 | } | ||
| 205 | // Expiry window is set to 10secs. | ||
| 206 | m.SetExpiration(roleCreds.Expiration, DefaultExpiryWindow) | ||
| 207 | |||
| 208 | return Value{ | ||
| 209 | AccessKeyID: roleCreds.AccessKeyID, | ||
| 210 | SecretAccessKey: roleCreds.SecretAccessKey, | ||
| 211 | SessionToken: roleCreds.Token, | ||
| 212 | SignerType: SignatureV4, | ||
| 213 | }, nil | ||
| 214 | } | ||
| 215 | |||
| 216 | // A ec2RoleCredRespBody provides the shape for unmarshaling credential | ||
| 217 | // request responses. | ||
| 218 | type ec2RoleCredRespBody struct { | ||
| 219 | // Success State | ||
| 220 | Expiration time.Time | ||
| 221 | AccessKeyID string | ||
| 222 | SecretAccessKey string | ||
| 223 | Token string | ||
| 224 | |||
| 225 | // Error state | ||
| 226 | Code string | ||
| 227 | Message string | ||
| 228 | |||
| 229 | // Unused params. | ||
| 230 | LastUpdated time.Time | ||
| 231 | Type string | ||
| 232 | } | ||
| 233 | |||
| 234 | // Get the final IAM role URL where the request will | ||
| 235 | // be sent to fetch the rolling access credentials. | ||
| 236 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
| 237 | func getIAMRoleURL(endpoint string) (*url.URL, error) { | ||
| 238 | u, err := url.Parse(endpoint) | ||
| 239 | if err != nil { | ||
| 240 | return nil, err | ||
| 241 | } | ||
| 242 | u.Path = DefaultIAMSecurityCredsPath | ||
| 243 | return u, nil | ||
| 244 | } | ||
| 245 | |||
| 246 | // listRoleNames lists of credential role names associated | ||
| 247 | // with the current EC2 service. If there are no credentials, | ||
| 248 | // or there is an error making or receiving the request. | ||
| 249 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
| 250 | func listRoleNames(client *http.Client, u *url.URL, token string) ([]string, error) { | ||
| 251 | req, err := http.NewRequest(http.MethodGet, u.String(), nil) | ||
| 252 | if err != nil { | ||
| 253 | return nil, err | ||
| 254 | } | ||
| 255 | if token != "" { | ||
| 256 | req.Header.Add(TokenRequestHeader, token) | ||
| 257 | } | ||
| 258 | resp, err := client.Do(req) | ||
| 259 | if err != nil { | ||
| 260 | return nil, err | ||
| 261 | } | ||
| 262 | defer resp.Body.Close() | ||
| 263 | if resp.StatusCode != http.StatusOK { | ||
| 264 | return nil, errors.New(resp.Status) | ||
| 265 | } | ||
| 266 | |||
| 267 | credsList := []string{} | ||
| 268 | s := bufio.NewScanner(resp.Body) | ||
| 269 | for s.Scan() { | ||
| 270 | credsList = append(credsList, s.Text()) | ||
| 271 | } | ||
| 272 | |||
| 273 | if err := s.Err(); err != nil { | ||
| 274 | return nil, err | ||
| 275 | } | ||
| 276 | |||
| 277 | return credsList, nil | ||
| 278 | } | ||
| 279 | |||
| 280 | func getEcsTaskCredentials(client *http.Client, endpoint, token string) (ec2RoleCredRespBody, error) { | ||
| 281 | req, err := http.NewRequest(http.MethodGet, endpoint, nil) | ||
| 282 | if err != nil { | ||
| 283 | return ec2RoleCredRespBody{}, err | ||
| 284 | } | ||
| 285 | |||
| 286 | if token != "" { | ||
| 287 | req.Header.Set("Authorization", token) | ||
| 288 | } | ||
| 289 | |||
| 290 | resp, err := client.Do(req) | ||
| 291 | if err != nil { | ||
| 292 | return ec2RoleCredRespBody{}, err | ||
| 293 | } | ||
| 294 | defer resp.Body.Close() | ||
| 295 | if resp.StatusCode != http.StatusOK { | ||
| 296 | return ec2RoleCredRespBody{}, errors.New(resp.Status) | ||
| 297 | } | ||
| 298 | |||
| 299 | respCreds := ec2RoleCredRespBody{} | ||
| 300 | if err := jsoniter.NewDecoder(resp.Body).Decode(&respCreds); err != nil { | ||
| 301 | return ec2RoleCredRespBody{}, err | ||
| 302 | } | ||
| 303 | |||
| 304 | return respCreds, nil | ||
| 305 | } | ||
| 306 | |||
| 307 | func fetchIMDSToken(client *http.Client, endpoint string) (string, error) { | ||
| 308 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
| 309 | defer cancel() | ||
| 310 | |||
| 311 | req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint+TokenPath, nil) | ||
| 312 | if err != nil { | ||
| 313 | return "", err | ||
| 314 | } | ||
| 315 | req.Header.Add(TokenRequestTTLHeader, TokenTTL) | ||
| 316 | resp, err := client.Do(req) | ||
| 317 | if err != nil { | ||
| 318 | return "", err | ||
| 319 | } | ||
| 320 | defer resp.Body.Close() | ||
| 321 | data, err := io.ReadAll(resp.Body) | ||
| 322 | if err != nil { | ||
| 323 | return "", err | ||
| 324 | } | ||
| 325 | if resp.StatusCode != http.StatusOK { | ||
| 326 | return "", errors.New(resp.Status) | ||
| 327 | } | ||
| 328 | return string(data), nil | ||
| 329 | } | ||
| 330 | |||
| 331 | // getCredentials - obtains the credentials from the IAM role name associated with | ||
| 332 | // the current EC2 service. | ||
| 333 | // | ||
| 334 | // If the credentials cannot be found, or there is an error | ||
| 335 | // reading the response an error will be returned. | ||
| 336 | func getCredentials(client *http.Client, endpoint string) (ec2RoleCredRespBody, error) { | ||
| 337 | if endpoint == "" { | ||
| 338 | endpoint = DefaultIAMRoleEndpoint | ||
| 339 | } | ||
| 340 | |||
| 341 | // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html | ||
| 342 | token, err := fetchIMDSToken(client, endpoint) | ||
| 343 | if err != nil { | ||
| 344 | // Return only errors for valid situations, if the IMDSv2 is not enabled | ||
| 345 | // we will not be able to get the token, in such a situation we have | ||
| 346 | // to rely on IMDSv1 behavior as a fallback, this check ensures that. | ||
| 347 | // Refer https://github.com/minio/minio-go/issues/1866 | ||
| 348 | if !errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, context.Canceled) { | ||
| 349 | return ec2RoleCredRespBody{}, err | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
| 354 | u, err := getIAMRoleURL(endpoint) | ||
| 355 | if err != nil { | ||
| 356 | return ec2RoleCredRespBody{}, err | ||
| 357 | } | ||
| 358 | |||
| 359 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
| 360 | roleNames, err := listRoleNames(client, u, token) | ||
| 361 | if err != nil { | ||
| 362 | return ec2RoleCredRespBody{}, err | ||
| 363 | } | ||
| 364 | |||
| 365 | if len(roleNames) == 0 { | ||
| 366 | return ec2RoleCredRespBody{}, errors.New("No IAM roles attached to this EC2 service") | ||
| 367 | } | ||
| 368 | |||
| 369 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
| 370 | // - An instance profile can contain only one IAM role. This limit cannot be increased. | ||
| 371 | roleName := roleNames[0] | ||
| 372 | |||
| 373 | // http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html | ||
| 374 | // The following command retrieves the security credentials for an | ||
| 375 | // IAM role named `s3access`. | ||
| 376 | // | ||
| 377 | // $ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access | ||
| 378 | // | ||
| 379 | u.Path = path.Join(u.Path, roleName) | ||
| 380 | req, err := http.NewRequest(http.MethodGet, u.String(), nil) | ||
| 381 | if err != nil { | ||
| 382 | return ec2RoleCredRespBody{}, err | ||
| 383 | } | ||
| 384 | if token != "" { | ||
| 385 | req.Header.Add(TokenRequestHeader, token) | ||
| 386 | } | ||
| 387 | |||
| 388 | resp, err := client.Do(req) | ||
| 389 | if err != nil { | ||
| 390 | return ec2RoleCredRespBody{}, err | ||
| 391 | } | ||
| 392 | defer resp.Body.Close() | ||
| 393 | if resp.StatusCode != http.StatusOK { | ||
| 394 | return ec2RoleCredRespBody{}, errors.New(resp.Status) | ||
| 395 | } | ||
| 396 | |||
| 397 | respCreds := ec2RoleCredRespBody{} | ||
| 398 | if err := jsoniter.NewDecoder(resp.Body).Decode(&respCreds); err != nil { | ||
| 399 | return ec2RoleCredRespBody{}, err | ||
| 400 | } | ||
| 401 | |||
| 402 | if respCreds.Code != "Success" { | ||
| 403 | // If an error code was returned something failed requesting the role. | ||
| 404 | return ec2RoleCredRespBody{}, errors.New(respCreds.Message) | ||
| 405 | } | ||
| 406 | |||
| 407 | return respCreds, nil | ||
| 408 | } | ||
| 409 | |||
| 410 | // isLoopback identifies if a uri's host is on a loopback address | ||
| 411 | func isLoopback(uri string) (bool, error) { | ||
| 412 | u, err := url.Parse(uri) | ||
| 413 | if err != nil { | ||
| 414 | return false, err | ||
| 415 | } | ||
| 416 | |||
| 417 | host := u.Hostname() | ||
| 418 | if len(host) == 0 { | ||
| 419 | return false, fmt.Errorf("can't parse host from uri: %s", uri) | ||
| 420 | } | ||
| 421 | |||
| 422 | ips, err := net.LookupHost(host) | ||
| 423 | if err != nil { | ||
| 424 | return false, err | ||
| 425 | } | ||
| 426 | for _, ip := range ips { | ||
| 427 | if !net.ParseIP(ip).IsLoopback() { | ||
| 428 | return false, nil | ||
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 432 | return true, nil | ||
| 433 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/signature_type.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/signature_type.go new file mode 100644 index 0000000..b794333 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/signature_type.go | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import "strings" | ||
| 21 | |||
| 22 | // SignatureType is type of Authorization requested for a given HTTP request. | ||
| 23 | type SignatureType int | ||
| 24 | |||
| 25 | // Different types of supported signatures - default is SignatureV4 or SignatureDefault. | ||
| 26 | const ( | ||
| 27 | // SignatureDefault is always set to v4. | ||
| 28 | SignatureDefault SignatureType = iota | ||
| 29 | SignatureV4 | ||
| 30 | SignatureV2 | ||
| 31 | SignatureV4Streaming | ||
| 32 | SignatureAnonymous // Anonymous signature signifies, no signature. | ||
| 33 | ) | ||
| 34 | |||
| 35 | // IsV2 - is signature SignatureV2? | ||
| 36 | func (s SignatureType) IsV2() bool { | ||
| 37 | return s == SignatureV2 | ||
| 38 | } | ||
| 39 | |||
| 40 | // IsV4 - is signature SignatureV4? | ||
| 41 | func (s SignatureType) IsV4() bool { | ||
| 42 | return s == SignatureV4 || s == SignatureDefault | ||
| 43 | } | ||
| 44 | |||
| 45 | // IsStreamingV4 - is signature SignatureV4Streaming? | ||
| 46 | func (s SignatureType) IsStreamingV4() bool { | ||
| 47 | return s == SignatureV4Streaming | ||
| 48 | } | ||
| 49 | |||
| 50 | // IsAnonymous - is signature empty? | ||
| 51 | func (s SignatureType) IsAnonymous() bool { | ||
| 52 | return s == SignatureAnonymous | ||
| 53 | } | ||
| 54 | |||
| 55 | // Stringer humanized version of signature type, | ||
| 56 | // strings returned here are case insensitive. | ||
| 57 | func (s SignatureType) String() string { | ||
| 58 | if s.IsV2() { | ||
| 59 | return "S3v2" | ||
| 60 | } else if s.IsV4() { | ||
| 61 | return "S3v4" | ||
| 62 | } else if s.IsStreamingV4() { | ||
| 63 | return "S3v4Streaming" | ||
| 64 | } | ||
| 65 | return "Anonymous" | ||
| 66 | } | ||
| 67 | |||
| 68 | func parseSignatureType(str string) SignatureType { | ||
| 69 | if strings.EqualFold(str, "S3v4") { | ||
| 70 | return SignatureV4 | ||
| 71 | } else if strings.EqualFold(str, "S3v2") { | ||
| 72 | return SignatureV2 | ||
| 73 | } else if strings.EqualFold(str, "S3v4Streaming") { | ||
| 74 | return SignatureV4Streaming | ||
| 75 | } | ||
| 76 | return SignatureAnonymous | ||
| 77 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/static.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/static.go new file mode 100644 index 0000000..7dde00b --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/static.go | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2017 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | // A Static is a set of credentials which are set programmatically, | ||
| 21 | // and will never expire. | ||
| 22 | type Static struct { | ||
| 23 | Value | ||
| 24 | } | ||
| 25 | |||
| 26 | // NewStaticV2 returns a pointer to a new Credentials object | ||
| 27 | // wrapping a static credentials value provider, signature is | ||
| 28 | // set to v2. If access and secret are not specified then | ||
| 29 | // regardless of signature type set it Value will return | ||
| 30 | // as anonymous. | ||
| 31 | func NewStaticV2(id, secret, token string) *Credentials { | ||
| 32 | return NewStatic(id, secret, token, SignatureV2) | ||
| 33 | } | ||
| 34 | |||
| 35 | // NewStaticV4 is similar to NewStaticV2 with similar considerations. | ||
| 36 | func NewStaticV4(id, secret, token string) *Credentials { | ||
| 37 | return NewStatic(id, secret, token, SignatureV4) | ||
| 38 | } | ||
| 39 | |||
| 40 | // NewStatic returns a pointer to a new Credentials object | ||
| 41 | // wrapping a static credentials value provider. | ||
| 42 | func NewStatic(id, secret, token string, signerType SignatureType) *Credentials { | ||
| 43 | return New(&Static{ | ||
| 44 | Value: Value{ | ||
| 45 | AccessKeyID: id, | ||
| 46 | SecretAccessKey: secret, | ||
| 47 | SessionToken: token, | ||
| 48 | SignerType: signerType, | ||
| 49 | }, | ||
| 50 | }) | ||
| 51 | } | ||
| 52 | |||
| 53 | // Retrieve returns the static credentials. | ||
| 54 | func (s *Static) Retrieve() (Value, error) { | ||
| 55 | if s.AccessKeyID == "" || s.SecretAccessKey == "" { | ||
| 56 | // Anonymous is not an error | ||
| 57 | return Value{SignerType: SignatureAnonymous}, nil | ||
| 58 | } | ||
| 59 | return s.Value, nil | ||
| 60 | } | ||
| 61 | |||
| 62 | // IsExpired returns if the credentials are expired. | ||
| 63 | // | ||
| 64 | // For Static, the credentials never expired. | ||
| 65 | func (s *Static) IsExpired() bool { | ||
| 66 | return false | ||
| 67 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_client_grants.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_client_grants.go new file mode 100644 index 0000000..9e92c1e --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_client_grants.go | |||
| @@ -0,0 +1,182 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2019-2022 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "bytes" | ||
| 22 | "encoding/xml" | ||
| 23 | "errors" | ||
| 24 | "fmt" | ||
| 25 | "io" | ||
| 26 | "net/http" | ||
| 27 | "net/url" | ||
| 28 | "strings" | ||
| 29 | "time" | ||
| 30 | ) | ||
| 31 | |||
| 32 | // AssumedRoleUser - The identifiers for the temporary security credentials that | ||
| 33 | // the operation returns. Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser | ||
| 34 | type AssumedRoleUser struct { | ||
| 35 | Arn string | ||
| 36 | AssumedRoleID string `xml:"AssumeRoleId"` | ||
| 37 | } | ||
| 38 | |||
| 39 | // AssumeRoleWithClientGrantsResponse contains the result of successful AssumeRoleWithClientGrants request. | ||
| 40 | type AssumeRoleWithClientGrantsResponse struct { | ||
| 41 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithClientGrantsResponse" json:"-"` | ||
| 42 | Result ClientGrantsResult `xml:"AssumeRoleWithClientGrantsResult"` | ||
| 43 | ResponseMetadata struct { | ||
| 44 | RequestID string `xml:"RequestId,omitempty"` | ||
| 45 | } `xml:"ResponseMetadata,omitempty"` | ||
| 46 | } | ||
| 47 | |||
| 48 | // ClientGrantsResult - Contains the response to a successful AssumeRoleWithClientGrants | ||
| 49 | // request, including temporary credentials that can be used to make MinIO API requests. | ||
| 50 | type ClientGrantsResult struct { | ||
| 51 | AssumedRoleUser AssumedRoleUser `xml:",omitempty"` | ||
| 52 | Audience string `xml:",omitempty"` | ||
| 53 | Credentials struct { | ||
| 54 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
| 55 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
| 56 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
| 57 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
| 58 | } `xml:",omitempty"` | ||
| 59 | PackedPolicySize int `xml:",omitempty"` | ||
| 60 | Provider string `xml:",omitempty"` | ||
| 61 | SubjectFromClientGrantsToken string `xml:",omitempty"` | ||
| 62 | } | ||
| 63 | |||
| 64 | // ClientGrantsToken - client grants token with expiry. | ||
| 65 | type ClientGrantsToken struct { | ||
| 66 | Token string | ||
| 67 | Expiry int | ||
| 68 | } | ||
| 69 | |||
| 70 | // A STSClientGrants retrieves credentials from MinIO service, and keeps track if | ||
| 71 | // those credentials are expired. | ||
| 72 | type STSClientGrants struct { | ||
| 73 | Expiry | ||
| 74 | |||
| 75 | // Required http Client to use when connecting to MinIO STS service. | ||
| 76 | Client *http.Client | ||
| 77 | |||
| 78 | // MinIO endpoint to fetch STS credentials. | ||
| 79 | STSEndpoint string | ||
| 80 | |||
| 81 | // getClientGrantsTokenExpiry function to retrieve tokens | ||
| 82 | // from IDP This function should return two values one is | ||
| 83 | // accessToken which is a self contained access token (JWT) | ||
| 84 | // and second return value is the expiry associated with | ||
| 85 | // this token. This is a customer provided function and | ||
| 86 | // is mandatory. | ||
| 87 | GetClientGrantsTokenExpiry func() (*ClientGrantsToken, error) | ||
| 88 | } | ||
| 89 | |||
| 90 | // NewSTSClientGrants returns a pointer to a new | ||
| 91 | // Credentials object wrapping the STSClientGrants. | ||
| 92 | func NewSTSClientGrants(stsEndpoint string, getClientGrantsTokenExpiry func() (*ClientGrantsToken, error)) (*Credentials, error) { | ||
| 93 | if stsEndpoint == "" { | ||
| 94 | return nil, errors.New("STS endpoint cannot be empty") | ||
| 95 | } | ||
| 96 | if getClientGrantsTokenExpiry == nil { | ||
| 97 | return nil, errors.New("Client grants access token and expiry retrieval function should be defined") | ||
| 98 | } | ||
| 99 | return New(&STSClientGrants{ | ||
| 100 | Client: &http.Client{ | ||
| 101 | Transport: http.DefaultTransport, | ||
| 102 | }, | ||
| 103 | STSEndpoint: stsEndpoint, | ||
| 104 | GetClientGrantsTokenExpiry: getClientGrantsTokenExpiry, | ||
| 105 | }), nil | ||
| 106 | } | ||
| 107 | |||
| 108 | func getClientGrantsCredentials(clnt *http.Client, endpoint string, | ||
| 109 | getClientGrantsTokenExpiry func() (*ClientGrantsToken, error), | ||
| 110 | ) (AssumeRoleWithClientGrantsResponse, error) { | ||
| 111 | accessToken, err := getClientGrantsTokenExpiry() | ||
| 112 | if err != nil { | ||
| 113 | return AssumeRoleWithClientGrantsResponse{}, err | ||
| 114 | } | ||
| 115 | |||
| 116 | v := url.Values{} | ||
| 117 | v.Set("Action", "AssumeRoleWithClientGrants") | ||
| 118 | v.Set("Token", accessToken.Token) | ||
| 119 | v.Set("DurationSeconds", fmt.Sprintf("%d", accessToken.Expiry)) | ||
| 120 | v.Set("Version", STSVersion) | ||
| 121 | |||
| 122 | u, err := url.Parse(endpoint) | ||
| 123 | if err != nil { | ||
| 124 | return AssumeRoleWithClientGrantsResponse{}, err | ||
| 125 | } | ||
| 126 | |||
| 127 | req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(v.Encode())) | ||
| 128 | if err != nil { | ||
| 129 | return AssumeRoleWithClientGrantsResponse{}, err | ||
| 130 | } | ||
| 131 | |||
| 132 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
| 133 | |||
| 134 | resp, err := clnt.Do(req) | ||
| 135 | if err != nil { | ||
| 136 | return AssumeRoleWithClientGrantsResponse{}, err | ||
| 137 | } | ||
| 138 | defer resp.Body.Close() | ||
| 139 | if resp.StatusCode != http.StatusOK { | ||
| 140 | var errResp ErrorResponse | ||
| 141 | buf, err := io.ReadAll(resp.Body) | ||
| 142 | if err != nil { | ||
| 143 | return AssumeRoleWithClientGrantsResponse{}, err | ||
| 144 | } | ||
| 145 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
| 146 | if err != nil { | ||
| 147 | var s3Err Error | ||
| 148 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
| 149 | return AssumeRoleWithClientGrantsResponse{}, err | ||
| 150 | } | ||
| 151 | errResp.RequestID = s3Err.RequestID | ||
| 152 | errResp.STSError.Code = s3Err.Code | ||
| 153 | errResp.STSError.Message = s3Err.Message | ||
| 154 | } | ||
| 155 | return AssumeRoleWithClientGrantsResponse{}, errResp | ||
| 156 | } | ||
| 157 | |||
| 158 | a := AssumeRoleWithClientGrantsResponse{} | ||
| 159 | if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil { | ||
| 160 | return AssumeRoleWithClientGrantsResponse{}, err | ||
| 161 | } | ||
| 162 | return a, nil | ||
| 163 | } | ||
| 164 | |||
| 165 | // Retrieve retrieves credentials from the MinIO service. | ||
| 166 | // Error will be returned if the request fails. | ||
| 167 | func (m *STSClientGrants) Retrieve() (Value, error) { | ||
| 168 | a, err := getClientGrantsCredentials(m.Client, m.STSEndpoint, m.GetClientGrantsTokenExpiry) | ||
| 169 | if err != nil { | ||
| 170 | return Value{}, err | ||
| 171 | } | ||
| 172 | |||
| 173 | // Expiry window is set to 10secs. | ||
| 174 | m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
| 175 | |||
| 176 | return Value{ | ||
| 177 | AccessKeyID: a.Result.Credentials.AccessKey, | ||
| 178 | SecretAccessKey: a.Result.Credentials.SecretKey, | ||
| 179 | SessionToken: a.Result.Credentials.SessionToken, | ||
| 180 | SignerType: SignatureV4, | ||
| 181 | }, nil | ||
| 182 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_custom_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_custom_identity.go new file mode 100644 index 0000000..e1f9ce4 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_custom_identity.go | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2015-2022 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "encoding/xml" | ||
| 22 | "errors" | ||
| 23 | "fmt" | ||
| 24 | "net/http" | ||
| 25 | "net/url" | ||
| 26 | "time" | ||
| 27 | ) | ||
| 28 | |||
| 29 | // CustomTokenResult - Contains temporary creds and user metadata. | ||
| 30 | type CustomTokenResult struct { | ||
| 31 | Credentials struct { | ||
| 32 | AccessKey string `xml:"AccessKeyId"` | ||
| 33 | SecretKey string `xml:"SecretAccessKey"` | ||
| 34 | Expiration time.Time `xml:"Expiration"` | ||
| 35 | SessionToken string `xml:"SessionToken"` | ||
| 36 | } `xml:",omitempty"` | ||
| 37 | |||
| 38 | AssumedUser string `xml:",omitempty"` | ||
| 39 | } | ||
| 40 | |||
| 41 | // AssumeRoleWithCustomTokenResponse contains the result of a successful | ||
| 42 | // AssumeRoleWithCustomToken request. | ||
| 43 | type AssumeRoleWithCustomTokenResponse struct { | ||
| 44 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithCustomTokenResponse" json:"-"` | ||
| 45 | Result CustomTokenResult `xml:"AssumeRoleWithCustomTokenResult"` | ||
| 46 | Metadata struct { | ||
| 47 | RequestID string `xml:"RequestId,omitempty"` | ||
| 48 | } `xml:"ResponseMetadata,omitempty"` | ||
| 49 | } | ||
| 50 | |||
| 51 | // CustomTokenIdentity - satisfies the Provider interface, and retrieves | ||
| 52 | // credentials from MinIO using the AssumeRoleWithCustomToken STS API. | ||
| 53 | type CustomTokenIdentity struct { | ||
| 54 | Expiry | ||
| 55 | |||
| 56 | Client *http.Client | ||
| 57 | |||
| 58 | // MinIO server STS endpoint to fetch STS credentials. | ||
| 59 | STSEndpoint string | ||
| 60 | |||
| 61 | // The custom token to use with the request. | ||
| 62 | Token string | ||
| 63 | |||
| 64 | // RoleArn associated with the identity | ||
| 65 | RoleArn string | ||
| 66 | |||
| 67 | // RequestedExpiry is to set the validity of the generated credentials | ||
| 68 | // (this value bounded by server). | ||
| 69 | RequestedExpiry time.Duration | ||
| 70 | } | ||
| 71 | |||
| 72 | // Retrieve - to satisfy Provider interface; fetches credentials from MinIO. | ||
| 73 | func (c *CustomTokenIdentity) Retrieve() (value Value, err error) { | ||
| 74 | u, err := url.Parse(c.STSEndpoint) | ||
| 75 | if err != nil { | ||
| 76 | return value, err | ||
| 77 | } | ||
| 78 | |||
| 79 | v := url.Values{} | ||
| 80 | v.Set("Action", "AssumeRoleWithCustomToken") | ||
| 81 | v.Set("Version", STSVersion) | ||
| 82 | v.Set("RoleArn", c.RoleArn) | ||
| 83 | v.Set("Token", c.Token) | ||
| 84 | if c.RequestedExpiry != 0 { | ||
| 85 | v.Set("DurationSeconds", fmt.Sprintf("%d", int(c.RequestedExpiry.Seconds()))) | ||
| 86 | } | ||
| 87 | |||
| 88 | u.RawQuery = v.Encode() | ||
| 89 | |||
| 90 | req, err := http.NewRequest(http.MethodPost, u.String(), nil) | ||
| 91 | if err != nil { | ||
| 92 | return value, err | ||
| 93 | } | ||
| 94 | |||
| 95 | resp, err := c.Client.Do(req) | ||
| 96 | if err != nil { | ||
| 97 | return value, err | ||
| 98 | } | ||
| 99 | |||
| 100 | defer resp.Body.Close() | ||
| 101 | if resp.StatusCode != http.StatusOK { | ||
| 102 | return value, errors.New(resp.Status) | ||
| 103 | } | ||
| 104 | |||
| 105 | r := AssumeRoleWithCustomTokenResponse{} | ||
| 106 | if err = xml.NewDecoder(resp.Body).Decode(&r); err != nil { | ||
| 107 | return | ||
| 108 | } | ||
| 109 | |||
| 110 | cr := r.Result.Credentials | ||
| 111 | c.SetExpiration(cr.Expiration, DefaultExpiryWindow) | ||
| 112 | return Value{ | ||
| 113 | AccessKeyID: cr.AccessKey, | ||
| 114 | SecretAccessKey: cr.SecretKey, | ||
| 115 | SessionToken: cr.SessionToken, | ||
| 116 | SignerType: SignatureV4, | ||
| 117 | }, nil | ||
| 118 | } | ||
| 119 | |||
| 120 | // NewCustomTokenCredentials - returns credentials using the | ||
| 121 | // AssumeRoleWithCustomToken STS API. | ||
| 122 | func NewCustomTokenCredentials(stsEndpoint, token, roleArn string, optFuncs ...CustomTokenOpt) (*Credentials, error) { | ||
| 123 | c := CustomTokenIdentity{ | ||
| 124 | Client: &http.Client{Transport: http.DefaultTransport}, | ||
| 125 | STSEndpoint: stsEndpoint, | ||
| 126 | Token: token, | ||
| 127 | RoleArn: roleArn, | ||
| 128 | } | ||
| 129 | for _, optFunc := range optFuncs { | ||
| 130 | optFunc(&c) | ||
| 131 | } | ||
| 132 | return New(&c), nil | ||
| 133 | } | ||
| 134 | |||
| 135 | // CustomTokenOpt is a function type to configure the custom-token based | ||
| 136 | // credentials using NewCustomTokenCredentials. | ||
| 137 | type CustomTokenOpt func(*CustomTokenIdentity) | ||
| 138 | |||
| 139 | // CustomTokenValidityOpt sets the validity duration of the requested | ||
| 140 | // credentials. This value is ignored if the server enforces a lower validity | ||
| 141 | // period. | ||
| 142 | func CustomTokenValidityOpt(d time.Duration) CustomTokenOpt { | ||
| 143 | return func(c *CustomTokenIdentity) { | ||
| 144 | c.RequestedExpiry = d | ||
| 145 | } | ||
| 146 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_ldap_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_ldap_identity.go new file mode 100644 index 0000000..ec5f3f0 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_ldap_identity.go | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2019-2022 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "bytes" | ||
| 22 | "encoding/xml" | ||
| 23 | "fmt" | ||
| 24 | "io" | ||
| 25 | "net/http" | ||
| 26 | "net/url" | ||
| 27 | "strings" | ||
| 28 | "time" | ||
| 29 | ) | ||
| 30 | |||
| 31 | // AssumeRoleWithLDAPResponse contains the result of successful | ||
| 32 | // AssumeRoleWithLDAPIdentity request | ||
| 33 | type AssumeRoleWithLDAPResponse struct { | ||
| 34 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithLDAPIdentityResponse" json:"-"` | ||
| 35 | Result LDAPIdentityResult `xml:"AssumeRoleWithLDAPIdentityResult"` | ||
| 36 | ResponseMetadata struct { | ||
| 37 | RequestID string `xml:"RequestId,omitempty"` | ||
| 38 | } `xml:"ResponseMetadata,omitempty"` | ||
| 39 | } | ||
| 40 | |||
| 41 | // LDAPIdentityResult - contains credentials for a successful | ||
| 42 | // AssumeRoleWithLDAPIdentity request. | ||
| 43 | type LDAPIdentityResult struct { | ||
| 44 | Credentials struct { | ||
| 45 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
| 46 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
| 47 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
| 48 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
| 49 | } `xml:",omitempty"` | ||
| 50 | |||
| 51 | SubjectFromToken string `xml:",omitempty"` | ||
| 52 | } | ||
| 53 | |||
| 54 | // LDAPIdentity retrieves credentials from MinIO | ||
| 55 | type LDAPIdentity struct { | ||
| 56 | Expiry | ||
| 57 | |||
| 58 | // Required http Client to use when connecting to MinIO STS service. | ||
| 59 | Client *http.Client | ||
| 60 | |||
| 61 | // Exported STS endpoint to fetch STS credentials. | ||
| 62 | STSEndpoint string | ||
| 63 | |||
| 64 | // LDAP username/password used to fetch LDAP STS credentials. | ||
| 65 | LDAPUsername, LDAPPassword string | ||
| 66 | |||
| 67 | // Session policy to apply to the generated credentials. Leave empty to | ||
| 68 | // use the full access policy available to the user. | ||
| 69 | Policy string | ||
| 70 | |||
| 71 | // RequestedExpiry is the configured expiry duration for credentials | ||
| 72 | // requested from LDAP. | ||
| 73 | RequestedExpiry time.Duration | ||
| 74 | } | ||
| 75 | |||
| 76 | // NewLDAPIdentity returns new credentials object that uses LDAP | ||
| 77 | // Identity. | ||
| 78 | func NewLDAPIdentity(stsEndpoint, ldapUsername, ldapPassword string, optFuncs ...LDAPIdentityOpt) (*Credentials, error) { | ||
| 79 | l := LDAPIdentity{ | ||
| 80 | Client: &http.Client{Transport: http.DefaultTransport}, | ||
| 81 | STSEndpoint: stsEndpoint, | ||
| 82 | LDAPUsername: ldapUsername, | ||
| 83 | LDAPPassword: ldapPassword, | ||
| 84 | } | ||
| 85 | for _, optFunc := range optFuncs { | ||
| 86 | optFunc(&l) | ||
| 87 | } | ||
| 88 | return New(&l), nil | ||
| 89 | } | ||
| 90 | |||
| 91 | // LDAPIdentityOpt is a function type used to configured the LDAPIdentity | ||
| 92 | // instance. | ||
| 93 | type LDAPIdentityOpt func(*LDAPIdentity) | ||
| 94 | |||
| 95 | // LDAPIdentityPolicyOpt sets the session policy for requested credentials. | ||
| 96 | func LDAPIdentityPolicyOpt(policy string) LDAPIdentityOpt { | ||
| 97 | return func(k *LDAPIdentity) { | ||
| 98 | k.Policy = policy | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | // LDAPIdentityExpiryOpt sets the expiry duration for requested credentials. | ||
| 103 | func LDAPIdentityExpiryOpt(d time.Duration) LDAPIdentityOpt { | ||
| 104 | return func(k *LDAPIdentity) { | ||
| 105 | k.RequestedExpiry = d | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | // NewLDAPIdentityWithSessionPolicy returns new credentials object that uses | ||
| 110 | // LDAP Identity with a specified session policy. The `policy` parameter must be | ||
| 111 | // a JSON string specifying the policy document. | ||
| 112 | // | ||
| 113 | // Deprecated: Use the `LDAPIdentityPolicyOpt` with `NewLDAPIdentity` instead. | ||
| 114 | func NewLDAPIdentityWithSessionPolicy(stsEndpoint, ldapUsername, ldapPassword, policy string) (*Credentials, error) { | ||
| 115 | return New(&LDAPIdentity{ | ||
| 116 | Client: &http.Client{Transport: http.DefaultTransport}, | ||
| 117 | STSEndpoint: stsEndpoint, | ||
| 118 | LDAPUsername: ldapUsername, | ||
| 119 | LDAPPassword: ldapPassword, | ||
| 120 | Policy: policy, | ||
| 121 | }), nil | ||
| 122 | } | ||
| 123 | |||
| 124 | // Retrieve gets the credential by calling the MinIO STS API for | ||
| 125 | // LDAP on the configured stsEndpoint. | ||
| 126 | func (k *LDAPIdentity) Retrieve() (value Value, err error) { | ||
| 127 | u, err := url.Parse(k.STSEndpoint) | ||
| 128 | if err != nil { | ||
| 129 | return value, err | ||
| 130 | } | ||
| 131 | |||
| 132 | v := url.Values{} | ||
| 133 | v.Set("Action", "AssumeRoleWithLDAPIdentity") | ||
| 134 | v.Set("Version", STSVersion) | ||
| 135 | v.Set("LDAPUsername", k.LDAPUsername) | ||
| 136 | v.Set("LDAPPassword", k.LDAPPassword) | ||
| 137 | if k.Policy != "" { | ||
| 138 | v.Set("Policy", k.Policy) | ||
| 139 | } | ||
| 140 | if k.RequestedExpiry != 0 { | ||
| 141 | v.Set("DurationSeconds", fmt.Sprintf("%d", int(k.RequestedExpiry.Seconds()))) | ||
| 142 | } | ||
| 143 | |||
| 144 | req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(v.Encode())) | ||
| 145 | if err != nil { | ||
| 146 | return value, err | ||
| 147 | } | ||
| 148 | |||
| 149 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
| 150 | |||
| 151 | resp, err := k.Client.Do(req) | ||
| 152 | if err != nil { | ||
| 153 | return value, err | ||
| 154 | } | ||
| 155 | |||
| 156 | defer resp.Body.Close() | ||
| 157 | if resp.StatusCode != http.StatusOK { | ||
| 158 | var errResp ErrorResponse | ||
| 159 | buf, err := io.ReadAll(resp.Body) | ||
| 160 | if err != nil { | ||
| 161 | return value, err | ||
| 162 | } | ||
| 163 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
| 164 | if err != nil { | ||
| 165 | var s3Err Error | ||
| 166 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
| 167 | return value, err | ||
| 168 | } | ||
| 169 | errResp.RequestID = s3Err.RequestID | ||
| 170 | errResp.STSError.Code = s3Err.Code | ||
| 171 | errResp.STSError.Message = s3Err.Message | ||
| 172 | } | ||
| 173 | return value, errResp | ||
| 174 | } | ||
| 175 | |||
| 176 | r := AssumeRoleWithLDAPResponse{} | ||
| 177 | if err = xml.NewDecoder(resp.Body).Decode(&r); err != nil { | ||
| 178 | return | ||
| 179 | } | ||
| 180 | |||
| 181 | cr := r.Result.Credentials | ||
| 182 | k.SetExpiration(cr.Expiration, DefaultExpiryWindow) | ||
| 183 | return Value{ | ||
| 184 | AccessKeyID: cr.AccessKey, | ||
| 185 | SecretAccessKey: cr.SecretKey, | ||
| 186 | SessionToken: cr.SessionToken, | ||
| 187 | SignerType: SignatureV4, | ||
| 188 | }, nil | ||
| 189 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_tls_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_tls_identity.go new file mode 100644 index 0000000..dee0a8c --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_tls_identity.go | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | // MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 2 | // Copyright 2021 MinIO, Inc. | ||
| 3 | // | ||
| 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | // you may not use this file except in compliance with the License. | ||
| 6 | // You may obtain a copy of the License at | ||
| 7 | // | ||
| 8 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | // | ||
| 10 | // Unless required by applicable law or agreed to in writing, software | ||
| 11 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | // See the License for the specific language governing permissions and | ||
| 14 | // limitations under the License. | ||
| 15 | |||
| 16 | package credentials | ||
| 17 | |||
| 18 | import ( | ||
| 19 | "bytes" | ||
| 20 | "crypto/tls" | ||
| 21 | "encoding/xml" | ||
| 22 | "errors" | ||
| 23 | "io" | ||
| 24 | "net" | ||
| 25 | "net/http" | ||
| 26 | "net/url" | ||
| 27 | "strconv" | ||
| 28 | "time" | ||
| 29 | ) | ||
| 30 | |||
| 31 | // CertificateIdentityOption is an optional AssumeRoleWithCertificate | ||
| 32 | // parameter - e.g. a custom HTTP transport configuration or S3 credental | ||
| 33 | // livetime. | ||
| 34 | type CertificateIdentityOption func(*STSCertificateIdentity) | ||
| 35 | |||
| 36 | // CertificateIdentityWithTransport returns a CertificateIdentityOption that | ||
| 37 | // customizes the STSCertificateIdentity with the given http.RoundTripper. | ||
| 38 | func CertificateIdentityWithTransport(t http.RoundTripper) CertificateIdentityOption { | ||
| 39 | return CertificateIdentityOption(func(i *STSCertificateIdentity) { i.Client.Transport = t }) | ||
| 40 | } | ||
| 41 | |||
| 42 | // CertificateIdentityWithExpiry returns a CertificateIdentityOption that | ||
| 43 | // customizes the STSCertificateIdentity with the given livetime. | ||
| 44 | // | ||
| 45 | // Fetched S3 credentials will have the given livetime if the STS server | ||
| 46 | // allows such credentials. | ||
| 47 | func CertificateIdentityWithExpiry(livetime time.Duration) CertificateIdentityOption { | ||
| 48 | return CertificateIdentityOption(func(i *STSCertificateIdentity) { i.S3CredentialLivetime = livetime }) | ||
| 49 | } | ||
| 50 | |||
| 51 | // A STSCertificateIdentity retrieves S3 credentials from the MinIO STS API and | ||
| 52 | // rotates those credentials once they expire. | ||
| 53 | type STSCertificateIdentity struct { | ||
| 54 | Expiry | ||
| 55 | |||
| 56 | // STSEndpoint is the base URL endpoint of the STS API. | ||
| 57 | // For example, https://minio.local:9000 | ||
| 58 | STSEndpoint string | ||
| 59 | |||
| 60 | // S3CredentialLivetime is the duration temp. S3 access | ||
| 61 | // credentials should be valid. | ||
| 62 | // | ||
| 63 | // It represents the access credential livetime requested | ||
| 64 | // by the client. The STS server may choose to issue | ||
| 65 | // temp. S3 credentials that have a different - usually | ||
| 66 | // shorter - livetime. | ||
| 67 | // | ||
| 68 | // The default livetime is one hour. | ||
| 69 | S3CredentialLivetime time.Duration | ||
| 70 | |||
| 71 | // Client is the HTTP client used to authenticate and fetch | ||
| 72 | // S3 credentials. | ||
| 73 | // | ||
| 74 | // A custom TLS client configuration can be specified by | ||
| 75 | // using a custom http.Transport: | ||
| 76 | // Client: http.Client { | ||
| 77 | // Transport: &http.Transport{ | ||
| 78 | // TLSClientConfig: &tls.Config{}, | ||
| 79 | // }, | ||
| 80 | // } | ||
| 81 | Client http.Client | ||
| 82 | } | ||
| 83 | |||
| 84 | var _ Provider = (*STSWebIdentity)(nil) // compiler check | ||
| 85 | |||
| 86 | // NewSTSCertificateIdentity returns a STSCertificateIdentity that authenticates | ||
| 87 | // to the given STS endpoint with the given TLS certificate and retrieves and | ||
| 88 | // rotates S3 credentials. | ||
| 89 | func NewSTSCertificateIdentity(endpoint string, certificate tls.Certificate, options ...CertificateIdentityOption) (*Credentials, error) { | ||
| 90 | if endpoint == "" { | ||
| 91 | return nil, errors.New("STS endpoint cannot be empty") | ||
| 92 | } | ||
| 93 | if _, err := url.Parse(endpoint); err != nil { | ||
| 94 | return nil, err | ||
| 95 | } | ||
| 96 | identity := &STSCertificateIdentity{ | ||
| 97 | STSEndpoint: endpoint, | ||
| 98 | Client: http.Client{ | ||
| 99 | Transport: &http.Transport{ | ||
| 100 | Proxy: http.ProxyFromEnvironment, | ||
| 101 | DialContext: (&net.Dialer{ | ||
| 102 | Timeout: 30 * time.Second, | ||
| 103 | KeepAlive: 30 * time.Second, | ||
| 104 | }).DialContext, | ||
| 105 | ForceAttemptHTTP2: true, | ||
| 106 | MaxIdleConns: 100, | ||
| 107 | IdleConnTimeout: 90 * time.Second, | ||
| 108 | TLSHandshakeTimeout: 10 * time.Second, | ||
| 109 | ExpectContinueTimeout: 5 * time.Second, | ||
| 110 | TLSClientConfig: &tls.Config{ | ||
| 111 | Certificates: []tls.Certificate{certificate}, | ||
| 112 | }, | ||
| 113 | }, | ||
| 114 | }, | ||
| 115 | } | ||
| 116 | for _, option := range options { | ||
| 117 | option(identity) | ||
| 118 | } | ||
| 119 | return New(identity), nil | ||
| 120 | } | ||
| 121 | |||
| 122 | // Retrieve fetches a new set of S3 credentials from the configured | ||
| 123 | // STS API endpoint. | ||
| 124 | func (i *STSCertificateIdentity) Retrieve() (Value, error) { | ||
| 125 | endpointURL, err := url.Parse(i.STSEndpoint) | ||
| 126 | if err != nil { | ||
| 127 | return Value{}, err | ||
| 128 | } | ||
| 129 | livetime := i.S3CredentialLivetime | ||
| 130 | if livetime == 0 { | ||
| 131 | livetime = 1 * time.Hour | ||
| 132 | } | ||
| 133 | |||
| 134 | queryValues := url.Values{} | ||
| 135 | queryValues.Set("Action", "AssumeRoleWithCertificate") | ||
| 136 | queryValues.Set("Version", STSVersion) | ||
| 137 | endpointURL.RawQuery = queryValues.Encode() | ||
| 138 | |||
| 139 | req, err := http.NewRequest(http.MethodPost, endpointURL.String(), nil) | ||
| 140 | if err != nil { | ||
| 141 | return Value{}, err | ||
| 142 | } | ||
| 143 | if req.Form == nil { | ||
| 144 | req.Form = url.Values{} | ||
| 145 | } | ||
| 146 | req.Form.Add("DurationSeconds", strconv.FormatUint(uint64(livetime.Seconds()), 10)) | ||
| 147 | |||
| 148 | resp, err := i.Client.Do(req) | ||
| 149 | if err != nil { | ||
| 150 | return Value{}, err | ||
| 151 | } | ||
| 152 | if resp.Body != nil { | ||
| 153 | defer resp.Body.Close() | ||
| 154 | } | ||
| 155 | if resp.StatusCode != http.StatusOK { | ||
| 156 | var errResp ErrorResponse | ||
| 157 | buf, err := io.ReadAll(resp.Body) | ||
| 158 | if err != nil { | ||
| 159 | return Value{}, err | ||
| 160 | } | ||
| 161 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
| 162 | if err != nil { | ||
| 163 | var s3Err Error | ||
| 164 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
| 165 | return Value{}, err | ||
| 166 | } | ||
| 167 | errResp.RequestID = s3Err.RequestID | ||
| 168 | errResp.STSError.Code = s3Err.Code | ||
| 169 | errResp.STSError.Message = s3Err.Message | ||
| 170 | } | ||
| 171 | return Value{}, errResp | ||
| 172 | } | ||
| 173 | |||
| 174 | const MaxSize = 10 * 1 << 20 | ||
| 175 | var body io.Reader = resp.Body | ||
| 176 | if resp.ContentLength > 0 && resp.ContentLength < MaxSize { | ||
| 177 | body = io.LimitReader(body, resp.ContentLength) | ||
| 178 | } else { | ||
| 179 | body = io.LimitReader(body, MaxSize) | ||
| 180 | } | ||
| 181 | |||
| 182 | var response assumeRoleWithCertificateResponse | ||
| 183 | if err = xml.NewDecoder(body).Decode(&response); err != nil { | ||
| 184 | return Value{}, err | ||
| 185 | } | ||
| 186 | i.SetExpiration(response.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
| 187 | return Value{ | ||
| 188 | AccessKeyID: response.Result.Credentials.AccessKey, | ||
| 189 | SecretAccessKey: response.Result.Credentials.SecretKey, | ||
| 190 | SessionToken: response.Result.Credentials.SessionToken, | ||
| 191 | SignerType: SignatureDefault, | ||
| 192 | }, nil | ||
| 193 | } | ||
| 194 | |||
| 195 | // Expiration returns the expiration time of the current S3 credentials. | ||
| 196 | func (i *STSCertificateIdentity) Expiration() time.Time { return i.expiration } | ||
| 197 | |||
| 198 | type assumeRoleWithCertificateResponse struct { | ||
| 199 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithCertificateResponse" json:"-"` | ||
| 200 | Result struct { | ||
| 201 | Credentials struct { | ||
| 202 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
| 203 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
| 204 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
| 205 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
| 206 | } `xml:"Credentials" json:"credentials,omitempty"` | ||
| 207 | } `xml:"AssumeRoleWithCertificateResult"` | ||
| 208 | ResponseMetadata struct { | ||
| 209 | RequestID string `xml:"RequestId,omitempty"` | ||
| 210 | } `xml:"ResponseMetadata,omitempty"` | ||
| 211 | } | ||
diff --git a/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_web_identity.go b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_web_identity.go new file mode 100644 index 0000000..2e2af50 --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_web_identity.go | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2019-2022 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package credentials | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "bytes" | ||
| 22 | "encoding/xml" | ||
| 23 | "errors" | ||
| 24 | "fmt" | ||
| 25 | "io" | ||
| 26 | "net/http" | ||
| 27 | "net/url" | ||
| 28 | "strconv" | ||
| 29 | "strings" | ||
| 30 | "time" | ||
| 31 | ) | ||
| 32 | |||
| 33 | // AssumeRoleWithWebIdentityResponse contains the result of successful AssumeRoleWithWebIdentity request. | ||
| 34 | type AssumeRoleWithWebIdentityResponse struct { | ||
| 35 | XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithWebIdentityResponse" json:"-"` | ||
| 36 | Result WebIdentityResult `xml:"AssumeRoleWithWebIdentityResult"` | ||
| 37 | ResponseMetadata struct { | ||
| 38 | RequestID string `xml:"RequestId,omitempty"` | ||
| 39 | } `xml:"ResponseMetadata,omitempty"` | ||
| 40 | } | ||
| 41 | |||
| 42 | // WebIdentityResult - Contains the response to a successful AssumeRoleWithWebIdentity | ||
| 43 | // request, including temporary credentials that can be used to make MinIO API requests. | ||
| 44 | type WebIdentityResult struct { | ||
| 45 | AssumedRoleUser AssumedRoleUser `xml:",omitempty"` | ||
| 46 | Audience string `xml:",omitempty"` | ||
| 47 | Credentials struct { | ||
| 48 | AccessKey string `xml:"AccessKeyId" json:"accessKey,omitempty"` | ||
| 49 | SecretKey string `xml:"SecretAccessKey" json:"secretKey,omitempty"` | ||
| 50 | Expiration time.Time `xml:"Expiration" json:"expiration,omitempty"` | ||
| 51 | SessionToken string `xml:"SessionToken" json:"sessionToken,omitempty"` | ||
| 52 | } `xml:",omitempty"` | ||
| 53 | PackedPolicySize int `xml:",omitempty"` | ||
| 54 | Provider string `xml:",omitempty"` | ||
| 55 | SubjectFromWebIdentityToken string `xml:",omitempty"` | ||
| 56 | } | ||
| 57 | |||
| 58 | // WebIdentityToken - web identity token with expiry. | ||
| 59 | type WebIdentityToken struct { | ||
| 60 | Token string | ||
| 61 | AccessToken string | ||
| 62 | Expiry int | ||
| 63 | } | ||
| 64 | |||
| 65 | // A STSWebIdentity retrieves credentials from MinIO service, and keeps track if | ||
| 66 | // those credentials are expired. | ||
| 67 | type STSWebIdentity struct { | ||
| 68 | Expiry | ||
| 69 | |||
| 70 | // Required http Client to use when connecting to MinIO STS service. | ||
| 71 | Client *http.Client | ||
| 72 | |||
| 73 | // Exported STS endpoint to fetch STS credentials. | ||
| 74 | STSEndpoint string | ||
| 75 | |||
| 76 | // Exported GetWebIDTokenExpiry function which returns ID | ||
| 77 | // tokens from IDP. This function should return two values | ||
| 78 | // one is ID token which is a self contained ID token (JWT) | ||
| 79 | // and second return value is the expiry associated with | ||
| 80 | // this token. | ||
| 81 | // This is a customer provided function and is mandatory. | ||
| 82 | GetWebIDTokenExpiry func() (*WebIdentityToken, error) | ||
| 83 | |||
| 84 | // RoleARN is the Amazon Resource Name (ARN) of the role that the caller is | ||
| 85 | // assuming. | ||
| 86 | RoleARN string | ||
| 87 | |||
| 88 | // roleSessionName is the identifier for the assumed role session. | ||
| 89 | roleSessionName string | ||
| 90 | } | ||
| 91 | |||
| 92 | // NewSTSWebIdentity returns a pointer to a new | ||
| 93 | // Credentials object wrapping the STSWebIdentity. | ||
| 94 | func NewSTSWebIdentity(stsEndpoint string, getWebIDTokenExpiry func() (*WebIdentityToken, error)) (*Credentials, error) { | ||
| 95 | if stsEndpoint == "" { | ||
| 96 | return nil, errors.New("STS endpoint cannot be empty") | ||
| 97 | } | ||
| 98 | if getWebIDTokenExpiry == nil { | ||
| 99 | return nil, errors.New("Web ID token and expiry retrieval function should be defined") | ||
| 100 | } | ||
| 101 | return New(&STSWebIdentity{ | ||
| 102 | Client: &http.Client{ | ||
| 103 | Transport: http.DefaultTransport, | ||
| 104 | }, | ||
| 105 | STSEndpoint: stsEndpoint, | ||
| 106 | GetWebIDTokenExpiry: getWebIDTokenExpiry, | ||
| 107 | }), nil | ||
| 108 | } | ||
| 109 | |||
| 110 | func getWebIdentityCredentials(clnt *http.Client, endpoint, roleARN, roleSessionName string, | ||
| 111 | getWebIDTokenExpiry func() (*WebIdentityToken, error), | ||
| 112 | ) (AssumeRoleWithWebIdentityResponse, error) { | ||
| 113 | idToken, err := getWebIDTokenExpiry() | ||
| 114 | if err != nil { | ||
| 115 | return AssumeRoleWithWebIdentityResponse{}, err | ||
| 116 | } | ||
| 117 | |||
| 118 | v := url.Values{} | ||
| 119 | v.Set("Action", "AssumeRoleWithWebIdentity") | ||
| 120 | if len(roleARN) > 0 { | ||
| 121 | v.Set("RoleArn", roleARN) | ||
| 122 | |||
| 123 | if len(roleSessionName) == 0 { | ||
| 124 | roleSessionName = strconv.FormatInt(time.Now().UnixNano(), 10) | ||
| 125 | } | ||
| 126 | v.Set("RoleSessionName", roleSessionName) | ||
| 127 | } | ||
| 128 | v.Set("WebIdentityToken", idToken.Token) | ||
| 129 | if idToken.AccessToken != "" { | ||
| 130 | // Usually set when server is using extended userInfo endpoint. | ||
| 131 | v.Set("WebIdentityAccessToken", idToken.AccessToken) | ||
| 132 | } | ||
| 133 | if idToken.Expiry > 0 { | ||
| 134 | v.Set("DurationSeconds", fmt.Sprintf("%d", idToken.Expiry)) | ||
| 135 | } | ||
| 136 | v.Set("Version", STSVersion) | ||
| 137 | |||
| 138 | u, err := url.Parse(endpoint) | ||
| 139 | if err != nil { | ||
| 140 | return AssumeRoleWithWebIdentityResponse{}, err | ||
| 141 | } | ||
| 142 | |||
| 143 | req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(v.Encode())) | ||
| 144 | if err != nil { | ||
| 145 | return AssumeRoleWithWebIdentityResponse{}, err | ||
| 146 | } | ||
| 147 | |||
| 148 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
| 149 | |||
| 150 | resp, err := clnt.Do(req) | ||
| 151 | if err != nil { | ||
| 152 | return AssumeRoleWithWebIdentityResponse{}, err | ||
| 153 | } | ||
| 154 | |||
| 155 | defer resp.Body.Close() | ||
| 156 | if resp.StatusCode != http.StatusOK { | ||
| 157 | var errResp ErrorResponse | ||
| 158 | buf, err := io.ReadAll(resp.Body) | ||
| 159 | if err != nil { | ||
| 160 | return AssumeRoleWithWebIdentityResponse{}, err | ||
| 161 | } | ||
| 162 | _, err = xmlDecodeAndBody(bytes.NewReader(buf), &errResp) | ||
| 163 | if err != nil { | ||
| 164 | var s3Err Error | ||
| 165 | if _, err = xmlDecodeAndBody(bytes.NewReader(buf), &s3Err); err != nil { | ||
| 166 | return AssumeRoleWithWebIdentityResponse{}, err | ||
| 167 | } | ||
| 168 | errResp.RequestID = s3Err.RequestID | ||
| 169 | errResp.STSError.Code = s3Err.Code | ||
| 170 | errResp.STSError.Message = s3Err.Message | ||
| 171 | } | ||
| 172 | return AssumeRoleWithWebIdentityResponse{}, errResp | ||
| 173 | } | ||
| 174 | |||
| 175 | a := AssumeRoleWithWebIdentityResponse{} | ||
| 176 | if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil { | ||
| 177 | return AssumeRoleWithWebIdentityResponse{}, err | ||
| 178 | } | ||
| 179 | |||
| 180 | return a, nil | ||
| 181 | } | ||
| 182 | |||
| 183 | // Retrieve retrieves credentials from the MinIO service. | ||
| 184 | // Error will be returned if the request fails. | ||
| 185 | func (m *STSWebIdentity) Retrieve() (Value, error) { | ||
| 186 | a, err := getWebIdentityCredentials(m.Client, m.STSEndpoint, m.RoleARN, m.roleSessionName, m.GetWebIDTokenExpiry) | ||
| 187 | if err != nil { | ||
| 188 | return Value{}, err | ||
| 189 | } | ||
| 190 | |||
| 191 | // Expiry window is set to 10secs. | ||
| 192 | m.SetExpiration(a.Result.Credentials.Expiration, DefaultExpiryWindow) | ||
| 193 | |||
| 194 | return Value{ | ||
| 195 | AccessKeyID: a.Result.Credentials.AccessKey, | ||
| 196 | SecretAccessKey: a.Result.Credentials.SecretKey, | ||
| 197 | SessionToken: a.Result.Credentials.SessionToken, | ||
| 198 | SignerType: SignatureV4, | ||
| 199 | }, nil | ||
| 200 | } | ||
| 201 | |||
| 202 | // Expiration returns the expiration time of the credentials | ||
| 203 | func (m *STSWebIdentity) Expiration() time.Time { | ||
| 204 | return m.expiration | ||
| 205 | } | ||