Installation

This guide covers how to install and set up Inmor Trust Anchor for development and production use.

Prerequisites

  • Docker and Docker Compose

  • Git

  • just command runner (optional but recommended)

  • uv for Python dependency management (for local development)

Installing just

just is a task runner similar to make. Install it using your package manager:

# macOS
brew install just

# Ubuntu/Debian
sudo apt install just

# Arch Linux
sudo pacman -S just

# Using cargo
cargo install just

Quick Installation

  1. Clone the repository:

    git clone https://github.com/SUNET/inmor.git
    cd inmor
    

    The repository includes development signing keys, so no key generation is needed to get started.

  2. Build the Docker images:

    just build
    
  3. Build binaries:

    just build-rs
    
  4. Start all services:

    just up
    
  5. Initialize the Trust Anchor:

    # Create the entity configuration
    curl -X POST http://localhost:8000/api/v1/server/entity
    
    # Create historical keys JWT (if you have any)
    curl -X POST http://localhost:8000/api/v1/server/historical_keys
    

The Trust Anchor is now running at http://localhost:8080 and the Admin API at http://localhost:8000.

Note

For production deployments, you should generate your own signing keys. See the Key Generation section below.

Docker Compose Files

The project has two Docker Compose configurations:

  • docker-compose.ymlProduction configuration. Uses baked-in Docker image code, release builds, granian, named volumes, and only exposes the TA port.

  • dev/docker-compose.dev.ymlDevelopment configuration. Mounts source code for live reloading, uses debug builds, exposes all ports, and uses trust auth for PostgreSQL.

The just commands automatically use the development compose file. To use the production configuration directly:

docker compose up -d

Key Generation

The repository includes development signing keys that are ready to use. These keys are sufficient for development and testing.

For production deployments, you should generate your own keys:

# Remove existing development keys
just clean

# Generate new keys for production
just dev

Inmor generates multiple key types for signing operations, following RFC 9864 Section 2:

  • RSA keys (RS256, PS256) - 2048 bit

  • EC keys (ES256, ES384, ES512) - P-256, P-384, P-521 curves

  • Edwards curve keys (Ed25519, Ed448)

Each key is stored as a JWK JSON file with the key ID (kid) as the thumbprint.

Warning

Regenerating keys will invalidate all existing entity statements and trust marks. Make sure to backup and properly rotate keys in production.

For a production server that only has the Docker image and not this source tree, generate the signing key with the bundled inmor-keygeneration binary instead. See Generating the Signing Key in the deployment guide.

Directory Structure

After installation, your directory structure should look like:

inmor/
├── publickeys/           # Public keys (JWK format)
│   └── *.json
├── privatekeys/          # Private keys (JWK format)
│   └── *.json
├── historical_keys/      # Expired/rotated keys
│   └── *.json
├── private.json          # TA primary signing key
├── admin/
│   └── private.json      # Admin signing key
├── dev/                  # Development files
│   ├── docker-compose.dev.yml
│   ├── rootCA.pem        # Dev root CA certificate
│   ├── localhost+2.pem   # Dev TLS certificate
│   └── localhost+2-key.pem
├── taconfig.toml         # TA configuration
└── docker-compose.yml    # Production compose

Verifying Installation

  1. Check that all containers are running:

    docker compose ps
    

    You should see four containers: ta, admin, db, and redis.

  2. Test the Trust Anchor:

    curl http://localhost:8080/.well-known/openid-federation
    

    This should return a signed JWT containing the entity configuration.

  3. Test the Admin API:

    curl http://localhost:8000/api/v1/trustmarktypes
    

    This should return an empty list or existing trust mark types.

Stopping Services

To stop all services:

just down

To stop and remove all data (including database):

just down
rm -rf db/ redis/

Development Setup

For local development without Docker:

  1. Install uv (if not already installed):

    # macOS/Linux
    curl -LsSf https://astral.sh/uv/install.sh | sh
    
    # Or with pip
    pip install uv
    
  2. Set up Python environment:

    just venv
    

    This runs uv sync in the admin directory to create a virtual environment and install all dependencies.

  3. Install the development root CA certificate to the system trust store.

    The repository includes self-signed TLS certificates for development under the dev/ directory. To allow your system to trust these certificates, install the root CA:

    Ubuntu/Debian:

    sudo cp dev/rootCA.pem /usr/local/share/ca-certificates/rootCA.crt
    sudo update-ca-certificates
    

    Fedora/RHEL/CentOS:

    sudo cp dev/rootCA.pem /etc/pki/ca-trust/source/anchors/rootCA.pem
    sudo update-ca-trust
    

    macOS:

    sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain dev/rootCA.pem
    

    Arch Linux:

    sudo cp dev/rootCA.pem /etc/ca-certificates/trust-source/anchors/rootCA.crt
    sudo trust extract-compat
    
  4. Set up Rust environment:

    cargo build --release
    
  5. Start dependencies (Redis and PostgreSQL):

    just up
    

    Or start only db and redis with the dev compose file:

    docker compose -f dev/docker-compose.dev.yml --project-directory . up -d db redis
    
  6. Run Django migrations:

    cd admin
    uv run python manage.py migrate
    
  7. Start the Admin server:

    uv run python manage.py runserver
    
  8. Start the Trust Anchor:

    cargo run --release -- -c taconfig.toml
    

Production Deployment

For production deployments:

  1. Build or pull the Docker images:

    docker compose build
    
  2. Configure localsettings.py with production Django settings (SECRET_KEY, ALLOWED_HOSTS, SECURE_SSL_REDIRECT, etc.) and place it in the repository root.

  3. Update TLS certificate paths in docker-compose.yml to point to your production certificates.

  4. Set POSTGRES_PASSWORD in docker-compose.yml (or use environment variables / Docker secrets).

  5. Generate an MFA_ENCRYPTION_KEY and set it in the admin service environment.

  6. Start services:

    docker compose up -d
    

The admin service runs with granian in production (PRODUCTION=true). Place a reverse proxy (e.g., nginx) in front of the admin and frontend services.

Troubleshooting

Container won’t start

Check the logs:

docker compose logs ta
docker compose logs admin

Common issues:

  • Port already in use - stop other services on ports 8000, 8080, 5432

  • Redis not ready - wait for healthcheck to pass

Database connection errors

Ensure PostgreSQL is running and healthy:

docker compose ps db

If the database is corrupted, remove and recreate:

just down
rm -rf db/
just up

Key file errors

Ensure private.json exists and is valid JSON:

cat private.json | python -m json.tool

If the file is corrupted or missing, restore from git:

git checkout -- private.json admin/private.json publickeys/

TLS certificate errors

If you see SSL/TLS certificate verification errors when running tests or making requests to the Trust Anchor, ensure the root CA is installed:

# Verify the root CA is installed (Ubuntu/Debian)
ls /usr/local/share/ca-certificates/rootCA.crt

# If missing, install it
sudo cp dev/rootCA.pem /usr/local/share/ca-certificates/rootCA.crt
sudo update-ca-certificates

For other operating systems, see the root CA installation steps in the Development Setup section above.