Skip to content

Commit 95a0a96

Browse files
committed
feat: add Envoy proxy support
1 parent fa1c67c commit 95a0a96

File tree

18 files changed

+531
-7
lines changed

18 files changed

+531
-7
lines changed

ansible/files/adminapi.sudoers.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
Cmnd_Alias ENVOY = /bin/systemctl start envoy.service, /bin/systemctl stop envoy.service, /bin/systemctl restart envoy.service, /bin/systemctl disable envoy.service, /bin/systemctl enable envoy.service, /bin/systemctl reload envoy.service
12
Cmnd_Alias KONG = /bin/systemctl start kong.service, /bin/systemctl stop kong.service, /bin/systemctl restart kong.service, /bin/systemctl disable kong.service, /bin/systemctl enable kong.service, /bin/systemctl reload kong.service
23
Cmnd_Alias POSTGREST = /bin/systemctl start postgrest.service, /bin/systemctl stop postgrest.service, /bin/systemctl restart postgrest.service, /bin/systemctl disable postgrest.service, /bin/systemctl enable postgrest.service
34
Cmnd_Alias GOTRUE = /bin/systemctl start gotrue.service, /bin/systemctl stop gotrue.service, /bin/systemctl restart gotrue.service, /bin/systemctl disable gotrue.service, /bin/systemctl enable gotrue.service

ansible/files/envoy.service

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[Unit]
2+
Description=Envoy
3+
After=postgrest.service gotrue.service adminapi.service
4+
Wants=postgrest.service gotrue.service adminapi.service
5+
Conflicts=kong.service
6+
7+
[Service]
8+
Type=simple
9+
ExecStart=/opt/envoy-hot-restarter.py /opt/start-envoy.sh
10+
ExecReload=/bin/kill -HUP $MAINPID
11+
ExecStop=/bin/kill -TERM $MAINPID
12+
User=envoy
13+
Slice=services.slice
14+
Restart=always
15+
RestartSec=3
16+
LimitNOFILE=100000
17+
18+
# The envoy user is unpriviledged and thus not permited to bind on ports < 1024
19+
# Via systemd we grant the process a set of priviledges to bind to 80/443
20+
# See http://archive.vn/36zJU
21+
AmbientCapabilities=CAP_NET_BIND_SERVICE
22+
23+
[Install]
24+
WantedBy=multi-user.target
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
function envoy_on_request(request_handle)
2+
local authorization = request_handle:headers():get("authorization")
3+
4+
if authorization and authorization:find("^[Bb][Aa][Ss][Ii][Cc] " .. request_handle:metadata():get("credentials")) then
5+
return
6+
end
7+
8+
request_handle:respond({
9+
[":status"] = "401",
10+
["WWW-Authenticate"] = "Basic realm=\"Unknown\""
11+
}, "Unauthorized")
12+
end

ansible/files/envoy_config/cds.yaml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
resources:
2+
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
3+
name: admin_api
4+
load_assignment:
5+
cluster_name: admin_api
6+
endpoints:
7+
- lb_endpoints:
8+
- endpoint:
9+
address:
10+
socket_address:
11+
address: 127.0.0.1
12+
port_value: 8085
13+
transport_socket:
14+
name: envoy.transport_sockets.tls
15+
typed_config:
16+
'@type': >-
17+
type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
18+
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
19+
name: gotrue
20+
load_assignment:
21+
cluster_name: gotrue
22+
endpoints:
23+
- lb_endpoints:
24+
- endpoint:
25+
address:
26+
socket_address:
27+
address: 127.0.0.1
28+
port_value: 9999
29+
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
30+
name: postgrest
31+
load_assignment:
32+
cluster_name: postgrest
33+
endpoints:
34+
- lb_endpoints:
35+
- endpoint:
36+
address:
37+
socket_address:
38+
address: 127.0.0.1
39+
port_value: 3000
40+
- '@type': type.googleapis.com/envoy.config.cluster.v3.Cluster
41+
name: postgrest_admin
42+
load_assignment:
43+
cluster_name: postgrest_admin
44+
endpoints:
45+
- lb_endpoints:
46+
- endpoint:
47+
address:
48+
socket_address:
49+
address: 127.0.0.1
50+
port_value: 3001
51+

ansible/files/envoy_config/envoy.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
dynamic_resources:
2+
cds_config:
3+
path_config_source:
4+
path: /etc/envoy/cds.yaml
5+
resource_api_version: V3
6+
lds_config:
7+
path_config_source:
8+
path: /etc/envoy/lds.yaml
9+
resource_api_version: V3
10+
node:
11+
cluster: cluster_0
12+
id: node_0
13+
overload_manager:
14+
resource_monitors:
15+
- name: envoy.resource_monitors.global_downstream_max_connections
16+
typed_config:
17+
'@type': >-
18+
type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig
19+
max_active_downstream_connections: 500000
20+
stats_config:
21+
stats_matcher:
22+
reject_all: true
23+

ansible/files/envoy_config/lds.yaml

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
resources:
2+
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
3+
name: http_listener
4+
address:
5+
socket_address:
6+
address: 0.0.0.0
7+
port_value: 80
8+
filter_chains:
9+
- filters: &ref_1
10+
- name: envoy.filters.network.http_connection_manager
11+
typed_config:
12+
'@type': >-
13+
type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
14+
generate_request_id: false
15+
http_filters:
16+
- name: envoy.filters.http.cors
17+
typed_config:
18+
'@type': >-
19+
type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
20+
- name: envoy.filters.http.rbac
21+
typed_config:
22+
'@type': >-
23+
type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC
24+
rules:
25+
action: DENY
26+
policies:
27+
api_key_missing:
28+
permissions:
29+
- any: true
30+
principals:
31+
- not_id:
32+
or_ids:
33+
ids:
34+
- header:
35+
name: apikey
36+
present_match: true
37+
- header:
38+
name: ':path'
39+
string_match:
40+
contains: apikey=
41+
api_key_not_valid:
42+
permissions:
43+
- any: true
44+
principals:
45+
- not_id:
46+
or_ids:
47+
ids:
48+
- header:
49+
name: apikey
50+
string_match:
51+
exact: anon_key
52+
- header:
53+
name: apikey
54+
string_match:
55+
exact: service_key
56+
- header:
57+
name: apikey
58+
string_match:
59+
exact: supabase_admin_key
60+
- header:
61+
name: ':path'
62+
string_match:
63+
contains: apikey=anon_key
64+
- header:
65+
name: ':path'
66+
string_match:
67+
contains: apikey=service_key
68+
- header:
69+
name: ':path'
70+
string_match:
71+
contains: apikey=supabase_admin_key
72+
- name: envoy.filters.http.lua
73+
typed_config:
74+
'@type': >-
75+
type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
76+
source_codes:
77+
basic_auth:
78+
filename: /etc/envoy/basic_auth.lua
79+
remove_apikey_query_parameter:
80+
filename: /etc/envoy/remove_apikey_query_parameter.lua
81+
- name: envoy.filters.http.router
82+
typed_config:
83+
'@type': >-
84+
type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
85+
dynamic_stats: false
86+
local_reply_config:
87+
mappers:
88+
- filter:
89+
and_filter:
90+
filters:
91+
- status_code_filter:
92+
comparison:
93+
value:
94+
default_value: 403
95+
runtime_key: unused
96+
- header_filter:
97+
header:
98+
name: ':path'
99+
string_match:
100+
prefix: /metrics/aggregated
101+
invert_match: true
102+
status_code: 401
103+
body_format_override:
104+
json_format:
105+
message: >-
106+
`apikey` request header or query parameter is either
107+
missing or invalid. Double check your Supabase `anon`
108+
or `service_role` API key.
109+
hint: '%RESPONSE_CODE_DETAILS%'
110+
json_format_options:
111+
sort_properties: false
112+
route_config:
113+
name: route_config_0
114+
virtual_hosts:
115+
- name: virtual_host_0
116+
domains:
117+
- '*'
118+
typed_per_filter_config:
119+
envoy.filters.http.cors:
120+
'@type': >-
121+
type.googleapis.com/envoy.extensions.filters.http.cors.v3.CorsPolicy
122+
allow_origin_string_match:
123+
- safe_regex:
124+
regex: \*
125+
allow_methods: GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS,TRACE,CONNECT
126+
allow_headers: apikey,authorization,x-client-info
127+
max_age: '3600'
128+
routes:
129+
- match:
130+
safe_regex:
131+
regex: >-
132+
/auth/v1/(verify|callback|authorize|sso/saml/(acs|metadata|slo))
133+
route:
134+
cluster: gotrue
135+
regex_rewrite:
136+
pattern:
137+
regex: ^/auth/v1
138+
substitution: ''
139+
retry_policy:
140+
num_retries: 3
141+
retry_on: 5xx
142+
typed_per_filter_config:
143+
envoy.filters.http.rbac: &ref_0
144+
'@type': >-
145+
type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute
146+
- match:
147+
prefix: /auth/v1/
148+
route:
149+
cluster: gotrue
150+
prefix_rewrite: /
151+
- match:
152+
prefix: /rest/v1/
153+
query_parameters:
154+
- name: apikey
155+
present_match: true
156+
request_headers_to_remove:
157+
- apikey
158+
route:
159+
cluster: postgrest
160+
prefix_rewrite: /
161+
timeout: 2m
162+
typed_per_filter_config:
163+
envoy.filters.http.lua:
164+
'@type': >-
165+
type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute
166+
name: remove_apikey_query_parameter
167+
- match:
168+
prefix: /rest/v1/
169+
request_headers_to_remove:
170+
- apikey
171+
route:
172+
cluster: postgrest
173+
prefix_rewrite: /
174+
timeout: 2m
175+
- match:
176+
prefix: /rest-admin/v1/
177+
query_parameters:
178+
- name: apikey
179+
present_match: true
180+
request_headers_to_remove:
181+
- apikey
182+
route:
183+
cluster: postgrest_admin
184+
prefix_rewrite: /
185+
typed_per_filter_config:
186+
envoy.filters.http.lua:
187+
'@type': >-
188+
type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute
189+
name: remove_apikey_query_parameter
190+
- match:
191+
prefix: /rest-admin/v1/
192+
request_headers_to_remove:
193+
- apikey
194+
route:
195+
cluster: postgrest_admin
196+
prefix_rewrite: /
197+
- match:
198+
path: /graphql/v1
199+
request_headers_to_add:
200+
header:
201+
key: Content-Profile
202+
value: graphql_public
203+
timeout: 2m
204+
route:
205+
cluster: postgrest
206+
prefix_rewrite: /rpc/graphql
207+
- match:
208+
prefix: /admin/v1/
209+
route:
210+
cluster: admin_api
211+
prefix_rewrite: /
212+
- match:
213+
prefix: /customer/v1/privileged/
214+
route:
215+
cluster: admin_api
216+
prefix_rewrite: /privileged/
217+
typed_per_filter_config:
218+
envoy.filters.http.lua:
219+
'@type': >-
220+
type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuaPerRoute
221+
name: basic_auth
222+
envoy.filters.http.rbac: *ref_0
223+
metadata:
224+
filter_metadata:
225+
envoy.filters.http.lua:
226+
credentials: c2VydmljZV9yb2xlOnNlcnZpY2Vfa2V5
227+
- match:
228+
prefix: /metrics/aggregated
229+
route:
230+
cluster: admin_api
231+
prefix_rewrite: /supabase-internal/metrics
232+
typed_per_filter_config:
233+
envoy.filters.http.rbac:
234+
'@type': >-
235+
type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute
236+
rbac:
237+
rules:
238+
action: DENY
239+
policies:
240+
not_private_ip:
241+
permissions:
242+
- any: true
243+
principals:
244+
- not_id:
245+
direct_remote_ip:
246+
address_prefix: 10.0.0.0
247+
prefix_len: 8
248+
stat_prefix: ingress_http
249+
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
250+
name: https_listener
251+
address:
252+
socket_address:
253+
address: 0.0.0.0
254+
port_value: 443
255+
filter_chains:
256+
- filters: *ref_1
257+
transport_socket:
258+
name: envoy.transport_sockets.tls
259+
typed_config:
260+
'@type': >-
261+
type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
262+
common_tls_context:
263+
tls_certificates:
264+
- certificate_chain:
265+
filename: /etc/envoy/fullChain.pem
266+
private_key:
267+
filename: /etc/envoy/privKey.pem
268+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function envoy_on_request(request_handle)
2+
local path = request_handle:headers():get(":path")
3+
4+
request_handle:headers():replace(":path", path:gsub("([&?])apikey=[^&]+&?", "%1"):gsub("&$", ""))
5+
end

0 commit comments

Comments
 (0)