mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 01:32:33 +00:00
Add support for signed GET requests for aws authentication (#10961)
* Support GET requests for aws-iam This is required to support presigned requests from aws-sdk-go-v2 * Add GET method tests for aws-iam auth login path * Update Website Documenation * Validate GET action even if iam-server header is not set * Combine URL checks * Add const amzSignedHeaders to aws credential builtin * Add test for multiple GET request actions * Add Changelog Entry --------- Co-authored-by: Max Coulombe <109547106+maxcoulombe@users.noreply.github.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
|
||||
const (
|
||||
amzHeaderPrefix = "X-Amz-"
|
||||
amzSignedHeaders = "X-Amz-SignedHeaders"
|
||||
operationPrefixAWS = "aws"
|
||||
)
|
||||
|
||||
@@ -32,7 +33,8 @@ var defaultAllowedSTSRequestHeaders = []string{
|
||||
"X-Amz-Date",
|
||||
"X-Amz-Security-Token",
|
||||
"X-Amz-Signature",
|
||||
"X-Amz-SignedHeaders",
|
||||
amzSignedHeaders,
|
||||
"X-Amz-User-Agent",
|
||||
}
|
||||
|
||||
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
@@ -388,6 +389,9 @@ type clientConfig struct {
|
||||
func (c *clientConfig) validateAllowedSTSHeaderValues(headers http.Header) error {
|
||||
for k := range headers {
|
||||
h := textproto.CanonicalMIMEHeaderKey(k)
|
||||
if h == "X-Amz-Signedheaders" {
|
||||
h = amzSignedHeaders
|
||||
}
|
||||
if strings.HasPrefix(h, amzHeaderPrefix) &&
|
||||
!strutil.StrListContains(defaultAllowedSTSRequestHeaders, h) &&
|
||||
!strutil.StrListContains(c.AllowedSTSHeaderValues, h) {
|
||||
@@ -397,6 +401,21 @@ func (c *clientConfig) validateAllowedSTSHeaderValues(headers http.Header) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *clientConfig) validateAllowedSTSQueryValues(params url.Values) error {
|
||||
for k := range params {
|
||||
h := textproto.CanonicalMIMEHeaderKey(k)
|
||||
if h == "X-Amz-Signedheaders" {
|
||||
h = amzSignedHeaders
|
||||
}
|
||||
if strings.HasPrefix(h, amzHeaderPrefix) &&
|
||||
!strutil.StrListContains(defaultAllowedSTSRequestHeaders, k) &&
|
||||
!strutil.StrListContains(c.AllowedSTSHeaderValues, k) {
|
||||
return errors.New("invalid request query param: " + k)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const pathConfigClientHelpSyn = `
|
||||
Configure AWS IAM credentials that are used to query instance and role details from the AWS API.
|
||||
`
|
||||
|
||||
@@ -97,7 +97,7 @@ significance.`,
|
||||
Type: framework.TypeString,
|
||||
Description: `HTTP method to use for the AWS request when auth_type is
|
||||
iam. This must match what has been signed in the
|
||||
presigned request. Currently, POST is the only supported value`,
|
||||
presigned request.`,
|
||||
},
|
||||
|
||||
"iam_request_url": {
|
||||
@@ -253,9 +253,8 @@ func (b *backend) pathLoginIamGetRoleNameCallerIdAndEntity(ctx context.Context,
|
||||
return "", nil, nil, logical.ErrorResponse("missing iam_http_request_method"), nil
|
||||
}
|
||||
|
||||
// In the future, might consider supporting GET
|
||||
if method != "POST" {
|
||||
return "", nil, nil, logical.ErrorResponse("invalid iam_http_request_method; currently only 'POST' is supported"), nil
|
||||
if method != http.MethodGet && method != http.MethodPost {
|
||||
return "", nil, nil, logical.ErrorResponse("invalid iam_http_request_method; currently only 'GET' and 'POST' are supported"), nil
|
||||
}
|
||||
|
||||
rawUrlB64 := data.Get("iam_request_url").(string)
|
||||
@@ -270,16 +269,12 @@ func (b *backend) pathLoginIamGetRoleNameCallerIdAndEntity(ctx context.Context,
|
||||
if err != nil {
|
||||
return "", nil, nil, logical.ErrorResponse("error parsing iam_request_url"), nil
|
||||
}
|
||||
if parsedUrl.RawQuery != "" {
|
||||
// Should be no query parameters
|
||||
return "", nil, nil, logical.ErrorResponse(logical.ErrInvalidRequest.Error()), nil
|
||||
if err = validateLoginIamRequestUrl(method, parsedUrl); err != nil {
|
||||
return "", nil, nil, logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
// TODO: There are two potentially valid cases we're not yet supporting that would
|
||||
// necessitate this check being changed. First, if we support GET requests.
|
||||
// Second if we support presigned POST requests
|
||||
bodyB64 := data.Get("iam_request_body").(string)
|
||||
if bodyB64 == "" {
|
||||
return "", nil, nil, logical.ErrorResponse("missing iam_request_body"), nil
|
||||
if bodyB64 == "" && method != http.MethodGet {
|
||||
return "", nil, nil, logical.ErrorResponse("missing iam_request_body which is required for POST requests"), nil
|
||||
}
|
||||
bodyRaw, err := base64.StdEncoding.DecodeString(bodyB64)
|
||||
if err != nil {
|
||||
@@ -305,7 +300,7 @@ func (b *backend) pathLoginIamGetRoleNameCallerIdAndEntity(ctx context.Context,
|
||||
maxRetries := awsClient.DefaultRetryerMaxNumRetries
|
||||
if config != nil {
|
||||
if config.IAMServerIdHeaderValue != "" {
|
||||
err = validateVaultHeaderValue(headers, parsedUrl, config.IAMServerIdHeaderValue)
|
||||
err = validateVaultHeaderValue(method, headers, parsedUrl, config.IAMServerIdHeaderValue)
|
||||
if err != nil {
|
||||
return "", nil, nil, logical.ErrorResponse(fmt.Sprintf("error validating %s header: %v", iamServerIdHeader, err)), nil
|
||||
}
|
||||
@@ -313,6 +308,11 @@ func (b *backend) pathLoginIamGetRoleNameCallerIdAndEntity(ctx context.Context,
|
||||
if err = config.validateAllowedSTSHeaderValues(headers); err != nil {
|
||||
return "", nil, nil, logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
if method == http.MethodGet {
|
||||
if err = config.validateAllowedSTSQueryValues(parsedUrl.Query()); err != nil {
|
||||
return "", nil, nil, logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
}
|
||||
if config.STSEndpoint != "" {
|
||||
endpoint = config.STSEndpoint
|
||||
}
|
||||
@@ -1534,6 +1534,31 @@ func hasWildcardBind(boundIamPrincipalARNs []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Validate that the iam_request_url passed is valid for the STS request
|
||||
func validateLoginIamRequestUrl(method string, parsedUrl *url.URL) error {
|
||||
switch method {
|
||||
case http.MethodGet:
|
||||
actions := map[string][]string(parsedUrl.Query())["Action"]
|
||||
if len(actions) == 0 {
|
||||
return fmt.Errorf("no action found in request")
|
||||
}
|
||||
if len(actions) != 1 {
|
||||
return fmt.Errorf("found multiple actions")
|
||||
}
|
||||
if actions[0] != "GetCallerIdentity" {
|
||||
return fmt.Errorf("unexpected action parameter, %s", actions[0])
|
||||
}
|
||||
return nil
|
||||
case http.MethodPost:
|
||||
if parsedUrl.RawQuery != "" {
|
||||
return logical.ErrInvalidRequest
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unsupported method, %s", method)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate that the iam_request_body passed is valid for the STS request
|
||||
func validateLoginIamRequestBody(body string) error {
|
||||
qs, err := url.ParseQuery(body)
|
||||
@@ -1570,11 +1595,11 @@ func hasValuesForEc2Auth(data *framework.FieldData) (bool, bool) {
|
||||
}
|
||||
|
||||
func hasValuesForIamAuth(data *framework.FieldData) (bool, bool) {
|
||||
_, hasRequestMethod := data.GetOk("iam_http_request_method")
|
||||
method, hasRequestMethod := data.GetOk("iam_http_request_method")
|
||||
_, hasRequestURL := data.GetOk("iam_request_url")
|
||||
_, hasRequestBody := data.GetOk("iam_request_body")
|
||||
_, hasRequestHeaders := data.GetOk("iam_request_headers")
|
||||
return (hasRequestMethod && hasRequestURL && hasRequestBody && hasRequestHeaders),
|
||||
return (hasRequestMethod && hasRequestURL && (method == http.MethodGet || hasRequestBody) && hasRequestHeaders),
|
||||
(hasRequestMethod || hasRequestURL || hasRequestBody || hasRequestHeaders)
|
||||
}
|
||||
|
||||
@@ -1628,7 +1653,7 @@ func parseIamArn(iamArn string) (*iamEntity, error) {
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
func validateVaultHeaderValue(headers http.Header, _ *url.URL, requiredHeaderValue string) error {
|
||||
func validateVaultHeaderValue(method string, headers http.Header, parsedUrl *url.URL, requiredHeaderValue string) error {
|
||||
providedValue := ""
|
||||
for k, v := range headers {
|
||||
if strings.EqualFold(iamServerIdHeader, k) {
|
||||
@@ -1644,25 +1669,29 @@ func validateVaultHeaderValue(headers http.Header, _ *url.URL, requiredHeaderVal
|
||||
if providedValue != requiredHeaderValue {
|
||||
return fmt.Errorf("expected %q but got %q", requiredHeaderValue, providedValue)
|
||||
}
|
||||
|
||||
if authzHeaders, ok := headers["Authorization"]; ok {
|
||||
// authzHeader looks like AWS4-HMAC-SHA256 Credential=AKI..., SignedHeaders=host;x-amz-date;x-vault-awsiam-id, Signature=...
|
||||
// We need to extract out the SignedHeaders
|
||||
re := regexp.MustCompile(".*SignedHeaders=([^,]+)")
|
||||
authzHeader := strings.Join(authzHeaders, ",")
|
||||
matches := re.FindSubmatch([]byte(authzHeader))
|
||||
if len(matches) < 1 {
|
||||
return fmt.Errorf("vault header wasn't signed")
|
||||
switch method {
|
||||
case http.MethodPost:
|
||||
if authzHeaders, ok := headers["Authorization"]; ok {
|
||||
// authzHeader looks like AWS4-HMAC-SHA256 Credential=AKI..., SignedHeaders=host;x-amz-date;x-vault-awsiam-id, Signature=...
|
||||
// We need to extract out the SignedHeaders
|
||||
re := regexp.MustCompile(".*SignedHeaders=([^,]+)")
|
||||
authzHeader := strings.Join(authzHeaders, ",")
|
||||
matches := re.FindSubmatch([]byte(authzHeader))
|
||||
if len(matches) < 1 {
|
||||
return fmt.Errorf("vault header wasn't signed")
|
||||
}
|
||||
if len(matches) > 2 {
|
||||
return fmt.Errorf("found multiple SignedHeaders components")
|
||||
}
|
||||
signedHeaders := string(matches[1])
|
||||
return ensureHeaderIsSigned(signedHeaders, iamServerIdHeader)
|
||||
}
|
||||
if len(matches) > 2 {
|
||||
return fmt.Errorf("found multiple SignedHeaders components")
|
||||
}
|
||||
signedHeaders := string(matches[1])
|
||||
return ensureHeaderIsSigned(signedHeaders, iamServerIdHeader)
|
||||
return fmt.Errorf("missing Authorization header")
|
||||
case http.MethodGet:
|
||||
return ensureHeaderIsSigned(parsedUrl.Query().Get(amzSignedHeaders), iamServerIdHeader)
|
||||
default:
|
||||
return fmt.Errorf("unsupported method, %s", method)
|
||||
}
|
||||
// TODO: If we support GET requests, then we need to parse the X-Amz-SignedHeaders
|
||||
// argument out of the query string and search in there for the header value
|
||||
return fmt.Errorf("missing Authorization header")
|
||||
}
|
||||
|
||||
func buildHttpRequest(method, endpoint string, parsedUrl *url.URL, body string, headers http.Header) *http.Request {
|
||||
|
||||
@@ -126,9 +126,129 @@ func TestBackend_pathLogin_parseIamArn(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackend_validateVaultHeaderValue(t *testing.T) {
|
||||
func TestBackend_validateVaultGetRequestValues(t *testing.T) {
|
||||
const canaryHeaderValue = "Vault-Server"
|
||||
requestURL, err := url.Parse("https://sts.amazonaws.com/")
|
||||
|
||||
getHeadersMissing := http.Header{
|
||||
"Host": []string{"Foo"},
|
||||
}
|
||||
getHeadersInvalid := http.Header{
|
||||
"Host": []string{"Foo"},
|
||||
iamServerIdHeader: []string{"InvalidValue"},
|
||||
}
|
||||
getHeadersValid := http.Header{
|
||||
"Host": []string{"Foo"},
|
||||
iamServerIdHeader: []string{canaryHeaderValue},
|
||||
}
|
||||
getQueryValid := url.Values(map[string][]string{
|
||||
"X-Amz-Algorithm": {"AWS4-HMAC-SHA256"},
|
||||
"X-Amz-Credential": {"AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request"},
|
||||
amzSignedHeaders: {"host;x-vault-aws-iam-server-id"},
|
||||
"X-Amz-Signature": {"5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"},
|
||||
"X-Amz-User-Agent": {"aws-sdk-go-v2/1.2.0 os/linux lang/go/1.16 md/GOOS/linux md/GOARCH/amd64"},
|
||||
"Action": {"GetCallerIdentity"},
|
||||
"Version": {"2011-06-15"},
|
||||
})
|
||||
getQueryUnsigned := url.Values(map[string][]string{
|
||||
"X-Amz-Algorithm": {"AWS4-HMAC-SHA256"},
|
||||
"X-Amz-Credential": {"AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request"},
|
||||
amzSignedHeaders: {"host"},
|
||||
"X-Amz-Signature": {"5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"},
|
||||
"X-Amz-User-Agent": {"aws-sdk-go-v2/1.2.0 os/linux lang/go/1.16 md/GOOS/linux md/GOARCH/amd64"},
|
||||
"Action": {"GetCallerIdentity"},
|
||||
"Version": {"2011-06-15"},
|
||||
})
|
||||
getQueryNoAction := url.Values(map[string][]string{
|
||||
"X-Amz-Algorithm": {"AWS4-HMAC-SHA256"},
|
||||
"X-Amz-Credential": {"AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request"},
|
||||
amzSignedHeaders: {"host;x-vault-aws-iam-server-id"},
|
||||
"X-Amz-Signature": {"5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"},
|
||||
"X-Amz-User-Agent": {"aws-sdk-go-v2/1.2.0 os/linux lang/go/1.16 md/GOOS/linux md/GOARCH/amd64"},
|
||||
"Version": {"2011-06-15"},
|
||||
})
|
||||
getQueryInvalidAction := url.Values(map[string][]string{
|
||||
"X-Amz-Algorithm": {"AWS4-HMAC-SHA256"},
|
||||
"X-Amz-Credential": {"AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request"},
|
||||
amzSignedHeaders: {"host;x-vault-aws-iam-server-id"},
|
||||
"X-Amz-Signature": {"5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"},
|
||||
"X-Amz-User-Agent": {"aws-sdk-go-v2/1.2.0 os/linux lang/go/1.16 md/GOOS/linux md/GOARCH/amd64"},
|
||||
"Action": {"GetSessionToken"},
|
||||
"Version": {"2011-06-15"},
|
||||
})
|
||||
getQueryMultipleActions := url.Values(map[string][]string{
|
||||
"X-Amz-Algorithm": {"AWS4-HMAC-SHA256"},
|
||||
"X-Amz-Credential": {"AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request"},
|
||||
amzSignedHeaders: {"host;x-vault-aws-iam-server-id"},
|
||||
"X-Amz-Signature": {"5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"},
|
||||
"X-Amz-User-Agent": {"aws-sdk-go-v2/1.2.0 os/linux lang/go/1.16 md/GOOS/linux md/GOARCH/amd64"},
|
||||
"Action": {"GetCallerIdentity;GetSessionToken"},
|
||||
"Version": {"2011-06-15"},
|
||||
})
|
||||
validGetRequestURL, err := url.Parse("https://sts.amazonaws.com/?" + getQueryValid.Encode())
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing test URL: %v", err)
|
||||
}
|
||||
unsignedGetRequestURL, err := url.Parse("https://sts.amazonaws.com/?" + getQueryUnsigned.Encode())
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing test URL: %v", err)
|
||||
}
|
||||
noActionGetRequestURL, err := url.Parse("https://sts.amazonaws.com/?" + getQueryNoAction.Encode())
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing test URL: %v", err)
|
||||
}
|
||||
invalidActionGetRequestURL, err := url.Parse("https://sts.amazonaws.com/?" + getQueryInvalidAction.Encode())
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing test URL: %v", err)
|
||||
}
|
||||
multipleActionsGetRequestURL, err := url.Parse("https://sts.amazonaws.com/?" + getQueryMultipleActions.Encode())
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing test URL: %v", err)
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(http.MethodGet, getHeadersMissing, validGetRequestURL, canaryHeaderValue)
|
||||
if err == nil {
|
||||
t.Error("validated GET request with missing Vault header")
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(http.MethodGet, getHeadersInvalid, validGetRequestURL, canaryHeaderValue)
|
||||
if err == nil {
|
||||
t.Error("validated GET request with invalid Vault header value")
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(http.MethodGet, getHeadersValid, unsignedGetRequestURL, canaryHeaderValue)
|
||||
if err == nil {
|
||||
t.Error("validated GET request with unsigned Vault header")
|
||||
}
|
||||
|
||||
err = validateLoginIamRequestUrl(http.MethodGet, noActionGetRequestURL)
|
||||
if err == nil {
|
||||
t.Error("validated GET request with no Action parameter")
|
||||
}
|
||||
|
||||
err = validateLoginIamRequestUrl(http.MethodGet, multipleActionsGetRequestURL)
|
||||
if err == nil {
|
||||
t.Error("validated GET request with multiple Action parameters")
|
||||
}
|
||||
|
||||
err = validateLoginIamRequestUrl(http.MethodGet, invalidActionGetRequestURL)
|
||||
if err == nil {
|
||||
t.Error("validated GET request with an invalid Action parameter")
|
||||
}
|
||||
|
||||
err = validateLoginIamRequestUrl(http.MethodGet, validGetRequestURL)
|
||||
if err != nil {
|
||||
t.Errorf("did NOT validate valid GET request: %v", err)
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(http.MethodGet, getHeadersValid, validGetRequestURL, canaryHeaderValue)
|
||||
if err != nil {
|
||||
t.Errorf("did NOT validate valid GET request: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackend_validateVaultPostRequestValues(t *testing.T) {
|
||||
const canaryHeaderValue = "Vault-Server"
|
||||
postRequestURL, err := url.Parse("https://sts.amazonaws.com/")
|
||||
if err != nil {
|
||||
t.Fatalf("error parsing test URL: %v", err)
|
||||
}
|
||||
@@ -151,34 +271,38 @@ func TestBackend_validateVaultHeaderValue(t *testing.T) {
|
||||
iamServerIdHeader: []string{canaryHeaderValue},
|
||||
"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-vault-aws-iam-server-id, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"},
|
||||
}
|
||||
|
||||
postHeadersSplit := http.Header{
|
||||
"Host": []string{"Foo"},
|
||||
iamServerIdHeader: []string{canaryHeaderValue},
|
||||
"Authorization": []string{"AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request", "SignedHeaders=content-type;host;x-amz-date;x-vault-aws-iam-server-id, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"},
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(postHeadersMissing, requestURL, canaryHeaderValue)
|
||||
err = validateVaultHeaderValue(http.MethodPost, postHeadersMissing, postRequestURL, canaryHeaderValue)
|
||||
if err == nil {
|
||||
t.Error("validated POST request with missing Vault header")
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(postHeadersInvalid, requestURL, canaryHeaderValue)
|
||||
err = validateVaultHeaderValue(http.MethodPost, postHeadersInvalid, postRequestURL, canaryHeaderValue)
|
||||
if err == nil {
|
||||
t.Error("validated POST request with invalid Vault header value")
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(postHeadersUnsigned, requestURL, canaryHeaderValue)
|
||||
err = validateVaultHeaderValue(http.MethodPost, postHeadersUnsigned, postRequestURL, canaryHeaderValue)
|
||||
if err == nil {
|
||||
t.Error("validated POST request with unsigned Vault header")
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(postHeadersValid, requestURL, canaryHeaderValue)
|
||||
err = validateVaultHeaderValue(http.MethodPost, postHeadersValid, postRequestURL, canaryHeaderValue)
|
||||
if err != nil {
|
||||
t.Errorf("did NOT validate valid POST request: %v", err)
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(postHeadersSplit, requestURL, canaryHeaderValue)
|
||||
err = validateLoginIamRequestUrl(http.MethodPost, postRequestURL)
|
||||
if err != nil {
|
||||
t.Errorf("did NOT validate valid POST request: %v", err)
|
||||
}
|
||||
|
||||
err = validateVaultHeaderValue(http.MethodPost, postHeadersSplit, postRequestURL, canaryHeaderValue)
|
||||
if err != nil {
|
||||
t.Errorf("did NOT validate valid POST request with split Authorization header: %v", err)
|
||||
}
|
||||
|
||||
3
changelog/10961.txt
Normal file
3
changelog/10961.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
auth/aws: Added support for signed GET requests for authenticating to vault using the aws iam method.
|
||||
```
|
||||
@@ -1078,18 +1078,18 @@ for more information on the signature types.
|
||||
enabled on either the role or the role tag, the `nonce` holds no significance.
|
||||
This is ignored unless using the ec2 auth method.
|
||||
- `iam_http_request_method` `(string: <required-iam>)` - HTTP method used in the
|
||||
signed request. Currently only POST is supported, but other methods may be
|
||||
supported in the future. This is required when using the iam auth method.
|
||||
signed request. This is required when using the iam auth method.
|
||||
- `iam_request_url` `(string: <required-iam>)` - Base64-encoded HTTP URL used in
|
||||
the signed request. Most likely just `aHR0cHM6Ly9zdHMuYW1hem9uYXdzLmNvbS8=`
|
||||
(base64-encoding of `https://sts.amazonaws.com/`) as most requests will
|
||||
probably use POST with an empty URI. This is required when using the iam auth
|
||||
method.
|
||||
probably use POST with an empty URI. If using GET method this will contain
|
||||
the authentication headers that have been hoisted out of the message body.
|
||||
This is required when using the iam auth method.
|
||||
- `iam_request_body` `(string: <required-iam>)` - Base64-encoded body of the
|
||||
signed request. Most likely
|
||||
`QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb249MjAxMS0wNi0xNQ==`, which is the
|
||||
base64 encoding of `Action=GetCallerIdentity&Version=2011-06-15`. This is
|
||||
required when using the iam auth method.
|
||||
required when using the iam auth method with POST signed requests.
|
||||
- `iam_request_headers` `(string: <required-iam>)` - Key/value pairs of headers
|
||||
for use in the `sts:GetCallerIdentity` HTTP requests headers. Can be either a
|
||||
Base64-encoded, JSON-serialized string, or a JSON object of key/value pairs. The
|
||||
|
||||
Reference in New Issue
Block a user