Skip to content

Commit

Permalink
example/aws/proxyWithTLSClientCert: Add HTTPS_PROXY client cert examp…
Browse files Browse the repository at this point in the history
…le (#2664)

Adds an example for using the SDK with an HTTPS_PROXY that requires the
client include a TLS certificate to the HTTPS proxy.
  • Loading branch information
jasdel committed Jun 25, 2019
1 parent 618bdd1 commit 0c361e5
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
23 changes: 23 additions & 0 deletions example/aws/proxyWithTLSClientCert/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Example

Example of using the AWS SDK for Go with an HTTPS_PROXY that requires client
TLS certificates. The example will use the proxy configured via the environment
variable `HTTPS_PROXY` proxy a request for the Amazon S3 `ListBuckets` API
operation call.

The example assumes credentials are provided in the environment, or shared
credentials file `~/.aws/credentials`. The `certificate` and `key` files paths
are required to be specified when the example is run. An certificate authority
(CA) file path can also be optionally specified.

Refer to [httpproxy.FromEnvironment](https://godoc.org/golang.org/x/net/http/httpproxy#FromEnvironment)
for details using `HTTPS_PROXY` with the Go HTTP client.

## Usage:

```sh
export HTTPS_PROXY=https://127.0.0.1:8443
export AWS_REGION=us-west-2
go run -cert <certfile> -key <keyfile> [-ca <cafile>]
```

123 changes: 123 additions & 0 deletions example/aws/proxyWithTLSClientCert/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// +build example

package main

import (
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"golang.org/x/net/http2"
)

// Example of creating an HTTP Client configured with a client TLS
// certificates. Can be used with endpoints such as HTTPS_PROXY that require
// client certificates.
//
// Requires a cert and key flags, and optionally takes a CA file.
//
// To run:
// go run -cert <certfile> -key <keyfile> [-ca <cafile>]
//
// You can generate self signed cert and key pem files
// go run $(go env GOROOT)/src/crypto/tls/generate_cert.go -host <hostname>
func main() {
var clientCertFile, clientKeyFile, caFile string
flag.StringVar(&clientCertFile, "cert", "cert.pem", "The `certificate file` to load.")
flag.StringVar(&clientKeyFile, "key", "key.pem", "The `key file` to load.")
flag.StringVar(&caFile, "ca", "ca.pem", "The `root CA` to load.")
flag.Parse()

if len(clientCertFile) == 0 || len(clientKeyFile) == 0 {
flag.PrintDefaults()
log.Fatalf("client certificate and key required")
}

tlsCfg, err := tlsConfigWithClientCert(clientCertFile, clientKeyFile, caFile)
if err != nil {
log.Fatalf("failed to load client cert, %v", err)
}

// Copy of net/http.DefaultTransport with TLS config loaded
tr := defaultHTTPTransport()
tr.TLSClientConfig = tlsCfg

// re-enable HTTP/2 because modifing TLS config will prevent auto support
// for HTTP/2.
http2.ConfigureTransport(tr)

// Configure the SDK's session with the HTTP client with TLS client
// certificate support enabled. This session will be used to create all
// SDK's API clients.
sess, err := session.NewSession(&aws.Config{
HTTPClient: &http.Client{
Transport: tr,
},
})

// Create each API client will the session configured with the client TLS
// certificate.
svc := s3.New(sess)

resp, err := svc.ListBuckets(&s3.ListBucketsInput{})
if err != nil {
log.Fatalf("failed to list buckets, %v", err)
}

fmt.Println("Buckets")
fmt.Println(resp)
}

func tlsConfigWithClientCert(clientCertFile, clientKeyFile, caFile string) (*tls.Config, error) {
clientCert, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
if err != nil {
return nil, fmt.Errorf("unable to load certificat files, %s, %s, %v",
clientCertFile, clientKeyFile, err)
}

tlsCfg := &tls.Config{
Certificates: []tls.Certificate{
clientCert,
},
}

if len(caFile) != 0 {
cert, err := ioutil.ReadFile(caFile)
if err != nil {
return nil, fmt.Errorf("unable to load root CA file, %s, %v",
caFile, err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(cert)
tlsCfg.RootCAs = caCertPool
}

tlsCfg.BuildNameToCertificate()

return tlsCfg, nil
}

func defaultHTTPTransport() *http.Transport {
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10, // Increased idle connections per host
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
}

0 comments on commit 0c361e5

Please sign in to comment.