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 }