hashicorp / vault

A tool for secrets management, encryption as a service, and privileged access management
https://www.vaultproject.io/
Other
31.1k stars 4.21k forks source link

CORS settings not working #24371

Open GiamBoscaro opened 10 months ago

GiamBoscaro commented 10 months ago

Describe the bug I set the CORS Allowed Origins through the sys/config/cors API, but on my frontend I still get a CORS error.

Current CORS config:

{
  "allowed_headers": [
    "Content-Type",
    "X-Requested-With",
    "X-Vault-AWS-IAM-Server-ID",
    "X-Vault-MFA",
    "X-Vault-No-Request-Forwarding",
    "X-Vault-Wrap-Format",
    "X-Vault-Wrap-TTL",
    "X-Vault-Policy-Override",
    "Authorization",
    "X-Vault-Token"
  ],
  "allowed_origins": [
    "*"
  ],
  "enabled": true
}

To Reproduce Run Vault and set the Allowed Origins with the sys/config/cors API:

DATA='{"allowed_origins": "'"$ALLOWED_ORIGINS"'", "allowed_headers": "'"$ALLOWED_HEADERS"'"}'
curl -s \
    -H "X-Vault-Token: $VAULT_TOKEN" \
    -X POST \
    -d "$DATA" \
    -H "Content-Type: application/json" \
    https://my-domain/v1/sys/config/cors

Try to do an API request from a browser to https://my-vault-url/status.

Get an error:

Access to XMLHttpRequest at 'my-vault-url' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Expected behavior Should not get a CORS error on the frontend

Environment:

Vault server configuration file(s):

{
  "storage": {
    "raft": {
      "path": "/vault/data",
      "node_id": "node"
    }
  },
  "listener": {
    "tcp": {
      "address": "0.0.0.0:8200",
      "tls_disable": true
    }
  },
  "api_addr": "my-vault-doman",
  "cluster_addr": "http://127.0.0.1:8201",
  "ui": true,
  "disable_mlock": true,
  "log_level": "Debug",
  "default_lease_ttl": "168h",
  "max_lease_ttl": "0h"
}

Additional context I have tried to use the wildcard *, and also setting manually the origins. I does not work, neither from localhost nor from our staging environment.

miagilepner commented 10 months ago

Hi, I can't seem to reproduce this. In order to help debug, can you please confirm:

  1. What the server's cors config value is? e.g.:

    curl \
    -H "X-Vault-Token: $VAULT_TOKEN" \
    https://your-domain/v1/sys/config/cors
  2. Check using developer tools in the web browser how the cross origin request is performed: a. Whether you see an OPTIONS request with the Origin header set? b. What the response headers to the OPTIONS request are? c. Whether the Origin header is set in the GET request to https://my-vault-url/status d. What the response headers to that GET request are?

GiamBoscaro commented 10 months ago

Hi, I can't seem to reproduce this. In order to help debug, can you please confirm:

  1. What the server's cors config value is? e.g.:
curl \
    -H "X-Vault-Token: $VAULT_TOKEN" \
    https://your-domain/v1/sys/config/cors

I had already in my OP, but anyway here it is:

{
  "allowed_headers": [
    "Content-Type",
    "X-Requested-With",
    "X-Vault-AWS-IAM-Server-ID",
    "X-Vault-MFA",
    "X-Vault-No-Request-Forwarding",
    "X-Vault-Wrap-Format",
    "X-Vault-Wrap-TTL",
    "X-Vault-Policy-Override",
    "Authorization",
    "X-Vault-Token"
  ],
  "allowed_origins": [
    "*"
  ],
  "enabled": true
}
  1. Check using developer tools in the web browser how the cross origin request is performed: a. Whether you see an OPTIONS request with the Origin header set? b. What the response headers to the OPTIONS request are?

I do not see an OPTIONS request. But I do not see it also for all the others API call that I am making and that are not failing.

c. Whether the Origin header is set in the GET request to https://my-vault-url/status

The origin is set to https://my-website, but it makes sense since the API call is made from a website in a different domain from the Vault one.

d. What the response headers to that GET request are?

alt-svc: h3=":443"; ma=2592000
cache-control: no-store
content-length: 14
content-type: application/json
date: Tue, 05 Dec 2023 13:34:34 GMT
strict-transport-security: max-age=31536000; includeSubDomains

For sure I am missing these headers, that appear in the other API calls:

access-control-allow-credentials: true
access-control-allow-origin: https://my-website
miagilepner commented 10 months ago

Thanks for providing that information. One additional question, are you using any proxying when accessing Vault, including perhaps vault proxy or vault agent in proxy mode?

GiamBoscaro commented 10 months ago

I am not using vault proxy or anything internal to Vault, but I am behind a company proxy. But I don't know if that could be the culprit because everything else is working.

miagilepner commented 10 months ago

Unfortunately I still can't reproduce this. I was thinking that perhaps the Origin header wasn't getting forwarded to Vault, but I agree that it seems unlikely if you're experiencing no other CORS errors.

Can you check what headers are returned when you use curl to directly query Vault and supply an Origin header? E.g.

curl --head -X GET -H 'Origin: http://example.com' -L https://your-vault-url/status
GiamBoscaro commented 10 months ago

This is what I get from curl:

< HTTP/2 404 
HTTP/2 404 
< alt-svc: h3=":443"; ma=2592000
alt-svc: h3=":443"; ma=2592000
< cache-control: no-store
cache-control: no-store
< content-type: application/json
content-type: application/json
< date: Wed, 06 Dec 2023 06:55:42 GMT
date: Wed, 06 Dec 2023 06:55:42 GMT
< strict-transport-security: max-age=31536000; includeSubDomains
strict-transport-security: max-age=31536000; includeSubDomains
< content-length: 14
content-length: 14

One thing I have noticed is this: I have pocked around with the CORS settings, and changed the Wildcard to some URL that we need to be able to connect from. These are basically https://my-website.com. I was working then on Vault UI and I could not save some changes that I have made because I was getting a CORS error by my Vault UI itself. I needed to add https://my-vault to the Allowed Origins in the Vault CORS to make it work again. This means that CORS settings are actually working somehow, but not completely.

I will also be more explicit with my setup. I am using an Angular 13 application and connecting to different services in the same domain but different subdomain. Until now everything was working with CORS. I can connect to api.my-domain, platform.my-domain, something-else.my-domain without any problem. These are mostly Node.js and Python services. obviously with CORS origins set up correctly.The only CORS error that I get is from vault.my-domain for some reason.

Obvously since it is a CORS problem I am getting this only on my browser, so curl is working, http request from our backend are working, wget is working. It is just the api call from the browser that is not working.

miagilepner commented 10 months ago

This is what I get from curl:

< HTTP/2 404 
HTTP/2 404 
< alt-svc: h3=":443"; ma=2592000
alt-svc: h3=":443"; ma=2592000
< cache-control: no-store
cache-control: no-store
< content-type: application/json
content-type: application/json
< date: Wed, 06 Dec 2023 06:55:42 GMT
date: Wed, 06 Dec 2023 06:55:42 GMT
< strict-transport-security: max-age=31536000; includeSubDomains
strict-transport-security: max-age=31536000; includeSubDomains
< content-length: 14
content-length: 14

This is what I would expect if either:

  1. CORS is not configured on Vault
  2. You didn't include an Origin header in the curl command

I would verify again what the server's CORS config value is:

curl \
    -H "X-Vault-Token: $VAULT_TOKEN" \
    https://your-vault-domain/v1/sys/config/cors

If you are trying to use a wildcard for the allowed_origins value, note that it must be the only element in the array. I.e. you cannot do:

"allowed_origins": ["*", "example.com"]

Unfortunately without a minimal example that can reproduce this, I won't be able to track down what's causing your issue.

GiamBoscaro commented 10 months ago

curl --head -X GET -H 'Origin: http://example.com' -L https://your-vault-url/status

Yes I was using the "*" alone, and I then switched to the list of our domains. I tried both and they're both not working. I have retried today with curl.

This works now: curl -X GET -H 'Origin: http://localhost:4200' -L https://my-vault/status

but also this works without Origin: curl -X GET -L https://my-vault/status

Then I tried again on Angular from localhost:4200 and I still get the error. Very confusing honestly. Angular is setting the headers correctly, I can see it on the browser console:

origin: http://localhost:4200
referer: http://localhost:4200/