Skip to content

Commit

Permalink
feat: remove https support for odin (#54)
Browse files Browse the repository at this point in the history
* fix(enki): allow problem to be published iff the sum of its tests scores is 100

* refactor(enki): use more conventional REST paths for endpoints and remove unused projs

* feat(odin): add http rerouting using envoy proxy

* feat(odin): add ssl termination

- add SSL termination for a newly exposed port and reroute traffic directly to services
- keep the HTTP listener which redirects traffic to Dapr Sidecars
- bug: quetzalcoatl app id not found for now using Dapr
- bug: HTTPS certificate not verified despite being added to CA Certs

* feat(odin): restrict access to eval-metadata

- deny access to enki eval-metadata endpoint using lua filter

* build: add github actions for publishing

* perf(odin): add support for env vars for cluster ports

* perf(odin): replace hard-coded clusters with dapr cluster

refactor: extract ancillary services to compose.override file

* fix: use proper paths for fixtures in seeder

* fix(mssql): pin docker image version based on ubuntu 22.04

* fix(ci/cd): remove redundant pipelines

* style(odin): add new line to Dockerfile

* ops: remove obsolete ci/cd pipelines

* perf(odin): remove https listener
  • Loading branch information
WarriorsSami authored Dec 9, 2024
1 parent 6e3e47f commit 179b66c
Showing 1 changed file with 189 additions and 189 deletions.
378 changes: 189 additions & 189 deletions odin-gateway/envoy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -190,195 +190,195 @@ static_resources:
end
- name: envoy.filters.http.router
# HTTPS listener - routes to services - SSL enabled
- name: https_listener
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: ${ENVOY_HTTPS_PORT}
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: asgard_route
virtual_hosts:
- name: asgard
domains: ["*"]
routes:
- name: "quetzalcoatl"
match:
prefix: "/api/identity"
route:
auto_host_rewrite: true
prefix_rewrite: "/v1.0/invoke/quetzalcoatl-auth/method/api"
cluster: dapr
- name: "enki"
match:
prefix: "/api/problems"
route:
auto_host_rewrite: true
prefix_rewrite: "/v1.0/invoke/enki-problems/method/api/enki/problem"
cluster: dapr
- name: "anubis"
match:
prefix: "/api/eval"
route:
auto_host_rewrite: true
prefix_rewrite: "/v1.0/invoke/anubis-eval/method/api"
cluster: dapr
http_filters:
- name: envoy.filters.http.lua
config:
inline_code: |
function envoy_on_request(request_handle)
local path = request_handle:headers():get(":path")
if string.match(path, "^/api/problems/[^/]+/eval%-metadata$") then
request_handle:logWarn("Request to eval-metadata should be denied for external clients")
request_handle:respond({ [":status"] = "404" }, "Not Found")
end
end
# get the content of the AccessToken cookie and add it to the request authorization header as bearer token
- name: envoy.filters.http.lua
config:
inline_code: |
function envoy_on_request(request_handle)
local headers = request_handle:headers()
local cookie = headers:get("cookie")
if cookie then
local token = string.match(cookie, ".AspNetCore.AccessToken=([^;]+)")
if token then
headers:add("authorization", "Bearer " .. token)
end
end
end
# get the content of the RefreshToken cookie
# get the userId from the request body
# add the userId and RefreshToken to the request body
# forward the request to the auth service
# get the new access token from the response body
# set the new access token in the response cookie
# forward the response to the client
- name: envoy.filters.http.lua
config:
inline_code: |
function envoy_on_request(request_handle)
local path = request_handle:headers():get(":path")
local method = request_handle:headers():get(":method")
request_handle:logInfo("Request path: " .. path)
request_handle:logInfo("Method: " .. method)
if string.match(path, "^/api/identity/auth/refresh%-token$") and method == "POST" then
request_handle:logInfo("Request path matched")
local headers = request_handle:headers()
request_handle:logInfo("Headers grabbed")
local cookie = headers:get("cookie")
request_handle:logInfo("Cookies grabbed")
if not cookie then
request_handle:logInfo("No cookies found")
request_handle:respond(
{
[":status"] = "400",
["access-control-allow-credentials"] = "true",
["access-control-allow-origin"] = headers:get("origin")
},
"Invalid refresh token, please login again"
)
return
end
local body = request_handle:body()
request_handle:logInfo("Body grabbed")
local body_str = body:getBytes(0, body:length())
request_handle:logInfo("Request body: " .. body_str)
local user_id = string.match(body_str, '"userId":"([^"]+)"')
local refresh_token = string.match(cookie, ".AspNetCore.RefreshToken=([^;]+)")
if not user_id or not refresh_token then
request_handle:respond(
{
[":status"] = "400",
["access-control-allow-credentials"] = "true",
["access-control-allow-origin"] = request_handle:headers():get("origin")
},
"Invalid refresh token, please login again"
)
return
end
request_handle:logInfo("UserId: " .. user_id)
request_handle:logInfo("RefreshToken: " .. refresh_token)
local new_body = '{"userId":"' .. user_id .. '","refreshToken":"' .. refresh_token .. '"}'
request_handle:logInfo("New body: " .. new_body)
local response_headers, response_body = request_handle:httpCall(
"quetzalcoatl",
{
[":method"] = "POST",
[":path"] = "/api/auth/refresh-token",
[":authority"] = request_handle:headers():get(":authority"),
["content-type"] = "application/json",
["content-length"] = string.len(new_body)
},
new_body,
5000
)
for key, value in pairs(response_headers) do
request_handle:logInfo("Response header: " .. key .. " = " .. value)
end
request_handle:logInfo("Response body: " .. response_body)
if response_headers[":status"] ~= "200" then
request_handle:respond(
response_headers,
response_body
)
return
end
local new_access_token = string.match(response_body, '"accessToken":"([^"]+)"')
request_handle:logInfo("New access token: " .. new_access_token)
local expirySeconds = 3600
local path = "/"
local cookieName = ".AspNetCore.AccessToken"
local expires = os.date("!%a, %d %b %Y %H:%M:%S GMT", os.time() + expirySeconds)
local cookieAttributes = {
"HttpOnly",
"Expires=" .. expires,
"Path=" .. path,
"SameSite=None",
"Secure"
}
local new_cookie = cookieName .. "=" .. new_access_token .. "; " .. table.concat(cookieAttributes, "; ")
response_headers["set-cookie"] = new_cookie
response_headers["access-control-allow-credentials"] = "true"
response_headers["access-control-allow-origin"] = request_handle:headers():get("origin")
request_handle:respond(
response_headers,
"{\"userId\":\"" .. user_id .. "\"}"
)
end
end
- name: envoy.filters.http.router
tls_context:
common_tls_context:
tls_certificates:
- certificate_chain:
filename: "/etc/ssl/certs/https.crt"
private_key:
filename: "/etc/ssl/certs/key.pem"
# - name: https_listener
# address:
# socket_address:
# protocol: TCP
# address: 0.0.0.0
# port_value: ${ENVOY_HTTPS_PORT}
# filter_chains:
# - filters:
# - name: envoy.filters.network.http_connection_manager
# typed_config:
# "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
# stat_prefix: ingress_http
# route_config:
# name: asgard_route
# virtual_hosts:
# - name: asgard
# domains: ["*"]
# routes:
# - name: "quetzalcoatl"
# match:
# prefix: "/api/identity"
# route:
# auto_host_rewrite: true
# prefix_rewrite: "/v1.0/invoke/quetzalcoatl-auth/method/api"
# cluster: dapr
# - name: "enki"
# match:
# prefix: "/api/problems"
# route:
# auto_host_rewrite: true
# prefix_rewrite: "/v1.0/invoke/enki-problems/method/api/enki/problem"
# cluster: dapr
# - name: "anubis"
# match:
# prefix: "/api/eval"
# route:
# auto_host_rewrite: true
# prefix_rewrite: "/v1.0/invoke/anubis-eval/method/api"
# cluster: dapr
# http_filters:
# - name: envoy.filters.http.lua
# config:
# inline_code: |
# function envoy_on_request(request_handle)
# local path = request_handle:headers():get(":path")
# if string.match(path, "^/api/problems/[^/]+/eval%-metadata$") then
# request_handle:logWarn("Request to eval-metadata should be denied for external clients")
# request_handle:respond({ [":status"] = "404" }, "Not Found")
# end
# end
# # get the content of the AccessToken cookie and add it to the request authorization header as bearer token
# - name: envoy.filters.http.lua
# config:
# inline_code: |
# function envoy_on_request(request_handle)
# local headers = request_handle:headers()
# local cookie = headers:get("cookie")
# if cookie then
# local token = string.match(cookie, ".AspNetCore.AccessToken=([^;]+)")
# if token then
# headers:add("authorization", "Bearer " .. token)
# end
# end
# end
# # get the content of the RefreshToken cookie
# # get the userId from the request body
# # add the userId and RefreshToken to the request body
# # forward the request to the auth service
# # get the new access token from the response body
# # set the new access token in the response cookie
# # forward the response to the client
# - name: envoy.filters.http.lua
# config:
# inline_code: |
# function envoy_on_request(request_handle)
# local path = request_handle:headers():get(":path")
# local method = request_handle:headers():get(":method")
# request_handle:logInfo("Request path: " .. path)
# request_handle:logInfo("Method: " .. method)
#
# if string.match(path, "^/api/identity/auth/refresh%-token$") and method == "POST" then
# request_handle:logInfo("Request path matched")
#
# local headers = request_handle:headers()
# request_handle:logInfo("Headers grabbed")
#
# local cookie = headers:get("cookie")
# request_handle:logInfo("Cookies grabbed")
#
# if not cookie then
# request_handle:logInfo("No cookies found")
# request_handle:respond(
# {
# [":status"] = "400",
# ["access-control-allow-credentials"] = "true",
# ["access-control-allow-origin"] = headers:get("origin")
# },
# "Invalid refresh token, please login again"
# )
# return
# end
#
# local body = request_handle:body()
# request_handle:logInfo("Body grabbed")
#
# local body_str = body:getBytes(0, body:length())
# request_handle:logInfo("Request body: " .. body_str)
#
# local user_id = string.match(body_str, '"userId":"([^"]+)"')
# local refresh_token = string.match(cookie, ".AspNetCore.RefreshToken=([^;]+)")
#
# if not user_id or not refresh_token then
# request_handle:respond(
# {
# [":status"] = "400",
# ["access-control-allow-credentials"] = "true",
# ["access-control-allow-origin"] = request_handle:headers():get("origin")
# },
# "Invalid refresh token, please login again"
# )
# return
# end
#
# request_handle:logInfo("UserId: " .. user_id)
# request_handle:logInfo("RefreshToken: " .. refresh_token)
#
# local new_body = '{"userId":"' .. user_id .. '","refreshToken":"' .. refresh_token .. '"}'
# request_handle:logInfo("New body: " .. new_body)
# local response_headers, response_body = request_handle:httpCall(
# "quetzalcoatl",
# {
# [":method"] = "POST",
# [":path"] = "/api/auth/refresh-token",
# [":authority"] = request_handle:headers():get(":authority"),
# ["content-type"] = "application/json",
# ["content-length"] = string.len(new_body)
# },
# new_body,
# 5000
# )
#
# for key, value in pairs(response_headers) do
# request_handle:logInfo("Response header: " .. key .. " = " .. value)
# end
# request_handle:logInfo("Response body: " .. response_body)
#
# if response_headers[":status"] ~= "200" then
# request_handle:respond(
# response_headers,
# response_body
# )
# return
# end
#
# local new_access_token = string.match(response_body, '"accessToken":"([^"]+)"')
# request_handle:logInfo("New access token: " .. new_access_token)
#
# local expirySeconds = 3600
# local path = "/"
# local cookieName = ".AspNetCore.AccessToken"
# local expires = os.date("!%a, %d %b %Y %H:%M:%S GMT", os.time() + expirySeconds)
#
# local cookieAttributes = {
# "HttpOnly",
# "Expires=" .. expires,
# "Path=" .. path,
# "SameSite=None",
# "Secure"
# }
#
# local new_cookie = cookieName .. "=" .. new_access_token .. "; " .. table.concat(cookieAttributes, "; ")
# response_headers["set-cookie"] = new_cookie
# response_headers["access-control-allow-credentials"] = "true"
# response_headers["access-control-allow-origin"] = request_handle:headers():get("origin")
#
# request_handle:respond(
# response_headers,
# "{\"userId\":\"" .. user_id .. "\"}"
# )
# end
# end
# - name: envoy.filters.http.router
# tls_context:
# common_tls_context:
# tls_certificates:
# - certificate_chain:
# filename: "/etc/ssl/certs/https.crt"
# private_key:
# filename: "/etc/ssl/certs/key.pem"
clusters:
- name: dapr
connect_timeout: 0.25s
Expand Down

0 comments on commit 179b66c

Please sign in to comment.