def create_namespaced_role_binding_with_api(name, namespace, labels, subject_name, subject_kind='ServiceAccount'): """Bind namespaced role to subject.""" # Using API because of bug https://bugs.launchpad.net/juju/+bug/1896076 logging.info('Creating role binding with K8s API') _load_kube_config() body = client.V1RoleBinding(metadata=client.V1ObjectMeta( name=name, namespace=namespace, labels=labels), role_ref=client.V1RoleRef( api_group='rbac.authorization.k8s.io', kind='Role', name=name, ), subjects=[ client.V1Subject(kind=subject_kind, name=subject_name), ]) with client.ApiClient() as api_client: api_instance = client.RbacAuthorizationV1Api(api_client) try: api_instance.create_namespaced_role_binding(namespace, body, pretty=True) except ApiException as err: if err.status == 409: # ignore "already exists" errors so that we can recover from # partially failed setups return else: raise
def create_k8s_rolebinding(self, k8s_role, aws_user): """Create k8s role-binding for specified role and user.""" rolebinding_name = self.generate_rolebinding_name() label_selector = self.label_selector.split('=') role_binding = client.V1RoleBinding( metadata=client.V1ObjectMeta( namespace=self.namespace, name=rolebinding_name, labels={label_selector[0]: label_selector[1]}, annotations={ self.expire_annotation: str(int(self.now + self.DAY_AND_NIGHT)) }), subjects=[ client.V1Subject(name=aws_user, kind="User", api_group="rbac.authorization.k8s.io") ], role_ref=client.V1RoleRef(kind="Role", api_group="rbac.authorization.k8s.io", name=k8s_role)) self.rbac_api = client.RbacAuthorizationV1Api() try: self.rbac_api.create_namespaced_role_binding( namespace=self.namespace, body=role_binding) except ApiException as e: print( "Exception when calling RbacAuthorizationV1Api->create_namespaced_role_binding: %s\n" % e) return rolebinding_name
def _create_namespaced_account_objects(self): namespace = self.get_user_namespace() account = self.service_account if not account: self.log.info("No service account defined.") return (None, None, None) md = client.V1ObjectMeta(name=account) svcacct = client.V1ServiceAccount(metadata=md) rules = [ client.V1PolicyRule( api_groups=[""], resources=["pods", "services"], verbs=["get", "list", "watch", "create", "delete"]), client.V1PolicyRule(api_groups=[""], resources=["pods/log"], verbs=["get", "list"]), ] role = client.V1Role(rules=rules, metadata=md) rolebinding = client.V1RoleBinding( metadata=md, role_ref=client.V1RoleRef(api_group="rbac.authorization.k8s.io", kind="Role", name=account), subjects=[ client.V1Subject(kind="ServiceAccount", name=account, namespace=namespace) ]) return svcacct, role, rolebinding
def create_role_binding(self, api_instance, namespace, sa_name): role_name = hashlib.sha1( str.encode(sa_name)).hexdigest()[:8] # $ID-role trigger bug! HaHa binding_name = "{}-binding".format(role_name) body = client.V1Role(api_version='rbac.authorization.k8s.io/v1', kind='Role', metadata=client.V1ObjectMeta(name=role_name, namespace=namespace), rules=[ client.V1PolicyRule(api_groups=['*'], resources=['*'], verbs=['*']) ]) api_instance.create_namespaced_role(namespace=namespace, body=body) role_binding = client.V1RoleBinding( metadata=client.V1ObjectMeta(namespace=namespace, name=binding_name), subjects=[ client.V1Subject(name=sa_name, kind="ServiceAccount", api_group="") ], role_ref=client.V1RoleRef(kind="Role", api_group="rbac.authorization.k8s.io", name=role_name)) api_instance.create_namespaced_role_binding(namespace=namespace, body=role_binding)
def clusterrolebindings_from_marker(item, namespace): """Create ClusterRoleBindings for the test case if the test case is marked with the `pytest.mark.clusterrolebinding` marker. Args: item (pytest.Item): The pytest test item. namespace (str): The namespace of the test case. Return: list[objects.ClusterRoleBinding]: The ClusterRoleBindings that were generated from the test case markers. """ clusterrolebindings = [] for mark in item.iter_markers(name='clusterrolebinding'): name = mark.args[0] subj_kind = mark.kwargs.get('subject_kind') subj_name = mark.kwargs.get('subject_name') subj = get_custom_rbac_subject(namespace, subj_kind, subj_name) if not subj: subj = get_default_rbac_subjects(namespace) clusterrolebindings.append(ClusterRoleBinding(client.V1ClusterRoleBinding( metadata=client.V1ObjectMeta( name='kubetest:{}'.format(item.name), ), role_ref=client.V1RoleRef( api_group='rbac.authorization.k8s.io', kind='ClusterRole', name=name, ), subjects=subj, ))) return clusterrolebindings
def _create_role_binding(self, namespace): # Creates RoleBinding instance for the given namespace. The role used will be the ClusterRole cluster-admin. # Note that roles referenced in RoleBindings are scoped to the namespace so re-using the cluster role prevents # the need for creating a new role with each kernel. # We will not use a try/except clause here since _create_kernel_namespace will handle exceptions. role_binding_name = 'kernel-rb' labels = { 'app': 'enterprise-gateway', 'component': 'kernel', 'kernel_id': self.kernel_id } binding_metadata = client.V1ObjectMeta(name=role_binding_name, labels=labels) binding_role_ref = client.V1RoleRef(api_group='', kind='ClusterRole', name='cluster-admin') binding_subjects = client.V1Subject(api_group='', kind='ServiceAccount', name='default', namespace=namespace) body = client.V1RoleBinding(kind='RoleBinding', metadata=binding_metadata, role_ref=binding_role_ref, subjects=[binding_subjects]) client.RbacAuthorizationV1Api().create_namespaced_role_binding( namespace=namespace, body=body) self.log.info( "Created kernel role-binding '{}' for namespace: {}".format( role_binding_name, namespace))
def create_namespaced_role_binding_with_api(name, namespace, labels, subject_name, subject_kind='ServiceAccount'): """Bind a namespaced role to a subject.""" # Using API because of bug https://bugs.launchpad.net/juju/+bug/1896076 logging.info('Creating role binding with K8s API') _load_kube_config() body = client.V1RoleBinding(metadata=client.V1ObjectMeta( name=name, namespace=namespace, labels=labels), role_ref=client.V1RoleRef( api_group='rbac.authorization.k8s.io', kind='Role', name=name, ), subjects=[ client.V1Subject(kind=subject_kind, name=subject_name), ]) with client.ApiClient() as api_client: api_instance = client.RbacAuthorizationV1Api(api_client) try: api_instance.create_namespaced_role_binding(namespace, body, pretty=True) except ApiException as err: logging.exception("Exception when calling RbacAuthorizationV1Api" "->create_namespaced_role_binding.") if err.status != 409: # Hook error except for 409 (AlreadyExists) errors sys.exit(1)
def _create_role_binding(self, namespace, service_account_name): # Creates RoleBinding instance for the given namespace. The role used will be the ClusterRole named by # EG_KERNEL_CLUSTER_ROLE. # Note that roles referenced in RoleBindings are scoped to the namespace so re-using the cluster role prevents # the need for creating a new role with each kernel. # The ClusterRole will be bound to the kernel service user identified by KERNEL_SERVICE_ACCOUNT_NAME then # EG_DEFAULT_KERNEL_SERVICE_ACCOUNT_NAME, respectively. # We will not use a try/except clause here since _create_kernel_namespace will handle exceptions. role_binding_name = kernel_cluster_role # use same name for binding as cluster role labels = { 'app': 'enterprise-gateway', 'component': 'kernel', 'kernel_id': self.kernel_id } binding_metadata = client.V1ObjectMeta(name=role_binding_name, labels=labels) binding_role_ref = client.V1RoleRef(api_group='', kind='ClusterRole', name=kernel_cluster_role) binding_subjects = client.V1Subject(api_group='', kind='ServiceAccount', name=service_account_name, namespace=namespace) body = client.V1RoleBinding(kind='RoleBinding', metadata=binding_metadata, role_ref=binding_role_ref, subjects=[binding_subjects]) client.RbacAuthorizationV1Api().create_namespaced_role_binding( namespace=namespace, body=body) self.log.info( "Created kernel role-binding '{}' in namespace: {} for service account: {}" .format(role_binding_name, namespace, service_account_name))
def create_namespaced_role_binding(self, role_binding_name, service_account_name, role_name, namespace="default"): """Create role binding using name=role_binding_name in namespace connecting role_name using service_account_name""" subject = client.V1Subject(kind="ServiceAccount", name=service_account_name, namespace=namespace) metadata = client.V1ObjectMeta(name=role_binding_name) role = client.V1RoleRef(kind="Role", name=role_name, api_group="rbac.authorization.k8s.io") body = client.V1RoleBinding(subjects=[subject], metadata=metadata, role_ref=role) try: self.rbac_cli.create_namespaced_role_binding(namespace=namespace, body=body) logger.info('Created role {} in namespace {}'.format( role_binding_name, namespace)) return True except client.rest.ApiException as e: self.check_create_error_and_response(e, "RoleBinding", role_binding_name) return False
def _bind_namespace_to_cluster_role(clusterrole, portal_ns): role_ref = client.V1RoleRef(name=clusterrole, kind="ClusterRole", api_group="rbac.authorization.k8s.io") # Subject for the cluster role are all service accounts in the namespace subject = client.V1Subject(name="system:serviceaccounts:" + portal_ns.name, kind="Group", api_group="rbac.authorization.k8s.io") metadata = client.V1ObjectMeta(name=clusterrole) new_rolebinding = client.V1RoleBinding(role_ref=role_ref, metadata=metadata, subjects=[subject, ]) rbac_v1.create_namespaced_role_binding(portal_ns.name, new_rolebinding)
def create_cluster_role_binding(): """ Create IBM Spectrum Scale CSI Operator ClusterRoleBinding object in Operator namepsace Args: None Returns: None Raises: Raises an exception on kubernetes client api failure and asserts """ cluster_role_binding_api_instance = client.RbacAuthorizationV1Api() pretty = True cluster_role_binding_labels = { "app.kubernetes.io/instance": "ibm-spectrum-scale-csi-operator", "app.kubernetes.io/managed-by": "ibm-spectrum-scale-csi-operator", "app.kubernetes.io/name": "ibm-spectrum-scale-csi-operator", "product": "ibm-spectrum-scale-csi", "release": "ibm-spectrum-scale-csi-operator" } cluster_role_binding_metadata = client.V1ObjectMeta( name="ibm-spectrum-scale-csi-operator", labels=cluster_role_binding_labels, namespace=namespace_value) cluster_role_binding_role_ref = client.V1RoleRef( api_group="rbac.authorization.k8s.io", kind="ClusterRole", name="ibm-spectrum-scale-csi-operator") cluster_role_binding_subjects = client.V1Subject( kind="ServiceAccount", name="ibm-spectrum-scale-csi-operator", namespace=namespace_value) cluster_role_binding_body = client.V1ClusterRoleBinding( kind='ClusterRoleBinding', api_version='rbac.authorization.k8s.io/v1', metadata=cluster_role_binding_metadata, role_ref=cluster_role_binding_role_ref, subjects=[cluster_role_binding_subjects]) try: LOGGER.info("creating cluster role binding") cluster_role_binding_api_response = cluster_role_binding_api_instance.create_cluster_role_binding( cluster_role_binding_body, pretty=pretty) LOGGER.debug(cluster_role_binding_api_response) except ApiException as e: LOGGER.error( f"Exception when calling RbacAuthorizationV1Api->create_cluster_role_binding: {e}" ) assert False
def create_sa_rb(cli, namespace, name, role_name, sa_name, sa_ns=DEFAULT_SA_NAMESPACE): role = k8c.V1RoleRef(name=role_name, api_group="rbac.authorization.k8s.io", kind="Role") subject = [ k8c.V1Subject(kind="ServiceAccount", name=sa_name, namespace=sa_ns) ] return create_role_binding(cli, namespace, name, role, subject)
def setup_job_and_deployment_service_accounts(namespace: str) -> None: """Setup a jobs-and-deployments service-account with required roles. :param namespace: Namespace in which the service-account will be placed. """ service_account_object = k8s.V1ServiceAccount( metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_JOBS_DEPLOYMENTS_SERVICE_ACCOUNT ) ) k8s.CoreV1Api().create_namespaced_service_account( namespace=namespace, body=service_account_object ) role_object = k8s.V1Role( metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_JOBS_DEPLOYMENTS_SERVICE_ACCOUNT ), rules=[ k8s.V1PolicyRule( api_groups=[""], resources=["secrets", "configmaps"], verbs=["get", "list"], ) ], ) k8s.RbacAuthorizationV1Api().create_namespaced_role( namespace=namespace, body=role_object ) role_binding_object = k8s.V1RoleBinding( metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_JOBS_DEPLOYMENTS_SERVICE_ACCOUNT ), role_ref=k8s.V1RoleRef( kind="Role", name=BODYWORK_JOBS_DEPLOYMENTS_SERVICE_ACCOUNT, api_group="rbac.authorization.k8s.io", ), subjects=[ k8s.V1Subject( kind="ServiceAccount", name=BODYWORK_JOBS_DEPLOYMENTS_SERVICE_ACCOUNT, namespace=namespace, ) ], ) k8s.RbacAuthorizationV1Api().create_namespaced_role_binding( namespace=namespace, body=role_binding_object )
def _cluster_role_binding(self): return client.V1ClusterRoleBinding( api_version='rbac.authorization.k8s.io/v1', kind='ClusterRoleBinding', metadata=metadata( name=self.name, labels=self.labels, ), role_ref=client.V1RoleRef(api_group='rbac.authorization.k8s.io', kind='ClusterRole', name=self.name), subjects=[ client.V1Subject(kind='ServiceAccount', name=self.name, namespace=self.namespace) ])
def create_quick_clusterrolebinding_definition(clusterRoleBindingName, clusterRoleName, serviceAccountName, saNamespace, annotationsDict={}): clusterrole = client.V1RoleRef(api_group="rbac.authorization.k8s.io", kind="ClusterRole", name=clusterRoleName) subjectsList = client.V1Subject(kind="ServiceAccount", name=serviceAccountName, namespace=saNamespace) clusterRoleBinding = client.V1ClusterRoleBinding( api_version="rbac.authorization.k8s.io/v1", kind="ClusterRoleBinding", metadata=client.V1ObjectMeta(name=clusterRoleBindingName, annotations=annotationsDict), role_ref=clusterrole, subjects=[subjectsList]) return clusterRoleBinding
def create(configuration, NAMESPACE_NAME, ROLE_NAME, ROLE_TITLE, USER_NAME): try: role_binding = client.V1RoleBinding( metadata=client.V1ObjectMeta(namespace=NAMESPACE_NAME, name=ROLE_TITLE), subjects=[ client.V1Subject(name=USER_NAME, kind="User", api_group="rbac.authorization.k8s.io") ], role_ref=client.V1RoleRef(kind="Role", api_group="rbac.authorization.k8s.io", name=ROLE_NAME)) rbac = client.RbacAuthorizationV1Api(client.ApiClient(configuration)) rbac.create_namespaced_role_binding(namespace=NAMESPACE_NAME, body=role_binding) return True except Exception as e: print(e) return False
def create_rolebinding(name, scope_name, id_token): api_version = 'rbac.authorization.k8s.io' scope = scope_name subject = k8s_client.V1Subject(kind='Group', name=scope, namespace=name) role_ref = k8s_client.V1RoleRef(api_group=api_version, kind='Role', name=name) meta = k8s_client.V1ObjectMeta(name=name, namespace=name) rolebinding = k8s_client.V1RoleBinding(metadata=meta, role_ref=role_ref, subjects=[subject]) rbac_api_instance = get_k8s_rbac_api_client(id_token) try: response = rbac_api_instance.create_namespaced_role_binding( name, rolebinding) except ApiException as apiException: KubernetesCreateException('rolebinding', apiException) logger.info("Rolebinding {} created".format(name)) return response
def create_cluster_role_binding(self, cluster_role_binding_name, user_name, cluster_role_name): """Create role binding using name=role_binding_name in namespace connecting role_name using service_account_name""" metadata = client.V1ObjectMeta(name=cluster_role_binding_name) role = client.V1RoleRef(kind="ClusterRole", name=cluster_role_name, api_group="rbac.authorization.k8s.io") subject = client.V1Subject(kind="User", name=user_name) body = client.V1ClusterRoleBinding(subjects=[subject], metadata=metadata, role_ref=role) try: self.rbac_cli.create_cluster_role_binding(body=body) logger.info('Created cluster role binding {}'.format( cluster_role_binding_name)) return True except client.rest.ApiException as e: self.check_create_error_and_response(e, "ClusterRoleBinding", cluster_role_binding_name) return False
def rolebindings_from_marker(item: pytest.Item, namespace: str) -> List[RoleBinding]: """Create RoleBindings for the test case if the test is marked with the `pytest.mark.rolebinding` marker. Args: item: The pytest test item. namespace: The namespace of the test case. Returns: The RoleBindings that were generated from the test case markers. """ rolebindings = [] for mark in item.iter_markers(name="rolebinding"): kind = mark.args[0] name = mark.args[1] subj_kind = mark.kwargs.get("subject_kind") subj_name = mark.kwargs.get("subject_name") subj = get_custom_rbac_subject(namespace, subj_kind, subj_name) if not subj: subj = get_default_rbac_subjects(namespace) rolebindings.append( RoleBinding( client.V1RoleBinding( metadata=client.V1ObjectMeta( name=f"kubetest:{item.name}", namespace=namespace, ), role_ref=client.V1RoleRef( api_group="rbac.authorization.k8s.io", kind=kind, name=name, ), subjects=subj, ))) return rolebindings
def bind_role_with_api(name, namespace, labels, subject_name, subject_kind='ServiceAccount'): """Bind namespaced role to subject.""" # Using API because of bug https://github.com/canonical/operator/issues/390 logging.info('Creating role binding with K8s API') _load_kube_config() body = client.V1RoleBinding( metadata=client.V1ObjectMeta( name=name, namespace=namespace, labels=labels ), role_ref=client.V1RoleRef( api_group='rbac.authorization.k8s.io', kind='Role', name=name, ), subjects=[ client.V1Subject( kind=subject_kind, name=subject_name ), ] ) with client.ApiClient() as api_client: api_instance = client.RbacAuthorizationV1Api(api_client) try: api_instance.create_namespaced_role_binding(namespace, body, pretty=True) return True except ApiException as err: logging.exception("Exception when calling RbacAuthorizationV1Api" "->create_namespaced_role_binding.") if err.status != 409: # ignoring 409 (AlreadyExists) errors return False else: return True
def __createRoleBinding(self): """Creates rolebinding for namespaced tunneling service and user. """ # generate metadata metadata = client.V1ObjectMeta(name=self.serviceName, namespace=self.namespace) subjects = [client.V1Subject(name="default", kind="ServiceAccount")] role_ref = client.V1RoleRef(kind="Role", api_group="rbac.authorization.k8s.io", name=self.namespace) body = client.V1RoleBinding(metadata=metadata, subjects=subjects, role_ref=role_ref) # create rolebindings try: self.rbac_instance.create_namespaced_role_binding( namespace=self.namespace, body=body) except ApiException as e: if e.status == 409: pass else: logging.error(e) raise
def def_namespaced_account_objects(self): """Define K8s objects for things we need in the namespace.""" with start_action(action_type="define_namespaced_account_objects"): namespace = self.namespace username = self.parent.user.escaped_name cfg = self.parent.config psnm = cfg.pull_secret_name pull_secret = get_pull_secret(pull_secret_name=psnm, api=self.parent.api, log=self.log) pull_secret_ref = get_pull_secret_reflist(pull_secret_name=psnm) account = "{}-svcacct".format(username) self.service_account = account acd = "argocd.argoproj.io/" md = client.V1ObjectMeta( name=account, labels={acd + "instance": "nublado-users"}, annotations={ acd + "compare-options": "IgnoreExtraneous", acd + "sync-options": "Prune=false", }, ) svcacct = client.V1ServiceAccount( metadata=md, image_pull_secrets=pull_secret_ref) # These rules let us manipulate Dask pods, Argo Workflows, and # Multus CNI interfaces rules = [ client.V1PolicyRule( api_groups=["argoproj.io"], resources=["workflows", "workflows/finalizers"], verbs=[ "get", "list", "watch", "update", "patch", "create", "delete", ], ), client.V1PolicyRule( api_groups=["argoproj.io"], resources=[ "workflowtemplates", "workflowtemplates/finalizers", ], verbs=["get", "list", "watch"], ), client.V1PolicyRule(api_groups=[""], resources=["secrets"], verbs=["get"]), client.V1PolicyRule( api_groups=[""], resources=["pods", "pods/exec", "services", "configmaps"], verbs=[ "get", "list", "watch", "create", "delete", "update", "patch", ], ), client.V1PolicyRule( api_groups=[""], resources=["pods/log", "serviceaccounts"], verbs=["get", "list", "watch"], ), ] role = client.V1Role(rules=rules, metadata=md) rbstr = "rbac.authorization.k8s.io" rolebinding = client.V1RoleBinding( metadata=md, role_ref=client.V1RoleRef(api_group=rbstr, kind="Role", name=account), subjects=[ client.V1Subject( kind="ServiceAccount", name=account, namespace=namespace, ) ], ) return pull_secret, svcacct, role, rolebinding
def _sync_namespaces(request, core_v1, rbac_v1): # K8S namespaces -> portal namespaces success_count_pull = 0 k8s_ns_list = None try: k8s_ns_list = core_v1.list_namespace() except Exception as e: logger.error("Exception: {0}".format(e)) messages.error( request, "Sync failed, error while fetching list of namespaces: {0}.". format(e)) return k8s_ns_uids = [] for k8s_ns in k8s_ns_list.items: try: k8s_ns_name = k8s_ns.metadata.name k8s_ns_uid = k8s_ns.metadata.uid # remember for later use k8s_ns_uids.append(k8s_ns_uid) portal_ns, created = KubernetesNamespace.objects.get_or_create( name=k8s_ns_name, uid=k8s_ns_uid) if created: # Create missing namespace record logger.info( "Creating record for Kubernetes namespace '{0}'".format( k8s_ns_name)) if k8s_ns_name in HIDDEN_NAMESPACES: portal_ns.visible = False else: portal_ns.visible = True portal_ns.save() messages.info( request, "Found new Kubernetes namespace '{0}'.".format( k8s_ns_name)) else: # No action needed logger.debug( "Found existing record for Kubernetes namespace '{0}'". format(k8s_ns_name)) success_count_pull += 1 except Exception as e: logger.error("Exception: {0}".format(e)) messages.error( request, "Sync from Kubernetes for namespace {0} failed: {1}.".format( k8s_ns_name, e)) # portal namespaces -> K8S namespaces success_count_push = 0 for portal_ns in KubernetesNamespace.objects.all(): try: if portal_ns.uid: # Portal namespace records with UID must be given in K8S, or they are # stale und should be deleted if portal_ns.uid in k8s_ns_uids: # No action needed logger.debug( "Found existing Kubernetes namespace for record '{0}'". format(portal_ns.name)) success_count_push += 1 else: # Remove stale namespace record logger.warning( "Removing stale record for Kubernetes namespace '{0}'". format(portal_ns.name)) portal_ns.delete() messages.info( request, "Namespace '{0}' no longer exists in Kubernetes and was removed." .format(portal_ns.name)) else: # Portal namespaces without UID are new and should be created in K8S logger.debug( "Namespace record {} has no UID, creating it in Kubernetes ..." .format(portal_ns.name)) # Sanitize name, K8S only allows DNS names for namespaces sanitized_name = re.sub('[^a-zA-Z0-9]', '', portal_ns.name).lower() if sanitized_name != portal_ns.name: logger.warning( "Given name '{}' for new Kubernetes namespace is invalid, replacing it with '{}'" .format(portal_ns.name, sanitized_name)) messages.warning( request, "Given name '{}' for new Kubernetes namespace was invalid, chosen name is now '{}'" .format(portal_ns.name, sanitized_name)) # TODO: May already exist? portal_ns.name = sanitized_name portal_ns.save() created_k8s_ns = _create_k8s_ns(portal_ns.name, core_v1) portal_ns.uid = created_k8s_ns.metadata.uid portal_ns.save() messages.success( request, "Created namespace '{0}' in Kubernetes.".format( portal_ns.name)) except Exception as e: logger.error("Exception: {0}".format(e)) messages.error( request, "Sync to Kubernetes for namespace {0} failed: {1}.".format( portal_ns, e)) if success_count_push == success_count_pull: messages.success(request, "All valid namespaces are in sync.") # check role bindings of namespaces # We only consider visible namespaces here, to prevent hitting # special namespaces and giving them (most likely unneccessary) # additional role bindings for portal_ns in KubernetesNamespace.objects.filter(visible=True): # Get role bindings in the current namespace try: rolebindings = rbac_v1.list_namespaced_role_binding(portal_ns.name) except Exception as e: logger.error("Exception: {0}".format(e)) messages.error( request, "Could not fetch role bindings for namespace '{0}': {1}.". format(portal_ns, e)) continue # Get all cluster roles this namespace is currently bound to clusterroles_active = [ rolebinding.role_ref.name for rolebinding in rolebindings.items if rolebinding.role_ref.kind == 'ClusterRole' ] logger.debug("Namespace '{0}' is bound to cluster roles {1}".format( portal_ns, clusterroles_active)) # Check list of default cluster roles from settings for clusterrole in settings.NAMESPACE_CLUSTERROLES: if clusterrole not in clusterroles_active: try: logger.info( "Namespace '{0}' is not bound to cluster role '{1}', fixing this ..." .format(portal_ns, clusterrole)) role_ref = client.V1RoleRef( name=clusterrole, kind="ClusterRole", api_group="rbac.authorization.k8s.io") # Subject for the cluster role are all service accounts in the namespace subject = client.V1Subject( name="system:serviceaccounts:" + portal_ns.name, kind="Group", api_group="rbac.authorization.k8s.io") metadata = client.V1ObjectMeta(name=clusterrole) new_rolebinding = client.V1RoleBinding(role_ref=role_ref, metadata=metadata, subjects=[ subject, ]) rbac_v1.create_namespaced_role_binding( portal_ns.name, new_rolebinding) except Exception as e: logger.exception(e) messages.error( request, "Could not create binding of namespace '{0}' to cluster role '{1}': {2}." .format(portal_ns.name, clusterrole, e)) continue
def run(namespace, tmpVolumeSize, outputVolumeSize, volumeName, storage_class_name=None, imagepullsecrets=None, ades_namespace=None, state=None): print( f"Preparing {namespace} tmpVolumeSize: {tmpVolumeSize} outputVolumeSize: {outputVolumeSize} volumeName: {volumeName}" ) apiclient = helpers.get_api_client() api_instance = client.RbacAuthorizationV1Api(apiclient) v1 = client.CoreV1Api(api_client=apiclient) print("####################################") print("######### Checking if namespace already exists") try: v1.read_namespace(namespace, pretty=True) print("Namespace already exists") return {"status": "success"} except ApiException as e: if e.status == 404: print("Namespace does not exists and will be created") else: print("Exception when creating namespace: %s\n" % e, file=sys.stderr) raise e ### Creating namespace print("####################################") print("######### Creating namespace") try: body = client.V1Namespace(metadata=client.V1ObjectMeta(name=namespace)) namespace_json = v1.create_namespace(body=body, async_req=False) print(str(namespace_json)) except ApiException as e: print("Exception when creating namespace: %s\n" % e, file=sys.stderr) raise e #### Creating pod manager role print("####################################") print("######### Creating pod_manager_role") metadata = client.V1ObjectMeta(name='pod-manager-role', namespace=namespace) rule = client.V1PolicyRule( api_groups=['*'], resources=['pods', 'pods/log'], verbs=['create', 'patch', 'delete', 'list', 'watch']) rules = [] rules.append(rule) body = client.V1Role(metadata=metadata, rules=rules) pretty = True try: api_response = api_instance.create_namespaced_role(namespace, body, pretty=pretty) pprint(api_response) except ApiException as e: print("Exception when creating pod-manager-role: %s\n" % e, file=sys.stderr) raise e #### Creating log-reader-role print("####################################") print("######### Creating log-reader-role") metadata = client.V1ObjectMeta(name='log-reader-role', namespace=namespace) rule = client.V1PolicyRule( api_groups=['*'], resources=['pods', 'pods/log'], verbs=['create', 'patch', 'delete', 'list', 'watch']) # verbs=['get', 'list']) rules = [] rules.append(rule) body = client.V1Role(metadata=metadata, rules=rules) pretty = True try: api_response = api_instance.create_namespaced_role(namespace, body, pretty=pretty) pprint(api_response) except ApiException as e: print("Exception when creating pod-manager-role: %s\n" % e, file=sys.stderr) raise e print("####################################") print("######### Creating pod-manager-default-binding") metadata = client.V1ObjectMeta(name='pod-manager-default-binding', namespace=namespace) role_ref = client.V1RoleRef(api_group='', kind='Role', name='pod-manager-role') subject = client.models.V1Subject(api_group='', kind='ServiceAccount', name='default', namespace=namespace) subjects = [] subjects.append(subject) body = client.V1RoleBinding(metadata=metadata, role_ref=role_ref, subjects=subjects) pretty = True try: api_response = api_instance.create_namespaced_role_binding( namespace, body, pretty=pretty) pprint(api_response) except ApiException as e: print("Exception when creating pod-manager-default-binding: %s\n" % e, file=sys.stderr) raise e print("####################################") print("######### Creating log-reader-default-binding") metadata = client.V1ObjectMeta(name='log-reader-default-binding', namespace=namespace) role_ref = client.V1RoleRef(api_group='', kind='Role', name='log-reader-role') subject = client.models.V1Subject(api_group='', kind='ServiceAccount', name='default', namespace=namespace) subjects = [] subjects.append(subject) body = client.V1RoleBinding(metadata=metadata, role_ref=role_ref, subjects=subjects) pretty = True try: api_response = api_instance.create_namespaced_role_binding( namespace, body, pretty=pretty) pprint(api_response) except ApiException as e: print("Exception when creating log-reader-default-binding: %s\n" % e, file=sys.stderr) raise e print("####################################") print("######### Creating cluster-role-binding") metadata = client.V1ObjectMeta(name=f"{namespace}-rbac", namespace=namespace) role_ref = client.V1RoleRef(api_group='rbac.authorization.k8s.io', kind='ClusterRole', name='cluster-admin') subject = client.models.V1Subject(api_group='', kind='ServiceAccount', name='default', namespace=namespace) subjects = [] subjects.append(subject) body = client.V1ClusterRoleBinding(metadata=metadata, role_ref=role_ref, subjects=subjects) pretty = True try: api_response = api_instance.create_cluster_role_binding(body=body, pretty=pretty) pprint(api_response) except ApiException as e: if e.status == 409: print( f"cluster-role-binding {namespace}-rbac has already been installed" ) else: print("Exception when creating cluster-role-binding: %s\n" % e, file=sys.stderr) raise e print("####################################") print("######### Creating Persistent Volume Claims") # metadata1 = client.V1ObjectMeta(name=f"{volumeName}-input-data", namespace=namespace) # spec1 = client.V1PersistentVolumeClaimSpec( # # must be ReadWriteOnce for EBS # # access_modes=["ReadWriteOnce", "ReadOnlyMany"], # access_modes=["ReadWriteMany"], # resources=client.V1ResourceRequirements( # requests={"storage": inputVolumeSize} # ) # ) # # if storage_class_name: # spec1.storage_class_name = storage_class_name # # body1 = client.V1PersistentVolumeClaim(metadata=metadata1, spec=spec1) metadata2 = client.V1ObjectMeta(name=f"{volumeName}-tmpout", namespace=namespace) spec2 = client.V1PersistentVolumeClaimSpec( access_modes=["ReadWriteMany"], resources=client.V1ResourceRequirements( requests={"storage": tmpVolumeSize})) if storage_class_name: spec2.storage_class_name = storage_class_name body2 = client.V1PersistentVolumeClaim(metadata=metadata2, spec=spec2) metadata3 = client.V1ObjectMeta(name=f"{volumeName}-output-data", namespace=namespace) spec3 = client.V1PersistentVolumeClaimSpec( access_modes=["ReadWriteMany"], resources=client.V1ResourceRequirements( requests={"storage": outputVolumeSize})) if storage_class_name: spec3.storage_class_name = storage_class_name body3 = client.V1PersistentVolumeClaim(metadata=metadata3, spec=spec3) pretty = True try: # api_response1 = v1.create_namespaced_persistent_volume_claim(namespace, body1, pretty=pretty) api_response2 = v1.create_namespaced_persistent_volume_claim( namespace, body2, pretty=pretty) api_response3 = v1.create_namespaced_persistent_volume_claim( namespace, body3, pretty=pretty) # pprint(api_response1) pprint(api_response2) pprint(api_response3) except ApiException as e: print("Exception when creating persistent_volume_claim: %s\n" % e, file=sys.stderr) raise e # we copy the secret from ades namespace to the new job namespace if imagepullsecrets is not None and ades_namespace is not None: for imagepullsecret in imagepullsecrets: # Create an instance of the API class secretname = imagepullsecret["name"] pretty = True # str | If 'true', then the output is pretty printed. (optional) exact = False # bool | Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'. Deprecated. Planned for removal in 1.18. (optional) export = True # bool | Should this value be exported. Export strips fields that a user can not specify. Deprecated. Planned for removal in 1.18. (optional) secret_export = None try: secret_export = v1.read_namespaced_secret(secretname, ades_namespace, pretty=pretty, exact=exact, export=export) except ApiException as e: print( "Exception when retrieving image pull secret from eoepca: %s\n" % e) time.sleep(5) try: api_response = v1.create_namespaced_secret(namespace, secret_export, pretty=pretty) except ApiException as e: print("Exception when creating image pull secret: %s\n" % e) time.sleep(5) name = 'default' try: service_account_body = v1.read_namespaced_service_account( name, namespace, pretty=True) pprint(service_account_body) time.sleep(5) if service_account_body.secrets is None: service_account_body.secrets = [] if service_account_body.image_pull_secrets is None: service_account_body.image_pull_secrets = [] service_account_body.secrets.append({"name": secretname}) service_account_body.image_pull_secrets.append( {"name": secretname}) api_response = v1.patch_namespaced_service_account( name, namespace, service_account_body, pretty=True) pprint(api_response) except ApiException as e: print( "Exception when calling CoreV1Api->patch_namespaced_service_account: %s\n" % e) return {"status": "success"}
# delete NS Role rbac.delete_namespaced_role("user-role", namespace) print("Delete Role : " + namespace + "/user-role") # create ns RoleBinding role_binding = client.V1RoleBinding(metadata=client.V1ObjectMeta( namespace=namespace, name="dev-role-binding"), subjects=[ client.V1Subject(namespace="account", name="dev", kind="ServiceAccount") ], role_ref=client.V1RoleRef( kind="Role", api_group="rbac.authorization.k8s.io", name="user-role", )) rbac = client.RbacAuthorizationV1Api() rbac.create_namespaced_role_binding(namespace=namespace, body=role_binding) print("Create RoleBinding : " + namespace + "/dev-role-binding Role : user-role") # delete NS RoleBinding rbac.delete_namespaced_role_binding("dev-role-binding", namespace) print("Delete RoleBinding : " + namespace + "/dev-role-binding Role : user-role") # delete K8s namespace ret = v1.delete_namespace(namespace) print("delete K8s namespace " + namespace)
def process_rbac(self, user_name): try: _ = self.rbac.create_namespaced_role( namespace="tool-{}".format(user_name), body=client.V1Role( api_version="rbac.authorization.k8s.io/v1", kind="Role", metadata=client.V1ObjectMeta( name="tool-{}-psp".format(user_name), namespace="tool-{}".format(user_name), ), rules=[ client.V1PolicyRule( api_groups=["policy"], resource_names=["tool-{}-psp".format(user_name)], resources=["podsecuritypolicies"], verbs=["use"], ) ], ), ) except ApiException as api_ex: if api_ex.status == 409 and "AlreadyExists" in api_ex.body: logging.info("Role tool-%s-psp already exists", user_name) return logging.error("Could not create psp role for %s", user_name) raise try: _ = self.rbac.create_namespaced_role_binding( namespace="tool-{}".format(user_name), body=client.V1RoleBinding( api_version="rbac.authorization.k8s.io/v1", kind="RoleBinding", metadata=client.V1ObjectMeta( name="tool-{}-psp-binding".format(user_name), namespace="tool-{}".format(user_name), ), role_ref=client.V1RoleRef( kind="Role", name="tool-{}-psp".format(user_name), api_group="rbac.authorization.k8s.io", ), subjects=[ client.V1Subject( kind="User", name=user_name, api_group="rbac.authorization.k8s.io", ) ], ), ) except ApiException as api_ex: if api_ex.status == 409 and "AlreadyExists" in api_ex.body: logging.info("RoleBinding tool-%s-psp-binding already exists", user_name) return logging.error("Could not create psp rolebinding for %s", user_name) raise try: _ = self.rbac.create_namespaced_role_binding( namespace="tool-{}".format(user_name), body=client.V1RoleBinding( api_version="rbac.authorization.k8s.io/v1", kind="RoleBinding", metadata=client.V1ObjectMeta( name="default-{}-psp-binding".format(user_name), namespace="tool-{}".format(user_name), ), role_ref=client.V1RoleRef( kind="Role", name="tool-{}-psp".format(user_name), api_group="rbac.authorization.k8s.io", ), subjects=[ client.V1Subject( kind="ServiceAccount", name="default", namespace="tool-{}".format(user_name), ) ], ), ) except ApiException as api_ex: if api_ex.status == 409 and "AlreadyExists" in api_ex.body: logging.info( "RoleBinding default-%s-psp-binding already exists", user_name, ) return logging.error( ("Could not create psp rolebinding for tool-%s:default " "serviceaccount"), user_name, ) raise try: _ = self.rbac.create_namespaced_role_binding( namespace="tool-{}".format(user_name), body=client.V1RoleBinding( api_version="rbac.authorization.k8s.io/v1", kind="RoleBinding", metadata=client.V1ObjectMeta( name="{}-tool-binding".format(user_name), namespace="tool-{}".format(user_name), ), role_ref=client.V1RoleRef( kind="ClusterRole", name="tools-user", api_group="rbac.authorization.k8s.io", ), subjects=[ client.V1Subject( kind="User", name=user_name, api_group="rbac.authorization.k8s.io", ) ], ), ) except ApiException as api_ex: if api_ex.status == 409 and "AlreadyExists" in api_ex.body: logging.info("RoleBinding %s-tool-binding already exists", user_name) return logging.error("Could not create rolebinding for %s", user_name) raise
def setup_workflow_service_account(namespace: str) -> None: """Setup a workflow controller service-account with required roles. :param namespace: Namespace in which the service-account will be placed. """ service_account_object = k8s.V1ServiceAccount(metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT)) k8s.CoreV1Api().create_namespaced_service_account( namespace=namespace, body=service_account_object) role_object = k8s.V1Role(metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT), rules=[ k8s.V1PolicyRule(api_groups=[''], resources=['*'], verbs=['*']), k8s.V1PolicyRule(api_groups=['apps', 'batch'], resources=['*'], verbs=['*']) ]) k8s.RbacAuthorizationV1Api().create_namespaced_role(namespace=namespace, body=role_object) role_binding_object = k8s.V1RoleBinding( metadata=k8s.V1ObjectMeta(namespace=namespace, name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT), role_ref=k8s.V1RoleRef(kind='Role', name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT, api_group='rbac.authorization.k8s.io'), subjects=[ k8s.V1Subject(kind='ServiceAccount', name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT, namespace=namespace) ]) k8s.RbacAuthorizationV1Api().create_namespaced_role_binding( namespace=namespace, body=role_binding_object) if not cluster_role_exists(BODYWORK_WORKFLOW_CLUSTER_ROLE): cluster_role_object = k8s.V1ClusterRole( metadata=k8s.V1ObjectMeta(name=BODYWORK_WORKFLOW_CLUSTER_ROLE), rules=[ k8s.V1PolicyRule(api_groups=[''], resources=['namespaces'], verbs=['get', 'list']), k8s.V1PolicyRule(api_groups=['rbac.authorization.k8s.io'], resources=['clusterrolebindings'], verbs=['get', 'list']) ]) k8s.RbacAuthorizationV1Api().create_cluster_role( body=cluster_role_object) if not cluster_role_binding_exists( workflow_cluster_role_binding_name(namespace)): cluster_role_binding_object = k8s.V1ClusterRoleBinding( metadata=k8s.V1ObjectMeta( name=workflow_cluster_role_binding_name(namespace), namespace=namespace), role_ref=k8s.V1RoleRef(kind='ClusterRole', name=BODYWORK_WORKFLOW_CLUSTER_ROLE, api_group='rbac.authorization.k8s.io'), subjects=[ k8s.V1Subject(kind='ServiceAccount', name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT, namespace=namespace) ]) k8s.RbacAuthorizationV1Api().create_cluster_role_binding( body=cluster_role_binding_object)
def def_namespaced_account_objects(self): '''Define K8s objects for things we need in the namespace. ''' with start_action(action_type="define_namespaced_account_objects"): namespace = self.namespace username = self.parent.user.escaped_name account = "{}-svcacct".format(username) self.service_account = account acd = 'argocd.argoproj.io/' md = client.V1ObjectMeta( name=account, labels={acd + 'instance': 'nublado-users'}, annotations={ acd + 'compare-options': 'IgnoreExtraneous', acd + 'sync-options': 'Prune=false', }) svcacct = client.V1ServiceAccount(metadata=md) # These rules let us manipulate Dask pods, Argo Workflows, and # Multus CNI interfaces rules = [ client.V1PolicyRule( api_groups=["argoproj.io"], resources=["workflows", "workflows/finalizers"], verbs=[ "get", "list", "watch", "update", "patch", "create", "delete" ]), client.V1PolicyRule( api_groups=["argoproj.io"], resources=[ "workflowtemplates", "workflowtemplates/finalizers" ], verbs=["get", "list", "watch"], ), client.V1PolicyRule(api_groups=[""], resources=["secrets"], verbs=["get"]), client.V1PolicyRule( api_groups=[""], resources=["pods", "pods/exec", "services", "configmaps"], verbs=[ "get", "list", "watch", "create", "delete", "update", "patch" ]), client.V1PolicyRule(api_groups=[""], resources=["pods/log", "serviceaccounts"], verbs=["get", "list", "watch"]), ] role = client.V1Role(rules=rules, metadata=md) rbstr = 'rbac.authorization.k8s.io' rolebinding = client.V1RoleBinding( metadata=md, role_ref=client.V1RoleRef(api_group=rbstr, kind="Role", name=account), subjects=[ client.V1Subject(kind="ServiceAccount", name=account, namespace=namespace) ]) return svcacct, role, rolebinding
def setup_workflow_service_account(namespace: str) -> None: """Setup a workflow controller service-account with required roles. :param namespace: Namespace in which the service-account will be placed. """ service_account_object = k8s.V1ServiceAccount( metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT ) ) k8s.CoreV1Api().create_namespaced_service_account( namespace=namespace, body=service_account_object ) role_object = k8s.V1Role( metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT ), rules=[ k8s.V1PolicyRule(api_groups=[""], resources=["*"], verbs=["*"]), k8s.V1PolicyRule( api_groups=["apps", "batch"], resources=["*"], verbs=["*"] ), k8s.V1PolicyRule( api_groups=["extensions"], resources=["ingresses"], verbs=["*"] ), ], ) k8s.RbacAuthorizationV1Api().create_namespaced_role( namespace=namespace, body=role_object ) role_binding_object = k8s.V1RoleBinding( metadata=k8s.V1ObjectMeta( namespace=namespace, name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT ), role_ref=k8s.V1RoleRef( kind="Role", name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT, api_group="rbac.authorization.k8s.io", ), subjects=[ k8s.V1Subject( kind="ServiceAccount", name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT, namespace=namespace, ) ], ) k8s.RbacAuthorizationV1Api().create_namespaced_role_binding( namespace=namespace, body=role_binding_object ) if not cluster_role_exists(BODYWORK_WORKFLOW_CLUSTER_ROLE): cluster_role_object = k8s.V1ClusterRole( metadata=k8s.V1ObjectMeta(name=BODYWORK_WORKFLOW_CLUSTER_ROLE), rules=[ k8s.V1PolicyRule( api_groups=[""], resources=["namespaces"], verbs=["get", "list"] ), k8s.V1PolicyRule( api_groups=["rbac.authorization.k8s.io"], resources=["clusterrolebindings"], verbs=["get", "list"], ), ], ) k8s.RbacAuthorizationV1Api().create_cluster_role(body=cluster_role_object) if not cluster_role_binding_exists(workflow_cluster_role_binding_name(namespace)): cluster_role_binding_object = k8s.V1ClusterRoleBinding( metadata=k8s.V1ObjectMeta( name=workflow_cluster_role_binding_name(namespace), namespace=namespace ), role_ref=k8s.V1RoleRef( kind="ClusterRole", name=BODYWORK_WORKFLOW_CLUSTER_ROLE, api_group="rbac.authorization.k8s.io", ), subjects=[ k8s.V1Subject( kind="ServiceAccount", name=BODYWORK_WORKFLOW_SERVICE_ACCOUNT, namespace=namespace, ) ], ) k8s.RbacAuthorizationV1Api().create_cluster_role_binding( body=cluster_role_binding_object )
def process_admin_rbac(self, username: str) -> None: # Let admins read anything try: _ = self.rbac.create_cluster_role_binding( body=client.V1ClusterRoleBinding( api_version="rbac.authorization.k8s.io/v1", kind="ClusterRoleBinding", metadata=client.V1ObjectMeta( name=f"{username}-view-binding"), role_ref=client.V1RoleRef( kind="ClusterRole", name="view", api_group="rbac.authorization.k8s.io", ), subjects=[ client.V1Subject( kind="User", name=username, api_group="rbac.authorization.k8s.io", ) ], )) except ApiException as api_ex: if api_ex.status == 409 and "AlreadyExists" in api_ex.body: logging.info( "ClusterRoleBinding %s-view-binding already exists", username, ) return logging.error("Could not create view clusterrolebinding for %s", username) raise # Also let admins impersonate anything, allowing full sudo access try: _ = self.rbac.create_cluster_role_binding( body=client.V1ClusterRoleBinding( api_version="rbac.authorization.k8s.io/v1", kind="ClusterRoleBinding", metadata=client.V1ObjectMeta(name=f"{username}-binding"), role_ref=client.V1RoleRef( kind="ClusterRole", name="k8s-admin", api_group="rbac.authorization.k8s.io", ), subjects=[ client.V1Subject( kind="User", name=username, api_group="rbac.authorization.k8s.io", ) ], )) except ApiException as api_ex: if api_ex.status == 409 and "AlreadyExists" in api_ex.body: logging.info("ClusterRoleBinding %s-binding already exists", username) return logging.error("Could not create admin clusterrolebinding for %s", username) raise