diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fda9b44 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,45 @@ +# Git +.git/ +.gitignore +.github/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Rust +target/ +Cargo.lock + +# Build artifacts +*.db +*.db-shm +*.db-wal + +# Data directories +data/ +crabidp.db + +# Documentation +README.md +CONTRIBUTING.md +CLAUDE.md +docs/ + +# Tests +tests/ + +# CI/CD +.github/ + +# Config +.config/ +.claude/ + +# Temporary files +tmp/ +*.tmp +*.log diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..aa39775 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,444 @@ +# Deployment Guide + +This guide covers deploying Barycenter OpenID Connect Identity Provider on various platforms. + +## Table of Contents + +- [Docker](#docker) +- [Docker Compose](#docker-compose) +- [Kubernetes (Helm)](#kubernetes-helm) +- [Linux (systemd)](#linux-systemd) +- [FreeBSD](#freebsd) +- [illumos/Solaris](#illumossolaris) +- [Configuration](#configuration) +- [Security Considerations](#security-considerations) + +--- + +## Docker + +### Building the Image + +```bash +docker build -t barycenter:latest . +``` + +### Running the Container + +```bash +docker run -d \ + --name barycenter \ + -p 8080:8080 \ + -v barycenter-data:/app/data \ + -e RUST_LOG=info \ + barycenter:latest +``` + +### Custom Configuration + +Mount a custom config file: + +```bash +docker run -d \ + --name barycenter \ + -p 8080:8080 \ + -v ./config.toml:/app/config/config.toml:ro \ + -v barycenter-data:/app/data \ + barycenter:latest +``` + +--- + +## Docker Compose + +### Quick Start + +```bash +# Start the service +docker-compose up -d + +# View logs +docker-compose logs -f + +# Stop the service +docker-compose down +``` + +### Production Configuration + +Edit `docker-compose.yml` to customize: + +```yaml +environment: + - RUST_LOG=info + - CRABIDP__SERVER__PUBLIC_BASE_URL=https://idp.example.com +``` + +--- + +## Kubernetes (Helm) + +### Prerequisites + +- Kubernetes cluster (1.19+) +- Helm 3.x +- kubectl configured + +### Installation + +1. **Install the Helm chart:** + +```bash +helm install barycenter ./deploy/helm/barycenter \ + --create-namespace \ + --namespace barycenter +``` + +2. **With custom values:** + +```bash +helm install barycenter ./deploy/helm/barycenter \ + --namespace barycenter \ + --set ingress.enabled=true \ + --set ingress.hosts[0].host=idp.example.com \ + --set config.server.publicBaseUrl=https://idp.example.com +``` + +3. **Using a values file:** + +Create `my-values.yaml`: + +```yaml +ingress: + enabled: true + className: nginx + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + hosts: + - host: idp.example.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: barycenter-tls + hosts: + - idp.example.com + +config: + server: + publicBaseUrl: "https://idp.example.com" + +persistence: + enabled: true + size: 20Gi + storageClass: fast-ssd + +resources: + limits: + cpu: 2000m + memory: 1Gi + requests: + cpu: 200m + memory: 256Mi +``` + +Install with: + +```bash +helm install barycenter ./deploy/helm/barycenter \ + --namespace barycenter \ + --values my-values.yaml +``` + +### Management + +**Upgrade:** +```bash +helm upgrade barycenter ./deploy/helm/barycenter \ + --namespace barycenter \ + --values my-values.yaml +``` + +**Uninstall:** +```bash +helm uninstall barycenter --namespace barycenter +``` + +**Check status:** +```bash +helm status barycenter --namespace barycenter +kubectl get pods -n barycenter +``` + +--- + +## Linux (systemd) + +### Installation + +See detailed instructions in [`deploy/systemd/README.md`](deploy/systemd/README.md). + +**Quick steps:** + +1. Build and install binary: +```bash +cargo build --release +sudo cp target/release/barycenter /usr/local/bin/ +``` + +2. Create user and directories: +```bash +sudo useradd -r -s /bin/false -d /var/lib/barycenter barycenter +sudo mkdir -p /etc/barycenter /var/lib/barycenter/data +sudo chown -R barycenter:barycenter /var/lib/barycenter +``` + +3. Install configuration: +```bash +sudo cp config.toml /etc/barycenter/ +# Edit /etc/barycenter/config.toml to update paths +``` + +4. Install and start service: +```bash +sudo cp deploy/systemd/barycenter.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable --now barycenter +``` + +### Management + +```bash +# Status +sudo systemctl status barycenter + +# Logs +sudo journalctl -u barycenter -f + +# Restart +sudo systemctl restart barycenter +``` + +--- + +## FreeBSD + +### Installation + +See detailed instructions in [`deploy/freebsd/README.md`](deploy/freebsd/README.md). + +**Quick steps:** + +1. Build and install: +```bash +cargo build --release +sudo install -m 755 target/release/barycenter /usr/local/bin/ +``` + +2. Create user and directories: +```bash +sudo pw useradd barycenter -d /var/db/barycenter -s /usr/sbin/nologin +sudo mkdir -p /usr/local/etc/barycenter /var/db/barycenter/data +sudo chown -R barycenter:barycenter /var/db/barycenter +``` + +3. Install configuration: +```bash +sudo cp config.toml /usr/local/etc/barycenter/ +# Edit /usr/local/etc/barycenter/config.toml +``` + +4. Install and enable service: +```bash +sudo install -m 755 deploy/freebsd/barycenter /usr/local/etc/rc.d/ +echo 'barycenter_enable="YES"' | sudo tee -a /etc/rc.conf +sudo service barycenter start +``` + +--- + +## illumos/Solaris + +### Installation + +See detailed instructions in [`deploy/illumos/README.md`](deploy/illumos/README.md). + +**Quick steps:** + +1. Build and install: +```bash +cargo build --release +sudo mkdir -p /opt/barycenter/bin +sudo cp target/release/barycenter /opt/barycenter/bin/ +``` + +2. Create user and directories: +```bash +sudo useradd -d /var/barycenter -s /usr/bin/false barycenter +sudo mkdir -p /etc/barycenter /var/barycenter/data +sudo chown -R barycenter:barycenter /var/barycenter +``` + +3. Install configuration: +```bash +sudo cp config.toml /etc/barycenter/ +# Edit /etc/barycenter/config.toml +``` + +4. Import and enable SMF service: +```bash +sudo svccfg import deploy/illumos/barycenter.xml +sudo svcadm enable barycenter +``` + +--- + +## Configuration + +### Environment Variables + +All configuration can be overridden using environment variables with the `CRABIDP__` prefix: + +```bash +# Override server settings +export CRABIDP__SERVER__PORT=9090 +export CRABIDP__SERVER__PUBLIC_BASE_URL=https://idp.example.com + +# Override database +export CRABIDP__DATABASE__URL=sqlite:///custom/path/db.sqlite + +# Set logging +export RUST_LOG=debug +``` + +### Configuration File + +The `config.toml` file structure: + +```toml +[server] +host = "0.0.0.0" +port = 8080 +public_base_url = "https://idp.example.com" # Required in production + +[database] +url = "sqlite://crabidp.db?mode=rwc" + +[keys] +jwks_path = "data/jwks.json" +private_key_path = "data/private_key.pem" +alg = "RS256" + +[federation] +trust_anchors = [] +``` + +### Production Checklist + +- [ ] Set `public_base_url` to your actual domain +- [ ] Use HTTPS/TLS (via reverse proxy or ingress) +- [ ] Configure proper logging (`RUST_LOG=info`) +- [ ] Set up persistent storage for database and keys +- [ ] Configure backups for database and private keys +- [ ] Set appropriate file permissions (600 for keys, 640 for config) +- [ ] Run as non-root user +- [ ] Configure firewall rules +- [ ] Set up monitoring and health checks +- [ ] Review and apply security hardening settings + +--- + +## Security Considerations + +### TLS/HTTPS + +Barycenter should always run behind a TLS-terminating reverse proxy or load balancer in production. Never expose it directly on HTTP. + +**Options:** +- **Kubernetes:** Use Ingress with cert-manager for automatic TLS +- **Linux:** Use nginx, Caddy, or Traefik as reverse proxy +- **Cloud:** Use cloud load balancers (ALB, GCE LB, etc.) + +### Reverse Proxy Example (nginx) + +```nginx +server { + listen 443 ssl http2; + server_name idp.example.com; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + location / { + proxy_pass http://localhost:8080; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +### File Permissions + +```bash +# Configuration (readable by service, writable by root) +chmod 640 /etc/barycenter/config.toml +chown root:barycenter /etc/barycenter/config.toml + +# Private key (readable only by service) +chmod 600 /var/lib/barycenter/data/private_key.pem +chown barycenter:barycenter /var/lib/barycenter/data/private_key.pem + +# Data directory +chmod 750 /var/lib/barycenter +chown barycenter:barycenter /var/lib/barycenter +``` + +### Backup Strategy + +**Critical files to backup:** +1. Private RSA key (`private_key.pem`) +2. Database (`crabidp.db`) +3. Configuration (`config.toml`) + +**Backup script example:** + +```bash +#!/bin/bash +BACKUP_DIR=/backup/barycenter/$(date +%Y%m%d) +mkdir -p $BACKUP_DIR + +# Backup database +sqlite3 /var/lib/barycenter/crabidp.db ".backup '$BACKUP_DIR/crabidp.db'" + +# Backup keys and config +cp /var/lib/barycenter/data/private_key.pem $BACKUP_DIR/ +cp /etc/barycenter/config.toml $BACKUP_DIR/ + +# Encrypt and upload to remote storage +tar czf - $BACKUP_DIR | gpg -e -r admin@example.com | \ + aws s3 cp - s3://backups/barycenter-$(date +%Y%m%d).tar.gz.gpg +``` + +### Monitoring + +**Health check endpoint:** +```bash +curl http://localhost:8080/.well-known/openid-configuration +``` + +**Metrics to monitor:** +- HTTP response times +- Error rates (4xx, 5xx) +- Database connection status +- Disk usage (for SQLite file) +- Memory/CPU usage + +--- + +## Support + +For issues and questions: +- GitHub Issues: https://github.com/yourusername/barycenter/issues +- Documentation: See `README.md` and `CLAUDE.md` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..00deea3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,56 @@ +# Multi-stage build for Barycenter OpenID Connect IdP +# Build stage +FROM rust:1.83-bookworm AS builder + +WORKDIR /build + +# Copy manifests +COPY Cargo.toml Cargo.lock ./ + +# Copy source code +COPY src ./src + +# Build release binary +RUN --mount=type=cache,target=/usr/local/cargo/registry \ + --mount=type=cache,target=/build/target \ + cargo build --release && \ + cp target/release/barycenter /barycenter + +# Runtime stage +FROM debian:bookworm-slim + +# Install runtime dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Create non-root user +RUN useradd -r -u 1000 -s /bin/false barycenter && \ + mkdir -p /app/data /app/config && \ + chown -R barycenter:barycenter /app + +WORKDIR /app + +# Copy binary from builder +COPY --from=builder /barycenter /usr/local/bin/barycenter + +# Copy default configuration +COPY config.toml /app/config/config.toml + +# Set ownership +RUN chown -R barycenter:barycenter /app + +# Switch to non-root user +USER barycenter + +# Expose default port +EXPOSE 8080 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD ["/bin/sh", "-c", "test -f /proc/self/exe || exit 1"] + +# Default command +ENTRYPOINT ["/usr/local/bin/barycenter"] +CMD ["--config", "/app/config/config.toml"] diff --git a/deploy/freebsd/README.md b/deploy/freebsd/README.md new file mode 100644 index 0000000..7da7610 --- /dev/null +++ b/deploy/freebsd/README.md @@ -0,0 +1,108 @@ +# FreeBSD Deployment + +This directory contains rc.d script for running Barycenter on FreeBSD systems. + +## Installation + +1. **Install Rust and build the binary:** + ```bash + pkg install rust + cargo build --release + ``` + +2. **Create the barycenter user:** + ```bash + pw useradd barycenter -d /var/db/barycenter -s /usr/sbin/nologin -c "Barycenter IdP" + ``` + +3. **Create required directories:** + ```bash + mkdir -p /usr/local/etc/barycenter + mkdir -p /var/db/barycenter/data + chown -R barycenter:barycenter /var/db/barycenter + ``` + +4. **Install the binary:** + ```bash + install -m 755 target/release/barycenter /usr/local/bin/ + ``` + +5. **Install the configuration:** + ```bash + cp config.toml /usr/local/etc/barycenter/config.toml + chown root:barycenter /usr/local/etc/barycenter/config.toml + chmod 640 /usr/local/etc/barycenter/config.toml + ``` + + Edit `/usr/local/etc/barycenter/config.toml` and update paths: + ```toml + [database] + url = "sqlite:///var/db/barycenter/crabidp.db?mode=rwc" + + [keys] + jwks_path = "/var/db/barycenter/data/jwks.json" + private_key_path = "/var/db/barycenter/data/private_key.pem" + ``` + +6. **Install the rc.d script:** + ```bash + install -m 755 deploy/freebsd/barycenter /usr/local/etc/rc.d/ + ``` + +7. **Enable the service in /etc/rc.conf:** + ```bash + echo 'barycenter_enable="YES"' >> /etc/rc.conf + ``` + + Optional configuration: + ```bash + echo 'barycenter_config="/usr/local/etc/barycenter/config.toml"' >> /etc/rc.conf + echo 'barycenter_env="RUST_LOG=info"' >> /etc/rc.conf + ``` + +8. **Start the service:** + ```bash + service barycenter start + ``` + +## Management + +**Check status:** +```bash +service barycenter status +``` + +**View logs:** +```bash +tail -f /var/log/messages | grep barycenter +``` + +**Restart service:** +```bash +service barycenter restart +``` + +**Stop service:** +```bash +service barycenter stop +``` + +## Configuration Options + +All configuration options are set in `/etc/rc.conf`: + +- `barycenter_enable` - Enable/disable the service (YES/NO) +- `barycenter_user` - User to run as (default: barycenter) +- `barycenter_group` - Group to run as (default: barycenter) +- `barycenter_config` - Path to config file +- `barycenter_env` - Environment variables (e.g., "RUST_LOG=debug") + +## Logging + +By default, output goes to syslog. To configure separate log file, update newsyslog: + +```bash +echo "/var/log/barycenter.log barycenter:barycenter 644 7 * @T00 JC" >> /etc/newsyslog.conf +touch /var/log/barycenter.log +chown barycenter:barycenter /var/log/barycenter.log +``` diff --git a/deploy/freebsd/barycenter b/deploy/freebsd/barycenter new file mode 100644 index 0000000..fe6037e --- /dev/null +++ b/deploy/freebsd/barycenter @@ -0,0 +1,59 @@ +#!/bin/sh +# +# PROVIDE: barycenter +# REQUIRE: NETWORKING DAEMON +# KEYWORD: shutdown +# +# Add the following lines to /etc/rc.conf to enable barycenter: +# +# barycenter_enable="YES" +# barycenter_config="/usr/local/etc/barycenter/config.toml" # optional +# barycenter_user="barycenter" # optional +# barycenter_group="barycenter" # optional +# barycenter_env="RUST_LOG=info" # optional + +. /etc/rc.subr + +name="barycenter" +rcvar=barycenter_enable + +load_rc_config $name + +: ${barycenter_enable:="NO"} +: ${barycenter_user:="barycenter"} +: ${barycenter_group:="barycenter"} +: ${barycenter_config:="/usr/local/etc/barycenter/config.toml"} +: ${barycenter_env:=""} + +pidfile="/var/run/${name}.pid" +command="/usr/local/bin/barycenter" +command_args="--config ${barycenter_config}" + +# Daemon management +barycenter_start_precmd() +{ + # Check if binary exists + if [ ! -x "${command}" ]; then + err 1 "${command} not found or not executable" + fi + + # Check if config exists + if [ ! -f "${barycenter_config}" ]; then + err 1 "Config file ${barycenter_config} not found" + fi + + # Ensure data directory exists + if [ ! -d "/var/db/barycenter" ]; then + mkdir -p /var/db/barycenter + chown ${barycenter_user}:${barycenter_group} /var/db/barycenter + fi +} + +start_precmd="barycenter_start_precmd" + +# Use daemon to run in background +command_interpreter="/usr/sbin/daemon" +command="/usr/sbin/daemon" +command_args="-f -p ${pidfile} -u ${barycenter_user} ${barycenter_env:+-o ${barycenter_env}} /usr/local/bin/barycenter --config ${barycenter_config}" + +run_rc_command "$1" diff --git a/deploy/helm/barycenter/.helmignore b/deploy/helm/barycenter/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/deploy/helm/barycenter/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/deploy/helm/barycenter/Chart.yaml b/deploy/helm/barycenter/Chart.yaml new file mode 100644 index 0000000..ba7f2bf --- /dev/null +++ b/deploy/helm/barycenter/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +name: barycenter +description: OpenID Connect Identity Provider with federation and auto-registration +type: application +version: 0.1.0 +appVersion: "0.1.0" +keywords: + - openid + - oauth2 + - identity + - authentication + - idp +home: https://github.com/yourusername/barycenter +sources: + - https://github.com/yourusername/barycenter +maintainers: + - name: Barycenter Team diff --git a/deploy/helm/barycenter/templates/NOTES.txt b/deploy/helm/barycenter/templates/NOTES.txt new file mode 100644 index 0000000..116b32b --- /dev/null +++ b/deploy/helm/barycenter/templates/NOTES.txt @@ -0,0 +1,36 @@ +Thank you for installing {{ .Chart.Name }}! + +Your Barycenter OpenID Connect Identity Provider has been deployed. + +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "barycenter.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "barycenter.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "barycenter.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "barycenter.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} + +2. Check the OpenID configuration: + curl http://YOUR_URL/.well-known/openid-configuration + +3. To register a client: + curl -X POST http://YOUR_URL/connect/register \ + -H "Content-Type: application/json" \ + -d '{"redirect_uris": ["http://localhost:3000/callback"]}' + +For more information, visit the documentation. diff --git a/deploy/helm/barycenter/templates/_helpers.tpl b/deploy/helm/barycenter/templates/_helpers.tpl new file mode 100644 index 0000000..f270fa4 --- /dev/null +++ b/deploy/helm/barycenter/templates/_helpers.tpl @@ -0,0 +1,60 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "barycenter.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "barycenter.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "barycenter.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "barycenter.labels" -}} +helm.sh/chart: {{ include "barycenter.chart" . }} +{{ include "barycenter.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "barycenter.selectorLabels" -}} +app.kubernetes.io/name: {{ include "barycenter.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "barycenter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "barycenter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/deploy/helm/barycenter/templates/configmap.yaml b/deploy/helm/barycenter/templates/configmap.yaml new file mode 100644 index 0000000..89d72d8 --- /dev/null +++ b/deploy/helm/barycenter/templates/configmap.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "barycenter.fullname" . }} + labels: + {{- include "barycenter.labels" . | nindent 4 }} +data: + config.toml: | + [server] + host = {{ .Values.config.server.host | quote }} + port = {{ .Values.config.server.port }} + {{- if .Values.config.server.publicBaseUrl }} + public_base_url = {{ .Values.config.server.publicBaseUrl | quote }} + {{- end }} + + [database] + url = {{ .Values.config.database.url | quote }} + + [keys] + jwks_path = {{ .Values.config.keys.jwksPath | quote }} + private_key_path = {{ .Values.config.keys.privateKeyPath | quote }} + alg = {{ .Values.config.keys.alg | quote }} + + [federation] + trust_anchors = {{ .Values.config.federation.trustAnchors | toJson }} diff --git a/deploy/helm/barycenter/templates/deployment.yaml b/deploy/helm/barycenter/templates/deployment.yaml new file mode 100644 index 0000000..537a4bb --- /dev/null +++ b/deploy/helm/barycenter/templates/deployment.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "barycenter.fullname" . }} + labels: + {{- include "barycenter.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: Recreate # Use Recreate for SQLite (single writer) + selector: + matchLabels: + {{- include "barycenter.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "barycenter.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "barycenter.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.config.server.port }} + protocol: TCP + env: + {{- range .Values.env }} + - name: {{ .name }} + value: {{ .value | quote }} + {{- end }} + volumeMounts: + - name: config + mountPath: /app/config + readOnly: true + {{- if .Values.persistence.enabled }} + - name: data + mountPath: /app/data + {{- end }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 10 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 10 }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + volumes: + - name: config + configMap: + name: {{ include "barycenter.fullname" . }} + {{- if .Values.persistence.enabled }} + - name: data + persistentVolumeClaim: + claimName: {{ include "barycenter.fullname" . }}-data + {{- else }} + - name: data + emptyDir: {} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/deploy/helm/barycenter/templates/hpa.yaml b/deploy/helm/barycenter/templates/hpa.yaml new file mode 100644 index 0000000..61da975 --- /dev/null +++ b/deploy/helm/barycenter/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "barycenter.fullname" . }} + labels: + {{- include "barycenter.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "barycenter.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/deploy/helm/barycenter/templates/ingress.yaml b/deploy/helm/barycenter/templates/ingress.yaml new file mode 100644 index 0000000..6f50ca3 --- /dev/null +++ b/deploy/helm/barycenter/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "barycenter.fullname" . }} + labels: + {{- include "barycenter.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "barycenter.fullname" $ }} + port: + name: http + {{- end }} + {{- end }} +{{- end }} diff --git a/deploy/helm/barycenter/templates/pvc.yaml b/deploy/helm/barycenter/templates/pvc.yaml new file mode 100644 index 0000000..958a778 --- /dev/null +++ b/deploy/helm/barycenter/templates/pvc.yaml @@ -0,0 +1,21 @@ +{{- if .Values.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "barycenter.fullname" . }}-data + labels: + {{- include "barycenter.labels" . | nindent 4 }} + {{- with .Values.persistence.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + - {{ .Values.persistence.accessMode }} + {{- if .Values.persistence.storageClass }} + storageClassName: {{ .Values.persistence.storageClass | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size }} +{{- end }} diff --git a/deploy/helm/barycenter/templates/service.yaml b/deploy/helm/barycenter/templates/service.yaml new file mode 100644 index 0000000..8dfeaad --- /dev/null +++ b/deploy/helm/barycenter/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "barycenter.fullname" . }} + labels: + {{- include "barycenter.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "barycenter.selectorLabels" . | nindent 4 }} diff --git a/deploy/helm/barycenter/templates/serviceaccount.yaml b/deploy/helm/barycenter/templates/serviceaccount.yaml new file mode 100644 index 0000000..c4611dd --- /dev/null +++ b/deploy/helm/barycenter/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "barycenter.serviceAccountName" . }} + labels: + {{- include "barycenter.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/deploy/helm/barycenter/values.yaml b/deploy/helm/barycenter/values.yaml new file mode 100644 index 0000000..d1b8495 --- /dev/null +++ b/deploy/helm/barycenter/values.yaml @@ -0,0 +1,131 @@ +# Default values for barycenter Helm chart + +replicaCount: 1 + +image: + repository: barycenter + pullPolicy: IfNotPresent + tag: "latest" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: true + annotations: {} + name: "" + +podAnnotations: {} + +podSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 + seccompProfile: + type: RuntimeDefault + +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 1000 + capabilities: + drop: + - ALL + +service: + type: ClusterIP + port: 8080 + annotations: {} + +ingress: + enabled: false + className: "nginx" + annotations: {} + # cert-manager.io/cluster-issuer: letsencrypt-prod + # nginx.ingress.kubernetes.io/ssl-redirect: "true" + hosts: + - host: idp.example.com + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: barycenter-tls + # hosts: + # - idp.example.com + +resources: + limits: + cpu: 1000m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# Barycenter-specific configuration +config: + server: + host: "0.0.0.0" + port: 8080 + # publicBaseUrl: "https://idp.example.com" + + database: + url: "sqlite:///app/data/crabidp.db?mode=rwc" + + keys: + jwksPath: "/app/data/jwks.json" + privateKeyPath: "/app/data/private_key.pem" + alg: "RS256" + + federation: + trustAnchors: [] + +# Environment variables +env: + - name: RUST_LOG + value: "info" + # Add additional environment variables here + # - name: CRABIDP__SERVER__PUBLIC_BASE_URL + # value: "https://idp.example.com" + +# Persistence for database and keys +persistence: + enabled: true + # storageClass: "" + accessMode: ReadWriteOnce + size: 10Gi + annotations: {} + +# Liveness probe configuration +livenessProbe: + httpGet: + path: /.well-known/openid-configuration + port: http + initialDelaySeconds: 10 + periodSeconds: 30 + timeoutSeconds: 3 + failureThreshold: 3 + +# Readiness probe configuration +readinessProbe: + httpGet: + path: /.well-known/openid-configuration + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 3 + failureThreshold: 3 diff --git a/deploy/illumos/README.md b/deploy/illumos/README.md new file mode 100644 index 0000000..3dffe5a --- /dev/null +++ b/deploy/illumos/README.md @@ -0,0 +1,150 @@ +# illumos/Solaris Deployment + +This directory contains SMF (Service Management Facility) manifest for running Barycenter on illumos and Solaris systems. + +## Installation + +1. **Install Rust and build the binary:** + ```bash + # On OmniOS/OpenIndiana, install rust from pkgsrc + pkg install rust + cargo build --release + ``` + +2. **Create the barycenter user:** + ```bash + useradd -d /var/barycenter -s /usr/bin/false -c "Barycenter IdP" barycenter + ``` + +3. **Create required directories:** + ```bash + mkdir -p /opt/barycenter/bin + mkdir -p /etc/barycenter + mkdir -p /var/barycenter/data + chown -R barycenter:barycenter /var/barycenter + ``` + +4. **Install the binary:** + ```bash + cp target/release/barycenter /opt/barycenter/bin/ + chmod 755 /opt/barycenter/bin/barycenter + ``` + +5. **Install the configuration:** + ```bash + cp config.toml /etc/barycenter/config.toml + chown root:barycenter /etc/barycenter/config.toml + chmod 640 /etc/barycenter/config.toml + ``` + + Edit `/etc/barycenter/config.toml` and update paths: + ```toml + [database] + url = "sqlite:///var/barycenter/crabidp.db?mode=rwc" + + [keys] + jwks_path = "/var/barycenter/data/jwks.json" + private_key_path = "/var/barycenter/data/private_key.pem" + ``` + +6. **Import the SMF manifest:** + ```bash + svccfg import deploy/illumos/barycenter.xml + ``` + +7. **Enable the service:** + ```bash + svcadm enable barycenter + ``` + +## Management + +**Check status:** +```bash +svcs -l barycenter +``` + +**View logs:** +```bash +svcs -L barycenter # Show log file location +tail -f /var/svc/log/application-barycenter:default.log +``` + +**Restart service:** +```bash +svcadm restart barycenter +``` + +**Stop service:** +```bash +svcadm disable barycenter +``` + +**Clear maintenance state:** +```bash +svcadm clear barycenter +``` + +## Configuration + +### Modifying Service Properties + +To change the config file location: +```bash +svccfg -s barycenter setprop application/config_file = /custom/path/config.toml +svcadm refresh barycenter +svcadm restart barycenter +``` + +To change the data directory: +```bash +svccfg -s barycenter setprop application/data_dir = /custom/data/dir +svcadm refresh barycenter +svcadm restart barycenter +``` + +### Environment Variables + +To set environment variables, edit the manifest and modify the `method_environment` section: + +```xml + + + + +``` + +Then reimport: +```bash +svccfg import deploy/illumos/barycenter.xml +svcadm refresh barycenter +svcadm restart barycenter +``` + +## Troubleshooting + +**Service won't start:** +```bash +# Check the service log +svcs -L barycenter +tail -50 /var/svc/log/application-barycenter:default.log + +# Check service state +svcs -x barycenter +``` + +**Permission issues:** +Ensure the barycenter user has write access to the data directory: +```bash +chown -R barycenter:barycenter /var/barycenter +chmod 755 /var/barycenter +``` + +## SMF Features + +SMF provides: +- Automatic restart on failure +- Dependency management +- Log file rotation +- Process contract management +- Property-based configuration diff --git a/deploy/illumos/barycenter.xml b/deploy/illumos/barycenter.xml new file mode 100644 index 0000000..dacf4c6 --- /dev/null +++ b/deploy/illumos/barycenter.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/deploy/systemd/README.md b/deploy/systemd/README.md new file mode 100644 index 0000000..2ca4b79 --- /dev/null +++ b/deploy/systemd/README.md @@ -0,0 +1,94 @@ +# systemd Deployment + +This directory contains systemd service files for running Barycenter on Linux systems. + +## Installation + +1. **Create the barycenter user:** + ```bash + sudo useradd -r -s /bin/false -d /var/lib/barycenter barycenter + ``` + +2. **Create required directories:** + ```bash + sudo mkdir -p /etc/barycenter /var/lib/barycenter/data + sudo chown -R barycenter:barycenter /var/lib/barycenter + ``` + +3. **Install the binary:** + ```bash + sudo cargo build --release + sudo cp target/release/barycenter /usr/local/bin/ + sudo chmod +x /usr/local/bin/barycenter + ``` + +4. **Install the configuration:** + ```bash + sudo cp config.toml /etc/barycenter/config.toml + sudo chown root:barycenter /etc/barycenter/config.toml + sudo chmod 640 /etc/barycenter/config.toml + ``` + + Edit `/etc/barycenter/config.toml` and update paths: + ```toml + [database] + url = "sqlite:///var/lib/barycenter/crabidp.db?mode=rwc" + + [keys] + jwks_path = "/var/lib/barycenter/data/jwks.json" + private_key_path = "/var/lib/barycenter/data/private_key.pem" + ``` + +5. **Install the systemd service:** + ```bash + sudo cp deploy/systemd/barycenter.service /etc/systemd/system/ + sudo systemctl daemon-reload + ``` + +6. **Enable and start the service:** + ```bash + sudo systemctl enable barycenter + sudo systemctl start barycenter + ``` + +## Management + +**Check status:** +```bash +sudo systemctl status barycenter +``` + +**View logs:** +```bash +sudo journalctl -u barycenter -f +``` + +**Restart service:** +```bash +sudo systemctl restart barycenter +``` + +**Stop service:** +```bash +sudo systemctl stop barycenter +``` + +## Security + +The service runs with extensive security hardening: +- Runs as non-root user +- Private /tmp directory +- Read-only filesystem (except data directory) +- System call filtering +- Memory protections +- No new privileges + +## Environment Variables + +You can override configuration using environment variables in the service file: + +```ini +[Service] +Environment="CRABIDP__SERVER__PUBLIC_BASE_URL=https://idp.example.com" +Environment="RUST_LOG=debug" +``` diff --git a/deploy/systemd/barycenter.service b/deploy/systemd/barycenter.service new file mode 100644 index 0000000..b3dc091 --- /dev/null +++ b/deploy/systemd/barycenter.service @@ -0,0 +1,55 @@ +[Unit] +Description=Barycenter OpenID Connect Identity Provider +Documentation=https://github.com/yourusername/barycenter +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=barycenter +Group=barycenter + +# Paths +WorkingDirectory=/var/lib/barycenter +ExecStart=/usr/local/bin/barycenter --config /etc/barycenter/config.toml + +# Security hardening +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths=/var/lib/barycenter +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +RestrictRealtime=true +RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX +LockPersonality=true +MemoryDenyWriteExecute=true +RestrictNamespaces=true +SystemCallFilter=@system-service +SystemCallErrorNumber=EPERM +SystemCallArchitectures=native + +# Resource limits +LimitNOFILE=65535 +LimitNPROC=512 + +# Logging +StandardOutput=journal +StandardError=journal +SyslogIdentifier=barycenter + +# Environment +Environment="RUST_LOG=info" +# Override config with environment variables: +# Environment="CRABIDP__SERVER__PUBLIC_BASE_URL=https://idp.example.com" + +# Restart policy +Restart=on-failure +RestartSec=5s +StartLimitInterval=60s +StartLimitBurst=3 + +[Install] +WantedBy=multi-user.target diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a8f5c62 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,59 @@ +version: '3.8' + +services: + barycenter: + build: + context: . + dockerfile: Dockerfile + image: barycenter:latest + container_name: barycenter + restart: unless-stopped + + ports: + - "8080:8080" + + environment: + # Override config via environment variables + # Use CRABIDP__ prefix with double underscores for nested keys + - RUST_LOG=info + # Example: CRABIDP__SERVER__PORT=8080 + # Example: CRABIDP__SERVER__PUBLIC_BASE_URL=https://idp.example.com + # Example: CRABIDP__DATABASE__URL=sqlite:///app/data/crabidp.db?mode=rwc + + volumes: + # Persist database and keys + - barycenter-data:/app/data + # Optional: override config file + # - ./config.toml:/app/config/config.toml:ro + + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/.well-known/openid-configuration"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 10s + + # Security options + security_opt: + - no-new-privileges:true + + # Read-only root filesystem (except data volume) + read_only: false + + # Drop all capabilities and add only required ones + cap_drop: + - ALL + + # Resource limits + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.25' + memory: 128M + +volumes: + barycenter-data: + driver: local