diff --git a/.github/workflows/delivery.yml b/.github/workflows/delivery.yml new file mode 100644 index 0000000..f0674cb --- /dev/null +++ b/.github/workflows/delivery.yml @@ -0,0 +1,39 @@ +name: Delivery + +on: + # Allow triggering pushing to GHCR manually. + workflow_dispatch: + +permissions: + contents: write + packages: write + +jobs: + publish-docker-image: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=raw,value=staging + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build container and push to GitHub Container Registry + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/docs/irma-server.md b/docs/irma-server.md index 91103ea..15890bf 100644 --- a/docs/irma-server.md +++ b/docs/irma-server.md @@ -72,7 +72,13 @@ In addition, when [developer mode is not enabled in the Yivi app](yivi-app.md#de ### Stateless mode By default session states are kept in memory. If you want to run several IRMA servers in parallel or if you wish data persistence for sessions, you can use [stateless mode](stateless.md) which is implemented in the IRMA server via a Redis data store. -You can enable the Redis data store in the `irma server` by setting the `store_type` option to `redis` and specifying the `redis_addr` and `redis_pw` options. +You can enable the Redis data store in the `irma server` by setting the `store_type` option to `redis`. For stand-alone mode, you should specify the `redis_addr` and `redis_pw` options. If you use ACLs in Redis, you should also specify the `redis_username` option. If you share the Redis instance with other applications and you want your Redis keys to be scoped, you can enable the `redis_acl_use_key_prefixes` option. All keys are prefixed with the Redis username (`:`) then. + +The IRMA server also supports Redis in Sentinel mode for high availability. Instead of `redis_addr` you should then specify `redis_sentinel_addrs` (list of strings) and `redis_sentinel_master_name`. + +Please note that if you use Redis in Sentinel mode, you need to consider whether you accept the risk of losing session state in case of a failover. Redis does not guarantee strong consistency in these setups. We mitigated this by waiting for a write to have reached the master node and at least one replica. This means that at least two replicas should be configured for every master node to achieve high availability. Even then, there is a small chance of losing session state when a replica fails at the same time as the master node. For example, this might be problematic if you want to guarantee that a credential is not issued twice or if you need a session QR to have a long lifetime but you do want the session to be finished soon after the QR is scanned. If you require IRMA sessions to be highly consistent, you should use the default in-memory store or Redis in standalone mode. If you accept this risk, then you can enable Sentinel mode support by setting the `redis_accept_inconsistency_risk` to true. + +For all configuration options, check the help output of the `irma server` command (`irma server --help`). ### Keys and certificates For each configuration option that refers to some kind of key or certificate (for example `jwt_privkey`), there is a corresponding option with the `_file` suffix (for example `jwt_privkey_file`). Keys can be specified either by setting former to a (PEM) string, or setting the the latter to a file containing the (PEM) string. diff --git a/docs/stateless.md b/docs/stateless.md index 4e91f1b..44ed4a5 100644 --- a/docs/stateless.md +++ b/docs/stateless.md @@ -25,8 +25,6 @@ irma server -vv --store-type redis --redis-addr "localhost:6379" --redis-pw "pla If you want to run several IRMA servers, you can now run them behind a load balancer and connect them to the same Redis instance. -> Currently a simple locking mechanism is implemented. When running several Redis instances in parallel, edge cases may occur. We recommend to use a single Redis instance. - By default the IRMA server connects to Redis with TLS, using the system store of certificate authorities. Alternatively, you can specify the certificate that Redis uses, or the certificate authority with which that certificate is signed, using the `redis-tls-cert` or `redis-tls-cert-file` options. A certificate may be configured in Redis as follows: ``` @@ -50,9 +48,9 @@ It is also possible to disable TLS altogether for connections to Redis, using th > In production, always using TLS for Redis is recommended. If you disable TLS, be sure to run your Redis server in an internal network protected against unauthorized access. ### Using multiple Redis instances -Currently the IRMA server does not support Redis clusters or a master/slave mode. You can only connect to one Redis address. This means that the Redis connection is currently a bottleneck and single point of failure. You could use [Redis Enterprise](https://redis.com/redis-enterprise-cloud/overview/) which will let you connect with one outward-facing Redis connection and will provide you with an underlying failover mechanism. +The IRMA server supports Redis in Sentinel mode, which allows you to use multiple Redis instances in a failover configuration. For data consistency, we currently require at least 1 replica to be present. This means that you need a minimum of 2 replicas for high availability. Please check the [configuration options](irma-server.md#stateless-mode) for more information about this mode. -Please get in touch with us, should you wish the IRMA server to support multiple Redis instances. +We currently do not support Redis in cluster mode. If you need support for Redis Cluster, please contact us. ### Server-sent events -Currently the IRMA server does not support a stateless mode in combination with server-sent events. Please contact us, should you be in need of this combination. \ No newline at end of file +Currently the IRMA server does not support a stateless mode in combination with server-sent events. Please contact us, should you be in need of this combination. diff --git a/website/versioned_docs/version-v0.15.0/irma-server.md b/website/versioned_docs/version-v0.15.0/irma-server.md new file mode 100644 index 0000000..5432751 --- /dev/null +++ b/website/versioned_docs/version-v0.15.0/irma-server.md @@ -0,0 +1,331 @@ +--- +title: irma server +id: version-v0.15.0-irma-server +original_id: irma-server +--- + + +`irma server` is an IRMA server executable (daemon) allowing you to perform IRMA sessions with +[Yivi apps](yivi-app.md). It handles all IRMA-specific cryptographic details of issuing or verifying IRMA attributes with an Yivi app on behalf of a [requestor](overview.md#participants) (the application wishing to verify or issue attributes). It exposes the following: + * HTTP endpoints under `/irma`, used by the Yivi app during IRMA sessions + * a JSON API under `/sessions` for requestors, allowing them to request the server to verify or issue attributes. + +`irma server` is a subcommand of the [`irma`](irma-cli.md) command line tool, which additionally contains subcommands to start or perform IRMA sessions, handle [IRMA schemes](schemes.md), and more. + +For installation instructions, see [`irma`](irma-cli.md). + +## Running the server + +Simply run `irma server` to run the server with the default configuration in development mode. Use `irma server -v` for more verbose logging, for example to see the current configuration. Use `irma server -vv` to also log session contents. + +Run `irma server --help` to see configuration options. In order to verify your configuration, run `irma server check -v`. + +## Starting a session +Assuming the server runs in the [default configuration](#default-configuration) (in particular [requestor authentication](#requestor-authentication) is disabled (`no_auth` is `true`) and the `irma-demo` [scheme](schemes.md) is installed), issue `irma-demo.MijnOverheid.ageLower` attributes using the [`session`](irma-cli.md) subcommand of the `irma` tool: +```shell +irma session --server http://localhost:8088 --issue irma-demo.MijnOverheid.ageLower=yes,yes,yes,no +``` +Verify the `irma-demo.MijnOverheid.ageLower.over18` attribute: +```shell +irma session --server http://localhost:8088 --disclose irma-demo.MijnOverheid.ageLower.over18 +``` +These print QRs in your terminal that you can scan with your [Yivi app](yivi-app.md) to perform the session. For more extensive examples, see [irmajs](irmajs.md). + +## Configuring +Run `irma server -h` to see all configuration options. Each option may be passed as: + 1. a command line flags (e.g. [`--listen-addr`](#http-server-endpoints)) + 2. a environmental variable (e.g. `IRMASERVER_LISTEN_ADDR`) + 3. an item in a configuration file (e.g. `"listen_addr"`) (which may be in JSON, TOML or YAML) + + with the following rules: + * Flags supersede environmental variables which supersede configuration file entries. + * Dashes are used in flags, but underscores are used in environmental variables and configuration file entries. + * Environmental variables are uppercased and prefixed with `IRMASERVER_`. + * The [`requestors`](#requestor-authentication) and [`static_sessions`](#static-irma-qrs) options are special: when passed as a flag or environmental variable, they must be passed as a JSON object (for example: `--requestors '{"myapp":{"auth_method":"token","key":"12345"}}'`). + * When passing a boolean flag [use an `=`](https://golang.org/pkg/flag/#hdr-Command_line_flag_syntax), for example [`--no-auth=false`](#requestor-authentication). + +In order to see the configuration that the server uses after having gathered input from these sources, specify `-v` or `-vv` or use the `verbose` option. Use `irma server check -v` (with the same flags, env vars and config files as `irma server`) to check your configuration for correctness before running the server. + +For a full configuation example, see [Getting started](getting-started.md#example-configuration-and-irma-session). + +In the remainder of this document, when referring to options we write them as configuration file entries, with underscores and without prefix. + +### Default configuration +In the default configuration (run `irma server check -v` to see it) the server is immediately usable. In particular, it +* uses the [default IRMA schemes](schemes.md#default-schemes-pbdf-and-irma-demo) ([`pbdf`](https://github.com/credentials/pbdf-schememanager) and [`irma-demo`](https://github.com/credentials/irma-demo-schememanager)), downloading them if necessary +* allows anyone to use the server [without authentication](#requestor-authentication) (the `no_auth` setting is `true`) +* saves the session state in memory. + +If the server is reachable from the internet, you should consider enabling authentication of session requests. + +### Configuration files +A configuration file can be provided using the `config` option (for example: `irma server --config ./irmaserver.json`). When not specified, the server looks for a configuration file called `irmaserver.json` or `irmaserver.toml` or `irmaserver.yaml` in (1) the current path; (2) `/etc/irmaserver/`; (3) `$HOME/irmaserver`, in that order. A configuration file is not required; if none is found at any of these locations the server takes its configuration from just command line flags and environmental variables. + +### Production mode +When running the server in production, you should enable the `production` option. This enables stricter defaults on the configuration options for safety and prints warnings on possibly unsafe configurations. In particular, when `production` is enabled, the default values of some options change as follows (cf. `diff <(irma server -h) <(irma server -h --production)`): + +* `url` from `"http://$YOUR_LOCAL_IP:port"` to `""`: in development mode the `url` to which Yivi apps will connect is set by default to your current local IP address; in `production` mode you must configure it yourself. +* [`no_auth`](#requestor-authentication) from `true` to `false`: you should consider enabling requestor authentication, or explicitly disable this by setting this flag to `true`. +* [`issue_perms`](#global-permissions) from `[*]` (everything) to `[]` (none). +* [`no_email`](email.md) from `true` to `false`: in `production` mode, opting out of providing an email address can be done by explicitly setting this flag to `true`. + +In addition, when [developer mode is not enabled in the Yivi app](yivi-app.md#developer-mode) (the default setting), the Yivi app wil refuse to perform sessions with IRMA servers not running in `production` mode. Since the majority of the Yivi app users will not have developer mode enabled, this requires IRMA servers facing those users to enable `production` mode. + +### Stateless mode +By default session states are kept in memory. If you want to run several IRMA servers in parallel or if you wish data persistence for sessions, you can use [stateless mode](stateless.md) which is implemented in the IRMA server via a Redis data store. + +You can enable the Redis data store in the `irma server` by setting the `store_type` option to `redis`. For stand-alone mode, you should specify the `redis_addr` and `redis_pw` options. If you use ACLs in Redis, you should also specify the `redis_username` option. If you share the Redis instance with other applications and you want your Redis keys to be scoped, you can enable the `redis_acl_use_key_prefixes` option. All keys are prefixed with the Redis username (`:`) then. + +The IRMA server also supports Redis in Sentinel mode for high availability. Instead of `redis_addr` you should then specify `redis_sentinel_addrs` (list of strings) and `redis_sentinel_master_name`. + +Please note that if you use Redis in Sentinel mode, you need to consider whether you accept the risk of losing session state in case of a failover. Redis does not guarantee strong consistency in these setups. We mitigated this by waiting for a write to have reached the master node and at least one replica. This means that at least two replicas should be configured for every master node to achieve high availability. Even then, there is a small chance of losing session state when a replica fails at the same time as the master node. For example, this might be problematic if you want to guarantee that a credential is not issued twice or if you need a session QR to have a long lifetime but you do want the session to be finished soon after the QR is scanned. If you require IRMA sessions to be highly consistent, you should use the default in-memory store or Redis in standalone mode. If you accept this risk, then you can enable Sentinel mode support by setting the `redis_accept_inconsistency_risk` to true. + +For all configuration options, check the help output of the `irma server` command (`irma server --help`). + +### Keys and certificates +For each configuration option that refers to some kind of key or certificate (for example `jwt_privkey`), there is a corresponding option with the `_file` suffix (for example `jwt_privkey_file`). Keys can be specified either by setting former to a (PEM) string, or setting the the latter to a file containing the (PEM) string. + +### HTTP server endpoints +The HTTP endpoints that this server offers is split into two parts: +* `/session`: used by the requestor to start sessions, check session status, or get session results. +* `/irma`: used by the Yivi app during IRMA sessions. + +In the default mode, the server starts one HTTP server that offers both, configured with `listen_addr` and `port`. If however the `client_port` and `client_listen_addr` options are provided, then the server starts two separate HTTP servers: +* `/session` attaches to the address and port provided with `port` and `listen_addr`. +* `/irma` attaches to the address and port provided with `client_port` and `client_listen_addr`. + +The `/irma` endpoints must always be reachable for the Yivi app. Using this double server mode you can restrict access to the `/session` endpoints by e.g. setting `listen_addr` to `127.0.0.1` or to an interface only reachable from an internal network. Restricting access to the `/session` endpoints in this way may make requestor authentication unnecessary. + +### Requestor authentication +The server runs in one of two modes: it either accepts all session requests from anyone that can reach the server, or it accepts only authenticated session requests from authorized requestors. This can be toggled with the `no_auth` boolean option. If the `/session` creation endpoint of your `irma server` is publicly accessible from the internet (i.e. the `client_port` option is used, see [above](#http-server-endpoints)), then you should consider enabling requestor authentication (i.e. turn `no_auth` off), otherwise anyone can use your `irma server`. + +The default is `true` (requests are not authenticated) when `production` is disabled and `false` otherwise. + +When authentication is enabled (`no_auth` is `false`), requestors that are authorized to use the server must be configured in the `requestor` option in the form of a map, for example: + +```json +{ + "requestors": { + "myapp": { + "auth_method": "token", + "key": "eGE2PSomOT84amVVdTU" + } + } +} +``` + +The server supports several authentication methods, one of which must be specified in the `auth_method` field for each requestor. The snippet above demonstrates the recommended and easiest to use authentication method, called `token`. When using this method the requestor must include the `key` as an API token in a HTTP header (for more details see the [API reference](api-irma-server.md#post-session)). + +In addition the server supports the following authentication methods: +* `hmac`: the requestor symmetrically [signs the session request](session-requests.md#jwts-signed-session-requests) in a [JWT](https://jwt.io/), with HMAC-SHA256 (`HS256`) using `key`. The `key` provided should be the Base64 encoding of the actual secret. +* `publickey`: the requestor asymmetrically [signs the session request](session-requests.md#jwts-signed-session-requests) in a [JWT](https://jwt.io/) with RSA (`RS256`), in this case `key` should be the PEM public key of the requestor. + +For each of these modes it is also possible to specify `key_file` instead `key`; in that case the file at `key_file` will be read and used as `key`. + +### Static IRMA QRs +Unlike normal QRs which differ per session (as they contain the session token), the server also supports static QRs which, when scanned by the Yivi app, start preconfigured IRMA sessions. This makes it possible to for example print such a static QR. These preconfigured sessions are configured with the `static_sessions` options, for example: +```json +{ + "static_sessions": { + "mystaticsession": { + "callbackUrl": "https://example.com/callbackUrl", + "request": { + "@context": "https://irma.app/ld/request/disclosure/v2", + "disclose": [[[ "irma-demo.MijnOverheid.ageLower.over18" ]]] + } + } + } +} +``` +Thus `static_sessions` must contain a map of which each item must be an [extended session request](session-requests.md#extra-parameters). Including a `callbackUrl` to which the [session result](api-irma-server.md#get-session-token-result) is sent after the session is required (since for these sessions there is no requestor waiting to receive the attributes after the session has finished). If a JWT private key is installed, then the session result is sent as a [JWT](api-irma-server.md#get-session-token-result-jwt). + +> If no JWT private key is installed, then the `callbackUrl` should either not be publically reachable, or it should include a secret token (e.g. https://example.com/cX5aTins5kEZpjDpfYcN) and have TLS enabled (which it should anyway as personal data will be POSTed to it). Otherwise there is no way of distinguishing POSTs from your `irma server` from POSTs made by someone else. + +Assuming the URL of the `irma server` is `http://example.com`, the session configured above is started when the Yivi app scans a QR with the following contents: +```json +{ + "irmaqr": "redirect", + "u": "http://example.com/irma/session/mystaticsession" +} +``` + +Only static [disclosure or attribute-based signature sessions](what-is-irma.md#session-types) are supported. + +### Permissions +For each of the [three IRMA session types](what-is-irma.md#session-types) (attribute verification; attribute-based signature sessions; and attribute issuance), permission to use specific attributes/credentials can be granted to requestors in the configuration. For example, including permissions in the `myapp` requestor from above: +```json +{ + "requestors": { + "myapp": { + "disclose_perms": [ "irma-demo.MijnOverheid.ageLower.over18" ], + "sign_perms": [ "irma-demo.MijnOverheid.ageLower.*" ], + "issue_perms": [ "irma-demo.MijnOverheid.ageLower" ], + "auth_method": "token", + "key": "eGE2PSomOT84amVVdTU" + } + } +} +``` +This means that `myapp` is authorized to request `irma-demo.MijnOverheid.ageLower.over18` in disclosure session, and any attribute from `irma-demo.MijnOverheid.ageLower` in attribute-based signature sessions. Additionally `myapp` can issue `irma-demo.MijnOverheid.ageLower` instances. In each level wildcards are permitted (`irma-demo.MijnOverheid.ageLower.*`, `irma-demo.MijnOverheid.*`, `irma-demo.*`, `*`). Thus `"disclose_perms": [ "*" ]` allows the requestor to verify any attribute. + +To use the [`host` option](session-requests.md#session-host) in session requests, you need to specify which hosts the requestor may use. You can do this by specifying `host_perms`. You can use glob patterns to grant permissions for a range of hosts. + +```json + { + "requestors": { + "myapp": { + ... + "host_perms": ["*.example.com"] + } + } + } +``` + +### Global permissions + +Global permissions can be applied to all requestors by using the global `disclose_perms`, `sign_perms` and `issue_perms` options. For each requestor, the effective set of permissions is the union of the permissions specified in its `requestors` map and the global permission set. + +The global options also work when `no_auth` is enabled. Thus in this case a session type can be disabled by granting no one the permission, e.g., `issue_perms: []` would disable issuance. + +In development mode, when `production` is `false`, the defaults for `disclose_perms`, `sign_perms` and `issue_perms` are `["*"]`. In order to protect any IRMA private keys that the server has access to from unintended use by others, when `production` is true the default of `issue_perms` is `[]`: no one can issue unless the global `issue_perms` is modified or unless specific requestors receive nonempty `issue_perms`. + +### Client return urls + +In session requests, the server can be asked to pass a [client return url](session-requests.md#client-return-url) to the Yivi app, which the app will open after completing the session for sessions that involve only one device. This feature is always enabled. + +### Session lifetime + +When a session is [started by the requestor](#starting-a-session), users have a limited amount of time to perform the session in their Yivi app. These lifetime constraints can be configured. + +By default, users have the maximum session lifetime to start the session in their Yivi app after it is started on the server. By default, this is set to 15 minutes. This global setting holds for all sessions on this server and can be changed in the configuration (see below). Per session, a custom timeout value can be chosen using the `timeout` option in the [extended session request](session-requests.md#extra-parameters). + +After a session is started by the user in the Yivi app, it has another full period of the maximum session lifetime to complete the session in their app. As mentioned above, this is 15 minutes by default. This part of the session lifetime is not affected by the `timeout` setting of the extended session request. The maximum session lifetime can be configured using the global `max_session_lifetime` option in the server configuration. + +When the user completes the session, the requestor has a limited amount of time to retrieve the session result from the server. By default, the lifetime of the session result on the server is 5 minutes. The session result lifetime can be configured using the global `session_result_lifetime` option in the server configuration. + +More information on how to configure global options for your server can be found [above](#configuring). + +### Augmented client return urls + +The server can be configured to [augment the client return url](session-requests.md#augmenting-the-client-return-url) when requested. In order to enable this feature, the `augment_client_return_url` setting needs to be set to `true`. + +### Static file hosting + +Apart from hosting endpoints under [`/session` and `/irma`](irma-server.md#http-server-endpoints), the server also supports statically hosting all files from a certain directory. This can be useful [for experimenting](getting-started.md#perform-browser-irma-session). It can be configured with the following options: + +* `static_path`: Host files under this path as static files. Leave empty to disable static file hosting. +* `static_prefix`: Host static files under this URL prefix (default: no prefix) + +### IRMA schemes + +The server uses [IRMA schemes](schemes.md) to retrieve issuer, credential and attribute names, as well as public and private keys with which attributes can be verified an issued, respectively. By default the server uses the [`pbdf` and `irma-demo` schemes](schemes.md#default-schemes-pbdf-and-irma-demo). This can be configured with the following options: + +* `schemes_path`: path containing IRMA schemes (often called `irma_configuration`). Default: `C:\Users\Username\AppData\Local\irma\irma_configuration` on Windows, `$HOME/.local/share/irma/irma_configuration` otherwise. Created if it does not exist. If empty, the default schemes [`pbdf` and `irma-demo`](schemes.md#default-schemes-pbdf-and-irma-demo) are downloaded into it. +* `schemes_assets_path`: path containing initial, read-only IRMA schemes. If specified, the schemes found here are copied into the path specified by `schemes_path`. Can be used to avoid downloading default schemes on first run. +* `schemes_update`: update IRMA schemes from their scheme URL every this many minutes. Default is `60`. Set to `0` to disable automatic scheme updating (not recommended). + +### IRMA issuer private keys + +If IRMA issuer private keys are included in the server configuration, then the server can issue all credential types of all issuers for which private keys are installed. IRMA issuer private keys can be configured in the following two ways: + +* Include the private keys within the [IRMA scheme](schemes.md) in the issuer's `PrivateKeys` folder, with filenames `0.xml`, `1.xml`, etc ([example](https://github.com/privacybydesign/irma-demo-schememanager/tree/master/MijnOverheid/PrivateKeys)). +* Set the `privkeys` option to a folder containing IRMA issuer private keys called `scheme.issuer.xml` or `scheme.issuer.counter.xml` (for example, `irma-demo.MijnOverheid.xml` or `irma-demo.MijnOverheid.2.xml`). + +If issuance is enabled in production and private keys are configured, then you should ensure that only authenticated requestors can start issuance requests (otherwise if anyone can use your server to issue attributes then those attributes cannot be trusted or used). You should either: + +* disable `no_auth` and [send authenticated session requests](irma-server.md#requestor-authentication), +* Restrict the [`/session` HTTP endpoints](#http-server-endpoints) to a internal network interface only accessible by your applications and not from outside. + +Taking neither approach is an unsafe configuration as in that case anyone can create issuance sessions. In this case, if `production` mode is enabled then the server will refuse to run. + +### Signed JWT session results + +If a `jwt_privkey` (or `jwt_privkey_file`) is given, then the following endpoints are enabled: + +* `GET /session/{sessiontoken}/result-jwt`: returns the session result signed by the `irma server` into a JWT. +* `GET /session/{sessiontoken}/getproof`: returns a JWT similar to the one from `result-jwt`, but with the same structure as the IRMA API server session result JWTs. +* `GET /publickey`: returns the public key with which the JWTs output by this server can be verified. + +This can be useful if the session result travels along an unsafe or untrusted route from the IRMA server to the requestor. As long as the `irma server` is trusted and its public key is known, the JWT can be verified to ensure that the session result was untampered with since it left the `irma server`. + +### TLS + +The [IRMA protocol](irma-protocol.md) relies on TLS for encryption of the attributes as they travel along the internet. If your server is connected to the internet and it handles actual attributes (personal data from people), then you ***must*** ensure that the attributes are protected in transit with TLS. In its default configuration (i.e. with [developer mode](yivi-app.md#developer-mode) disabled), the Yivi app will refuse to connect to servers not using TLS. + +You can enable TLS in the `irma server` with the `tls_cert` and `tls_privkey` options (or the `_file` equivalents), specifying a PEM certificate (chain) and PEM private key. If you use [separate requestor and app endpoints](#http-server-endpoints), additionally use `client_tls_cert` and `client_tls_privkey`. + +Alternatively, if your IRMA server is connected to the internet through a reverse proxy then your reverse proxy probably handles TLS for you. + +### Email + +Users of the server are encouraged to provide an email address with the `email` option, subscribing for notifications about changes in the IRMA software or ecosystem. [More information](email.md). In `production` mode, it is required to either provide an email address or to explicitly out with the `no_email` option. + +### Logging and verbosity + +The server's verbosity can be increased by two degrees: +* `-v` flag is given, or `verbosity` option set to `1`: includes `DEBUG` messages. Logs server configuration when starting the server, stack traces of errors, and more. +* `-vv` flag is given, or `verbosity` option set to `2`: includes `TRACE` messages. Additionally includes dumps of all HTTP traffic from and to the server. + +> in its default mode, the server will not log untrusted user input and attribute values (personal data). If the verbosity is increased, sensitive or dangerous content may be logged. You should avoid doing this in production. + +The output is [structured](https://github.com/sirupsen/logrus#fields), putting certain recurring values in fields: +```text +[2019-02-28T20:51:09+01:00] INFO Session started action=disclosing session=WdypvSs97JTotpfl1Dtd +``` +Outputting JSON is enabled with the `log-json` option: +```json +{"action":"disclosing","level":"info","msg":"Session started","session":"WdypvSs97JTotpfl1Dtd","time":"2019-02-28T20:51:09+01:00"} +``` + +## Running as daemon + +On most Linux systems, the `irma server` can be made into an automatically started daemon as follows: + +1. Write a new systemd unit file to `/etc/systemd/system/irmaserver.service`: + ```ini + [Unit] + Description=IRMA server + Documentation=https://irma.app/docs/irma-server + Requires=network.target + + [Service] + Type=simple + ExecStart=/usr/local/bin/irma server --config=/etc/irmaserver/config.json + TimeoutStopSec=60 + Restart=always + RestartSec=1 + StandardOutput=syslog + StandardError=syslog + SyslogIdentifier=irma + User=irmaserver + Group=irmaserver + + [Install] + WantedBy=multi-user.target + ``` + Modify the path to `irma` and [your configuration file (or flags or environmental variables)](#configuring) in `ExecStart` as needed, as well as `User` and `Group`. +2. Start the daemon and schedule it for automatic start on boot by running `systemctl start irmaserver.service && systemctl enable irmaserver.service`. + +See `systemctl status irmaserver.service` for the status of the daemon, and `journalctl -u irmaserver.service` for the console output of the IRMA server. + +## Design goals + +The server was designed with the following goals in mind. +- Developer and user friendliness + - Each of the [configuration options](#configuring) can be specified in a configuration file, command line flag, or environmental vars (see `-h`) + - Default configuration (demo mode) is immediately useful + - Thorough and configurable logging (`-v`, `-vv`; by default logs exclude attribute values) + - Partial backwards compatibility with predecessor [`irma_api_server`](https://github.com/privacybydesign/irma_api_server) + - Small startup time +- Also available as [Go library](irma-server-lib.md) instead of standalone server + - Bindings to other programming languages (Python, Ruby) are expected + +Being written in [Go](https://golang.org/), this server (in fact, the containing [`irma` binary](irma-cli.md)) additionally automatically has the following properties. +- Simple to install (one binary, no dependencies, cross platform) and/or compile +- [Reproducible builds](https://www.gnu.org/software/mes/manual/html_node/Reproducible-Builds.html) +- [API documentation](https://godoc.org/github.com/privacybydesign/irmago) (generated automatically from `master` branch) + +Referring to Go packages (i.e. folders) under [`irmago`](https://github.com/privacybydesign/irmago), the server is structured as follows. +* [`server/irmaserver`](irma-server-lib.md): Go library implementing the HTTP endpoints for the [IRMA protocol](irma-protocol.md) (in which the Yivi app is the client), and a Go API for requestors to manage sessons. ([Godoc API documentation](https://godoc.org/github.com/privacybydesign/irmago/server/irmaserver)) +* `server/requestorserver`: Go library wrapping `server/irmaserver`, exposing the requestor API as a second HTTP endpoint set under `/session` URLs instead of as Go functions (next to `/irma` for the Yivi app endpoints). ([Godoc API documentation](https://godoc.org/github.com/privacybydesign/irmago/server/requestorserver)) +* `irma`: executuable whose `server` commands wraps `server/requestorserver`. diff --git a/website/versioned_docs/version-v0.15.0/stateless.md b/website/versioned_docs/version-v0.15.0/stateless.md new file mode 100644 index 0000000..737aed8 --- /dev/null +++ b/website/versioned_docs/version-v0.15.0/stateless.md @@ -0,0 +1,58 @@ +--- +title: Stateless IRMA server +id: version-v0.15.0-stateless +original_id: stateless +--- + +For each IRMA session the [IRMA server](irma-server.md) needs to keep track of the [session state](irma-protocol.md#the-session-state). +By default the session state is kept in memory. With version 0.9.0 of the IRMA server it is possible to run the IRMA server in a stateless mode. The session data will then be stored in a Redis datastore. This page explains how the stateless IRMA server works and how to run the IRMA server in stateless mode. + +## Overview +During an IRMA session, the IRMA server acts as a state machine which is described in detail on the [IRMA protocol page](irma-protocol.md). The IRMA session progresses through various states such as `INITIALIZED`, `CONNECTED` and `DONE`. The IRMA server contains logic when to switch from one state into the other. The state itself can be kept in memory or, alternatively, in a Redis data store. Saving the session state in memory requires no extra setup and is currently the default behaviour of the IRMA server. However, the data in memory cannot be shared between several IRMA servers. This means that you cannot scale the IRMA server horizontally when using this in-memory solution. Next to poor scalability, the in-memory solution is problematic when the IRMA server needs to be restarted or - even worse - when the server crashes. In such cases, the in-memory information of all sessions gets irreversibly lost. + +With the new feature of running the IRMA server in stateless mode, the session data gets decoupled from the IRMA server, making the server itself stateless. The IRMA server still contains the logic when to switch between states but will retrieve and update the session data from and to a dedicated store. Hence, several IRMA servers can be run in parallel and connect to the same data store. Also, no data is lost when the IRMA server restarts or crashes. + +### Use cases +* Scaling the IRMA server horizontally, i.e. running several IRMA severs in parallel. +* Preventing data loss when restarting an IRMA server. +* Preventing data loss in case of IRMA server crashes. + +## Running the IRMA server in stateless mode +### Example +You can start the IRMA server in stateless mode by setting the `store-type` option to `redis`. Additionally you need to provide a Redis server address and password. For test purposes you can override the need for a password by setting the `redis-allow-empty-password` option to `true`. However, make sure to use a secure Redis password in production. Your Redis data store will contain sensitive data and must be password-protected. + +``` +irma server -vv --store-type redis --redis-addr "localhost:6379" --redis-pw "placeholderPassword" +``` + +If you want to run several IRMA servers, you can now run them behind a load balancer and connect them to the same Redis instance. + +By default the IRMA server connects to Redis with TLS, using the system store of certificate authorities. Alternatively, you can specify the certificate that Redis uses, or the certificate authority with which that certificate is signed, using the `redis-tls-cert` or `redis-tls-cert-file` options. A certificate may be configured in Redis as follows: + +``` +requirepass placeholderPassword + +# Disable the non-TLS port completely +port 0 +# Enable TLS on the default Redis port +tls-port 6379 + +# X.509 certificate and a private key +tls-cert-file /path/to/cert.pem +tls-key-file /path/to/privkey.pem + +# Disable TLS client authentication +tls-auth-clients no +``` + +It is also possible to disable TLS altogether for connections to Redis, using the `redis-no-tls` option. + +> In production, always using TLS for Redis is recommended. If you disable TLS, be sure to run your Redis server in an internal network protected against unauthorized access. + +### Using multiple Redis instances +The IRMA server supports Redis in Sentinel mode, which allows you to use multiple Redis instances in a failover configuration. For data consistency, we currently require at least 1 replica to be present. This means that you need a minimum of 2 replicas for high availability. Please check the [configuration options](irma-server.md#stateless-mode) for more information about this mode. + +We currently do not support Redis in cluster mode. If you need support for Redis Cluster, please contact us. + +### Server-sent events +Currently the IRMA server does not support a stateless mode in combination with server-sent events. Please contact us, should you be in need of this combination. diff --git a/website/versions.json b/website/versions.json index 2410c54..fc4d3a5 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,4 +1,5 @@ [ + "v0.15.0", "v0.14.2", "v0.14.0", "v0.13.0",