Description
Unable to use minio-go with STS with certificate.
Calling credentials.NewSTSCertificateIdentity triggers panic
How to repeat problem ?
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"log"
"net"
"net/http"
"os"
"time"
)
func main() {
endpoint := "localhost:9000"
certPath := "public.crt"
keyPath := "private.key"
caPath := "ca.crt"
caCert, err := os.ReadFile(caPath)
if err != nil {
log.Printf("unable to setup CA certificate: %v", err)
os.Exit(1)
}
var caCertPool *x509.CertPool
caCertPool = x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
log.Printf("unable to setup client certificate: %v", err)
os.Exit(1)
}
// default transportCreds with added CA cert and client cert
transportCreds := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 5 * time.Second,
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
},
}
creds, err := credentials.NewSTSCertificateIdentity("https://" + endpoint, cert, credentials.CertificateIdentityWithTransport(transportCreds))
if err != nil {
log.Printf("unable to setup client credentials: %v", err)
os.Exit(1)
}
transportClient, err := minio.DefaultTransport(true)
if err != nil {
log.Printf("unable to init transport layer for minio client: %v", err)
os.Exit(1)
}
transportClient.TLSClientConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
}
client, err := minio.New(endpoint, &minio.Options{
Transport: transportCreds,
Creds: creds,
Secure: true,
})
if err != nil {
log.Fatalln(err)
}
log.Printf("setup client correctly")
err = client.MakeBucket(context.Background(), "examplebucket", minio.MakeBucketOptions{})
if err != nil {
log.Fatalln(err)
}
log.Printf("bucket has been created successfully")
}
Output
❯ ./minioexample
2023/02/09 12:58:50 setup client correctly
panic: assignment to entry in nil map
goroutine 1 [running]:
net/url.Values.Add(...)
/Users/milosz/.gvm/gos/go1.19/src/net/url/url.go:902
github.com/miloszminio-go/v7/pkg/credentials.(*STSCertificateIdentity).Retrieve(0x140001d9960)
/Users/miloszgit_repo/minio-sandbox/go/minio2/client/vendor/github.com/minio/minio-go/v7/pkg/credentials/sts_tls_identity.go:144 +0x2a8
github.com/minio/minio-go/v7/pkg/credentials.(*Credentials).Get(0x140000a4540)
/Users/milosz/git_repo/minio-sandbox/go/minio2/client/vendor/github.com/minio/minio-go/v7/pkg/credentials/credentials.go:155 +0x108
github.com/minio/minio-go/v7.(*Client).newRequest(0x140000ba370, {0x10500ff30, 0x14000028090}, {0x104eecb22?, 0x0?}, {0x0, {0x104eefe33, 0xd}, {0x0, 0x0}, ...})
/Users/milosz/git_repo/minio-sandbox/go/minio2/client/vendor/github.com/minio/minio-go/v7/api.go:756 +0x258
github.com/minio/minio-go/v7.(*Client).executeMethod(0x140000ba370, {0x10500ff30, 0x14000028090}, {0x104eecb22, 0x3}, {0x0, {0x104eefe33, 0xd}, {0x0, 0x0}, ...})
/Users/milosz/git_repo/minio-sandbox/go/minio2/client/vendor/github.com/minio/minio-go/v7/api.go:610 +0x62c
github.com/minio/minio-go/v7.(*Client).doMakeBucket(0x140000ba370, {0x10500ff30, 0x14000028090}, {0x104eefe33, 0xd}, {0x104eee71d, 0x9}, 0xe0?)
/Users/milosz/git_repo/minio-sandbox/go/minio2/client/vendor/github.com/minio/minio-go/v7/api-put-bucket.go:90 +0x378
github.com/minio/minio-go/v7.(*Client).makeBucket(0x104ef3a57?, {0x10500ff30, 0x14000028090}, {0x104eefe33, 0xd}, {{0x0?, 0x0?}, 0x0?})
/Users/milosz/git_repo/minio-sandbox/go/minio2/client/vendor/github.com/minio/minio-go/v7/api-put-bucket.go:36 +0x7c
github.com/minio/minio-go/v7.(*Client).MakeBucket(...)
/Users/milosz/git_repo/minio-sandbox/go/minio2/client/vendor/github.com/minio/minio-go/v7/api-put-bucket.go:122
main.main()
/Users/milosz/git_repo/minio-sandbox/go/minio2/client/main.go:81 +0x618
What's the reason ?
sts_tls_identity.go
queryValues := url.Values{}
queryValues.Set("Action", "AssumeRoleWithCertificate")
queryValues.Set("Version", STSVersion)
endpointURL.RawQuery = queryValues.Encode()
req, err := http.NewRequest(http.MethodPost, endpointURL.String(), nil)
if err != nil {
return Value{}, err
}
req.Form.Add("DurationSeconds", strconv.FormatUint(uint64(livetime.Seconds()), 10))
req.Form is nil in this situation, function ParseForm is not used
docs
// Form contains the parsed form data, including both the URL
// field's query parameters and the PATCH, POST, or PUT form data.
// This field is only available after ParseForm is called.
// The HTTP client ignores Form and uses Body instead.
Form url.Values
How to fix ?
Add DurationSeconds parameter within queryValues:
sts_tls_identity.go
queryValues := url.Values{}
queryValues.Set("Action", "AssumeRoleWithCertificate")
queryValues.Set("Version", STSVersion)
queryValues.Set("DurationSeconds", strconv.FormatUint(uint64(livetime.Seconds()), 10))
endpointURL.RawQuery = queryValues.Encode()
req, err := http.NewRequest(http.MethodPost, endpointURL.String(), nil)
if err != nil {
return Value{}, err
}
Description
Unable to use
minio-gowith STS with certificate.Calling
credentials.NewSTSCertificateIdentitytriggerspanicHow to repeat problem ?
Output
What's the reason ?
sts_tls_identity.goreq.Formis nil in this situation, functionParseFormis not useddocs
How to fix ?
Add
DurationSecondsparameter withinqueryValues:sts_tls_identity.go