Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
783 changes: 783 additions & 0 deletions deploy/systemd/README.md

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions deploy/systemd/examples/10-spire-dependency.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## SPIRE Agent Dependency Drop-in
## Install this file to /etc/systemd/system/harbor-satellite.service.d/10-spire-dependency.conf
## when using SPIFFE authentication (join-token, x509pop, or sshpop methods)
##
## This creates a hard dependency on the SPIRE agent service:
## - Harbor Satellite will start only after SPIRE agent is running
## - Harbor Satellite requires SPIRE agent to be active
##
## After installing: sudo systemctl daemon-reload

[Unit]
# Start after SPIRE agent is ready
After=spire-agent.service

# Require SPIRE agent to be running
Requires=spire-agent.service

# Optional: Stop Harbor Satellite if SPIRE agent stops
# Uncomment the line below for joint lifecycle management
# BindsTo=spire-agent.service
24 changes: 24 additions & 0 deletions deploy/systemd/examples/20-cri-mirroring.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## CRI Mirroring Support Drop-in
## Install this file to /etc/systemd/system/harbor-satellite.service.d/20-cri-mirroring.conf
## ONLY if you need container runtime mirroring (--mirrors flag)
##
## WARNING: This drop-in significantly relaxes security restrictions
## - Grants CAP_SYS_ADMIN and CAP_DAC_OVERRIDE capabilities
## - Allows writing to CRI configuration directories
## - Permits systemctl access to restart Docker/containerd
##
## Only install if you are using the --mirrors flag for CRI configuration
## After installing: sudo systemctl daemon-reload

[Service]
# Grant filesystem write access for CRI config files
ReadWritePaths=/etc/docker /etc/containerd /etc/containers /etc/crio /run/systemd/system

# Grant capabilities needed for systemctl and config file manipulation
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE

# Disable private user namespace (systemctl needs root namespace)
PrivateUsers=no

# Allow privileged system calls needed for service management
SystemCallFilter=@system-service
15 changes: 15 additions & 0 deletions deploy/systemd/examples/30-mirrors-containerd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Containerd Mirroring Configuration
## Install this file to /etc/systemd/system/harbor-satellite.service.d/30-mirrors-containerd.conf
## to enable containerd registry mirroring
##
## PREREQUISITE: Install 20-cri-mirroring.conf first for required privileges
## After installing: sudo systemctl daemon-reload
##
## This configures containerd to mirror docker.io and quay.io through the local Zot registry
## Customize the --mirrors flag to match your registry requirements

[Service]
# Override ExecStart to add --mirrors flag
# Note: Must clear ExecStart first (empty ExecStart= line), then set new value
ExecStart=
ExecStart=/opt/harbor-satellite/satellite --mirrors=containerd:docker.io,quay.io
15 changes: 15 additions & 0 deletions deploy/systemd/examples/30-mirrors-docker.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Docker Mirroring Configuration
## Install this file to /etc/systemd/system/harbor-satellite.service.d/30-mirrors-docker.conf
## to enable Docker registry mirroring
##
## PREREQUISITE: Install 20-cri-mirroring.conf first for required privileges
## After installing: sudo systemctl daemon-reload
##
## NOTE: Docker only supports mirroring docker.io (Docker Hub)
## Use --mirrors=docker:true to enable

[Service]
# Override ExecStart to add --mirrors flag for Docker
# Note: Must clear ExecStart first (empty ExecStart= line), then set new value
ExecStart=
ExecStart=/opt/harbor-satellite/satellite --mirrors=docker:true
15 changes: 15 additions & 0 deletions deploy/systemd/examples/30-mirrors-podman.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Podman Mirroring Configuration
## Install this file to /etc/systemd/system/harbor-satellite.service.d/30-mirrors-podman.conf
## to enable Podman registry mirroring
##
## PREREQUISITE: Install 20-cri-mirroring.conf first for required privileges
## After installing: sudo systemctl daemon-reload
##
## This configures Podman to mirror docker.io through the local Zot registry
## Customize the --mirrors flag to match your registry requirements

[Service]
# Override ExecStart to add --mirrors flag for Podman
# Note: Must clear ExecStart first (empty ExecStart= line), then set new value
ExecStart=
ExecStart=/opt/harbor-satellite/satellite --mirrors=podman:docker.io
57 changes: 57 additions & 0 deletions deploy/systemd/examples/satellite.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Harbor Satellite Environment Configuration
## Copy this file to /etc/harbor-satellite/satellite.env and customize

## REQUIRED: Ground Control URL
## The URL of the Harbor Satellite Ground Control server
GROUND_CONTROL_URL=https://ground-control.example.com:8080

## REQUIRED (unless SPIFFE enabled): Satellite Token
## Authentication token for this satellite instance
## Leave empty if using SPIFFE authentication
TOKEN=your-satellite-token-here

## Optional: Use insecure HTTP connections (development only)
## Set to 'true' to disable TLS verification for registry connections
## Default: false (use HTTPS with TLS verification)
# USE_UNSECURE=false

## Optional: Enable JSON logging
## Set to 'false' for human-readable console logging
## Default: true
# JSON_LOGGING=true

## SPIFFE/SPIRE Authentication Configuration
## Enable these settings to use SPIFFE-based zero-trust authentication
## instead of token-based auth

## Enable SPIFFE authentication
## Set to 'true' to use SPIFFE Workload API for mTLS authentication
## When enabled, TOKEN is not required
# SPIFFE_ENABLED=false

## SPIFFE Workload API endpoint socket
## Path to the SPIRE agent socket
## Default: unix:///run/spire/sockets/agent.sock
# SPIFFE_ENDPOINT_SOCKET=unix:///run/spire/sockets/agent.sock

## Expected SPIFFE ID of Ground Control server
## Used to verify the identity of the Ground Control server
## Example: spiffe://harbor-satellite.local/gc/main
# SPIFFE_EXPECTED_SERVER_ID=spiffe://your-trust-domain/ground-control

## NOTE: CRI Mirroring Configuration
## The --mirrors flag is NOT supported via environment variables
## To enable container runtime mirroring:
## 1. Install the 20-cri-mirroring.conf drop-in (see README)
## 2. Create a 30-mirrors.conf drop-in to override ExecStart with --mirrors flags
## Example: ExecStart=/opt/harbor-satellite/satellite --mirrors=containerd:docker.io,quay.io
Comment on lines +42 to +47
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Minor: drop-in filename in comment doesn't match actual example filenames.

Line 46 references 30-mirrors.conf, but the actual example files in this PR are named 30-mirrors-containerd.conf, 30-mirrors-docker.conf, and 30-mirrors-podman.conf. Consider updating the reference to avoid confusion.

Suggested fix
-## 2. Create a 30-mirrors.conf drop-in to override ExecStart with --mirrors flags
-## Example: ExecStart=/opt/harbor-satellite/satellite --mirrors=containerd:docker.io,quay.io
+## 2. Install a 30-mirrors-<runtime>.conf drop-in to override ExecStart with --mirrors flags
+## See examples: 30-mirrors-containerd.conf, 30-mirrors-docker.conf, 30-mirrors-podman.conf
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## NOTE: CRI Mirroring Configuration
## The --mirrors flag is NOT supported via environment variables
## To enable container runtime mirroring:
## 1. Install the 20-cri-mirroring.conf drop-in (see README)
## 2. Create a 30-mirrors.conf drop-in to override ExecStart with --mirrors flags
## Example: ExecStart=/opt/harbor-satellite/satellite --mirrors=containerd:docker.io,quay.io
## NOTE: CRI Mirroring Configuration
## The --mirrors flag is NOT supported via environment variables
## To enable container runtime mirroring:
## 1. Install the 20-cri-mirroring.conf drop-in (see README)
## 2. Install a 30-mirrors-<runtime>.conf drop-in to override ExecStart with --mirrors flags
## See examples: 30-mirrors-containerd.conf, 30-mirrors-docker.conf, 30-mirrors-podman.conf
🤖 Prompt for AI Agents
In `@deploy/systemd/examples/satellite.env.example` around lines 42 - 47, Update
the comment block in deploy/systemd/examples/satellite.env.example that
references the drop-in filename: instead of saying "Create a 30-mirrors.conf
drop-in" update the text and the ExecStart example to reference the actual
example filenames (e.g., 30-mirrors-containerd.conf, 30-mirrors-docker.conf,
30-mirrors-podman.conf) so the note and the ExecStart example match the provided
drop-in files and avoid confusion when following the instructions.


## Additional Runtime Configuration
## The following settings are managed in config.json after first run:
## - State replication interval
## - Registration interval (heartbeat)
## - Zot registry configuration (port, storage, logging)
## - Log level
## - TLS certificates
##
## See config.example.json for runtime configuration options
33 changes: 33 additions & 0 deletions deploy/systemd/examples/spiffe-jointoken.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## SPIFFE Join Token Authentication (Method 2)
## Zero-touch provisioning using SPIRE agent with join token attestation
##
## Prerequisites:
## - SPIRE agent installed and running (spire-agent.service)
## - Join token generated and configured in SPIRE agent
## - Install 10-spire-dependency.conf drop-in for service dependency
##
## Use this for:
## - Zero-touch provisioning of new edge devices
## - Initial fleet deployment scenarios
## - Environments where devices can be pre-registered with join tokens
##
## Security: mTLS via SPIFFE SVIDs with automatic rotation

## REQUIRED: Ground Control URL
GROUND_CONTROL_URL=https://ground-control.example.com:8080

## REQUIRED: Enable SPIFFE authentication
SPIFFE_ENABLED=true

## SPIFFE Workload API socket (default: unix:///run/spire/sockets/agent.sock)
SPIFFE_ENDPOINT_SOCKET=unix:///run/spire/sockets/agent.sock

## REQUIRED: Expected SPIFFE ID of Ground Control server
## This must match the SPIFFE ID presented by Ground Control
SPIFFE_EXPECTED_SERVER_ID=spiffe://harbor-satellite.local/gc/main

## Token not required when SPIFFE is enabled
# TOKEN is not needed

## Optional: Logging
# JSON_LOGGING=true
34 changes: 34 additions & 0 deletions deploy/systemd/examples/spiffe-sshpop.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## SPIFFE SSH Proof-of-Possession Authentication (Method 4)
## SSH certificate-based identity using SPIRE agent with sshpop attestation
##
## Prerequisites:
## - SPIRE agent installed and running (spire-agent.service)
## - SSH CA infrastructure configured
## - SSH certificates provisioned on device
## - SPIRE agent configured for sshpop attestation
## - Install 10-spire-dependency.conf drop-in for service dependency
##
## Use this for:
## - Environments with existing SSH PKI infrastructure
## - Organizations already managing SSH certificates at scale
## - Integration with SSH-based access control systems
##
## Security: SSH certificate-based identity with mTLS and SPIFFE SVIDs

## REQUIRED: Ground Control URL
GROUND_CONTROL_URL=https://ground-control.example.com:8080

## REQUIRED: Enable SPIFFE authentication
SPIFFE_ENABLED=true

## SPIFFE Workload API socket (default: unix:///run/spire/sockets/agent.sock)
SPIFFE_ENDPOINT_SOCKET=unix:///run/spire/sockets/agent.sock

## REQUIRED: Expected SPIFFE ID of Ground Control server
SPIFFE_EXPECTED_SERVER_ID=spiffe://harbor-satellite.local/gc/main

## Token not required when SPIFFE is enabled
# TOKEN is not needed

## Optional: Logging
# JSON_LOGGING=true
33 changes: 33 additions & 0 deletions deploy/systemd/examples/spiffe-x509pop.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## SPIFFE X.509 Proof-of-Possession Authentication (Method 3)
## Hardware-bound identity using SPIRE agent with x509pop attestation
##
## Prerequisites:
## - SPIRE agent installed and running (spire-agent.service)
## - X.509 certificates pre-provisioned on device (manufacturing/bootstrap)
## - SPIRE agent configured for x509pop attestation
## - Install 10-spire-dependency.conf drop-in for service dependency
##
## Use this for:
## - Pre-provisioned hardware with embedded certificates
## - Manufacturing environments where devices receive certs during production
## - High-security deployments requiring hardware-bound identity
##
## Security: Hardware-bound identity with mTLS and SPIFFE SVIDs

## REQUIRED: Ground Control URL
GROUND_CONTROL_URL=https://ground-control.example.com:8080

## REQUIRED: Enable SPIFFE authentication
SPIFFE_ENABLED=true

## SPIFFE Workload API socket (default: unix:///run/spire/sockets/agent.sock)
SPIFFE_ENDPOINT_SOCKET=unix:///run/spire/sockets/agent.sock

## REQUIRED: Expected SPIFFE ID of Ground Control server
SPIFFE_EXPECTED_SERVER_ID=spiffe://harbor-satellite.local/gc/main

## Token not required when SPIFFE is enabled
# TOKEN is not needed

## Optional: Logging
# JSON_LOGGING=true
21 changes: 21 additions & 0 deletions deploy/systemd/examples/token-auth.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Token-Based Authentication (Method 1)
## Simple authentication using a bearer token
##
## Use this for:
## - Development and testing environments
## - Simple deployments without SPIFFE infrastructure
## - Quick proof-of-concept setups
##
## Security: Basic bearer token authentication, no mTLS

## REQUIRED: Ground Control URL
GROUND_CONTROL_URL=https://ground-control.example.com:8080

## REQUIRED: Satellite authentication token
TOKEN=your-satellite-token-here

## Optional: Use HTTP for development (insecure)
# USE_UNSECURE=true

## Optional: Enable human-readable logging
# JSON_LOGGING=false
76 changes: 76 additions & 0 deletions deploy/systemd/harbor-satellite.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
[Unit]
Description=Harbor Satellite - Edge Registry Fleet Management
Documentation=https://github.com/goharbor/harbor-satellite
After=network-online.target
Wants=network-online.target
StartLimitBurst=5
StartLimitIntervalSec=300

[Service]
Type=exec
User=harbor-satellite
Group=harbor-satellite
WorkingDirectory=/var/lib/harbor-satellite

# Binary and configuration
ExecStart=/opt/harbor-satellite/satellite
EnvironmentFile=/etc/harbor-satellite/satellite.env

# Restart policy
Restart=on-failure
RestartSec=10s

# Signal handling - Go app handles SIGTERM for graceful shutdown
KillSignal=SIGTERM
TimeoutStopSec=30s
KillMode=mixed

# Logging - Go binary logs to stderr
StandardOutput=journal
StandardError=journal
SyslogIdentifier=harbor-satellite

# Security Hardening - Strict defaults
# Filesystem protection
ProtectSystem=strict
ReadWritePaths=/var/lib/harbor-satellite
ProtectHome=true
PrivateTmp=true
NoNewPrivileges=true

# User namespace isolation
PrivateUsers=yes

# System call filtering
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources @mount
SystemCallErrorNumber=EPERM

# No capabilities needed for base service (no CRI mirroring)
CapabilityBoundingSet=

# Memory protection - Safe for statically compiled Go binaries (CGO_ENABLED=0)
MemoryDenyWriteExecute=true

# Additional hardening
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
PrivateDevices=true
ProtectClock=true
ProtectProc=invisible
ProcSubset=pid

# Resource limits (optional - adjust as needed)
# LimitNOFILE=65536
# MemoryMax=2G
# CPUQuota=200%

[Install]
WantedBy=multi-user.target
Loading