Ejemplo n.º 1
0
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
Ejemplo n.º 3
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, 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)
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
    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))
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
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))
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
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
Ejemplo n.º 12
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)
Ejemplo n.º 13
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
    )
 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)
         ])
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
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
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
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
Ejemplo n.º 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
Ejemplo n.º 21
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
Ejemplo n.º 22
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

            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
Ejemplo n.º 23
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
Ejemplo n.º 24
0
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"}
Ejemplo n.º 25
0
# 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)
Ejemplo n.º 26
0
    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
Ejemplo n.º 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.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)
Ejemplo n.º 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
Ejemplo n.º 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.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
        )
Ejemplo n.º 30
0
    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