open-consul/agent/connect/ca/provider_vault_auth_aws.go
John Eikenberry 5ac637f07d
add provider ca auth-method support for azure
Does the required dance with the local HTTP endpoint to get the required
data for the jwt based auth setup in Azure. Keeps support for 'legacy'
mode where all login data is passed on via the auth methods parameters.
Refactored check for hardcoded /login fields.
2023-03-01 00:07:33 +00:00

116 lines
4.1 KiB
Go

package ca
import (
"fmt"
"os"
"strconv"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/awsutil"
"github.com/hashicorp/consul/agent/structs"
)
// NewAWSAuthClient returns a VaultAuthClient that can log into Vault using the AWS auth method.
func NewAWSAuthClient(authMethod *structs.VaultAuthMethod) *VaultAuthClient {
authClient := NewVaultAPIAuthClient(authMethod, "")
// Inspect the config params to see if they are already in the format required for
// the auth/aws/login API call. If so, we want to call the login API with the params
// exactly as they are configured. This supports the Vault CA config in a backwards
// compatible way so that we don't break existing configurations.
keys := []string{
"identity", // EC2 identity
"pkcs7", // EC2 PKCS7
"iam_http_request_method", // IAM
}
if legacyCheck(authMethod.Params, keys...) {
return authClient
}
// None of the known config is present so use the login data generator to transform
// the auth method config params into the login data request needed to authenticate
// via AWS.
lgd := &AWSLoginDataGenerator{}
authClient.LoginDataGen = lgd.GenerateLoginData
return authClient
}
// AWSLoginDataGenerator is a LoginDataGenerator for AWS authentication.
type AWSLoginDataGenerator struct {
// credentials supports explicitly setting the AWS credentials to use for authenticating with AWS.
// It is un-exported and intended for testing purposes only.
credentials *credentials.Credentials
}
// GenerateLoginData derives the login data for the Vault AWS auth login request from the CA
// provider auth method config.
func (g *AWSLoginDataGenerator) GenerateLoginData(authMethod *structs.VaultAuthMethod) (map[string]interface{}, error) {
// Create the credential configuration from the parameters.
credsConfig, headerValue, err := newAWSCredentialsConfig(authMethod.Params)
if err != nil {
return nil, fmt.Errorf("aws auth failed to create credential configuration: %w", err)
}
// Use the provided credentials if they are present.
creds := g.credentials
if creds == nil {
// Generate the credential chain
creds, err = credsConfig.GenerateCredentialChain()
if err != nil {
return nil, fmt.Errorf("aws auth failed to generate credential chain: %w", err)
}
}
// Derive the login data
loginData, err := awsutil.GenerateLoginData(creds, headerValue, credsConfig.Region, hclog.NewNullLogger())
if err != nil {
return nil, fmt.Errorf("aws auth failed to generate login data: %w", err)
}
return loginData, nil
}
// newAWSCredentialsConfig creates an awsutil.CredentialsConfig from the given set of parameters.
// It is mostly copied from the awsutil package because that package does not currently provide
// an easy way to configure all the available options.
func newAWSCredentialsConfig(config map[string]interface{}) (*awsutil.CredentialsConfig, string, error) {
params, err := toMapStringString(config)
if err != nil {
return nil, "", fmt.Errorf("misconfiguration of AWS auth parameters: %w", err)
}
// Populate the AWS credentials configuration. Empty strings will use the defaults.
c := &awsutil.CredentialsConfig{
AccessKey: params["access_key"],
SecretKey: params["secret_key"],
SessionToken: params["session_token"],
IAMEndpoint: params["iam_endpoint"],
STSEndpoint: params["sts_endpoint"],
Region: params["region"],
Filename: params["filename"],
Profile: params["profile"],
RoleARN: params["role_arn"],
RoleSessionName: params["role_session_name"],
WebIdentityTokenFile: params["web_identity_token_file"],
HTTPClient: cleanhttp.DefaultClient(),
}
if maxRetries, err := strconv.Atoi(params["max_retries"]); err == nil {
c.MaxRetries = &maxRetries
}
if c.Region == "" {
c.Region = os.Getenv("AWS_REGION")
if c.Region == "" {
c.Region = os.Getenv("AWS_DEFAULT_REGION")
if c.Region == "" {
c.Region = "us-east-1"
}
}
}
return c, params["header_value"], nil
}