Signed Input Configuration

Introduction

The system provides a security mechanism to restrict access to system resources to require valid signatures. Signatures are always enabled by default and use internally generated keys if no custom keys are configured.

The system provides the option to require any input URIs to be cryptographically signed. This is disabled by default.

Architecture

Signing keys are stored in the system PostgreSQL database. Any changes to the relevant tables are automatically propagated to the i3dhub-keystore service, which in turn broadcasts changes via an internal queue in RabbitMQ. Any services requiring signing keys listen to these changes and update their keys appropriately.

Custom Keys

Custom keys can be provided by directly inserting these into a running instance of the system. Keys are expected to be in PEM format. There are several methods to provide keys:

Upload

Upload a key directly to the KeyStore, which will then also persist the provided key in PostgreSQL:

curl --data-binary @key.pem --header 'Content-Type: application/x-pem-file' i3dhub-keystore:8080/addKeys

Insert

Warning

Only the HTTP method will check the validity of the provided key before persisting it to PostgreSQL. Other methods will insert any data without validation.

Insert the key directly into PostgreSQL via a stored procedure:

select keys.insert_key('key.pem contents here');

Insert the key directly into the correct table:

insert into keys.active_keys(key)
values ('key.pem contents here');

Signed Input

Note

Custom keys are required when using signed input. Without custom keys the system will not be able to validate the input and will reject all requests.

In order to validate input URIs the system needs to know which part of the URIs is the signature, and which the signed part. A set of regex rules must be provided to extract the relevant parts from inputs.

Each regex must provide at least two capture groups. The first capture group must capture the signed part, the second the signature of the signed part.

Configuration is provided to the system via values.yaml and the respective entries in the datapools section:

# Set data pools for external data sources. These define how data is accessed or
# how inputs should be rewritten. The system will attempt to download data from
# the given urlTemplate and use the data as input for transcoding.
#
# Either "urn" or "regex" must be set. A URN rule provides a more simplified way
# to define abstract identifiers for data sources. Regex allows for more complex
# matching of URLs. A URN rule must always be accompanied by a urlTemplate, a
# regex rule can be used without requiring a rewrite.
#
# For urlTemplates in URN rules, ${n} is the n-th value in the URN separated
# after urn:namespace:specifier:xxx:yyy.
# For example, urn:x-i3d:shape:sphere:large would map ${1} -> sphere and
# ${2} -> large.
#
# For regex templates, ${n} is the n-th capture group value in the regex.
# Capture groups are defined by parentheses in the regex. See
# https://pkg.go.dev/regexp/syntax for an overview of available regex syntax.
# If no urlTemplate is set, the incoming URL is preserved and not rewritten.
datapools:
- regex: "https://example.com/(.*)"
  urlContentType: # optional
    - "openjt"
  urlTemplate: https://example.com/rewritten/${1}.jt # optional
  authUrlTemplate: https://auth.example.com/${1}.jt # optional
  # Set rules to verify input signatures. The first capture group is the
  # signed part, the second the signature. For example, applying
  # https?://([^\\?]+).*sig=([^&]+) to http://example.com/secret.jt?sig=123456
  # results in the first capture group being example.com/secret.jt and the
  # second being 123456. This causes the system to attempt to verify 123456
  # as the signature of example.com/secret.jt.
  signatureRegex: "https?://([^\\?]+).*sig=([^&]+)" # optional