-
Notifications
You must be signed in to change notification settings - Fork 294
[RemoteRuntime] Secret token mounting for RemoteRuntime #9050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
liranbg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some suggestions and renamings, overall very well. I suggest to run some nuclio system tests to see how it plays and no regressions were made.
server/py/services/api/launcher.py
Outdated
| # TODO In ML-11600, implement token name resolution and validation + tests | ||
| def _enrich_and_validate_auth_token_name(self, run: mlrun.run.RunObject): | ||
| auth = run.spec.auth or {} | ||
| def enrich_and_validate_auth_token_name_on_object( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| def enrich_and_validate_auth_token_name_on_object( | |
| def enrich_and_validate_auth_token_name( |
why renaming? also, function name should reflect what it does (enriches/validates the auth token) the added information is subjected to the argument - which can be omitted from the name for redundancy or (TMI)
| else url.startswith("http") | ||
| ) | ||
|
|
||
| def test_compile_function_config_iguazio_v4_mounts_auth_secret(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| def test_compile_function_config_iguazio_v4_mounts_auth_secret(self): | |
| def test_compile_function_config_with_auth_secret(self): |
| runtime.spec.volumes = initial_volumes.copy() | ||
| runtime.spec.volume_mounts = initial_mounts.copy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to copy them?
server/py/services/api/launcher.py
Outdated
| def enrich_and_validate_auth_token_name_on_object( | ||
| self, object: Union[mlrun.run.RunObject, mlrun.runtimes.RemoteRuntime] | ||
| ): | ||
| # Ensure the auth dictionary exists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # Ensure the auth dictionary exists |
code is self explanatory
server/py/services/api/launcher.py
Outdated
| # Resolve token name | ||
| if provided_token_name: | ||
| token_name = provided_token_name | ||
| self._validate_token_name(token_name, raise_error_on_failure=True) | ||
| else: | ||
| token_name = "default" | ||
| self._validate_token_name(token_name, raise_error_on_failure=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is default token name a constant? I think it should be
also, comment on why you raise an exception?
| # Resolve token name | |
| if provided_token_name: | |
| token_name = provided_token_name | |
| self._validate_token_name(token_name, raise_error_on_failure=True) | |
| else: | |
| token_name = "default" | |
| self._validate_token_name(token_name, raise_error_on_failure=False) | |
| # explain me | |
| raise_error_on_failure = bool(provided_token_name) | |
| token_name = provided_token_name or "default" | |
| self._validate_token_name(token_name, raise_error_on_failure=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@quaark I can use mlconf.auth_with_oauth_token.token_name, however if user sets this env var prior to importing mlrun, then runs/deploy a function, the token resolution logic will use that instead.
I assume we don't want that behavior right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok so we'll make it a constant not a config
| for vol in volumes: | ||
| if "secret" in vol: | ||
| secret = vol["secret"] | ||
| secret_name = secret.get("secretName", "") | ||
|
|
||
| # Pattern of auth secret volumes | ||
| if secret_name.startswith("mlrun-auth-secrets"): | ||
| volumes_to_remove.add(vol["name"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| for vol in volumes: | |
| if "secret" in vol: | |
| secret = vol["secret"] | |
| secret_name = secret.get("secretName", "") | |
| # Pattern of auth secret volumes | |
| if secret_name.startswith("mlrun-auth-secrets"): | |
| volumes_to_remove.add(vol["name"]) | |
| for volume in volumes: | |
| if secret := volume.get("secret"): | |
| secret_name = secret.get("secretName", "") | |
| if secret_name.startswith("mlrun-auth-secrets"): | |
| volumes_to_remove.add(volume["name"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shorter, with full name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rokatyy's suggestion is more robust. Using her's instead
| runtime.spec.volumes = [ | ||
| v for v in volumes if v["name"] not in volumes_to_remove | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| runtime.spec.volumes = [ | |
| v for v in volumes if v["name"] not in volumes_to_remove | |
| ] | |
| runtime.spec.volumes = [ | |
| volume | |
| for volume in volumes | |
| if volume["name"] not in volumes_to_remove | |
| ] |
use full name, makes it more readable
|
|
||
| # Filter out matching mounts | ||
| runtime.spec.volume_mounts = [ | ||
| m for m in mounts if m["name"] not in volumes_to_remove |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it readable
| ) | ||
|
|
||
| # Remove any existing auth secret volumes/mounts | ||
| services.api.crud.secrets.Secrets._remove_auth_secret_volumes(runtime) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seeing these calls (static method) from within same class static method) shows me that the decision to put the logic under Secrets class that it was a bit wrong.
I think we need to change it and move logic under runtime/etc. then we could do
runtime.enrich_and_validate()
function.remove_auth_secret_volumes()
using self, etc
| function = services.api.crud.secrets.Secrets.mount_secret_token_to_runtime( | ||
| function, | ||
| token_name=function.spec.auth.get("token_name"), | ||
| username=auth_info.username, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function.mount_secret_token_to_runtime(token_name, auth_info)
rokatyy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor suggestions
…umes' logic from outside the 'Secrets' class into the baseRuntime and the BaseRuntimeHandler. The '_mount_secret_token_to_runtime' is now used inside the 'add_k8s_secrets_to_spec' method which is called both from the runtime handler flow and the nuclio deployment flow. Tests have been updated respectively to match the new functions locations (however not refactored based on other PR comments)
… the mlrun.utils.get_in method, using constant for auth secret name prefix and using full name for variables. The used constant returns a trailing dot in the prefix name which allowed me to discover that the examples in the tests didn't perfectly match real life - so tests have been adjusted accordingly
…d changes. Refactor enrich_and_validate_auth_token_name to run on ig4 only, removed if/else condition and used constant name for default token name
rokatyy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
| silent=True | ||
| ).is_running_inside_kubernetes_cluster(): | ||
| _add_secrets_config_to_function_spec(function) | ||
| token_name = mlrun.utils.get_in(function.spec, "auth.token_name", None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we want to skip if token is empty? Or will it be handled later in the flow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Later in the flow it will try to list the secrets matching that token, but there won't be such, so we won't perform the mounting.
…tion was updated to only run on ig4 mode
liranbg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks much much better. minor suggestion to keep the coding better
|
|
||
|
|
||
| def _resolve_env_vars(function, auth_info=None): | ||
| def _enrich_config_spec(function, username): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not passing auth_info entirely? a better practice as you might late on use its other fields
| runtime: mlrun.runtimes.pod.KubeResource, | ||
| project_name: Optional[str] = None, | ||
| token_name: Optional[str] = None, | ||
| username: Optional[str] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pass auth_info
| project_name: Optional[str] = None, | ||
| encode_key_names: bool = True, | ||
| token_name: Optional[str] = None, | ||
| username: Optional[str] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pass auth_info
|
|
||
| @staticmethod | ||
| def _mount_secret_token_to_runtime( | ||
| runtime: mlrun.runtimes.base.BaseRuntime, token_name: str, username: str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pass auth_info
| runtime, | ||
| project_name=run.metadata.project, | ||
| token_name=(run.spec.auth or {}).get("token_name"), | ||
| username=auth_info.username, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simply pass the auto info - it allows the function to extend and use the class capabilities later on when we want to identify user not just by username but even perhaps its group
…ow extension in the class capabilities in the future. Fixed tests accordingly.
📝 Description
Add secret token mounting for RemoteRuntime functions.
Save
authas part of the function's spec. Use it to mount the secret into the runtime during function config compilation.🛠️ Changes Made
authas part ofNuclioSpec,ApplicationSpecandServingSpecmount_secret_token_to_runtimeto remove existing auth secret volumes/mounts_enrich_and_validate_auth_token_nametoenrich_and_validate_auth_token_name_on_objectto support bothrunObjectandremoteRuntime✅ Checklist
🧪 Testing
Unit tests + manual tests of deployment of nuclio/application/serving
🔗 References
🚨 Breaking Changes?
🔍️ Additional Notes
As part of https://iguazio.atlassian.net/browse/ML-11599, need to handle redeployment of a function with a different auth token name.