Row-Level Security in Apache Superset: A Production Implementation Guide
Master RLS in Apache Superset with Jinja templating and RBAC. Implement multi-tenant security, enforce data access controls, and deploy production-grade analytics.
Row-Level Security in Apache Superset: A Production Implementation Guide
Row-Level Security (RLS) in Apache Superset is the mechanism that determines which rows of data a user can see based on their role, permissions, and organizational context. In production environments serving multiple teams, departments, or tenants, RLS isn’t optional—it’s foundational infrastructure. Without it, you’re either building separate dashboards for each user segment or exposing sensitive data across your organization.
This guide walks you through implementing RLS in Superset from first principles through production deployment. We’ll cover the mechanics of how Superset applies security filters, the Jinja templating patterns that make dynamic filtering possible, RBAC (Role-Based Access Control) configuration, and real-world multi-tenant scenarios that data leaders face at scale-ups and mid-market companies.
Understanding Row-Level Security in Apache Superset
Row-Level Security in Superset operates at the dataset level, not the chart or dashboard level. This distinction matters because it means security is enforced at the query execution stage—before results are returned to the user. When a user queries a dataset with RLS rules attached, Superset automatically appends SQL WHERE clauses to filter rows based on the user’s assigned roles and the rules you’ve defined.
Think of RLS as a permission layer between the user and the underlying data. A sales representative in the Northeast region shouldn’t see sales data from the West region, even if they query the same sales table that executives use. Without RLS, you’d need separate tables or separate dashboards. With RLS, you have one table, one set of dashboards, and Superset automatically restricts what each user sees.
According to the official Apache Superset security documentation, RLS filters are applied to tables and combined with user roles to control data access. The security model is straightforward: define roles, assign users to roles, create RLS rules that bind roles to SQL filter conditions, and Superset handles the rest.
The power of Superset’s RLS implementation lies in its flexibility. Unlike some BI platforms that lock you into predefined filter types, Superset lets you write arbitrary SQL conditions using Jinja templating. This means you can filter by user attributes, organization IDs, geographic regions, or any custom logic your data model requires.
The Architecture of RLS in Superset
Superset’s RLS architecture consists of three interconnected layers:
Layer 1: User Roles and Permissions Every user in Superset belongs to one or more roles. Roles are collections of permissions that determine what a user can do (create dashboards, edit datasets, view specific databases). When you implement RLS, you’re not creating new roles—you’re using existing roles as the trigger for data filtering.
Layer 2: RLS Rules RLS rules are the actual filters. Each rule binds a role to a dataset and specifies a SQL WHERE clause condition. For example, “users in the Sales_Northeast role can only see rows where region = ‘Northeast’.” Rules are stored in Superset’s metadata layer and evaluated at query time.
Layer 3: Query Execution When a user executes a query (by viewing a dashboard, exploring data, or running an ad-hoc query), Superset retrieves all RLS rules that apply to that user’s roles and that dataset. It then constructs the final SQL query by appending these WHERE clauses to the user’s query. The database executes the modified query and returns only the rows the user is authorized to see.
This three-layer architecture means RLS enforcement is deterministic and database-agnostic. Whether you’re using PostgreSQL, MySQL, Snowflake, or BigQuery, the mechanism is the same: Superset modifies the SQL before sending it to the database.
Jinja Templating for Dynamic RLS Filters
The real power of Superset’s RLS comes from Jinja templating. Instead of hardcoding filter values, you can reference user attributes dynamically. Superset provides access to a current_user_id variable and user attributes through Jinja syntax, allowing you to write filters that adapt based on who’s executing the query.
Here’s a practical example. Suppose you have a sales dataset with a sales_rep_id column and you want each sales rep to see only their own records:
sales_rep_id = {{ current_user_id }}
When a user with ID 42 views a dashboard, Superset replaces {{ current_user_id }} with 42, and the rule becomes sales_rep_id = 42. The user sees only rows where sales_rep_id equals their ID.
For more complex scenarios, you can access user attributes through the current_user object. If your users have a custom attribute called department, you might write:
department = '{{ current_user.department }}'
Or for multi-tenant scenarios where each user belongs to a company:
company_id = {{ current_user.company_id }}
Jinja templating also supports conditional logic. If you need different filtering rules based on a user’s role, you can use:
{% if 'admin' in current_user.roles %}
1=1
{% else %}
user_id = {{ current_user_id }}
{% endif %}
This filter allows admins to see all rows (the 1=1 condition is always true) while restricting regular users to their own data.
The Preset documentation on Row-Level Security provides detailed examples of implementing RLS rules, including regional data access roles and exclusionary filters that show how to combine Jinja templating with complex business logic.
Setting Up RBAC for Multi-Tenant Deployments
Role-Based Access Control (RBAC) is the foundation of any scalable RLS implementation. In multi-tenant environments, you typically have users from different organizations accessing the same Superset instance. RBAC ensures that users can only access dashboards and datasets relevant to their organization.
Here’s a typical RBAC structure for a multi-tenant SaaS platform:
Tenant Admin Role Users with this role can create and manage dashboards and datasets within their organization. They have full visibility of their organization’s data but cannot see data from other organizations.
Tenant User Role Regular users can view dashboards and explore datasets. RLS rules restrict them to their organization’s data and, potentially, to specific departments or regions within their organization.
Platform Admin Role Platform administrators have unrestricted access across all organizations. This role is typically limited to your internal team managing the Superset instance.
To implement this structure:
- Create roles in Superset’s admin interface that correspond to your organizational hierarchy
- Assign users to roles based on their organization and function
- Create RLS rules that bind each role to appropriate data filters
- Test that users can only access data relevant to their role
For a multi-tenant deployment, a practical example is implementing tenant-based filtering. As described in the DEV Community guide on tenant-based filtering in Apache Superset, you can use dynamic WHERE clauses based on a user’s company_id attribute. When a user from Company A queries the orders table, Superset automatically appends WHERE company_id = 123 (assuming Company A has ID 123). Users from Company B see only their orders because Superset appends WHERE company_id = 456.
Implementing RLS Rules: Step-by-Step
Let’s walk through creating an RLS rule in Superset. The process is straightforward but requires precision.
Step 1: Navigate to Dataset Security In the Superset admin interface, go to Data > Datasets and select the dataset you want to protect. Click the dropdown menu and select “Row Level Security.”
Step 2: Create a New RLS Rule Click “Add RLS Rule” and you’ll see a form with three fields:
- Clause: The SQL WHERE clause that will be appended to queries
- Roles: Which roles this rule applies to
- Tables: Which tables in the dataset this rule applies to (if the dataset contains multiple tables)
Step 3: Define Your Filter Clause This is where you write your Jinja-templated SQL. For a simple example, if you want users in the “Sales” role to see only their region’s data:
region = '{{ current_user.region }}'
For a multi-tenant scenario:
tenant_id = {{ current_user.tenant_id }}
Step 4: Select Applicable Roles Choose which roles this rule applies to. You can select multiple roles if they should all have the same filter applied.
Step 5: Test and Deploy Before deploying to production, test the rule by logging in as a user with the target role and verifying that they see only the filtered data.
The GitHub discussion on RLS enforcement clarifies an important limitation: RLS is enforced at the dataset level, not at the chart or dimension level. This means you can’t have different RLS rules for different charts using the same dataset. The rule applies to the entire dataset, and all charts built on that dataset inherit the same filtering.
Real-World Multi-Tenant Example
Let’s build a complete multi-tenant scenario. Imagine you’re hosting analytics for a portfolio of e-commerce companies. Each company has multiple users, and you want to ensure complete data isolation.
Database Schema
CREATE TABLE companies (
company_id INT PRIMARY KEY,
company_name VARCHAR(255)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
company_id INT,
customer_id INT,
order_date DATE,
revenue DECIMAL(10, 2),
FOREIGN KEY (company_id) REFERENCES companies(company_id)
);
CREATE TABLE users (
user_id INT PRIMARY KEY,
username VARCHAR(255),
company_id INT,
role VARCHAR(50),
FOREIGN KEY (company_id) REFERENCES companies(company_id)
);
Superset Configuration
First, configure user attributes in Superset. When users log in (via LDAP, OAuth, or your authentication system), their company_id should be stored as a user attribute. This might happen in your authentication provider or through a custom Superset authentication backend.
Next, create an RLS rule on the orders dataset:
Rule Name: Tenant Isolation
Clause: company_id = {{ current_user.company_id }}
Roles: Apply to all non-admin roles (e.g., “Company User”, “Company Analyst”)
Tables: orders
Now, when a user from Company A (company_id = 1) views the orders dashboard, Superset appends WHERE company_id = 1 to every query. They see only their company’s orders. A user from Company B (company_id = 2) sees only their orders. Complete isolation is achieved with a single RLS rule.
For more granular control, you might add a second rule for department-level filtering:
Rule Name: Department Filtering
Clause: department = '{{ current_user.department }}'
Roles: “Company Analyst” (but not “Company Admin”)
Tables: orders
Now, analysts see only their department’s data within their company, while admins see all company data.
Handling Complex Filtering Scenarios
Not all RLS requirements fit the simple column = value pattern. Production environments often require more sophisticated filtering logic.
Scenario 1: Geographic Hierarchies A global company might have users in different regions, but they should also see data from sub-regions. For example, a user in the “North America” region should see data from “North America”, “USA”, “Canada”, and “Mexico”. A simple equality filter won’t work.
Instead, use a subquery or CASE statement:
region_id IN (
SELECT region_id FROM region_hierarchy
WHERE parent_region = '{{ current_user.region }}'
OR region = '{{ current_user.region }}'
)
Scenario 2: Time-Based Access Some data should only be visible after a certain date, or during specific periods. You might restrict access to historical data:
order_date >= DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR)
AND (
user_id = {{ current_user_id }}
OR '{{ current_user.role }}' = 'admin'
)
Scenario 3: Exclusionary Filters Instead of specifying what users can see, sometimes it’s easier to specify what they can’t see. For example, hide test data or internal transactions:
NOT (customer_id IN (SELECT customer_id FROM test_customers))
AND status != 'internal'
The Preset blog on understanding Row-Level Security in Superset provides in-depth explanations of RLS implementation use cases and best practices for securing data access in Superset deployments.
Performance Considerations
RLS filtering happens at query time, which means every query includes the additional WHERE clauses. For large datasets, this can impact performance if your filters aren’t indexed properly.
Optimization Best Practices
Index Your Filter Columns Ensure that the columns used in RLS filters (company_id, user_id, region, etc.) are indexed. Without indexes, the database must scan entire tables to apply filters.
CREATE INDEX idx_orders_company_id ON orders(company_id);
CREATE INDEX idx_orders_user_id ON orders(user_id);
Use Column-Level Statistics If your database supports it (Snowflake, BigQuery, etc.), maintain statistics on filter columns so the query planner can optimize execution.
Avoid Expensive Subqueries Subqueries in RLS filters can become expensive if they’re not optimized. If you’re using subqueries for hierarchical filtering, consider materializing the results in a lookup table:
region_id IN (
SELECT region_id FROM materialized_region_hierarchy
WHERE parent_region = '{{ current_user.region }}'
)
Cache Aggressively Superset supports result caching. Cache dashboard queries aggressively to reduce the number of times RLS filters are evaluated.
Monitor Query Performance After deploying RLS rules, monitor query performance using your database’s query logs. Identify slow queries and optimize the underlying data model or RLS filters.
Testing RLS in Development
Before deploying RLS rules to production, test them thoroughly. Testing RLS is different from testing regular Superset functionality because you need to verify that users see the correct filtered data.
Test Strategy
- Create Test Users: Set up test users with different roles and attributes (company_id, region, department, etc.)
- Create Test Data: Populate your database with test data that includes records for each user’s expected scope
- Verify Visibility: Log in as each test user and verify they see only their expected data
- Check Edge Cases: Test users who belong to multiple roles, users with missing attributes, and admin users who should see all data
- Validate Performance: Run queries as test users and monitor query execution time
For example, if you have test users Alice (company_id = 1) and Bob (company_id = 2), create test orders for both companies. When Alice logs in and views the orders dashboard, verify she sees only company 1’s orders. When Bob logs in, verify he sees only company 2’s orders.
The YouTube tutorial on implementing RLS in Apache Superset demonstrates the step-by-step process of configuring Row-Level Security, including user roles and filter creation in a working environment.
Integrating RLS with Your Data Pipeline
RLS in Superset works best when your underlying data model is designed with security in mind. If you’re using dbt to manage your data transformations, you can coordinate RLS implementation with your dbt models.
The dbt blog guide on Row-Level Security in Superset provides detailed guidance on RLS setup in Superset for production analytics, integrating with dbt models and focusing on secure multi-tenant environments.
Best Practices
- Include Tenant/User IDs in Models: Ensure every fact table includes the columns needed for RLS filtering (company_id, user_id, region, etc.)
- Document Security Requirements: In your dbt project, document which columns should be used for RLS filtering
- Version Control RLS Rules: While RLS rules are stored in Superset’s metadata, document them in your project repository so your team knows what security rules are in place
- Coordinate with Superset Admins: When you add new tables or columns to your data warehouse, communicate with your Superset team about potential RLS requirements
Debugging RLS Issues
When RLS rules don’t work as expected, debugging can be tricky because the filtering happens inside the database. Here are common issues and how to troubleshoot them:
Issue 1: Users See No Data This usually means the RLS filter is too restrictive or the user’s attributes don’t match any records. Check:
- Is the user’s attribute (company_id, region, etc.) set correctly?
- Does the database contain records matching that attribute?
- Is the Jinja template rendering correctly? Add logging to see what SQL is being generated.
Issue 2: Users See Data They Shouldn’t This means the RLS filter isn’t being applied. Verify:
- Is the RLS rule assigned to the correct dataset?
- Is the rule assigned to the user’s role?
- Is the role applied to the user in Superset’s user management?
Issue 3: Slow Queries If queries are slow after adding RLS, the filter columns might not be indexed, or the filter logic might be inefficient. Check:
- Are the filter columns indexed in the database?
- Is the RLS filter using expensive subqueries or functions?
- Can you rewrite the filter to be more efficient?
To debug, you can temporarily log in as a Superset admin and check the actual SQL being executed. In Superset’s query editor, you can often see the compiled SQL with RLS filters applied.
Superset and Competing BI Platforms
When evaluating BI platforms for multi-tenant deployments, RLS implementation is a critical differentiator. D23 provides managed Apache Superset with production-grade RLS, RBAC, and AI-powered analytics without the platform overhead of Looker, Tableau, or Power BI.
Unlike proprietary platforms that charge per user or per query, Superset’s open-source model means you pay for compute, not for access. This makes it economically feasible to deploy RLS across hundreds of users without per-user licensing costs. For scale-ups and mid-market companies, this translates to significant cost savings—often 50-70% less than Looker or Tableau for comparable deployments.
Moreover, Superset’s flexibility with Jinja templating and custom SQL gives you fine-grained control over RLS logic that some proprietary platforms restrict. You’re not limited to predefined filter types; you can implement any security model your business requires.
Advanced: Custom Authentication and User Attributes
For sophisticated RLS implementations, you need reliable user attributes. If Superset’s default authentication doesn’t provide the attributes you need, you can implement a custom authentication backend.
Superset supports OAuth, LDAP, SAML, and custom authentication methods. If you’re using OAuth (e.g., with Auth0 or Okta), you can map OAuth claims to Superset user attributes:
class CustomOAuthSecurityManager(SupersetSecurityManager):
def get_oauth_user_info(self, provider, resp):
user_info = super().get_oauth_user_info(provider, resp)
# Add custom attributes from OAuth provider
user_info['company_id'] = resp.get('company_id')
user_info['region'] = resp.get('region')
user_info['department'] = resp.get('department')
return user_info
With custom authentication, you can ensure that user attributes are always accurate and up-to-date, which is critical for RLS to work correctly.
Monitoring and Auditing RLS
In regulated industries (finance, healthcare, etc.), you need to audit who accessed what data and when. Superset logs query execution, and you can configure audit logging to track RLS-filtered queries.
Enable Superset’s query logging and monitor for:
- Users accessing datasets they shouldn’t have access to (which would indicate an RLS misconfiguration)
- Unusual query patterns that might indicate unauthorized access attempts
- Performance degradation due to RLS filters
For compliance-critical deployments, integrate Superset’s logs with your SIEM (Security Information and Event Management) system to centralize security monitoring.
The Towards Data Science article on Row-Level Security in Apache Superset details RLS configuration, SQL filter clauses, role assignments, and production considerations for Superset deployments.
Conclusion: RLS as Infrastructure
Row-Level Security in Apache Superset is not a feature you add as an afterthought—it’s foundational infrastructure for any multi-tenant or regulated analytics deployment. By understanding how RLS works at the query level, mastering Jinja templating for dynamic filters, and implementing proper RBAC, you can build secure, scalable analytics platforms that serve hundreds of users without exposing sensitive data.
The combination of Superset’s flexibility, open-source economics, and production-grade RLS capabilities makes it an attractive alternative to expensive proprietary BI platforms. For data leaders evaluating managed open-source BI solutions, D23’s managed Superset platform provides production-ready RLS, expert data consulting, and AI-powered analytics without the complexity of self-hosting or the cost of Looker, Tableau, or Power BI.
Start with simple RLS rules (tenant isolation), test thoroughly in development, optimize for performance, and iterate as your security requirements evolve. RLS done right is invisible to users—they simply see the data relevant to them, never knowing that Superset is silently filtering billions of rows in the background.