Skip to content

Commit

Permalink
add support for profile
Browse files Browse the repository at this point in the history
Fixes #94

Signed-off-by: Anthony O'Brien <[email protected]>
  • Loading branch information
Anthony O'Brien committed Jun 7, 2018
1 parent 8c9b1bd commit 2748b56
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 9 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ Some good choices are:

The [Vault documentation](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method) also explains this attack (see `X-Vault-AWS-IAM-Server-ID`).

## AWS profiles
The AWS profile can be specified with the `--profile` flag, this takes precedence over the `AWS_PROFILE` environment variable. If no profile
is specified, the 'default' profile is used.

## Troubleshooting

If your client fails with an error like `could not get token: AccessDenied [...]`, you can try assuming the role with the AWS CLI directly:
Expand Down Expand Up @@ -219,6 +223,9 @@ They can share the same exact configuration file, since there are no secrets sto
# a unique-per-cluster identifier to prevent replay attacks (see above)
clusterID: my-dev-cluster.example.com

# AWS profile that specifies which credentials to use
profile: production

# default IAM role to assume for `heptio-authenticator-aws token`
defaultRole: arn:aws:iam::000000000000:role/KubernetesAdmin

Expand Down
9 changes: 9 additions & 0 deletions cmd/heptio-authenticator-aws/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ func init() {
)
viper.BindPFlag("clusterID", rootCmd.PersistentFlags().Lookup("cluster-id"))
viper.BindEnv("clusterID", "KUBERNETES_AWS_AUTHENTICATOR_CLUSTER_ID")

rootCmd.PersistentFlags().StringP(
"profile",
"p",
"",
"Specify the AWS profile to use. This takes precedence over the `AWS_PROFILE` env var.",
)
viper.BindPFlag("profile", rootCmd.PersistentFlags().Lookup("profile"))
}

func initConfig() {
Expand All @@ -76,6 +84,7 @@ func initConfig() {
func getConfig() (config.Config, error) {
config := config.Config{
ClusterID: viper.GetString("clusterID"),
Profile: viper.GetString("profile"),
ServerEC2DescribeInstancesRoleARN: viper.GetString("server.ec2DescribeInstancesRoleARN"),
LocalhostPort: viper.GetInt("server.port"),
GenerateKubeconfigPath: viper.GetString("server.generateKubeconfig"),
Expand Down
5 changes: 3 additions & 2 deletions cmd/heptio-authenticator-aws/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var tokenCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
roleARN := viper.GetString("role")
clusterID := viper.GetString("clusterID")
profile := viper.GetString("profile")

if clusterID == "" {
fmt.Fprintf(os.Stderr, "Error: cluster ID not specified\n")
Expand All @@ -49,10 +50,10 @@ var tokenCmd = &cobra.Command{
}
if roleARN != "" {
// if a role was provided, assume that role for the token
tok, err = gen.GetWithRole(clusterID, roleARN)
tok, err = gen.GetWithRole(clusterID, profile, roleARN)
} else {
// otherwise sign the token with immediately available credentials
tok, err = gen.Get(clusterID)
tok, err = gen.Get(clusterID, profile)
}
if err != nil {
fmt.Fprintf(os.Stderr, "could not get token: %v\n", err)
Expand Down
5 changes: 5 additions & 0 deletions pkg/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ type Config struct {
// heptio-authenticator-aws installation.
ClusterID string

// Profile specifies which credentials to use when authenticating
// via IAM. If not set, the profile in the `AWS_PROFILE` env var
// is used. If neither is set, the 'default' profile is used.
Profile string

// KubeconfigPregenerated is set to `true` when a webhook kubeconfig is
// pre-generated by running the `init` command, and therefore the
// `server` shouldn't unnecessarily re-generate a new one.
Expand Down
19 changes: 12 additions & 7 deletions pkg/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ type getCallerIdentityWrapper struct {

// Generator provides new tokens for the heptio authenticator.
type Generator interface {
// Get a token using credentials in the default credentials chain.
Get(string) (string, error)
// GetWithRole creates a token by assuming the provided role, using the credentials in the default chain.
GetWithRole(clusterID, roleARN string) (string, error)
// Get a token using credentials in the credentials chain specified by profile.
Get(string, string) (string, error)
// GetWithRole creates a token by assuming the provided role, using the
// credentials specified by profile.
GetWithRole(clusterID, profile, roleARN string) (string, error)
// FormatJSON returns the client auth formatted json for the ExecCredential auth
FormatJSON(string) string
}
Expand All @@ -142,8 +143,11 @@ func NewGenerator() (Generator, error) {

// Get uses the directly available AWS credentials to return a token valid for
// clusterID. It follows the default AWS credential handling behavior.
func (g generator) Get(clusterID string) (string, error) {
return g.GetWithRole(clusterID, "")
// If a profile is specified, those profile credentials will be used.
// If no profile is specified but the `AWS_PROFILE` env var is set, that
// profile will be used.
func (g generator) Get(clusterID string, profile string) (string, error) {
return g.GetWithRole(clusterID, profile, "")
}

func StdinStderrTokenProvider() (string, error) {
Expand All @@ -155,12 +159,13 @@ func StdinStderrTokenProvider() (string, error) {

// GetWithRole assumes the given AWS IAM role and returns a token valid for
// clusterID. If roleARN is empty, behaves like Get (does not assume a role).
func (g generator) GetWithRole(clusterID string, roleARN string) (string, error) {
func (g generator) GetWithRole(clusterID string, profile string, roleARN string) (string, error) {
// create a session with the "base" credentials available
// (from environment variable, profile files, EC2 metadata, etc)
sess, err := session.NewSessionWithOptions(session.Options{
AssumeRoleTokenProvider: StdinStderrTokenProvider,
SharedConfigState: session.SharedConfigEnable,
Profile: profile,
})
if err != nil {
return "", fmt.Errorf("could not create session: %v", err)
Expand Down

0 comments on commit 2748b56

Please sign in to comment.