Browse Source

feat(admin): support env var and security.toml for credentials (#8606)

* feat(security): add [admin] section to security.toml scaffold

Add admin credential fields (user, password, readonly.user,
readonly.password) to security.toml. Via viper's WEED_ env prefix and
AutomaticEnv(), these are automatically overridable as WEED_ADMIN_USER,
WEED_ADMIN_PASSWORD, etc.

Ref: https://github.com/seaweedfs/seaweedfs/discussions/8586

* feat(admin): support env var and security.toml fallbacks for credentials

Add applyViperFallback() to read admin credentials from security.toml /
WEED_* environment variables when CLI flags are not explicitly set.
This allows systems like NixOS to pass secrets via env vars instead of
CLI flags, which appear in process listings.

Precedence: CLI flag > env var / security.toml > default value.

Also change -adminUser default from "admin" to "" so that credentials
are fully opt-in.

Ref: https://github.com/seaweedfs/seaweedfs/discussions/8586

* feat(helm): use WEED_ env vars for admin credentials instead of CLI flags

Rename SEAWEEDFS_ADMIN_USER/PASSWORD to WEED_ADMIN_USER/PASSWORD so
viper picks them up natively. Remove -adminUser/-adminPassword shell
expansion from command args since the Go binary now reads these
directly via viper.

* docs(admin): document env var and security.toml credential support

Add environment variable mapping table, security.toml example, and
precedence rules to the admin README.

* style(security): use nested [admin.readonly] table in security.toml

Use a nested TOML table instead of dotted keys for the readonly
credentials. More idiomatic and easier to read; no change in how
Viper parses it.

* fix(admin): use util.GetViper() for env var support and fix README example

applyViperFallback() was using viper.GetString() directly, which
bypasses the WEED_ env prefix and AutomaticEnv setup that only
happens in util.GetViper(). Switch to util.GetViper().GetString()
so WEED_ADMIN_* environment variables are actually picked up.

Also fix the README example to include WEED_ADMIN_USER alongside
WEED_ADMIN_PASSWORD, since runAdmin() rejects an empty username
when a password is set.

* fix(admin): restore default adminUser to "admin"

Defaulting adminUser to "" broke the common flow of setting only
WEED_ADMIN_PASSWORD — runAdmin() rejects an empty username when a
password is set. Restore "admin" as the default so that setting
only the password works out of the box.

* docs(admin): align README security.toml example with scaffold format

Use nested [admin.readonly] table instead of flat dotted keys to
match the format in weed/command/scaffold/security.toml.

* docs(admin): remove README.md in favor of wiki page

Admin documentation lives at the wiki (Admin-UI.md). Remove the
in-repo README to avoid maintaining duplicate docs.

---------

Co-authored-by: Copilot <copilot@github.com>
pull/8607/head
Chris Lu 2 days ago
committed by GitHub
parent
commit
e4a77b8b16
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 8
      k8s/charts/seaweedfs/templates/admin/admin-statefulset.yaml
  2. 279
      weed/admin/README.md
  3. 28
      weed/command/admin.go
  4. 13
      weed/command/scaffold/security.toml

8
k8s/charts/seaweedfs/templates/admin/admin-statefulset.yaml

@ -93,12 +93,12 @@ spec:
{{- $adminSecretName := .Values.admin.secret.existingSecret | default (printf "%s-admin-secret" (include "seaweedfs.fullname" .)) }}
env:
{{- if $adminAuthEnabled }}
- name: SEAWEEDFS_ADMIN_USER
- name: WEED_ADMIN_USER
valueFrom:
secretKeyRef:
name: {{ $adminSecretName }}
key: {{ if .Values.admin.secret.existingSecret }}{{ .Values.admin.secret.userKey }}{{ else }}adminUser{{ end }}
- name: SEAWEEDFS_ADMIN_PASSWORD
- name: WEED_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $adminSecretName }}
@ -153,10 +153,6 @@ spec:
{{- else if .Values.admin.dataDir }}
-dataDir={{ .Values.admin.dataDir }} \
{{- end }}
{{- if $adminAuthEnabled }}
-adminUser="${SEAWEEDFS_ADMIN_USER}" \
-adminPassword="${SEAWEEDFS_ADMIN_PASSWORD}" \
{{- end }}
{{- if .Values.admin.masters }}
-masters={{ .Values.admin.masters }}{{- if .Values.admin.extraArgs }} \{{ end }}
{{- else if .Values.global.masterServer }}

279
weed/admin/README.md

@ -1,279 +0,0 @@
# SeaweedFS Admin Component
A modern web-based administration interface for SeaweedFS clusters built with Go, Gin, Templ, and Bootstrap.
## Features
- **Dashboard**: Real-time cluster status and metrics
- **Master Management**: Monitor master nodes and leadership status
- **Volume Server Management**: View volume servers, capacity, and health
- **Object Store Bucket Management**: Create, delete, and manage Object Store buckets with web interface
- **S3 Tables Management**: Manage table buckets, namespaces, tables, tags, and policies via the admin UI
- **System Health**: Overall cluster health monitoring
- **Responsive Design**: Bootstrap-based UI that works on all devices
- **Authentication**: Optional user authentication with sessions
- **TLS Support**: HTTPS support for production deployments
## Building
### Using the Admin Makefile
The admin component has its own Makefile for development and building:
```bash
# Navigate to admin directory
cd weed/admin
# View all available targets
make help
# Generate templates and build
make build
# Development mode with template watching
make dev
# Run the admin server
make run
# Clean build artifacts
make clean
```
### Using the Root Makefile
The root SeaweedFS Makefile automatically integrates the admin component:
```bash
# From the root directory
make install # Builds weed with admin component
make full_install # Full build with all tags
make test # Runs tests including admin component
# Admin-specific targets from root
make admin-generate # Generate admin templates
make admin-build # Build admin component
make admin-run # Run admin server
make admin-dev # Development mode
make admin-clean # Clean admin artifacts
```
### Manual Building
If you prefer to build manually:
```bash
# Install templ compiler
go install github.com/a-h/templ/cmd/templ@latest
# Generate templates
templ generate
# Build the main weed binary
cd ../../../
go build -o weed ./weed
```
## Development
### Template Development
The admin interface uses [Templ](https://templ.guide/) for type-safe HTML templates:
```bash
# Watch for template changes and auto-regenerate
make watch
# Or manually generate templates
make generate
# Format templates
make fmt
```
### File Structure
```
weed/admin/
├── Makefile # Admin-specific build tasks
├── README.md # This file
├── admin.go # Main application entry point
├── dash/ # Server and handler logic
│ ├── admin_server.go # HTTP server setup
│ ├── handler_admin.go # Admin dashboard handlers
│ ├── handler_auth.go # Authentication handlers
│ └── middleware.go # HTTP middleware
├── static/ # Static assets
│ ├── css/admin.css # Admin-specific styles
│ └── js/admin.js # Admin-specific JavaScript
└── view/ # Templates
├── app/ # Application templates
│ ├── admin.templ # Main dashboard template
│ ├── s3_buckets.templ # Object Store bucket management template
│ ├── s3tables_*.templ # S3 Tables management templates
│ └── *_templ.go # Generated Go code
└── layout/ # Layout templates
├── layout.templ # Base layout template
└── layout_templ.go # Generated Go code
```
### Object Store Management
The admin interface includes Object Store and S3 Tables management capabilities:
- Create/delete Object Store buckets and adjust quotas or ownership.
- Manage S3 Tables buckets, namespaces, and tables.
- Update S3 Tables policies and tags via the UI and API endpoints.
## Usage
### Basic Usage
```bash
# Start admin interface on default port (23646)
weed admin
# Start with custom configuration
weed admin -port=8080 -masters="master1:9333,master2:9333"
# Start with authentication
weed admin -adminUser=admin -adminPassword=secret123
# Start with HTTPS
weed admin -port=443 -tlsCert=/path/to/cert.pem -tlsKey=/path/to/key.pem
```
### Configuration Options
| Option | Default | Description |
|--------|---------|-------------|
| `-port` | 23646 | Admin server port |
| `-masters` | localhost:9333 | Comma-separated master servers |
| `-adminUser` | admin | Admin username (if auth enabled) |
| `-adminPassword` | "" | Admin password (empty = no auth) |
| `-tlsCert` | "" | Path to TLS certificate |
| `-tlsKey` | "" | Path to TLS private key |
### Docker Usage
```bash
# Build Docker image with admin component
make docker-build
# Run with Docker
docker run -p 23646:23646 seaweedfs/seaweedfs:latest admin -masters=host.docker.internal:9333
```
## Development Workflow
### Quick Start
```bash
# Clone and setup
git clone <seaweedfs-repo>
cd seaweedfs/weed/admin
# Install dependencies and build
make install-deps
make build
# Start development server
make dev
```
### Making Changes
1. **Template Changes**: Edit `.templ` files in `view/`
- Templates auto-regenerate in development mode
- Use `make generate` to manually regenerate
2. **Go Code Changes**: Edit `.go` files
- Restart the server to see changes
- Use `make build` to rebuild
3. **Static Assets**: Edit files in `static/`
- Changes are served immediately
### Testing
```bash
# Run admin component tests
make test
# Run from root directory
make admin-test
# Lint code
make lint
# Format code
make fmt
```
## Production Deployment
### Security Considerations
1. **Authentication**: Always set `adminPassword` in production
2. **HTTPS**: Use TLS certificates for encrypted connections
3. **Firewall**: Restrict admin interface access to authorized networks
### Example Production Setup
```bash
# Production deployment with security
weed admin \
-port=443 \
-masters="master1:9333,master2:9333,master3:9333" \
-adminUser=admin \
-adminPassword=your-secure-password \
-tlsCert=/etc/ssl/certs/admin.crt \
-tlsKey=/etc/ssl/private/admin.key
```
### Monitoring
The admin interface provides endpoints for monitoring:
- `GET /health` - Health check endpoint
- `GET /metrics` - Prometheus metrics (if enabled)
- `GET /api/status` - JSON status information
## Troubleshooting
### Common Issues
1. **Templates not found**: Run `make generate` to create template files
2. **Build errors**: Ensure `templ` is installed with `make install-templ`
3. **Static files not loading**: Check that `static/` directory exists and has proper files
4. **Connection errors**: Verify master and filer addresses are correct
### Debug Mode
```bash
# Enable debug logging
weed -v=2 admin
# Check generated templates
ls -la view/app/*_templ.go view/layout/*_templ.go
```
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run tests: `make test`
5. Format code: `make fmt`
6. Submit a pull request
## Architecture
The admin component follows a clean architecture:
- **Presentation Layer**: Templ templates + Bootstrap CSS
- **HTTP Layer**: Gin router with middleware
- **Business Logic**: Handler functions in `dash/` package
- **Data Layer**: Communicates with SeaweedFS masters and filers
This separation makes the code maintainable and testable.

28
weed/command/admin.go

@ -17,6 +17,8 @@ import (
"syscall"
"time"
flag "github.com/seaweedfs/seaweedfs/weed/util/fla9"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"github.com/spf13/viper"
@ -98,6 +100,9 @@ var cmdAdmin = &Command{
- IMPORTANT: When read-only credentials are configured, adminPassword MUST also be set
- This ensures an admin account exists to manage and authorize read-only access
- Sessions are secured with auto-generated session keys
- Credentials can also be set via security.toml [admin] section or environment variables:
WEED_ADMIN_USER, WEED_ADMIN_PASSWORD, WEED_ADMIN_READONLY_USER, WEED_ADMIN_READONLY_PASSWORD
- Precedence: CLI flag > env var / security.toml > default value
Security Configuration:
- The admin server reads TLS configuration from security.toml
@ -137,6 +142,13 @@ func runAdmin(cmd *Command, args []string) bool {
// Load security configuration
util.LoadSecurityConfiguration()
// Apply security.toml / env var fallbacks for credential flags.
// CLI flags take precedence over security.toml / WEED_* env vars.
applyViperFallback(cmd, a.adminUser, "adminUser", "admin.user")
applyViperFallback(cmd, a.adminPassword, "adminPassword", "admin.password")
applyViperFallback(cmd, a.readOnlyUser, "readOnlyUser", "admin.readonly.user")
applyViperFallback(cmd, a.readOnlyPassword, "readOnlyPassword", "admin.readonly.password")
// Backward compatibility: if -masters is provided, use it
if *a.masters != "" {
*a.master = *a.masters
@ -534,6 +546,22 @@ func loadOrGenerateSessionKeys(dataDir string) ([]byte, []byte, error) {
return key[:keyLen], key[keyLen:], nil
}
// applyViperFallback sets a flag's value from viper (security.toml / env var)
// when the flag was not explicitly set on the command line.
func applyViperFallback(cmd *Command, flagPtr *string, flagName, viperKey string) {
explicitlySet := false
cmd.Flag.Visit(func(f *flag.Flag) {
if f.Name == flagName {
explicitlySet = true
}
})
if !explicitlySet {
if v := util.GetViper().GetString(viperKey); v != "" {
*flagPtr = v
}
}
}
// expandHomeDir expands the tilde (~) in a path to the user's home directory
func expandHomeDir(path string) (string, error) {
if path == "" {

13
weed/command/scaffold/security.toml

@ -165,6 +165,19 @@ cert = ""
key = ""
ca = ""
# Admin server authentication
# If password is set, users must login to access the admin interface
# These can be overridden by environment variables with WEED_ prefix:
# WEED_ADMIN_USER, WEED_ADMIN_PASSWORD
# WEED_ADMIN_READONLY_USER, WEED_ADMIN_READONLY_PASSWORD
[admin]
user = ""
password = ""
[admin.readonly]
user = ""
password = ""
# white list. It's checking request ip address.
[guard]
white_list = ""
Loading…
Cancel
Save