Terraform-provider-vault: Vault provider does not support IAM authentication with docker task role

Created on 17 Sep 2020  路  4Comments  路  Source: hashicorp/terraform-provider-vault

Terraform Version

0.12.28

Affected Resource(s)

Please list the resources as a list, for example:

  • provider "vault"

Terraform Configuration Files

provider "vault" {
  address         = "https://vault.mycompany.com:443"
  skip_tls_verify = false
  auth_login {
    path = "auth/aws/login"
    parameters = {
      role                 = "atlantis-admin"
      iam_http_post_method = "POST"
      # this is base64 for https://sts.amazonaws.com/
      iam_request_url      = "aHR0cHM6Ly9zdHMuYW1hem9uYXdzLmNvbS8="
      # this is base64 for Action=GetCallerIdentity&Version=2011-06-15
      iam_request_body     = "QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb249MjAxMS0wNi0xNQ=="
    }
  }
}

Expected Behavior

Provider should work

Actual Behavior

Error: Error making API request.

URL: PUT https://vault.mycompany.com:443/v1/auth/aws/login
Code: 400. Errors:

* didn't supply required authentication values

  on providers.tf line 1, in provider "vault":
   1: provider "vault" {

Steps to Reproduce

  1. terraform apply

Important Factoids

This is running in an ECS container. The task role of that container is allowed to assume the vault role atlantis-admin. It seems the vault provider behaves differently from vault login -method=aws.

I guess we could install vault in atlantis and run vault login instead, but it would be nice if this worked using just terraform.

bug resourcaws_auth

Most helpful comment

@catsby We've encountered the same issue and an identical error message when trying to plan/apply locally.

provider "vault" {
  address         = var.vault_url
  skip_tls_verify = false
  auth_login {
    path = "auth/aws/login"
    parameters = {
      iam_http_request_method = "POST"
      role = "my_role"
      iam_request_url = base64encode("https://sts.amazonaws.com/")
      iam_request_body = base64encode("Action=GetCallerIdentity&Version=2011-06-15")
    }
  }
}

and we're able to login successfully using vault login -method=aws role=my_role
(aws credentials stored at default location, ~/.aws/credentials).

EDIT

we've made some progress after adding the iam-required iam_request_headers key.

provider "vault" {
  ...
    parameters = {
      iam_http_request_method = "POST"
      role = "my_role"
      iam_request_url = base64encode("https://sts.amazonaws.com/")
      iam_request_body = base64encode("Action=GetCallerIdentity&Version=2011-06-15")
      iam_request_headers = jsonencode({
        Host = "sts.amazonaws.com"
        Content-Type = "application/x-www-form-urlencoded"
      })
    }
  }
}

Now we're seeing a more informative error message:

Error: Error making API request.

URL: PUT https://vault.mycompany.com/v1/auth/aws/login
Code: 400. Errors:

* error making upstream request: received error code 403 from STS: <ErrorResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
  <Error>
    <Type>Sender</Type>
    <Code>MissingAuthenticationToken</Code>
    <Message>Request is missing Authentication Token</Message>
  </Error>
  <RequestId>REDACTED_UUID</RequestId>
</ErrorResponse>

It does seem like there's no message signing being made for the sts:GetCallerIdentity call
https://github.com/hashicorp/vault/blob/master/builtin/credential/aws/path_login.go#L1610
and that the Authorization header is assumed to be already present on the iam_request_headers map read by the
https://github.com/hashicorp/vault/blob/master/builtin/credential/aws/path_login.go#L1208

would it be possible to rely on the sts package instead, and provide it with a Session object which contains the optionally-overridden STS endpoint as demonstrated by the example in the endpoints package?

if not, would it be possible to sign the message directly with the signer/v4 package?

All 4 comments

Hello -

I believe there is a typo in your parameters block; the parameter iam_http_post_method should instead be iam_http_request_method. Please give that a try and let us know!

@catsby We've encountered the same issue and an identical error message when trying to plan/apply locally.

provider "vault" {
  address         = var.vault_url
  skip_tls_verify = false
  auth_login {
    path = "auth/aws/login"
    parameters = {
      iam_http_request_method = "POST"
      role = "my_role"
      iam_request_url = base64encode("https://sts.amazonaws.com/")
      iam_request_body = base64encode("Action=GetCallerIdentity&Version=2011-06-15")
    }
  }
}

and we're able to login successfully using vault login -method=aws role=my_role
(aws credentials stored at default location, ~/.aws/credentials).

EDIT

we've made some progress after adding the iam-required iam_request_headers key.

provider "vault" {
  ...
    parameters = {
      iam_http_request_method = "POST"
      role = "my_role"
      iam_request_url = base64encode("https://sts.amazonaws.com/")
      iam_request_body = base64encode("Action=GetCallerIdentity&Version=2011-06-15")
      iam_request_headers = jsonencode({
        Host = "sts.amazonaws.com"
        Content-Type = "application/x-www-form-urlencoded"
      })
    }
  }
}

Now we're seeing a more informative error message:

Error: Error making API request.

URL: PUT https://vault.mycompany.com/v1/auth/aws/login
Code: 400. Errors:

* error making upstream request: received error code 403 from STS: <ErrorResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
  <Error>
    <Type>Sender</Type>
    <Code>MissingAuthenticationToken</Code>
    <Message>Request is missing Authentication Token</Message>
  </Error>
  <RequestId>REDACTED_UUID</RequestId>
</ErrorResponse>

It does seem like there's no message signing being made for the sts:GetCallerIdentity call
https://github.com/hashicorp/vault/blob/master/builtin/credential/aws/path_login.go#L1610
and that the Authorization header is assumed to be already present on the iam_request_headers map read by the
https://github.com/hashicorp/vault/blob/master/builtin/credential/aws/path_login.go#L1208

would it be possible to rely on the sts package instead, and provide it with a Session object which contains the optionally-overridden STS endpoint as demonstrated by the example in the endpoints package?

if not, would it be possible to sign the message directly with the signer/v4 package?

I'm quite new to terraform, not sure what is the cleanest way to write this but with this python script I get signed request and update values in vars.auto.tfvars.
And this works for me:

 provider "vault" {
  address = "https://vault.foo.com/"

  auth_login {
    path = "auth/aws/login"

    parameters = {
      iam_http_request_method = "POST"
      role  = var.auth_login_role
      iam_request_url  = var.iam_request_url
      iam_request_body = var.iam_request_body
      iam_request_headers = var.iam_request_headers
    }
  }
}

Terraform v0.13.4

TBH it's a little incredible that this doesn't work with just, like, AWS credentials. Seems like an awful lot wheel reinvention going on here that we have to craft our own body and sign our own headers.

Was this page helpful?
0 / 5 - 0 ratings