Skip to content

Commit

Permalink
Work around an azure HTTP/2 bug (#183)
Browse files Browse the repository at this point in the history
Backport of the Azure HTTP/2 workaround to vault 1.12.x maintenance branch.
---------

Co-authored-by: Jim <jlambert@hashicorp.com>
  • Loading branch information
sgmiller and jimlambrt committed Sep 5, 2023
1 parent e6c91bd commit 07aff97
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 2 deletions.
45 changes: 43 additions & 2 deletions wrappers/azurekeyvault/azurekeyvault.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ package azurekeyvault

import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"net"
"net/http"
"os"
"strings"
"sync/atomic"
"time"

"golang.org/x/net/http2"

"github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault"
"github.com/Azure/go-autorest/autorest"
Expand Down Expand Up @@ -156,7 +163,7 @@ func (v *Wrapper) SetConfig(_ context.Context, opt ...wrapping.Option) (*wrappin
v.baseURL = v.buildBaseURL()

if v.client == nil {
client, err := v.getKeyVaultClient()
client, err := v.getKeyVaultClient(nil)
if err != nil {
return nil, fmt.Errorf("error initializing Azure Key Vault wrapper client: %w", err)
}
Expand Down Expand Up @@ -292,7 +299,7 @@ func (v *Wrapper) buildBaseURL() string {
return fmt.Sprintf("https://%s.%s/", v.vaultName, v.environment.KeyVaultDNSSuffix)
}

func (v *Wrapper) getKeyVaultClient() (*keyvault.BaseClient, error) {
func (v *Wrapper) getKeyVaultClient(withCertPool *x509.CertPool) (*keyvault.BaseClient, error) {
var authorizer autorest.Authorizer
var err error

Expand All @@ -318,8 +325,42 @@ func (v *Wrapper) getKeyVaultClient() (*keyvault.BaseClient, error) {
}
}

dialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
customTransport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dialer.DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
Renegotiation: tls.RenegotiateFreelyAsClient,
RootCAs: withCertPool,
},
}
if http2Transport, err := http2.ConfigureTransports(customTransport); err == nil {
// if the connection has been idle for 10 seconds, send a ping frame for a health check
http2Transport.ReadIdleTimeout = 10 * time.Second
// if there's no response to the ping within 2 seconds, close the connection
http2Transport.PingTimeout = 2 * time.Second
}

client := keyvault.New()
client.Authorizer = authorizer
client.SendDecorators = append(client.SendDecorators, func(s autorest.Sender) autorest.Sender {
if ar, ok := s.(autorest.Client); ok {
ar.Sender = &http.Client{
Transport: customTransport,
}
return ar
}
return s
})
return &client, nil
}

Expand Down
67 changes: 67 additions & 0 deletions wrappers/azurekeyvault/azurekeyvault_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ package azurekeyvault

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"net/http/httptest"
"os"
"reflect"
"testing"

"github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -99,3 +105,64 @@ func TestAzureKeyVault_Lifecycle(t *testing.T) {
t.Fatalf("expected %s, got %s", input, pt)
}
}

func Test_getKeyVaultClient(t *testing.T) {
t.Parallel()
config := map[string]string{
"disallow_env_vars": "true",
"tenant_id": "a-tenant-id",
"client_id": "a-client-id",
"client_secret": "a-client-secret",
"environment": azure.PublicCloud.Name,
"resource": "a-resource",
"vault_name": "a-vault-name",
"key_name": "a-key-name",
}
s := NewWrapper()
_, err := s.SetConfig(
context.Background(),
wrapping.WithConfigMap(config),
WithKeyNotRequired(true),
)
require.NoError(t, err)
t.Run("send-decorators-set", func(t *testing.T) {
// let's at least ensure that the custom SendDecorator is being properly
// set.
t.Parallel()
got, err := s.getKeyVaultClient(nil)
require.NoError(t, err)
assert.NotEmpty(t, got.SendDecorators)
})
t.Run("force-tls-error", func(t *testing.T) {
// not great, but this test will at least ensure that the client's
// custom TLS transport is being used
t.Parallel()
ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf("version: %s", tls.VersionName(r.TLS.Version))))
}))
ts.TLS = &tls.Config{
MinVersion: tls.VersionTLS10,
MaxVersion: tls.VersionTLS10,
}
ts.StartTLS()
defer ts.Close()

certPool := x509.NewCertPool()
certPool.AddCert(ts.Certificate())

assert.NoError(t, err)
client, err := s.getKeyVaultClient(certPool)
require.NoError(t, err)
assert.NotEmpty(t, client.SendDecorators)
client.Authorizer = &authorizer{}
_, err = client.GetKey(context.Background(), ts.URL, "global", "1")
require.Error(t, err)
assert.ErrorContains(t, err, "tls: protocol version not supported")
})
}

type authorizer struct{}

func (*authorizer) WithAuthorization() autorest.PrepareDecorator {
return autorest.WithNothing()
}
2 changes: 2 additions & 0 deletions wrappers/azurekeyvault/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/hashicorp/go-hclog v1.1.0
github.com/hashicorp/go-kms-wrapping/v2 v2.0.0
github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
)

require (
Expand All @@ -33,6 +34,7 @@ require (
github.com/rogpeppe/go-internal v1.6.1 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
2 changes: 2 additions & 0 deletions wrappers/azurekeyvault/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand All @@ -94,6 +95,7 @@ golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down

0 comments on commit 07aff97

Please sign in to comment.