hashicorp / terraform-provider-vault

Terraform Vault provider
https://www.terraform.io/docs/providers/vault/
Mozilla Public License 2.0
458 stars 537 forks source link

Vault AppRole login use PUT instead of POST #688

Closed bogaertg closed 2 years ago

bogaertg commented 4 years ago

Hi,

I use terraform 11 with vault provider (2.8.0) on MAC OS. I try to login with ROLE_ID and SECRET_ID

variable VAULT_ROLE_ID {
}

variable VAULT_SECRET_ID {
}

provider "vault" {
  address = "*****"
  namespace = "*****"

  auth_login {
    path = "auth/approle/login"

    namespace = "*****"
    parameters = {
      role_id   = "*****"
      secret_id = "*****"
    }
  }
}

data "vault_generic_secret" "tf_creds" {
  path = ""*****""
}

With terraform plan with DEBUG, i have the following stacktrace :

2020-02-25T19:50:44.698Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: ---[ REQUEST ]---------------------------------------
2020-02-25T19:50:44.698Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: PUT /v1/auth/approle/login HTTP/1.1
2020-02-25T19:50:44.698Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: Host: *****
2020-02-25T19:50:44.698Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: User-Agent: Go-http-client/1.1
2020-02-25T19:50:44.698Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: Content-Length: 100
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: X-Vault-Namespace: *****
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: Accept-Encoding: gzip
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: 
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: {
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4:  "role_id": "*****",
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4:  "secret_id": "*****"
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: }
2020-02-25T19:50:44.699Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: -----------------------------------------------------
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: 2020/02/25 19:50:44 [DEBUG] Vault API Response Details:
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: ---[ RESPONSE ]--------------------------------------
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: HTTP/2.0 400 Bad Request
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: Content-Length: 33
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: Cache-Control: no-store
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: Content-Type: application/json
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: Date: Tue, 25 Feb 2020 19:50:44 GMT
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: 
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: {
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4:  "errors": [
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4:   "invalid secret id"
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4:  ]
2020-02-25T19:50:44.973Z [DEBUG] plugin.terraform-provider-vault_v2.8.0_x4: }

I saw PUT request in log but the API for login use POST method

Here is the following code use in vault provider

Regards,

bogaertg commented 4 years ago

I always have the error. I fixit locally for testing.

I modify the following code

secret, err := client.Logical().Write(authLoginPath, authLoginParameters)

client.Logical().Write() make a PUT request or API for AppRole require POST Method.

Regards,

bogaertg commented 4 years ago

News ?

bogaertg commented 4 years ago

help ? plz

mbrancato commented 4 years ago

hi @bogaertg

The PUT and POST verbs have the same effect in Vault. If you are seeing a difference in their actions, you might consider looking upstream.

Have you tried reproducing this with curl? You can follow the API example here: https://www.vaultproject.io/api/auth/approle/index.html#sample-request-13

https://www.vaultproject.io/api-docs/#api-operations

Vault currently considers PUT and POST to be synonyms. Rather than trust a client's stated intentions, Vault backends can implement an existence check to discover whether an operation is actually a create or update operation based on the data already stored within Vault. This makes permission management via ACLs more flexible.

Also, support was dropped by official providers a few months ago for Terraform 0.11-only issues. https://www.hashicorp.com/blog/deprecating-terraform-0-11-support-in-terraform-providers/

kalinon commented 3 years ago

@mbrancato I'm also seeing this on terraform v0.15.0 and vault 1.7.0+ent

Terraform v0.15.0
on linux_amd64
Configuring remote state backend...
Initializing Terraform configuration...
╷
│ Error: Error making API request.
│
│ URL: PUT https://test-cluster.93993939393.aws.hashicorp.cloud:8200/v1/auth/approle/login
│ Code: 400. Errors:
│
│ * missing client token
│
│   on main.tf line 11, in provider "vault":
│   11: provider "vault" {
│

I've also tried to do this manually, it will always return "missing client token" unless the X-Vault-Token header is set. So im guessing this may be on the vault side...

mbrancato commented 3 years ago

@kalinon can you provide a snippet of your Terraform code and provider config with any sensitive info removed?

kalinon commented 3 years ago

@kalinon can you provide a snippet of your Terraform code and provider config with any sensitive info removed?

Its super basic:

terraform {
  backend "remote" {
    organization = "org-io"

    workspaces {
      name = "vault-cluster-test"
    }
  }
}

variable "login_approle_role_id" {}
variable "login_approle_secret_id" {}

provider "vault" {
  # Configuration options
  address = var.vault_address
  # token   = var.vault_token

  # Only enable after
  auth_login {
    path = "auth/approle/login"
    parameters = {
      role_id   = var.login_approle_role_id
      secret_id = var.login_approle_secret_id
    }
  }
}
kalinon commented 3 years ago

@mbrancato Did some more experimenting. Looks like this error comes from a missing namespace header: X-Vault-Namespace: admin/

Generating a curl via the command line got me the following:

vault write -output-curl-string auth/approle/login role_id=C1420235-8062-4784-97A4-592F6C440C36 secret_id=C0B4AD6D-0711-4ACE-B945-EB6596B8266C

curl -X PUT -H "X-Vault-Namespace: admin/" -H "X-Vault-Token: $(vault print token)" -H "X-Vault-Request: true" -d '{"role_id":"C1420235-8062-4784-97A4-592F6C440C36","secret_id":"C0B4AD6D-0711-4ACE-B945-EB6596B8266C"}' https://myvault:8200/v1/auth/approle/login

So notice the output also is a PUT, so we can prob leave the PUT vs POST issue behind.

Now, knowing i shouldn't need the vault token, i remove it. Allowing me to generate a token:

curl -X PUT -H "X-Vault-Namespace: admin/" -H "X-Vault-Request: true" -d '{"role_id":"C1420235-8062-4784-97A4-592F6C440C36","secret_id":"C0B4AD6D-0711-4ACE-B945-EB6596B8266C"}' https://myvault:8200/v1/auth/approle/login

{"request_id":"bb2a464f-1307-ec9d-c2e1-81fa03ce0563","lease_id":"","renewable":false,"lease_duration":0,"data":null,"wrap_info":null,"warnings":null,"auth":{"client_token":"s.token.cJj7n","accessor":"agqrpOtDiKHRHTgg8Xd0Jem9.cJj7n","policies":["default","tfe"],"token_policies":["default","tfe"],"metadata":{"role_name":"tfe"},"lease_duration":86400,"renewable":true,"entity_id":"ec822daa-d525-6037-da4b-7948f94ed5c1","token_type":"service","orphan":true}}

Removing the namespace header gives me:

curl -X PUT -H "X-Vault-Request: true" -d '{"role_id":"C1420235-8062-4784-97A4-592F6C440C36","secret_id":"C0B4AD6D-0711-4ACE-B945-EB6596B8266C"}' https://myvault:8200/v1/auth/approle/login

{"errors":["missing client token"]}

TADA! Missing client token. Very misleading. So I updated my provider block in terraform to include namespace:

provider "vault" {
  # Configuration options
  address = var.vault_address
  namespace = "admin"

  auth_login {
    path      = "auth/approle/login"
    parameters = {
      role_id   = var.login_approle_role_id
      secret_id = var.login_approle_secret_id
      namespace = "admin"
    }
  }
}

From there i needed to add update access to the policy i was using:

path "auth/token/create" {
  capabilities=["update"]
}

But after that my issue was resolved!