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_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)
Exemple #4
0
 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, 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_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)
Exemple #7
0
    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
Exemple #9
0
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
Exemple #11
0
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)
Exemple #12
0
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
    )
Exemple #13
0
def get_default_rbac_subjects(namespace):
    """Get the default RBAC Subjects.

    The default subjects will allow:
      - all authenticated users
      - all unauthenticated users
      - all service accounts

    Args:
        namespace (str): The namespace of the Subjects.

    Returns:
        list[client.V1Subject]: The default RBAC subjects.
    """
    return [
        # all authenticated users
        client.V1Subject(
            api_group='rbac.authorization.k8s.io',
            namespace=namespace,
            name='system:authenticated',
            kind='Group',
        ),
        # all unauthenticated users
        client.V1Subject(
            api_group='rbac.authorization.k8s.io',
            namespace=namespace,
            name='system:unauthenticated',
            kind='Group',
        ),
        # all service accounts
        client.V1Subject(
            api_group='rbac.authorization.k8s.io',
            namespace=namespace,
            name='system:serviceaccounts',
            kind='Group',
        ),
    ]
Exemple #14
0
def get_default_rbac_subjects(namespace: str) -> List[client.V1Subject]:
    """Get the default RBAC Subjects.

    The default subjects will allow:
      - all authenticated users
      - all unauthenticated users
      - all service accounts

    Args:
        namespace: The namespace of the Subjects.

    Returns:
        The default RBAC subjects.
    """
    return [
        # all authenticated users
        client.V1Subject(
            api_group="rbac.authorization.k8s.io",
            namespace=namespace,
            name="system:authenticated",
            kind="Group",
        ),
        # all unauthenticated users
        client.V1Subject(
            api_group="rbac.authorization.k8s.io",
            namespace=namespace,
            name="system:unauthenticated",
            kind="Group",
        ),
        # all service accounts
        client.V1Subject(
            api_group="rbac.authorization.k8s.io",
            namespace=namespace,
            name="system:serviceaccounts",
            kind="Group",
        ),
    ]
 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_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(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_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
Exemple #20
0
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
Exemple #21
0
def get_custom_rbac_subject(namespace, kind, name):
    """Create a custom RBAC subject for the given namespace.

    Both `kind` and `name` must be specified. If one is set and
    the other is not (None), an error will be raised.

    Args:
        namespace (str): The namespace of the Subject.
        kind (str): The subject kind. This should be one of:
            'User', 'Group', or 'ServiceAccount'.
        name (str): The name of the Subject.

    Returns:
        list[client.V1Subject]: The custom RBAC subject.

    Raises:
        ValueError: One of `kind` and `name` are None.
    """
    # check that both `kind` and `name` are set.
    if (kind and not name) or (not kind and name):
        raise ValueError(
            'One of subject_kind and subject_name were specified, but both must '
            'be specified when defining a custom Subject.'
        )

    # otherwise, if a custom subject is specified, create it
    if name is not None and kind is not None:
        return [
            client.V1Subject(
                api_group='rbac.authorization.k8s.io',
                namespace=namespace,
                kind=kind,
                name=name,
            )
        ]
    else:
        return []
Exemple #22
0
    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
Exemple #24
0
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
Exemple #25
0
role = client.V1Role(rules=rules)
role.metadata = client.V1ObjectMeta(namespace=namespace, name="user-role")
rbac = client.RbacAuthorizationV1Api()
rbac.create_namespaced_role(namespace, role)
print("Create Role : " + namespace + "/user-role")

# 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 +
    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
Exemple #27
0
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
        )
Exemple #28
0
 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
Exemple #29
0
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 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