# How r-nacos Implements Namespace Isolation for Configurations and Service Registrations

> Discover how r-nacos enforces namespace isolation for configurations and service registrations. Learn about its unique approach to data access and privilege validation.

- Repository: [Nacos Group/r-nacos](https://github.com/nacos-group/r-nacos)
- Tags: deep-dive
- Published: 2026-03-07

---

**r-nacos enforces strict namespace isolation by embedding a namespace identifier into every configuration key and service key, then validating user privileges against whitelist and blacklist rules before allowing any data access.**

r-nacos is a lightweight, high-performance Rust implementation of the Nacos service discovery and configuration management platform. This article examines how the project achieves namespace isolation for configurations and service registrations by analyzing the source code architecture in the `nacos-group/r-nacos` repository. The isolation mechanism operates through three integrated layers: namespace identifier management, user privilege validation, and data model scoping.

## Namespace Identifier Architecture

### Default Namespace Handling

The system ensures backward compatibility through automatic namespace assignment in [`src/namespace/mod.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/namespace/mod.rs). The `default_namespace` function injects the built-in identifier `"public"` whenever a request omits an explicit namespace value:

```rust
// src/namespace/mod.rs
pub fn default_namespace(val: String) -> String {
    if val.is_empty() { "public".to_string() } else { val }
}

```

This helper is invoked throughout the API layer, including in [`src/openapi/naming/service.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/openapi/naming/service.rs), ensuring that empty namespace parameters never propagate to the storage layer. The companion function `is_default_namespace` identifies the built-in namespace, allowing privilege checks to short-circuit validation for globally readable public data.

### Namespace Management Utilities

Administrative operations on namespaces themselves are handled by `NamespaceUtils` in [`src/console/mod.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/console/mod.rs). This utility provides CRUD operations for namespace objects, persisting them in the dedicated `tb_tenant` table. Every new namespace receives a unique `tenant_id`, which downstream components reference as the `namespace_id` in all data keys.

## Privilege-Based Access Control

### User Privilege Model

Each user record defined in [`src/user/model.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/user/model.rs) carries specific namespace access controls through the `UserDO` struct:

```rust
// src/user/model.rs
pub struct UserDO {
    pub namespace_privilege_flags: Option<u32>,
    pub namespace_white_list: Vec<String>,
    pub namespace_black_list: Vec<String>,
}

```

The `build_namespace_privilege` method constructs a `PrivilegeGroup<Arc<String>>` that encodes access rights. This group evaluates three conditions: an explicit **whitelist** of allowed namespaces, a **blacklist** of denied namespaces, and a flag that disables namespace checks entirely for super-administrators.

### Permission Checking in API Handlers

The permission evaluation logic resides in [`src/common/model/privilege.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/common/model/privilege.rs). The `PrivilegeGroup` implementation provides the `check_permission` method, which returns `true` only if the requested namespace passes the whitelist and blacklist filters.

All API handlers obtain the current user's privilege set via the `user_namespace_privilege!` macro, visible in entry points like [`src/naming/ops/ops_api.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/naming/ops/ops_api.rs). Before executing any read or write operation, handlers invoke `check_permission(&namespace_id)` to ensure the user cannot cross namespace boundaries:

```rust
// Conceptual flow in src/naming/ops/ops_api.rs
let privilege = user_namespace_privilege!();
if !privilege.check_permission(&namespace_id) {
    return Err(PermissionDenied);
}

```

## Data Model Isolation

### Configuration Keys

Configuration data isolation is enforced through the `ConfigKey` struct defined in [`src/config/model.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/config/model.rs):

```rust
// src/config/model.rs
pub struct ConfigKey {
    pub data_id: Arc<String>,
    pub group: Arc<String>,
    pub tenant: Arc<String>,   // namespace identifier
}

```

The `tenant` field carries the namespace identifier. All CRUD operations in [`src/config/api.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/config/api.rs) construct this key after applying the default namespace logic. The underlying SQLite or MySQL storage engines persist data in tables (`tb_config`, `tb_config_history`) that include a `tenant_id` column, ensuring physical separation at the database level.

### Service Registration Keys

Service registration follows an identical pattern using `ServiceKey` in [`src/naming/service_key.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/naming/service_key.rs):

```rust
// src/naming/service_key.rs
pub struct ServiceKey {
    pub namespace_id: Arc<String>,
    pub group_name: Arc<String>,
    pub service_name: Arc<String>,
}

```

The `ServiceIndex` in [`src/naming/service_index.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/naming/service_index.rs) maintains a per-namespace map structure (`namespace_group: HashMap<Arc<String>, ServiceIndex>`). When processing registration or discovery requests, the system first validates the caller's privilege against the target `namespace_id` (lines 237-244 in [`src/naming/service_index.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/naming/service_index.rs)) before accessing the service map.

## End-to-End Request Flow

The following example demonstrates how a client interaction triggers the isolation mechanisms across all layers:

```rust
use r_nacos::client::ConfigClient;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Authenticate as user with whitelist containing only "dev"
    let client = ConfigClient::builder()
        .endpoint("http://127.0.0.1:8848")
        .username("alice")
        .password("pwd")
        .build()
        .await?;

    // Publish to the "dev" namespace
    let namespace_id = Some(Arc::new("dev".to_string()));
    client
        .publish_config(
            "my-key".into(),
            "DEFAULT_GROUP".into(),
            "value".into(),
            namespace_id.clone(),
        )
        .await?;

    // Attempt to read from unauthorized "prod" namespace
    let other_ns = Some(Arc::new("prod".to_string()));
    let result = client
        .get_config("my-key".into(), "DEFAULT_GROUP".into(), other_ns)
        .await;

    assert!(result.is_err(), "Cross-namespace access denied");
    Ok(())
}

```

**Execution flow:**

1. **Key Construction**: The `publish_config` call builds a `ConfigKey` with `tenant = "dev"` after the API layer applies `NamingUtils::default_namespace`.
2. **Privilege Validation**: The handler extracts Alice's `NamespacePrivilegeGroup` from [`src/user/model.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/user/model.rs). Since `"dev"` appears in the whitelist, `check_permission("dev")` returns `true`.
3. **Storage**: The configuration persists to `tb_config` with `tenant_id = "dev"`.
4. **Access Denial**: When `get_config` targets `"prod"`, the same privilege check fails (`check_permission("prod") == false`), and the handler returns a permission error before querying the database.

## Summary

- **Every data entity** carries an explicit namespace identifier through `ConfigKey.tenant` or `ServiceKey.namespace_id`.
- **User-level privilege groups** defined in [`src/common/model/privilege.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/common/model/privilege.rs) enforce access control via whitelist and blacklist validation.
- **Default namespace handling** in [`src/namespace/mod.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/namespace/mod.rs) ensures backward compatibility while maintaining security boundaries.
- **API handlers** in [`src/console/api.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/console/api.rs) and [`src/naming/ops/ops_api.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/naming/ops/ops_api.rs) gate all requests through the `user_namespace_privilege!` macro before delegating to storage engines.

## Frequently Asked Questions

### What is the default namespace in r-nacos?

The default namespace is the string `"public"`, generated by the `default_namespace` function in [`src/namespace/mod.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/namespace/mod.rs). When API requests omit a namespace parameter, this value is injected automatically, ensuring all data carries a namespace identifier while maintaining compatibility with legacy clients.

### How does r-nacos prevent unauthorized cross-namespace access?

The system prevents unauthorized access through the `PrivilegeGroup` implementation in [`src/common/model/privilege.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/common/model/privilege.rs). Every request invokes `check_permission` against the user's configured whitelist and blacklist before the handler accesses any data storage. If the requested namespace is not explicitly allowed, the request terminates with a permission error.

### Where is the namespace identifier physically stored for configurations?

The namespace identifier is stored in the `tenant` field of the `ConfigKey` struct (defined in [`src/config/model.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/config/model.rs)) and persisted in the `tenant_id` column of the `tb_config` and `tb_config_history` database tables. This ensures physical data separation at the storage layer.

### Are service registrations isolated using the same mechanism?

Yes, service registrations utilize the identical isolation pattern. The `ServiceKey` struct in [`src/naming/service_key.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/naming/service_key.rs) includes a `namespace_id` field, and the `ServiceIndex` in [`src/naming/service_index.rs`](https://github.com/nacos-group/r-nacos/blob/main/src/naming/service_index.rs) maintains separate internal maps per namespace. All naming API handlers perform privilege checks using the same `NamespacePrivilegeGroup` logic as configuration handlers.