Skip to content

Conversation

@michaelruelas
Copy link
Contributor

  • Add namespace-scoped RBAC creation in controller for provisioner jobs
  • Update documentation to reflect CRDs as single source of truth and job-based provisioning
  • Change Helm repository URLs to official Supabase charts
  • Update API status mappings and add new status constants
  • Fix CLI test mocks and update troubleshooting guides
  • Add new documentation guide and update development prerequisites

BREAKING CHANGE: RBAC permissions now use a two-tiered model with namespace-scoped provisioner roles. Existing deployments must be updated to use the new ClusterRole and Role structure. See docs/security/ADVISORY-001-provisioner-rbac.md for details.

Pull Request

Description

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Test coverage improvement
  • CI/CD improvement
  • Other (please describe):

Related Issues

  • Fixes #
  • Related to #

Changes Made

Testing

Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No tests needed (documentation, minor changes)

Test Results

Backend Tests:

cd server
go test ./...

# Output:
# Paste test results here

Frontend Tests:

cd ui
npm test

# Output:
# Paste test results here

Manual Testing:

  1. Tested scenario: [description]
    • Result: [pass/fail]
  2. Tested scenario: [description]
    • Result: [pass/fail]

Screenshots (if applicable)

Deployment Notes

  • Requires database migration
  • Requires configuration changes
  • Requires Helm chart update
  • Breaking API changes (requires version bump)
  • No special deployment steps needed

Deployment instructions:

# If applicable, provide deployment commands

Documentation

  • Updated README.md
  • Updated CONTRIBUTING.md
  • Updated API documentation
  • Updated ARCHITECTURE.md
  • Updated code comments
  • Created/updated tests documentation
  • No documentation needed

Performance Impact

  • No performance impact
  • Performance improved
  • Performance degraded (explained below)

Performance notes:

Security Considerations

  • No security impact
  • Security improved
  • Requires security review

Security notes:

Breaking Changes

Breaking changes:

Migration guide:

# Provide instructions for users to migrate

Checklist

Code Quality

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have run gofmt (for Go code) or npm run lint (for JavaScript)

Testing

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have tested this on a real Kubernetes cluster
  • I have verified that instances can still be created/deleted

Documentation

  • I have updated the documentation accordingly
  • I have added/updated code comments where necessary
  • I have updated the CHANGELOG (if applicable)

Commit Standards

  • My commits follow conventional commit format (e.g., feat:, fix:, docs:)
  • My commit messages are clear and descriptive
  • I have squashed/rebased my commits appropriately

Dependencies

  • I have not introduced unnecessary dependencies
  • All new dependencies are documented with rationale
  • I have updated go.mod/package.json as needed

Collaboration

  • I have assigned appropriate reviewers
  • I have added relevant labels
  • I have linked related issues
  • I am available for review feedback and discussions

Additional Notes

Review Checklist (for maintainers)

  • Code quality meets standards
  • Tests are sufficient and passing
  • Documentation is complete and accurate
  • No security concerns
  • No performance regressions
  • Breaking changes are justified and documented
  • Commit history is clean

Thank you for contributing to SupaControl! 🎉

We appreciate your time and effort in improving the project. Our maintainers will review your PR as soon as possible.

- Add namespace-scoped RBAC creation in controller for provisioner jobs
- Update documentation to reflect CRDs as single source of truth and job-based provisioning
- Change Helm repository URLs to official Supabase charts
- Update API status mappings and add new status constants
- Fix CLI test mocks and update troubleshooting guides
- Add new documentation guide and update development prerequisites

BREAKING CHANGE: RBAC permissions now use a two-tiered model with namespace-scoped provisioner roles. Existing deployments must be updated to use the new ClusterRole and Role structure. See docs/security/ADVISORY-001-provisioner-rbac.md for details.
@gemini-code-assist
Copy link

Summary of Changes

Hello @michaelruelas, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the security and clarity of the SupaControl platform by introducing a robust two-tiered RBAC model for instance provisioning, ensuring strict isolation and least privilege. Accompanying these core architectural changes are comprehensive documentation updates that clarify the CRD-centric and job-based provisioning patterns, streamline Helm chart references, and refine API status reporting for asynchronous operations. This refactoring improves both the operational security and the overall understanding of the system's behavior.

Highlights

  • Two-Tiered RBAC Model: Implemented a new, more secure RBAC model for provisioning jobs, ensuring namespace-scoped permissions and adhering to the principle of least privilege.
  • Comprehensive Documentation Updates: Extensive updates across multiple documentation files (e.g., ARCHITECTURE.md, README.md, API.md, DEPLOYMENT.md, SECURITY.md, TROUBLESHOOTING.md) and the addition of new guides (GEMINI.md, docs/DOCUMENTATION.md) to reflect the CRD-centric, job-based provisioning, and the new RBAC architecture.
  • Official Helm Chart Repository: Switched to the official Supabase Helm charts repository for provisioning, ensuring up-to-date and reliable deployments.
  • Refined API Status Handling: Enhanced API responses for instance creation and deletion to clearly communicate asynchronous operations and detailed status phases (e.g., "Pending", "Provisioning", "ProvisioningInProgress").
  • Controller-Managed RBAC Creation: The Kubernetes controller now programmatically creates namespaces and the necessary namespace-scoped RBAC roles (Role and RoleBinding) for provisioner jobs before initiating the provisioning process.
  • Breaking Change Advisory: Existing deployments must update their RBAC to align with the new ClusterRole and Role structure, as detailed in docs/security/ADVISORY-001-provisioner-rbac.md.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is an excellent and substantial pull request that significantly improves the security and architecture of the project. The move to a two-tiered RBAC model is a critical security enhancement, and the adoption of a job-based provisioning pattern aligns the controller with Kubernetes best practices, improving reliability and observability. The documentation updates across the board are thorough and accurately reflect these major architectural changes. I've included one suggestion to further enhance tenant isolation by running provisioning jobs within the instance's own namespace.

Comment on lines 433 to 501
// createProvisionerRBAC creates the Role and RoleBinding for the provisioner Job
func (r *SupabaseInstanceReconciler) createProvisionerRBAC(ctx context.Context, instance *supacontrolv1alpha1.SupabaseInstance) error {
namespace := fmt.Sprintf("supa-%s", instance.Spec.ProjectName)

// Create namespace-scoped Role
role := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: "supacontrol-provisioner",
Namespace: namespace,
},
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"secrets", "services", "configmaps", "pods", "serviceaccounts", "persistentvolumeclaims"},
Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"},
},
{
APIGroups: []string{"apps"},
Resources: []string{"deployments", "statefulsets", "replicasets"},
Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"},
},
{
APIGroups: []string{"networking.k8s.io"},
Resources: []string{"ingresses"},
Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"},
},
{
APIGroups: []string{"batch"},
Resources: []string{"jobs"},
Verbs: []string{"create", "delete", "get", "list", "watch"},
},
{
APIGroups: []string{"rbac.authorization.k8s.io"},
Resources: []string{"roles", "rolebindings"},
Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"},
},
},
}

if err := r.Create(ctx, role); err != nil && !apierrors.IsAlreadyExists(err) {
return err
}

// Create RoleBinding
roleBinding := &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "supacontrol-provisioner",
Namespace: namespace,
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: "supacontrol-provisioner",
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: ServiceAccountName,
Namespace: ControllerNamespace,
},
},
}

if err := r.Create(ctx, roleBinding); err != nil && !apierrors.IsAlreadyExists(err) {
return err
}

return nil
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current RBAC model is a significant improvement. However, for even stronger tenant isolation, the provisioning Job itself should be created and run within the instance's namespace (supa-<instance-name>) rather than the controller's namespace. This ensures that the entire provisioning process, including the pod executing the logic, is fully contained within the tenant's namespace, further reducing the potential blast radius of a compromised job.

This change would involve:

  1. Creating the ServiceAccount for the job within the instance's namespace.
  2. Creating the Role and RoleBinding within the instance's namespace, binding the new in-namespace ServiceAccount to the Role.
  3. Modifying the createProvisioningJob and createCleanupJob functions (in job_helpers.go) to create the Job within the instance's namespace and specifying the new in-namespace ServiceAccount in its pod spec.

The suggested code refactors createProvisionerRBAC to create all necessary RBAC resources within the instance namespace. You would also need to update the job creation functions accordingly.

// createProvisionerRBAC creates the ServiceAccount, Role and RoleBinding for the provisioner Job
// inside the instance's own namespace for better isolation.
func (r *SupabaseInstanceReconciler) createProvisionerRBAC(ctx context.Context, instance *supacontrolv1alpha1.SupabaseInstance) error {
	namespace := fmt.Sprintf("supa-%s", instance.Spec.ProjectName)

	// 1. Create ServiceAccount in the instance namespace
	sa := &corev1.ServiceAccount{
		ObjectMeta: metav1.ObjectMeta{
			Name:      ServiceAccountName,
			Namespace: namespace,
		},
	}
	if err := r.Create(ctx, sa); err != nil && !apierrors.IsAlreadyExists(err) {
		return fmt.Errorf("failed to create provisioner service account: %w", err)
	}

	// 2. Create namespace-scoped Role
	role := &rbacv1.Role{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "supacontrol-provisioner",
			Namespace: namespace,
		},
		Rules: []rbacv1.PolicyRule{
			{
				APIGroups: []string{""},
				Resources: []string{"secrets", "services", "configmaps", "pods", "serviceaccounts", "persistentvolumeclaims"},
				Verbs:     []string{"create", "delete", "get", "list", "patch", "update", "watch"},
			},
			{
				APIGroups: []string{"apps"},
				Resources: []string{"deployments", "statefulsets", "replicasets"},
				Verbs:     []string{"create", "delete", "get", "list", "patch", "update", "watch"},
			},
			{
				APIGroups: []string{"networking.k8s.io"},
				Resources: []string{"ingresses"},
				Verbs:     []string{"create", "delete", "get", "list", "patch", "update", "watch"},
			},
			{
				APIGroups: []string{"batch"},
				Resources: []string{"jobs"},
				Verbs:     []string{"create", "delete", "get", "list", "watch"},
			},
			{
				APIGroups: []string{"rbac.authorization.k8s.io"},
				Resources: []string{"roles", "rolebindings"},
				Verbs:     []string{"create", "delete", "get", "list", "patch", "update", "watch"},
			},
		},
	}
	if err := r.Create(ctx, role); err != nil && !apierrors.IsAlreadyExists(err) {
		return fmt.Errorf("failed to create provisioner role: %w", err)
	}

	// 3. Create RoleBinding in the instance namespace
	roleBinding := &rbacv1.RoleBinding{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "supacontrol-provisioner",
			Namespace: namespace,
		},
		RoleRef: rbacv1.RoleRef{
			APIGroup: "rbac.authorization.k8s.io",
			Kind:     "Role",
			Name:     "supacontrol-provisioner",
		},
		Subjects: []rbacv1.Subject{
			{
				Kind:      "ServiceAccount",
				Name:      ServiceAccountName,
				Namespace: namespace, // Subject is now in the instance namespace
			},
		},
	}
	if err := r.Create(ctx, roleBinding); err != nil && !apierrors.IsAlreadyExists(err) {
		return fmt.Errorf("failed to create provisioner role binding: %w", err)
	}

	return nil
}

…olation

- Update provisioning and cleanup jobs to operate within instance namespace
- Create ServiceAccount, Role, and RoleBinding in instance namespace for better security
- Modify job status retrieval to use dynamic namespace parameter
- Remove namespace creation/deletion from job scripts and handle in controller
- Delete instance namespace after successful cleanup job completion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants