-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
allow TF_TOKEN_... variables to specify host-specific credentials #477
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package tfe | ||
|
||
import ( | ||
"log" | ||
"os" | ||
"strings" | ||
|
||
svchost "github.com/hashicorp/terraform-svchost" | ||
"github.com/hashicorp/terraform-svchost/disco" | ||
) | ||
|
||
func collectCredentialsFromEnv() map[svchost.Hostname]string { | ||
const prefix = "TF_TOKEN_" | ||
|
||
ret := make(map[svchost.Hostname]string) | ||
for _, ev := range os.Environ() { | ||
eqIdx := strings.Index(ev, "=") | ||
if eqIdx < 0 { | ||
continue | ||
} | ||
name := ev[:eqIdx] | ||
value := ev[eqIdx+1:] | ||
if !strings.HasPrefix(name, prefix) { | ||
continue | ||
} | ||
rawHost := name[len(prefix):] | ||
|
||
// We accept double underscores in place of hyphens because hyphens are not valid | ||
// identifiers in most shells and are therefore hard to set. | ||
// This is unambiguous with replacing single underscores below because | ||
// hyphens are not allowed at the beginning or end of a label and therefore | ||
// odd numbers of underscores will not appear together in a valid variable name. | ||
rawHost = strings.ReplaceAll(rawHost, "__", "-") | ||
|
||
// We accept underscores in place of dots because dots are not valid | ||
// identifiers in most shells and are therefore hard to set. | ||
// Underscores are not valid in hostnames, so this is unambiguous for | ||
// valid hostnames. | ||
rawHost = strings.ReplaceAll(rawHost, "_", ".") | ||
|
||
// Because environment variables are often set indirectly by OS | ||
// libraries that might interfere with how they are encoded, we'll | ||
// be tolerant of them being given either directly as UTF-8 IDNs | ||
// or in Punycode form, normalizing to Punycode form here because | ||
// that is what the Terraform credentials helper protocol will | ||
// use in its requests. | ||
// | ||
// Using ForDisplay first here makes this more liberal than Terraform | ||
// itself would usually be in that it will tolerate pre-punycoded | ||
// hostnames that Terraform normally rejects in other contexts in order | ||
// to ensure stored hostnames are human-readable. | ||
dispHost := svchost.ForDisplay(rawHost) | ||
hostname, err := svchost.ForComparison(dispHost) | ||
if err != nil { | ||
// Ignore invalid hostnames | ||
continue | ||
} | ||
|
||
ret[hostname] = value | ||
} | ||
|
||
return ret | ||
} | ||
|
||
// hostTokenFromFallbackSources returns a token credential by searching for a hostname-specific | ||
// environment variable, a TFE_TOKEN, or a CLI config credentials block. The host parameter | ||
// is expected to be in the "comparison" form, for example, hostnames containing non-ASCII | ||
// characters like "café.fr" should be expressed as "xn--caf-dma.fr". If the variable based | ||
// on the hostname is not defined, nil is returned. | ||
// | ||
// Hyphen and period characters are allowed in environment variable names, but are not valid POSIX | ||
// variable names. However, it's still possible to set variable names with these characters using | ||
// utilities like env or docker. Variable names may have periods translated to underscores and | ||
// hyphens translated to double underscores in the variable name. | ||
// For the example "café.fr", you may use the variable names "TF_TOKEN_xn____caf__dma_fr", | ||
// "TF_TOKEN_xn--caf-dma_fr", or "TF_TOKEN_xn--caf-dma.fr" | ||
func hostTokenFromFallbackSources(hostname svchost.Hostname, services *disco.Disco) string { | ||
token, ok := collectCredentialsFromEnv()[hostname] | ||
|
||
if ok { | ||
log.Printf("[DEBUG] TF_TOKEN_... used for token value for host %s", hostname) | ||
} else { | ||
// If a token wasn't set in the host-specific variable, try and fetch it | ||
// from the environment or from Terraform's CLI configuration or configured credential helper. | ||
if os.Getenv("TFE_TOKEN") != "" { | ||
log.Printf("[DEBUG] TFE_TOKEN used for token value") | ||
return os.Getenv("TFE_TOKEN") | ||
} else if services != nil { | ||
log.Printf("[DEBUG] Attempting to fetch token from Terraform CLI configuration for hostname %s...", hostname) | ||
creds, err := services.CredentialsForHost(hostname) | ||
if err != nil { | ||
log.Printf("[DEBUG] Failed to get credentials for %s: %s (ignoring)", hostname, err) | ||
} | ||
if creds != nil { | ||
token = creds.Token() | ||
} | ||
} | ||
} | ||
|
||
return token | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious here on readability: Would it be better to
strings.Split()
on=
and compare each index rather than using ranges ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Split might be slightly more readable, but this version doesn't do any array allocation and is shared with terraform already. I think I'd like to keep it.