hashicorp / consul

Consul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure.
https://www.consul.io
Other
28.44k stars 4.43k forks source link

Origin Policy CORS problem with Consul connect #13940

Open ventaubain opened 2 years ago

ventaubain commented 2 years ago

Overview of the Issue

I experiment Consul to explore their capacities. I have developed a simple front developed in Javascript that requests an API endpoint and I have a CORS problem:

Cross-Origin Request Blocked: The same Origin Policy disallows reading the remote resources at http://localhost:7000/health (Reason: CORS request did not succeed).

I don't find anything in the documentation to deal with CORS issue.

Reproduction Steps

job "myjob" {
  datacenters = ["MicroservicePlatform"]

  group "api" {
    network {
      mode = "bridge"
    }

    service {
      name = "bapi"
      port = 8080

      connect {
        sidecar_service {}
      }
    }

    task "web" {
      driver = "docker"

      config {
        image = "REGISTRY/back"
      }
    }
  }

  group "front" {
    network {
      mode = "bridge"

      port "http" {
        static = 3000
        to     = 3000
      }
    }

    service {
      name = "bfront"
      port = "http"

      connect {
        sidecar_service {
          proxy {
            upstreams {
              destination_name = "bapi"
              local_bind_port  = 7000
            }
          }
        }
      }
    }

    task "dashboard" {
      driver = "docker"

      config {
        image = "REGISTRY/front"
      }
    }
  }
}

Operating system and Environment details

Log Fragments

I check logs from Envoy sidecar proxies (back and front) and I didn't see interesting thing.

huikang commented 2 years ago

@moutroll , do you mind pasting the details of the request sent from front end to the backend (e.g., http headers) to help reproduce? Thanks.

ventaubain commented 2 years ago

@huikang Of course !

The js function used is pretty simple: const res = await fetch(domain+"health") Maybe it is necessary to custom the parameters with some options...

Headers:

Host: localhost:7000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:3000/
Origin: http://localhost:3000
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site

.har request/response:

{
  "log": {
    "version": "1.2",
    "creator": {
      "name": "Firefox",
      "version": "91.11.0"
    },
    "browser": {
      "name": "Firefox",
      "version": "91.11.0"
    },
    "pages": [
      {
        "startedDateTime": "2022-07-29T09:21:25.780+02:00",
        "id": "page_1",
        "title": "http://localhost:3000/",
        "pageTimings": {
          "onContentLoad": -1,
          "onLoad": -1
        }
      }
    ],
    "entries": [
      {
        "pageref": "page_1",
        "startedDateTime": "2022-07-29T09:21:25.780+02:00",
        "request": {
          "bodySize": 0,
          "method": "GET",
          "url": "http://localhost:7000/health",
          "httpVersion": "",
          "headers": [
            {
              "name": "Host",
              "value": "localhost:7000"
            },
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0"
            },
            {
              "name": "Accept",
              "value": "*/*"
            },
            {
              "name": "Accept-Language",
              "value": "en-US,en;q=0.5"
            },
            {
              "name": "Accept-Encoding",
              "value": "gzip, deflate"
            },
            {
              "name": "Referer",
              "value": "http://localhost:3000/"
            },
            {
              "name": "Origin",
              "value": "http://localhost:3000"
            },
            {
              "name": "Connection",
              "value": "keep-alive"
            },
            {
              "name": "Sec-Fetch-Dest",
              "value": "empty"
            },
            {
              "name": "Sec-Fetch-Mode",
              "value": "cors"
            },
            {
              "name": "Sec-Fetch-Site",
              "value": "cross-site"
            }
          ],
          "cookies": [],
          "queryString": [],
          "headersSize": 367
        },
        "response": {
          "status": 0,
          "statusText": "",
          "httpVersion": "",
          "headers": [],
          "cookies": [],
          "content": {
            "mimeType": "",
            "size": 0,
            "encoding": "base64",
            "text": ""
          },
          "redirectURL": "",
          "bodySize": 0
        },
        "cache": {},
        "timings": {
          "blocked": 0,
          "dns": 0,
          "connect": 0,
          "ssl": 0,
          "send": 0,
          "wait": 0,
          "receive": 0
        },
        "time": 0,
        "_securityState": "insecure"
      }
    ]
  }
}
huikang commented 2 years ago

The error message shows Cross-Origin Request Blocked: The same Origin Policy disallows reading the remote resources at and the request header has Sec-Fetch-Mode: cors; Sec-Fetch-Site: cross-site. Will this cause any conflict?

ventaubain commented 2 years ago

@huikang
Maybe. The request is for localhost:7000 so the headers may have this structure:

Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors (maybe same-origin?)
Sec-Fetch-Site: same-site

When I use the fetch function without parameter:

If I overwrite the headers with:

async function testRequest() {
  const res = await fetch(domain+"/health", {
    headers: {
      "Sec-Fetch-Site: "same-site",
      "Sec-Fetch-Mode": "same-origin"
    }
 })
 const json = await res.json();
 testString = json;
}

I obtain:

Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site

So the headers customization seems to be ignored... Maybe the problem is only a JS problem but I don't find a solution to force the Sec-Fetch headers and why, with Consul connect, the request is automatically updated.