Skip to content

Instantly share code, notes, and snippets.

@jnahelou
Last active October 16, 2020 20:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnahelou/02e0f727ae298a06933f9f85481bb398 to your computer and use it in GitHub Desktop.
Save jnahelou/02e0f727ae298a06933f9f85481bb398 to your computer and use it in GitHub Desktop.
Terraform patch to add authentication headers during provider download
diff --git a/command/providers_mirror.go b/command/providers_mirror.go
index 029b08630..db0760d95 100644
--- a/command/providers_mirror.go
+++ b/command/providers_mirror.go
@@ -4,6 +4,8 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
+ "log"
+ "net/http"
"net/url"
"os"
"path/filepath"
@@ -27,6 +29,16 @@ func (c *ProvidersMirrorCommand) Synopsis() string {
return "Mirrors the provider plugins needed for the current configuration"
}
+type transport struct {
+ underlyingTransport http.RoundTripper
+ token string
+}
+
+func (t transport) RoundTrip(req *http.Request) (*http.Response, error) {
+ req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", t.token))
+ return t.underlyingTransport.RoundTrip(req)
+}
+
func (c *ProvidersMirrorCommand) Run(args []string) int {
args = c.Meta.process(args)
cmdFlags := c.Meta.defaultFlagSet("providers mirror")
@@ -90,14 +102,6 @@ func (c *ProvidersMirrorCommand) Run(args []string) int {
getproviders.NewRegistrySource(c.Services),
)
- // Providers from registries always use HTTP, so we don't need the full
- // generality of go-getter but it's still handy to use the HTTP getter
- // as an easy way to download over HTTP into a file on disk.
- httpGetter := getter.HttpGetter{
- Client: httpclient.New(),
- Netrc: true,
- }
-
// The following logic is similar to that used by the provider installer
// in package providercache, but different in a few ways:
// - It produces the packed directory layout rather than the unpacked
@@ -185,6 +189,30 @@ func (c *ProvidersMirrorCommand) Run(args []string) int {
// it discoverable to mirror clients. (stagingPath intentionally
// does not follow the filesystem mirror file naming convention.)
targetPath := meta.PackedFilePath(outputDir)
+
+ // Providers from registries always use HTTP, so we don't need the full
+ // generality of go-getter but it's still handy to use the HTTP getter
+ // as an easy way to download over HTTP into a file on disk.
+ creds, err := c.Services.CredentialsForHost(provider.Hostname)
+ if err != nil {
+ diags = diags.Append(tfdiags.Sourceless(
+ tfdiags.Error,
+ "Invalid credentials",
+ fmt.Sprintf("Invalide credentials found for provider %s : %s.", provider.String(), err),
+ ))
+ continue
+ }
+ gclient := httpclient.New()
+ if creds.Token() != "" {
+ gclient.Transport = &transport{underlyingTransport: gclient.Transport, token: creds.Token()}
+ }
+
+ // Add auth on every requests
+ httpGetter := getter.HttpGetter{
+ Client: gclient,
+ Netrc: true,
+ }
+
stagingPath := filepath.Join(filepath.Dir(targetPath), "."+filepath.Base(targetPath))
err = httpGetter.GetFile(stagingPath, urlObj)
if err != nil {
diff --git a/internal/getproviders/registry_client.go b/internal/getproviders/registry_client.go
index 8c0256661..c5c8edc5c 100644
--- a/internal/getproviders/registry_client.go
+++ b/internal/getproviders/registry_client.go
@@ -435,7 +435,10 @@ func (c *registryClient) errUnauthorized(hostname svchost.Hostname) error {
}
func (c *registryClient) getFile(url *url.URL) ([]byte, error) {
- resp, err := c.httpClient.Get(url.String())
+ req, _ := http.NewRequest("GET", url.String(), nil)
+ req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.creds.Token()))
+
+ resp, err := c.httpClient.Do(&retryablehttp.Request{Request: req})
if err != nil {
return nil, err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment