diff --git a/deploy/nuvolaris-permissions/whisk-user-crd.yaml b/deploy/nuvolaris-permissions/whisk-user-crd.yaml index 2fc7402f..878805f7 100644 --- a/deploy/nuvolaris-permissions/whisk-user-crd.yaml +++ b/deploy/nuvolaris-permissions/whisk-user-crd.yaml @@ -69,7 +69,10 @@ spec: type: string namespace: description: ow namespace assigned to the user - type: string + type: string + x-kubernetes-validations: + - rule: "self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$')" + message: "Invalid namespace name" auth: description: ow auth used to authenticate the user type: string @@ -87,6 +90,9 @@ spec: prefix: description: redis key prefixused to configure a user custom made ACL type: string + x-kubernetes-validations: + - rule: "self.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$')" + message: "Invalid redis username name" password: description: user redis password type: string diff --git a/nuvolaris/ingress_data.py b/nuvolaris/ingress_data.py index 1ac7e3d7..c564a972 100644 --- a/nuvolaris/ingress_data.py +++ b/nuvolaris/ingress_data.py @@ -110,6 +110,8 @@ def render_template(self,namespace,tpl= "generic-ingress-tpl.yaml"): """ uses the given template to render a final ingress template and returns the path to the template """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") logging.info(f"*** Rendering ingress template using host {self._data['hostname']} endpoint for {self._data['ingress_name']} via template {tpl}") out = f"/tmp/__{namespace}_{tpl}" file = ntp.spool_template(tpl, out, self._data) @@ -118,7 +120,9 @@ def render_template(self,namespace,tpl= "generic-ingress-tpl.yaml"): def render_traefik_middleware_template(self, namespace,tpl="traefik-middleware-tpl.yaml"): """ uses the given template policy to render a final ingress template. By default renders an addPrefix middleware. - """ + """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") logging.info(f"*** Rendering traefik middleware template using host {self._data['hostname']} endpoint for {self._data['ingress_name']} via template {tpl}") out = f"/tmp/__{namespace}_{tpl}" file = ntp.spool_template(tpl, out, self._data) diff --git a/nuvolaris/mongodb.py b/nuvolaris/mongodb.py index 50bf5c83..58c5ea99 100644 --- a/nuvolaris/mongodb.py +++ b/nuvolaris/mongodb.py @@ -114,12 +114,16 @@ def init(): def render_mongodb_script(namespace,template,data): """ uses the given template to render a js script to execute as a json. - """ + """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") out = f"/tmp/__{namespace}_{template}" file = ntp.spool_template(template, out, data) return os.path.abspath(file) def exec_mongosh_command(pod_name,path_to_mdb_script): + if not os.path.exists(path_to_mdb_script): + raise ValueError(f"invalid path script in exec_mongosh_command") logging.info(f"passing script {path_to_mdb_script} to pod {pod_name}") res = kube.kubectl("cp",path_to_mdb_script,f"{pod_name}:{path_to_mdb_script}") res = kube.kubectl("exec","-it",pod_name,"--","/bin/bash","-c",f"mongosh --file {path_to_mdb_script}") diff --git a/nuvolaris/postgres_operator.py b/nuvolaris/postgres_operator.py index fb11659a..7274e871 100644 --- a/nuvolaris/postgres_operator.py +++ b/nuvolaris/postgres_operator.py @@ -173,12 +173,16 @@ def _add_pdb_user_metadata(ucfg:UserConfig, user_metadata: UserMetadata): def render_postgres_script(namespace,template,data): """ uses the given template to render a sh script to execute via psql. - """ + """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") out = f"/tmp/__{namespace}_{template}" file = ntp.spool_template(template, out, data) return os.path.abspath(file) def exec_psql_command(pod_name,path_to_psql_script,path_to_pgpass,additional_psql_args=''): + if not os.path.exists(path_to_psql_script): + raise ValueError(f"invalid path script in exec_mongosh_command") logging.info(f"passing script {path_to_psql_script} to pod {pod_name}") res = kube.kubectl("cp",path_to_psql_script,f"{pod_name}:{path_to_psql_script}") res = kube.kubectl("cp",path_to_pgpass,f"{pod_name}:/tmp/.pgpass") diff --git a/nuvolaris/redis.py b/nuvolaris/redis.py index f6ed2f89..fe514405 100644 --- a/nuvolaris/redis.py +++ b/nuvolaris/redis.py @@ -152,12 +152,19 @@ def delete(owner=None): def render_redis_script(namespace,template,data): """ uses the given template to render a redis-cli script to be executed. - """ + """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") + out = f"/tmp/__{namespace}_{template}" file = ntp.spool_template(template, out, data) return os.path.abspath(file) def exec_redis_command(pod_name,path_to_script): + if not os.path.exists(path_to_script): + raise ValueError(f"invalid path script in exec_redis_command") + + logging.info(f"passing script {path_to_script} to pod {pod_name}") res = kube.kubectl("cp",path_to_script,f"{pod_name}:{path_to_script}") res = kube.kubectl("exec","-it",pod_name,"--","/bin/bash","-c",f"cat {path_to_script} | redis-cli") diff --git a/nuvolaris/route_data.py b/nuvolaris/route_data.py index 63a9b0b7..7e6b0e84 100644 --- a/nuvolaris/route_data.py +++ b/nuvolaris/route_data.py @@ -81,7 +81,9 @@ def render_template(self,namespace,tpl= "generic-openshift-route-tpl.yaml"): logging.info(f"*** Rendering route template using host {self._data['hostname']} endpoint for {self._data['route_name']} via template {tpl}") """ uses the given template to render a final route template and returns the path to the template - """ + """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") out = f"/tmp/__{namespace}_{tpl}" file = ntp.spool_template(tpl, out, self._data) return os.path.abspath(file) \ No newline at end of file diff --git a/nuvolaris/secret_htpasswd_data.py b/nuvolaris/secret_htpasswd_data.py index 7a636d4b..821aa14f 100644 --- a/nuvolaris/secret_htpasswd_data.py +++ b/nuvolaris/secret_htpasswd_data.py @@ -20,6 +20,7 @@ import os import nuvolaris.kustomize as kus import nuvolaris.template as ntp +import nuvolaris.util as util import bcrypt import base64 @@ -59,6 +60,8 @@ def render_template(self,namespace,tpl= "generic-secret-htpassword-tpl.yaml"): """ uses the given template to render a final htpassword secret template and returns the path to the template """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") logging.info(f"*** Rendering htpassword secret template with name {self._data['secret_name']} via template {tpl}") out = f"/tmp/__{namespace}_{tpl}" file = ntp.spool_template(tpl, out, self._data) diff --git a/nuvolaris/secret_imagepull_data.py b/nuvolaris/secret_imagepull_data.py index f842d13e..03e9d137 100644 --- a/nuvolaris/secret_imagepull_data.py +++ b/nuvolaris/secret_imagepull_data.py @@ -20,6 +20,7 @@ import os import nuvolaris.kustomize as kus import nuvolaris.template as ntp +import nuvolaris.util as util import base64 class ImagePullSecretData: @@ -65,6 +66,8 @@ def render_template(self,namespace,tpl= "generic-secret-docker-tpl.yaml"): """ uses the given template to render a final ImagePull secret template and returns the path to the template """ + if not util.validate_namespace(namespace): + raise ValueError(f"Invalid namespace {namespace}") logging.info(f"*** Rendering ImagePull secret template with name {self._data['secret_name']} via template {tpl}") out = f"/tmp/__{namespace}_{self._data['secret_name']}_{tpl}" file = ntp.spool_template(tpl, out, self._data) diff --git a/nuvolaris/util.py b/nuvolaris/util.py index fae2c7f5..34a1bb27 100644 --- a/nuvolaris/util.py +++ b/nuvolaris/util.py @@ -22,6 +22,7 @@ import time import uuid import os +import re from base64 import b64decode, b64encode from typing import List, Union from urllib.parse import urlparse @@ -386,6 +387,17 @@ def get_standalone_config_data(): standalone_affinity_tolerations_data(data) return data +def validate_namespace(namespace: str) -> bool: + """ + >>> import nuvolaris.util as util + >>> util.validate_namespace("demouser") + True + >>> util.validate_namespace('x;id;#') + False + """ + NAMESPACE_RE = re.compile(r"^[a-z0-9](?:[-a-z0-9]{0,61}[a-z0-9])?$") + return bool(NAMESPACE_RE.fullmatch(namespace)) + def validate_ow_auth(auth): """ >>> import nuvolaris.testutil as tutil diff --git a/tests/kind/userdb_util_test.ipy b/tests/kind/userdb_util_test.ipy index ec3b04e9..84d4272f 100644 --- a/tests/kind/userdb_util_test.ipy +++ b/tests/kind/userdb_util_test.ipy @@ -15,10 +15,6 @@ # specific language governing permissions and limitations # under the License. # - -!kubectl -n nuvolaris delete all --all -!kubectl -n nuvolaris delete pvc --all - import json import nuvolaris.config as cfg @@ -30,13 +26,18 @@ import nuvolaris.user_config as user_config import nuvolaris.user_metadata as user_metadata import nuvolaris.userdb_util as userdb import nuvolaris.bcrypt_util as bu +import nuvolaris.testutil as tu + +tu.run_proc("kubectl -n nuvolaris delete all --all") +tu.run_proc("kubectl -n nuvolaris delete pvc --all") + assert(cfg.configure(tu.load_sample_config())) assert(cfg.detect_labels()["nuvolaris.kube"] == "kind") assert(cfg.detect_storage()["nuvolaris.storageclass"] == "standard") assert(cfg.put("couchdb.host", "localhost")) -!kubectl apply -f tests/kind/whisk.yaml +tu.run_proc("kubectl apply -f tests/kind/whisk.yaml") wsk = kube.get("wsk/controller") cdb.create(wsk) @@ -49,7 +50,8 @@ assert(db.configure_no_reduce_limit()) assert(cdb.init_users_metadata(db)) # test user metadata creation -!kubectl apply -f tests/kind/whisk-user.yaml +tu.run_proc("kubectl apply -f tests/kind/whisk-user.yaml") + wsku = kube.get("wsku/franztt") ucfg = user_config.UserConfig(wsku['spec']) metadata = user_metadata.UserMetadata(ucfg) @@ -64,7 +66,7 @@ assert(len(docs) > 0) # test password verification doc = docs[0] -assert(bu.verify_password(ucfg.get('password'),doc['password'])) +assert(bu.verify_password(ucfg.get('password') or '',doc['password'])) # test password change new_password = 'test123' @@ -83,6 +85,6 @@ docs = list(response['docs']) assert(len(docs) == 0) # cleanup -!kubectl -n nuvolaris delete all --all -!kubectl -n nuvolaris delete pvc --all +tu.run_proc("kubectl -n nuvolaris delete all --all") +tu.run_proc("kubectl -n nuvolaris delete pvc --all")