A modern, self-hosted web application for managing multiple Kubernetes clusters in a single pane of glass with Google SSO authentication and admin approval workflow.
- π Google SSO Authentication - Secure login using Google OAuth2
- π₯ Admin Approval System - Admins can approve/reject user access
- π― Multi-Cluster Management - Connect and manage multiple Kubernetes clusters
- π Resource Visualization - View pods, deployments, services, and more
- π Self-Hosted - Deploy in your own Kubernetes cluster with Helm
- π Accessible Anywhere - Web-based UI accessible from any browser
- π Role-Based Access Control - User and admin roles with different permissions
- π³ Container Images - Pre-built Docker images published to GitHub Container Registry
- βοΈ CI/CD Ready - GitHub Actions workflows for automated testing and deployment
- Go with Gin framework
- PostgreSQL for data persistence
- Kubernetes client-go for cluster interactions
- JWT for session management
- OAuth2 for Google SSO
- React with TypeScript
- Material-UI for modern UI components
- React Router for navigation
- Axios for API communication
Choose the installation method that best fits your needs:
- Helm Chart - Production deployment to Kubernetes (Recommended)
- Docker Compose - Quick local testing
- Manual Setup - Development environment
The fastest and recommended way to deploy Surfer to your Kubernetes cluster:
# Add the Surfer Helm repository
helm repo add surfer https://mysticrenji.github.io/surfer/charts
# Update Helm repositories
helm repo update
# Install Surfer
helm install surfer surfer/surfer \
--namespace surfer \
--create-namespace \
--set secrets.googleClientId="YOUR_CLIENT_ID" \
--set secrets.googleClientSecret="YOUR_CLIENT_SECRET" \
--set ingress.hosts[0].host="surfer.yourdomain.com"
# Check deployment status
kubectl get pods -n surfer
Benefits:
- β No repository cloning required
- β
Automatic updates with
helm repo update
- β Easy version management
- β Uses pre-built Docker images
# Clone and install
git clone https://github.com/mysticrenji/surfer.git
cd surfer
helm install surfer ./helm/surfer \
--namespace surfer \
--create-namespace \
--set secrets.googleClientId="YOUR_CLIENT_ID" \
--set secrets.googleClientSecret="YOUR_CLIENT_SECRET" \
--set ingress.hosts[0].host="surfer.yourdomain.com"
π Full Helm Deployment Guide
For quick local testing with Docker Compose:
-
Clone the repository
git clone https://github.com/mysticrenji/surfer.git cd surfer
-
Setup Google OAuth2
- Go to Google Cloud Console
- Create a new project or select existing one
- Enable Google+ API
- Create OAuth 2.0 credentials
- Add authorized redirect URI:
http://localhost:8080/api/v1/auth/google/callback
- Copy Client ID and Client Secret
-
Configure environment variables
cp .env.example .env # Edit .env and add your Google OAuth credentials
-
Start with Docker Compose
docker-compose up -d
-
Access the application
- Frontend: http://localhost:3000
- Backend API: http://localhost:8080
# Install dependencies
cd backend
go mod download
# Run database migrations (PostgreSQL should be running)
go run cmd/main.go
# The backend will start on port 8080
# Install dependencies
cd frontend
npm install
# Start development server
npm start
# The frontend will start on port 3000
- Kubernetes cluster (v1.20+)
- kubectl configured
- Ingress controller (e.g., nginx-ingress)
-
Update Kubernetes secrets
Edit
k8s/deployment.yaml
and update the following in thesurfer-secrets
Secret:GOOGLE_CLIENT_ID: "your-google-client-id" GOOGLE_CLIENT_SECRET: "your-google-client-secret" GOOGLE_REDIRECT_URL: "https://your-domain.com/api/v1/auth/google/callback" JWT_SECRET: "your-secure-jwt-secret"
-
Update Ingress host
Edit
k8s/deployment.yaml
and update the Ingress host:spec: rules: - host: surfer.your-domain.com
-
Build Docker images
# Build backend docker build -f Dockerfile.backend -t surfer-backend:latest . # Build frontend docker build -f Dockerfile.frontend -t surfer-frontend:latest .
-
Deploy to Kubernetes
kubectl apply -f k8s/deployment.yaml
-
Verify deployment
kubectl get pods -n surfer kubectl get ingress -n surfer
Variable | Description | Default |
---|---|---|
PORT | Backend server port | 8080 |
GOOGLE_CLIENT_ID | Google OAuth Client ID | - |
GOOGLE_CLIENT_SECRET | Google OAuth Client Secret | - |
GOOGLE_REDIRECT_URL | OAuth callback URL | - |
JWT_SECRET | Secret for JWT token signing | - |
DB_HOST | PostgreSQL host | localhost |
DB_PORT | PostgreSQL port | 5432 |
DB_USER | PostgreSQL username | surfer |
DB_PASSWORD | PostgreSQL password | surfer |
DB_NAME | PostgreSQL database name | surfer |
Variable | Description | Default |
---|---|---|
REACT_APP_API_URL | Backend API URL | http://localhost:8080/api/v1 |
-
Login with Google
- Navigate to the application URL
- Click "Sign in with Google"
- Authenticate with your Google account
-
Wait for Admin Approval
- After first login, your account will be in "pending" status
- Contact your administrator to approve your account
-
Admin Creates First User (Bootstrap)
- For the first admin user, manually update the database:
UPDATE users SET role='admin', status='approved' WHERE email='[email protected]';
-
Add a Cluster
- Click "Add Cluster" button
- Provide cluster name and description
- Paste your kubeconfig content
- Specify context name (optional)
- Click "Add" to save
-
View Cluster Resources
- Click on a cluster card
- Select namespace from dropdown
- Browse Pods, Deployments, and Services tabs
- View resource details and logs
Admins have access to additional features:
-
Approve Users
- Navigate to Admin Panel
- View pending user requests
- Click "Approve" or "Reject" for each user
-
Manage User Roles
- View all users
- Update user roles (user/admin)
- Revoke access if needed
GET /api/v1/auth/google/login
- Get Google OAuth login URLGET /api/v1/auth/google/callback
- OAuth callback handlerPOST /api/v1/auth/logout
- Logout user
GET /api/v1/users/me
- Get current userGET /api/v1/users
- List all users
GET /api/v1/admin/pending-users
- Get pending user approvalsPOST /api/v1/admin/approve-user/:id
- Approve userPOST /api/v1/admin/reject-user/:id
- Reject userPUT /api/v1/admin/users/:id/role
- Update user role
GET /api/v1/clusters
- List clustersPOST /api/v1/clusters
- Add clusterGET /api/v1/clusters/:id
- Get cluster detailsPUT /api/v1/clusters/:id
- Update clusterDELETE /api/v1/clusters/:id
- Delete clusterPOST /api/v1/clusters/:id/test
- Test cluster connection
GET /api/v1/k8s/clusters/:clusterId/namespaces
- List namespacesGET /api/v1/k8s/clusters/:clusterId/namespaces/:namespace/pods
- List podsGET /api/v1/k8s/clusters/:clusterId/namespaces/:namespace/deployments
- List deploymentsGET /api/v1/k8s/clusters/:clusterId/namespaces/:namespace/services
- List servicesGET /api/v1/k8s/clusters/:clusterId/namespaces/:namespace/pods/:pod/logs
- Get pod logsDELETE /api/v1/k8s/clusters/:clusterId/namespaces/:namespace/pods/:pod
- Delete pod
-
Secrets Management
- Never commit secrets to version control
- Use Kubernetes Secrets or external secret managers
- Rotate JWT secrets regularly
-
Kubeconfig Storage
- Kubeconfig files are stored encrypted in the database
- Consider using service accounts with limited permissions
- Implement kubeconfig rotation policies
-
Network Security
- Use HTTPS in production
- Configure appropriate CORS settings
- Implement rate limiting
-
RBAC
- Follow principle of least privilege
- Regularly review user permissions
- Audit admin actions
Pre-built Docker images are automatically published to GitHub Container Registry:
# Pull backend image
docker pull ghcr.io/mysticrenji/surfer-backend:latest
# Pull frontend image
docker pull ghcr.io/mysticrenji/surfer-frontend:latest
# Use specific version
docker pull ghcr.io/mysticrenji/surfer-backend:v1.0.0
Available tags:
latest
- Latest stable release from main branchv1.0.0
- Semantic version tagsmain
- Latest commit from main branchdevelop
- Latest commit from develop branch
π GitHub Actions CI/CD Guide
- Database connection failed: Check PostgreSQL is running and credentials are correct
- OAuth error: Verify Google OAuth credentials and redirect URL
- Kubeconfig error: Ensure kubeconfig format is valid
- API connection failed: Check backend is running and API URL is correct
- Login redirect fails: Verify OAuth redirect URL matches configuration
- Pods not starting: Check logs with
kubectl logs -n surfer <pod-name>
- Ingress not working: Verify ingress controller is installed and configured
- Database persistence: Ensure PVC is bound correctly
- π Architecture Overview
- π οΈ Development Guide
- π Deployment Guide
- β Helm Deployment
- π GitHub Actions CI/CD
- π Google OAuth Setup
- π¨ Application UI Guide
- π§ͺ Test Results
- π€ Contributing Guidelines
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by Plural
- Built with Gin and React
- Uses Kubernetes client-go
For issues, questions, or contributions, please open an issue on GitHub.