mirror of
https://github.com/CloudNebulaProject/barycenter.git
synced 2026-04-10 21:20:41 +00:00
feat: add user sync init container support to Helm chart
- Add userSync configuration to values.yaml (existingSecret only) - Add conditional init container to deployment.yaml - Create comprehensive README.md with: - Installation and configuration instructions - User sync workflow and examples - Troubleshooting guide - Security best practices - Add examples/user-sync-secret.yaml with sample users - Support declarative user management for Kubernetes/GitOps 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f2f7f4be00
commit
57a0df9080
4 changed files with 525 additions and 0 deletions
405
deploy/helm/barycenter/README.md
Normal file
405
deploy/helm/barycenter/README.md
Normal file
|
|
@ -0,0 +1,405 @@
|
||||||
|
# Barycenter Helm Chart
|
||||||
|
|
||||||
|
OpenID Connect Identity Provider with built-in user management and federation support.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- OpenID Connect / OAuth 2.0 Authorization Server
|
||||||
|
- User synchronization from JSON files (idempotent)
|
||||||
|
- GraphQL Admin API for management
|
||||||
|
- Background job scheduler
|
||||||
|
- PostgreSQL and SQLite support
|
||||||
|
- Persistent storage for database and keys
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes 1.20+
|
||||||
|
- Helm 3.0+
|
||||||
|
- PersistentVolume provisioner (optional, for production)
|
||||||
|
|
||||||
|
## Installing the Chart
|
||||||
|
|
||||||
|
### Basic Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install barycenter ./barycenter
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Custom Values
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install barycenter ./barycenter -f my-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Installation with User Sync
|
||||||
|
|
||||||
|
1. **Create users secret:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy the example
|
||||||
|
cp examples/user-sync-secret.yaml my-users-secret.yaml
|
||||||
|
|
||||||
|
# Edit with your users
|
||||||
|
nano my-users-secret.yaml
|
||||||
|
|
||||||
|
# Create the secret
|
||||||
|
kubectl create secret generic barycenter-users \
|
||||||
|
--from-file=users.json=./users.json \
|
||||||
|
-n default
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Install with user sync enabled:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install barycenter ./barycenter \
|
||||||
|
--set userSync.enabled=true \
|
||||||
|
--set userSync.existingSecret=barycenter-users \
|
||||||
|
--set config.server.publicBaseUrl=https://auth.example.com \
|
||||||
|
--set ingress.enabled=true \
|
||||||
|
--set ingress.hosts[0].host=auth.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Basic Configuration
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `replicaCount` | Number of replicas (use 1 for SQLite) | `1` |
|
||||||
|
| `image.repository` | Image repository | `barycenter` |
|
||||||
|
| `image.tag` | Image tag | `Chart.appVersion` |
|
||||||
|
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
|
||||||
|
|
||||||
|
### Service Configuration
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `service.type` | Service type | `ClusterIP` |
|
||||||
|
| `service.port` | Service port | `8080` |
|
||||||
|
|
||||||
|
### Barycenter Configuration
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `config.server.host` | Listen address | `0.0.0.0` |
|
||||||
|
| `config.server.port` | Listen port | `8080` |
|
||||||
|
| `config.server.publicBaseUrl` | Public base URL (OIDC issuer) | `""` |
|
||||||
|
| `config.database.url` | Database connection string | `sqlite:///app/data/barycenter.db?mode=rwc` |
|
||||||
|
| `config.keys.alg` | Signing algorithm | `RS256` |
|
||||||
|
|
||||||
|
### User Sync Configuration
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `userSync.enabled` | Enable user sync init container | `false` |
|
||||||
|
| `userSync.existingSecret` | Name of secret containing users.json | `""` |
|
||||||
|
| `userSync.secretKey` | Key in secret containing users.json | `users.json` |
|
||||||
|
| `userSync.resources` | Init container resources | See values.yaml |
|
||||||
|
|
||||||
|
### Persistence
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `persistence.enabled` | Enable persistent storage | `true` |
|
||||||
|
| `persistence.size` | PVC size | `10Gi` |
|
||||||
|
| `persistence.accessMode` | PVC access mode | `ReadWriteOnce` |
|
||||||
|
| `persistence.storageClass` | Storage class | `""` (default) |
|
||||||
|
|
||||||
|
### Ingress
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `ingress.enabled` | Enable ingress | `false` |
|
||||||
|
| `ingress.className` | Ingress class name | `nginx` |
|
||||||
|
| `ingress.hosts` | Ingress hosts | `[{host: idp.example.com, paths: [{path: /, pathType: Prefix}]}]` |
|
||||||
|
| `ingress.tls` | TLS configuration | `[]` |
|
||||||
|
|
||||||
|
## User Synchronization
|
||||||
|
|
||||||
|
The user sync feature allows you to manage users declaratively using a JSON file. This is perfect for:
|
||||||
|
|
||||||
|
- Initial user provisioning
|
||||||
|
- Kubernetes init containers
|
||||||
|
- CI/CD pipelines
|
||||||
|
- GitOps workflows
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
1. Create a Kubernetes Secret with your users.json
|
||||||
|
2. Enable user sync in Helm values
|
||||||
|
3. An init container runs before the main app
|
||||||
|
4. Users are created/updated idempotently
|
||||||
|
5. Main app starts with users ready
|
||||||
|
|
||||||
|
### User JSON Schema
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"password": "secure-password",
|
||||||
|
"enabled": true,
|
||||||
|
"email_verified": true,
|
||||||
|
"properties": {
|
||||||
|
"role": "administrator",
|
||||||
|
"custom_field": "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a User Secret
|
||||||
|
|
||||||
|
**From a file:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl create secret generic barycenter-users \
|
||||||
|
--from-file=users.json=./my-users.json \
|
||||||
|
-n default
|
||||||
|
```
|
||||||
|
|
||||||
|
**From stdin (for CI/CD):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: barycenter-users
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
users.json: |
|
||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"password": "${ADMIN_PASSWORD}",
|
||||||
|
"enabled": true,
|
||||||
|
"email_verified": true,
|
||||||
|
"properties": {
|
||||||
|
"role": "administrator"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### Idempotent Behavior
|
||||||
|
|
||||||
|
The user sync is **idempotent** - safe to run multiple times:
|
||||||
|
|
||||||
|
- **New users**: Created with hashed passwords
|
||||||
|
- **Existing users**: Updated if changed (email, enabled, email_verified)
|
||||||
|
- **Passwords**: NOT updated for existing users (security)
|
||||||
|
- **Properties**: Always synced to match the JSON
|
||||||
|
|
||||||
|
### Example: GitOps Workflow
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# kustomization.yaml
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- users-secret.yaml
|
||||||
|
|
||||||
|
helmCharts:
|
||||||
|
- name: barycenter
|
||||||
|
repo: https://charts.example.com
|
||||||
|
version: 0.2.0
|
||||||
|
releaseName: barycenter
|
||||||
|
namespace: barycenter
|
||||||
|
valuesInline:
|
||||||
|
userSync:
|
||||||
|
enabled: true
|
||||||
|
existingSecret: barycenter-users
|
||||||
|
config:
|
||||||
|
server:
|
||||||
|
publicBaseUrl: https://auth.example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Example 1: Development with SQLite
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install barycenter ./barycenter \
|
||||||
|
--set persistence.enabled=false \
|
||||||
|
--set config.database.url="sqlite:///tmp/barycenter.db?mode=rwc"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Production with PostgreSQL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install barycenter ./barycenter \
|
||||||
|
--set config.database.url="postgresql://user:pass@postgres:5432/barycenter" \
|
||||||
|
--set replicaCount=3 \
|
||||||
|
--set persistence.enabled=true \
|
||||||
|
--set persistence.size=20Gi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: With User Sync and Ingress
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# values-production.yaml
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
config:
|
||||||
|
server:
|
||||||
|
publicBaseUrl: "https://auth.example.com"
|
||||||
|
database:
|
||||||
|
url: "postgresql://barycenter:password@postgres:5432/barycenter"
|
||||||
|
|
||||||
|
userSync:
|
||||||
|
enabled: true
|
||||||
|
existingSecret: "barycenter-users"
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
hosts:
|
||||||
|
- host: auth.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- secretName: barycenter-tls
|
||||||
|
hosts:
|
||||||
|
- auth.example.com
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 20Gi
|
||||||
|
storageClass: fast-ssd
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create users secret first
|
||||||
|
kubectl create secret generic barycenter-users \
|
||||||
|
--from-file=users.json=./production-users.json
|
||||||
|
|
||||||
|
# Install with custom values
|
||||||
|
helm install barycenter ./barycenter -f values-production.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Upgrading
|
||||||
|
|
||||||
|
### Update User List
|
||||||
|
|
||||||
|
To update users after deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Method 1: Update secret and restart
|
||||||
|
kubectl create secret generic barycenter-users \
|
||||||
|
--from-file=users.json=./updated-users.json \
|
||||||
|
--dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
kubectl rollout restart deployment/barycenter
|
||||||
|
|
||||||
|
# Method 2: Run sync job manually (requires creating a Job)
|
||||||
|
kubectl run user-sync --rm -it --restart=Never \
|
||||||
|
--image=barycenter:latest \
|
||||||
|
-- barycenter sync-users --file /secrets/users.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Upgrade Chart
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade barycenter ./barycenter -f values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uninstalling
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm uninstall barycenter
|
||||||
|
|
||||||
|
# Also delete PVC if needed
|
||||||
|
kubectl delete pvc barycenter-data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Check Init Container Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View user sync logs
|
||||||
|
kubectl logs deployment/barycenter -c user-sync
|
||||||
|
|
||||||
|
# Expected output:
|
||||||
|
# Loading users from /secrets/users.json
|
||||||
|
# Found 3 user(s) in file
|
||||||
|
# Creating user: alice
|
||||||
|
# User sync complete: 3 created, 0 updated, 0 unchanged
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Main Container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl logs deployment/barycenter -c barycenter -f
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify Users Created
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Port forward to admin API
|
||||||
|
kubectl port-forward svc/barycenter 8081:8081
|
||||||
|
|
||||||
|
# Query users via GraphQL
|
||||||
|
curl -X POST http://localhost:8081/admin/graphql \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"query": "{ user { nodes { username email enabled } } }"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**Init container fails with "secret not found":**
|
||||||
|
- Ensure the secret exists: `kubectl get secret barycenter-users`
|
||||||
|
- Check the secret name in values.yaml matches
|
||||||
|
|
||||||
|
**Users not created:**
|
||||||
|
- Check init container logs for JSON parsing errors
|
||||||
|
- Verify users.json format matches the schema
|
||||||
|
|
||||||
|
**Permission denied on /app/data:**
|
||||||
|
- Check fsGroup in podSecurityContext (should be 1000)
|
||||||
|
- Verify PVC permissions
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
1. **Never commit secrets to Git:**
|
||||||
|
```bash
|
||||||
|
# Use .gitignore
|
||||||
|
echo "my-users-secret.yaml" >> .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Use secret management tools:**
|
||||||
|
- Sealed Secrets
|
||||||
|
- External Secrets Operator
|
||||||
|
- HashiCorp Vault
|
||||||
|
- Cloud provider secret managers
|
||||||
|
|
||||||
|
3. **Rotate passwords regularly:**
|
||||||
|
- Update users.json with new passwords
|
||||||
|
- Recreate the secret
|
||||||
|
- Restart deployment
|
||||||
|
|
||||||
|
4. **Restrict admin API access:**
|
||||||
|
- Use NetworkPolicies
|
||||||
|
- Don't expose admin port publicly
|
||||||
|
- Use VPN or bastion for access
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
- Documentation: https://github.com/CloudNebulaProject/barycenter
|
||||||
|
- Issues: https://github.com/CloudNebulaProject/barycenter/issues
|
||||||
65
deploy/helm/barycenter/examples/user-sync-secret.yaml
Normal file
65
deploy/helm/barycenter/examples/user-sync-secret.yaml
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Example Secret for User Synchronization
|
||||||
|
#
|
||||||
|
# This secret contains the users.json file that will be used by the
|
||||||
|
# user-sync init container to create/update users in Barycenter.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# 1. Copy this file and customize the users list
|
||||||
|
# 2. Create the secret: kubectl apply -f user-sync-secret.yaml
|
||||||
|
# 3. Enable userSync in values.yaml:
|
||||||
|
# userSync:
|
||||||
|
# enabled: true
|
||||||
|
# existingSecret: "barycenter-users"
|
||||||
|
#
|
||||||
|
# Security Notes:
|
||||||
|
# - NEVER commit this file with real passwords to version control
|
||||||
|
# - Consider using a secret management tool (Sealed Secrets, External Secrets, Vault, etc.)
|
||||||
|
# - Passwords should be strong and unique per environment
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: barycenter-users
|
||||||
|
namespace: default # Change to your namespace
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
users.json: |
|
||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"password": "CHANGE-ME-IN-PRODUCTION",
|
||||||
|
"enabled": true,
|
||||||
|
"email_verified": true,
|
||||||
|
"properties": {
|
||||||
|
"role": "administrator",
|
||||||
|
"display_name": "System Administrator"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "alice",
|
||||||
|
"email": "alice@example.com",
|
||||||
|
"password": "alice-secure-password",
|
||||||
|
"enabled": true,
|
||||||
|
"email_verified": false,
|
||||||
|
"properties": {
|
||||||
|
"department": "Engineering",
|
||||||
|
"role": "developer",
|
||||||
|
"display_name": "Alice Johnson",
|
||||||
|
"team": "Platform"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "service-account",
|
||||||
|
"email": "service@example.com",
|
||||||
|
"password": "service-account-password",
|
||||||
|
"enabled": true,
|
||||||
|
"email_verified": true,
|
||||||
|
"properties": {
|
||||||
|
"role": "service_account",
|
||||||
|
"display_name": "Application Service Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,35 @@ spec:
|
||||||
serviceAccountName: {{ include "barycenter.serviceAccountName" . }}
|
serviceAccountName: {{ include "barycenter.serviceAccountName" . }}
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
{{- if .Values.userSync.enabled }}
|
||||||
|
initContainers:
|
||||||
|
- name: user-sync
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- barycenter
|
||||||
|
- sync-users
|
||||||
|
- --file
|
||||||
|
- /secrets/{{ .Values.userSync.secretKey }}
|
||||||
|
env:
|
||||||
|
- name: RUST_LOG
|
||||||
|
value: "info"
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /app/config
|
||||||
|
readOnly: true
|
||||||
|
{{- if .Values.persistence.enabled }}
|
||||||
|
- name: data
|
||||||
|
mountPath: /app/data
|
||||||
|
{{- end }}
|
||||||
|
- name: user-sync-secret
|
||||||
|
mountPath: /secrets
|
||||||
|
readOnly: true
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.userSync.resources | nindent 10 }}
|
||||||
|
{{- end }}
|
||||||
containers:
|
containers:
|
||||||
- name: {{ .Chart.Name }}
|
- name: {{ .Chart.Name }}
|
||||||
securityContext:
|
securityContext:
|
||||||
|
|
@ -71,6 +100,11 @@ spec:
|
||||||
- name: data
|
- name: data
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.userSync.enabled }}
|
||||||
|
- name: user-sync-secret
|
||||||
|
secret:
|
||||||
|
secretName: {{ .Values.userSync.existingSecret }}
|
||||||
|
{{- end }}
|
||||||
{{- with .Values.nodeSelector }}
|
{{- with .Values.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
|
|
|
||||||
|
|
@ -153,3 +153,24 @@ readinessProbe:
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
timeoutSeconds: 3
|
timeoutSeconds: 3
|
||||||
failureThreshold: 3
|
failureThreshold: 3
|
||||||
|
|
||||||
|
# User synchronization from JSON file
|
||||||
|
userSync:
|
||||||
|
# Enable user sync init container
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Name of existing secret containing users.json
|
||||||
|
existingSecret: ""
|
||||||
|
# Example: barycenter-users
|
||||||
|
|
||||||
|
# Secret key containing the users.json file
|
||||||
|
secretKey: "users.json"
|
||||||
|
|
||||||
|
# Init container resources
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue