Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic when using STS with certificate #1769

Closed
kukulam-form3 opened this issue Feb 9, 2023 · 3 comments · Fixed by #1770
Closed

Panic when using STS with certificate #1769

kukulam-form3 opened this issue Feb 9, 2023 · 3 comments · Fixed by #1770

Comments

@kukulam-form3
Copy link

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
	}
klauspost added a commit to klauspost/minio-go that referenced this issue Feb 9, 2023
Initialize request form before writing.

Fixes minio#1769
@klauspost
Copy link
Contributor

#1770 should fix the issue.

@klauspost klauspost reopened this Feb 9, 2023
@kukulam-form3
Copy link
Author

kukulam-form3 commented Feb 9, 2023

#1770 should fix the issue.

Great, thank you 😃 do you know when it will be released ? it's kind of blocker for us.

harshavardhana pushed a commit that referenced this issue Feb 9, 2023
Initialize request form before writing.

Fixes #1769
@harshavardhana
Copy link
Member

harshavardhana commented Feb 9, 2023

#1770 should fix the issue.

Great, thank you smiley do you know when it will be released ? it's kind of blocker for us.

Soon @kukulam-form3 - use go get github.com/minio/minio-go/v7@master for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants