Skip to content

Commit 9dd52e1

Browse files
authored
Rename allowed env configuration traits (#1137)
* Deprecate env-whitelist traits, send client-envs in kernelspec * Address changes in docs and deployment scripts * Update tests * Revert changes to drop wildcard support and send client_envs in kspec
1 parent edafec5 commit 9dd52e1

File tree

19 files changed

+104
-80
lines changed

19 files changed

+104
-80
lines changed

docs/source/developers/custom-images.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,6 @@ cp -r python_kubernetes python_myCustomKernel
164164
}
165165
```
166166

167-
- If using a whitelist (`EG_KERNEL_WHITELIST`), be sure to update it with the new kernel specification directory name (e.g., `python_myCustomKernel`) and restart/redeploy Enterprise Gateway.
167+
- If using kernel filtering (`EG_ALLOWED_KERNELS`), be sure to update it with the new kernel specification directory name (e.g., `python_myCustomKernel`) and restart/redeploy Enterprise Gateway.
168168
- Launch or refresh your Notebook session and confirm `My Custom Kernel` appears in the _new kernel_ drop-down.
169169
- Create a new notebook using `My Custom Kernel`.

docs/source/operators/config-cli.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ EnterpriseGatewayApp(EnterpriseGatewayConfigMixin, JupyterApp) options
121121
The full path to a certificate authority certificate for SSL/TLS client
122122
authentication. (EG_CLIENT_CA env var)
123123
Default: None
124+
--EnterpriseGatewayApp.client_envs=<list-item-1>...
125+
Environment variables allowed to be set when a client requests a
126+
new kernel. (EG_CLIENT_ENVS env var)
127+
Default: []
124128
--EnterpriseGatewayApp.conductor_endpoint=<Unicode>
125129
The http url for accessing the Conductor REST API. (EG_CONDUCTOR_ENDPOINT
126130
env var)
@@ -140,13 +144,10 @@ EnterpriseGatewayApp(EnterpriseGatewayConfigMixin, JupyterApp) options
140144
(EG_DYNAMIC_CONFIG_INTERVAL env var)
141145
Default: 0
142146
--EnterpriseGatewayApp.env_process_whitelist=<list-item-1>...
143-
Environment variables allowed to be inherited from the spawning process by
144-
the kernel. (EG_ENV_PROCESS_WHITELIST env var)
147+
DEPRECATED, use inherited_envs
145148
Default: []
146149
--EnterpriseGatewayApp.env_whitelist=<list-item-1>...
147-
Environment variables allowed to be set when a client requests a new kernel.
148-
Use '*' to allow all environment variables sent in the request.
149-
(EG_ENV_WHITELIST env var)
150+
DEPRECATED, use client_envs.
150151
Default: []
151152
--EnterpriseGatewayApp.expose_headers=<Unicode>
152153
Sets the Access-Control-Expose-Headers header. (EG_EXPOSE_HEADERS env var)
@@ -158,6 +159,10 @@ EnterpriseGatewayApp(EnterpriseGatewayConfigMixin, JupyterApp) options
158159
Indicates whether impersonation will be performed during kernel launch.
159160
(EG_IMPERSONATION_ENABLED env var)
160161
Default: False
162+
--EnterpriseGatewayApp.inherited_envs=<list-item-1>...
163+
Environment variables allowed to be inherited
164+
from the spawning process by the kernel. (EG_INHERITED_ENVS env var)
165+
Default: []
161166
--EnterpriseGatewayApp.ip=<Unicode>
162167
IP address on which to listen (EG_IP env var)
163168
Default: '127.0.0.1'

docs/source/operators/config-kernel-override.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ those same-named variables in the kernel.json `env` stanza.
3838

3939
Environment variables for which this can occur are any variables prefixed with `KERNEL_`
4040
as well as any variables
41-
listed in the `EnterpriseGatewayApp.env_whitelist` configurable trait (or via
42-
the `EG_ENV_WHITELIST` variable). Locally defined variables listed in `EG_PROCESS_ENV_WHITELIST`
41+
listed in the `EnterpriseGatewayApp.client_envs` configurable trait (or via
42+
the `EG_CLIENT_ENVS` variable). Likewise, environment variables of the Enterprise Gateway
43+
server process listed in the `EnterpriseGatewayApp.inherited_envs` configurable trait
44+
(or via the `EG_INHERITED_ENVS` variable)
4345
are also available for replacement in the kernel process' environment.
4446

4547
See [Kernel Environment Variables](../users/kernel-envs.md) in the Users documentation section for a complete set of recognized `KERNEL_` variables.

enterprise_gateway/enterprisegatewayapp.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ def init_webapp(self) -> None:
236236
eg_expose_headers=self.expose_headers,
237237
eg_max_age=self.max_age,
238238
eg_max_kernels=self.max_kernels,
239-
eg_env_process_whitelist=self.env_process_whitelist,
240-
eg_env_whitelist=self.env_whitelist,
239+
eg_inherited_envs=self.inherited_envs,
240+
eg_client_envs=self.client_envs,
241241
eg_kernel_headers=self.kernel_headers,
242242
eg_list_kernels=self.list_kernels,
243243
eg_authorized_users=self.authorized_users,

enterprise_gateway/mixins.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -372,30 +372,49 @@ def list_kernels_default(self) -> bool:
372372
== "true"
373373
)
374374

375-
env_whitelist_env = "EG_ENV_WHITELIST"
376375
env_whitelist = ListTrait(
376+
config=True,
377+
help="""DEPRECATED, use client_envs.""",
378+
)
379+
380+
@observe("env_whitelist")
381+
def _update_env_whitelist(self, change):
382+
self.log.warning("env_whitelist is deprecated, use client_envs")
383+
self.client_envs = change["new"]
384+
385+
client_envs_env = "EG_CLIENT_ENVS"
386+
client_envs = ListTrait(
377387
config=True,
378388
help="""Environment variables allowed to be set when a client requests a
379-
new kernel. Use '*' to allow all environment variables sent in the request.
380-
(EG_ENV_WHITELIST env var)""",
389+
new kernel. (EG_CLIENT_ENVS env var)""",
381390
)
382391

383-
@default("env_whitelist")
384-
def env_whitelist_default(self) -> List[str]:
385-
return os.getenv(self.env_whitelist_env, os.getenv("KG_ENV_WHITELIST", "")).split(",")
392+
@default("client_envs")
393+
def client_envs_default(self):
394+
return os.getenv(self.client_envs_env, os.getenv("EG_ENV_WHITELIST", "")).split(",")
386395

387-
env_process_whitelist_env = "EG_ENV_PROCESS_WHITELIST"
388396
env_process_whitelist = ListTrait(
397+
config=True,
398+
help="""DEPRECATED, use inherited_envs""",
399+
)
400+
401+
@observe("env_process_whitelist")
402+
def _update_env_process_whitelist(self, change):
403+
self.log.warning("env_process_whitelist is deprecated, use inherited_envs")
404+
self.inherited_envs = change["new"]
405+
406+
inherited_envs_env = "EG_INHERITED_ENVS"
407+
inherited_envs = ListTrait(
389408
config=True,
390409
help="""Environment variables allowed to be inherited
391-
from the spawning process by the kernel. (EG_ENV_PROCESS_WHITELIST env var)""",
410+
from the spawning process by the kernel. (EG_INHERITED_ENVS env var)""",
392411
)
393412

394-
@default("env_process_whitelist")
395-
def env_process_whitelist_default(self) -> List[str]:
396-
return os.getenv(
397-
self.env_process_whitelist_env, os.getenv("KG_ENV_PROCESS_WHITELIST", "")
398-
).split(",")
413+
@default("inherited_envs")
414+
def inherited_envs_default(self) -> List[str]:
415+
return os.getenv(self.inherited_envs_env, os.getenv("EG_ENV_PROCESS_WHITELIST", "")).split(
416+
","
417+
)
399418

400419
kernel_headers_env = "EG_KERNEL_HEADERS"
401420
kernel_headers = ListTrait(

enterprise_gateway/services/api/swagger.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
},
161161
"env": {
162162
"type": "object",
163-
"description": "A dictionary of environment variables and values to include in the kernel process - subject to whitelisting.",
163+
"description": "A dictionary of environment variables and values to include in the kernel process - subject to filtering.",
164164
"additionalProperties": {
165165
"type": "string"
166166
}

enterprise_gateway/services/api/swagger.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ paths:
141141
type: object
142142
description: |
143143
A dictionary of environment variables and values to include in the
144-
kernel process - subject to whitelisting.
144+
kernel process - subject to filtering.
145145
additionalProperties:
146146
type: string
147147
responses:

enterprise_gateway/services/kernels/handlers.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ class MainKernelHandler(
2222
"""
2323

2424
@property
25-
def env_whitelist(self):
26-
return self.settings["eg_env_whitelist"]
25+
def client_envs(self):
26+
return self.settings["eg_client_envs"]
2727

2828
@property
29-
def env_process_whitelist(self):
30-
return self.settings["eg_env_process_whitelist"]
29+
def inherited_envs(self):
30+
return self.settings["eg_inherited_envs"]
3131

3232
async def post(self):
3333
"""Overrides the super class method to manage env in the request body.
@@ -54,24 +54,24 @@ async def post(self):
5454
# Start with the PATH from the current env. Do not provide the entire environment
5555
# which might contain server secrets that should not be passed to kernels.
5656
env = {"PATH": os.getenv("PATH", "")}
57-
# Whitelist environment variables from current process environment
57+
# Transfer inherited environment variables from current process
5858
env.update(
59-
{
60-
key: value
61-
for key, value in os.environ.items()
62-
if key in self.env_process_whitelist
63-
}
59+
{key: value for key, value in os.environ.items() if key in self.inherited_envs}
6460
)
65-
# Whitelist KERNEL_* args and those allowed by configuration from client. If all
66-
# envs are requested, just use the keys from the payload.
67-
env_whitelist = self.env_whitelist
68-
if env_whitelist == ["*"]:
69-
env_whitelist = model["env"].keys()
61+
# Allow all KERNEL_* envs and those specified in client_envs and set from client. If this EG
62+
# instance is configured to accept all envs in the payload (i.e., client_envs == '*'), go ahead
63+
# and add those keys to the "working" allowed_envs list, otherwise, just transfer the configured envs.
64+
allowed_envs: List[str]
65+
if self.client_envs == ["*"]:
66+
allowed_envs = model["env"].keys()
67+
else:
68+
allowed_envs = self.client_envs
69+
# Allow KERNEL_* args and those allowed by configuration.
7070
env.update(
7171
{
7272
key: value
7373
for key, value in model["env"].items()
74-
if key.startswith("KERNEL_") or key in env_whitelist
74+
if key.startswith("KERNEL_") or key in allowed_envs
7575
}
7676
)
7777

enterprise_gateway/services/kernels/remotemanager.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,8 @@ def _link_dependent_props(self):
427427
"port_range",
428428
"impersonation_enabled",
429429
"max_kernels_per_user",
430-
"env_whitelist",
431-
"env_process_whitelist",
430+
"client_envs",
431+
"inherited_envs",
432432
"yarn_endpoint",
433433
"alt_yarn_endpoint",
434434
"yarn_endpoint_security_enabled",
@@ -456,7 +456,7 @@ async def start_kernel(self, **kwargs):
456456

457457
def _capture_user_overrides(self, **kwargs):
458458
"""
459-
Make a copy of any whitelist or KERNEL_ env values provided by user. These will be injected
459+
Make a copy of any allowed or KERNEL_ env values provided by user. These will be injected
460460
back into the env after the kernelspec env has been applied. This enables defaulting behavior
461461
of the kernelspec env stanza that would have otherwise overridden the user-provided values.
462462
"""
@@ -470,8 +470,8 @@ def _capture_user_overrides(self, **kwargs):
470470
key: value
471471
for key, value in env.items()
472472
if key.startswith("KERNEL_")
473-
or key in self.env_process_whitelist
474-
or key in self.env_whitelist
473+
or key in self.inherited_envs
474+
or key in self.client_envs
475475
}
476476
)
477477

enterprise_gateway/services/kernelspecs/handlers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def kernel_spec_cache(self) -> KernelSpecCache:
6969

7070
@web.authenticated
7171
async def get(self) -> None:
72-
ksm = self.kernel_spec_cache
72+
ksc = self.kernel_spec_cache
7373
km = self.kernel_manager
7474
model = {}
7575
model["default"] = km.default_kernel_name
@@ -82,7 +82,7 @@ async def get(self) -> None:
8282
if kernel_user:
8383
self.log.debug("Searching kernels for user '%s' " % kernel_user)
8484

85-
kspecs = await ensure_async(ksm.get_all_specs())
85+
kspecs = await ensure_async(ksc.get_all_specs())
8686

8787
list_kernels_found = []
8888
for kernel_name, kernel_info in kspecs.items():
@@ -122,14 +122,14 @@ def kernel_spec_cache(self) -> KernelSpecCache:
122122

123123
@web.authenticated
124124
async def get(self, kernel_name: str) -> None:
125-
ksm = self.kernel_spec_cache
125+
ksc = self.kernel_spec_cache
126126
kernel_name = url_unescape(kernel_name)
127127
kernel_user_filter = self.request.query_arguments.get("user")
128128
kernel_user = None
129129
if kernel_user_filter:
130130
kernel_user = kernel_user_filter[0].decode("utf-8")
131131
try:
132-
spec = await ensure_async(ksm.get_kernel_spec(kernel_name))
132+
spec = await ensure_async(ksc.get_kernel_spec(kernel_name))
133133
except KeyError:
134134
raise web.HTTPError(404, "Kernel spec %s not found" % kernel_name)
135135
if is_kernelspec_model(spec):
@@ -166,9 +166,9 @@ def initialize(self) -> None:
166166

167167
@web.authenticated
168168
async def get(self, kernel_name: str, path: str, include_body: bool = True) -> None:
169-
ksm = self.kernel_spec_cache
169+
ksc = self.kernel_spec_cache
170170
try:
171-
kernelspec = await ensure_async(ksm.get_kernel_spec(kernel_name))
171+
kernelspec = await ensure_async(ksc.get_kernel_spec(kernel_name))
172172
self.root = kernelspec.resource_dir
173173
except KeyError as e:
174174
raise web.HTTPError(404, "Kernel spec %s not found" % kernel_name) from e

0 commit comments

Comments
 (0)