github.com/thiagoyeds/go-cloud@v0.26.0/aws/rds/rds.go (about)

     1  // Copyright 2018 The Go Cloud Development Kit Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package rds contains Wire providers that are common across RDS.
    16  package rds // import "gocloud.dev/aws/rds"
    17  
    18  import (
    19  	"context"
    20  	"crypto/x509"
    21  	"encoding/pem"
    22  	"fmt"
    23  	"io"
    24  	"io/ioutil"
    25  	"net/http"
    26  
    27  	"github.com/google/wire"
    28  	"golang.org/x/net/context/ctxhttp"
    29  )
    30  
    31  // CertFetcherSet is a Wire provider set that provides the RDS certificate pool
    32  // by pulling from Amazon's servers.
    33  var CertFetcherSet = wire.NewSet(
    34  	wire.Struct(new(CertFetcher), "Client"),
    35  	wire.Bind(new(CertPoolProvider), new(*CertFetcher)),
    36  )
    37  
    38  // A CertPoolProvider obtains a certificate pool that contains the RDS CA certificate.
    39  type CertPoolProvider interface {
    40  	RDSCertPool(context.Context) (*x509.CertPool, error)
    41  }
    42  
    43  // caBundleURL is the URL to the public RDS Certificate Authority keys.
    44  const caBundleURL = "https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem"
    45  
    46  // CertFetcher pulls the RDS CA certificates from Amazon's servers. The zero
    47  // value will fetch certificates using the default HTTP client.
    48  type CertFetcher struct {
    49  	// Client is the HTTP client used to make requests. If nil, then
    50  	// http.DefaultClient is used.
    51  	Client *http.Client
    52  }
    53  
    54  // RDSCertPool fetches the RDS CA certificates and places them into a pool.
    55  // It is safe to call from multiple goroutines.
    56  func (cf *CertFetcher) RDSCertPool(ctx context.Context) (*x509.CertPool, error) {
    57  	certs, err := cf.Fetch(ctx)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	certPool := x509.NewCertPool()
    62  	for _, c := range certs {
    63  		certPool.AddCert(c)
    64  	}
    65  	return certPool, nil
    66  }
    67  
    68  // Fetch fetches the RDS CA certificates. It is safe to call from multiple goroutines.
    69  func (cf *CertFetcher) Fetch(ctx context.Context) ([]*x509.Certificate, error) {
    70  	client := cf.Client
    71  	if client == nil {
    72  		client = http.DefaultClient
    73  	}
    74  	resp, err := ctxhttp.Get(ctx, client, caBundleURL)
    75  	if err != nil {
    76  		return nil, fmt.Errorf("fetch RDS certificates: %v", err)
    77  	}
    78  	defer resp.Body.Close()
    79  	if resp.StatusCode != http.StatusOK {
    80  		return nil, fmt.Errorf("fetch RDS certificates: HTTP %s", resp.Status)
    81  	}
    82  	pemData, err := ioutil.ReadAll(&io.LimitedReader{R: resp.Body, N: 1 << 20}) // limit to 1MiB
    83  	if err != nil {
    84  		return nil, fmt.Errorf("fetch RDS certificates: %v", err)
    85  	}
    86  	var certs []*x509.Certificate
    87  	for len(pemData) > 0 {
    88  		var block *pem.Block
    89  		block, pemData = pem.Decode(pemData)
    90  		if block == nil {
    91  			break
    92  		}
    93  		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
    94  			continue
    95  		}
    96  		c, err := x509.ParseCertificate(block.Bytes)
    97  		if err != nil {
    98  			return nil, fmt.Errorf("fetch RDS certificates: %v", err)
    99  		}
   100  		certs = append(certs, c)
   101  	}
   102  	return certs, nil
   103  }