How to set up a private custom post type that is accessible in the administrative dashboard?

For the frontend, you can use template_redirect action to identify the page, and perform redirects or adjust the request on the fly (untested):

add_action( 'template_redirect', static function () {
    if ( ! is_singular( 'cpt' ) && ! is_post_type_archive( 'cpt' ) ) {
        return;
    }

    if ( current_user_can( 'read_private_pages' ) || current_user_can( 'read_private_posts' ) ) {
        return;
    }

    global $wp_query;
    $wp_query->set_404();
    status_header( 404 );
    nocache_headers();
} );

For excluding from search, you’ll have to use pre_get_posts to prevent the posts form being listed in the results, unless you change exclude_from_search to true in the CPT registration.

tech