Setup
System Requirements
Meerkat DSA requires NodeJS version 17 or higher. With heavy usage, you can expect Meerkat DSA's memory usage to get up to 300MB. It would be wise to anticipate the extreme and ensure that Meerkat DSA has at least 500MB of memory.
In addition to this, Meerkat DSA needs a database (as detailed below), which may take a lot more memory. You may also wish to set up a reverse HTTP proxy such as Nginx, Caddy, or Apache, which will also consume some resources.
Added together, you should probably have no less than 1 GB of memory free for Meerkat DSA, the database, and a reverse proxy (if used).
Meerkat DSA has only been tested on x86-64 platforms, so no guarantees can be made about how it will run on other architectures. Meerkat DSA should run just fine on Windows, Mac OS, Linux, and possibly more operating systems, and it has been briefly tested on all three.
X.500 directory traffic is typically not time-sensitive, so high latency is
usually tolerable. However, the network may need to be able to afford high
throughput, since certain operations, such as search
and list
, can
potentially return a lot of data all at once.
Installation / Deployment
It is recommended that you install Meerkat DSA in a Kubernetes cluster using Helm. However, Meerkat DSA can be installed as a Docker Compose app and can also run locally.
Database
In any case that you deploy Meerkat DSA, you will need to configure a MySQL database that will hold the DSA's data. Ideally, you should use a secure password and TLS to secure the connection to the database. It is also strongly recommended that Meerkat DSA coexist in a physically nearby location to the database so that latency is low; if your Meerkat DSA instance has to send its queries to a MySQL database on the other side of the planet, it will mean that Meerkat DSA will respond slowly to requests!
You will need to manually create a database within your database server that
Meerkat DSA can use exclusively. Conventionally, this is named directory
, but
you can name it anything you want as long as you configure your DATABASE_URL
to use that database.
The bitnami/mysql
Helm chart will allow you to define a database to create
on startup, so you will not need to manually log into this database server to
create this database. Different container images may also allow you to define
a database to create on startup as well.
The MySQL database will then need to be seeded with database schema. In technical terms, we need to "deploy a migration" to the database. You will need a user account that has all permissions to alter database schema. It is fine if this is a root / administrator account, since this will only be used once. How you actually deploy the migration will depend on how you have deployed Meerkat DSA, so this will be described on a case-by-case basis in the sections to follow.
After the database migration is complete, you can run Meerkat DSA with a database account having just create + read + update + delete permissions for the database.
Bitnami Helm Chart
One of the easiest ways to get a MySQL instance ready to go in a Kubernetes cluster is the Bitnami Helm chart.
Here is one way to do this:
Run this command to create a secret in Kubernetes:
kubectl create secret generic <your secret name> \
--from-literal=mysql-root-password=<your root password> \
--from-literal=mysql-replication-password=<your rep password> \
--from-literal=mysql-password=<your other password> \
--namespace=<your namespace>
Add the Bitnami Helm repo via this command:
helm repo add bitnami https://charts.bitnami.com/bitnami
Finally, install MySQL from the Bitnami Helm repo via this command:
helm install <your database name> bitnami/mysql \
--set auth.existingSecret=<your secret name> \
--set auth.database=directory \
--atomic \
--namespace=<your namespace>
Configuration
Meerkat DSA is configured through environment variables. These environment variables and their effects are documented here.
At minimum, you MUST define DATABASE_URL
. Besides that, you SHOULD define the
following other environment variables:
MEERKAT_SIGNING_CERTS_CHAIN_FILE
, which is documented here.MEERKAT_SIGNING_KEY_FILE
, which is documented here.MEERKAT_TLS_CERT_FILE
, which is documented here.MEERKAT_TLS_KEY_FILE
, which is documented here.NODE_ENV
, which should always be set toproduction
unless you are debugging or developing Meerkat DSA.LANG
, which should be set to the locale identifier for your desired locale. This will determine the language used for logging as well as the language for error messages. For American English, this should been_US.utf8
.
The LANG
environment variable will NOT affect the web administration console.
The web administration console does not support internationalization at all.
Local
To do this, you must have Node.js version 17 or higher installed. This will
also install Node Package Manager (npm
). You will also need Git installed.
You will also need a MySQL database somewhere ofr
You can run Meerkat DSA locally by cloning the
source repository for Meerkat DSA
by running git clone https://github.com/Wildboar-Software/directory
.
Then run npm install
. This will install all of the dependencies for this
project to build and work.
Run npx nx run meerkat:build:production
to build Meerkat DSA for the system
you are running. This will put the compiled output into
./dist/apps/meerkat/main.js
. You can run this JavaScript file via
node ./dist/apps/meerkat/main.js
, however, it will probably not work right
away.
You will need to configure Meerkat DSA using environment variables. How you do this will depend on whether you are using Windows, Linux, Mac, or some other operating system, but you can look at what you need to get it up and running on the Configuration Environment Variables documentation.
There is technically only one environment variable that is required, which is
DATABASE_URL
. Set this to the URL of your database.
Once you have your environment variables defined to configure Meerkat DSA as
you'd like, you will need to actually configure the database with the schema
needed to store Meerkat DSA's data, which you can do by running
npx prisma migrate deploy --schema=apps/meerkat/src/prisma/schema.prisma
.
Then run node ./dist/apps/meerkat/main.js
. You should see your application
start up on the console (unless you turned off console logging).
Docker / Docker-Compose
You can define your own Docker-Compose stack that will pull the Meerkat DSA
image ghcr.io/wildboar-software/meerkat-dsa
and wire it up to a MySQL
database, but the
source repository for Meerkat DSA
has a
starter template
that you can use.
The starter template will create a MySQL database, deploy the migrations to it, and start Meerkat DSA. Pretty much all you have to do is configure the environment variables and mount volumes for your signing key and cert, your TLS key and cert, your CA certificates bundle, your CRLs, your init script, and any other files that you may want to be in the container.
Kubernetes
There is a lot that goes into using Kubernetes and Helm--far more than I could possibly teach you in this documentation. Therefore, this documentation will assume that you have a working understanding of Kubernetes.
As with Docker-Compose, you may define your own Kubernetes manifests to deploy Meerkat DSA, however, Wildboar Software has defined a Helm chart for easy installation and removal.
To install via Helm, first you must have helm
installed, which you can do by
following these instructions. You must
also have a Kubernetes cluster running.
Note that you do not have to run the official Kubernetes control plane. There are plenty of other great alternatives such as K3s, Microk8s, and Minikube, all of which should work, and some of which are more suitable for lower-powered devices.
If you haven't set up the database, by now, do so.
When you have helm
installed, a Kubernetes cluster up and running, and you
have authenticated to the cluster, you need to define a Kubernetes secret that
your Meerkat DSA deployment can use to access your database. This needs to be
a Kubernetes Secret
and not a ConfigMap
, because your database URL will most
likely include a username and password. You can create this secret using this
command:
kubectl create secret generic <your secret name> \
--from-literal=databaseUrl=<your database url> \
--namespace=<your namespace>
Obviously, substitute <your secret name>
, <your database url>
, and
<your namespace>
in the example above. The Kubernetes secret MUST have the
key databaseUrl
. You CANNOT name this something else. Note that
Wildboar Software's Helm chart, by default, will seek to mount a secret named
meerkat-database-secret
, so this is what you SHOULD name this secret, unless
you have multiple DSA instances that you expect to run.
There may be other secrets that you wish to create, such as the signing secret
and TLS secret. These can be done with a slightly different command. Both of
these secrets are of type kubernetes.io/tls
and can be created using the
command kubectl create secret tls ...
.
When you have created all of the ConfigMap
s and Secret
s you plan to create,
run these commands to deploy Meerkat DSA:
- Run
helm repo add wildboar https://wildboarprod.blob.core.windows.net/helm-charts
. This will install Wildboar Software's Helm repository to your saved list of repositories so you can use Helm charts defined by Wildboar Software. - Run
helm repo update
. This will update your local cache of all Helm charts that are available in your configured repositories. - Run
helm install <release-name> wildboar/meerkat-dsa ...
, but replace<release-name>
with any name you choose for your Meerkat DSA deployment, and replace the...
with any other command arguments you need to supply to Helm to customize your deployment. At a minimum, you may want to append--set databaseSecretName=<your database secret name>
. If you want your instance to be publicly accessible, add--set service.type=LoadBalancer
to that command.
You should configure Kubernetes
inter-pod affinity
so that your Meerkat DSA runs on the same node as your database to minimize
latency. It does not seem like there is an easy way to do this using the Helm
CLI alone: you might have to define a values override file. See
.github/workflows/main.yml
within this repository for an example
(specifically, the deploy_demo
job).
If you want access to the web admin console, add
--set dangerouslyExposeWebAdmin=true
to the command above, but be sure to
configure authentication for it or put it behind a secure reverse HTTP proxy
that requires authentication and TLS. Client TLS authentication would be even
better than basic authentication.
Access to the web administration console means full permission to do anything. It is highly recommended that you not only configure authentication for it, but also use Kubernetes Network Policy to ensure that other pods cannot even reach it.
As an even more secure measure, you may simply not expose a service for that pod
at all, requiring that you use
kubectl port-forward
to access it. This means that only your Kubernetes cluster administrators would
be able to reach the web admin console, but this might work for your use case.
You can see example deployments to Kubernetes clusters in Bash scripts here and in GitHub Actions YAML configuration here.
DSA Initialization
When your DSA comes online, if there is not root DSE, your DSA will create it. Otherwise, there are no entries in existence.
Access Control
At this point, your DSA will be world-readable and world-writeable. If you do not want this, you will need to implement access controls. To do this, you will need to define an Access Control Specific Area (ACSA) that spans the entirety of your autonomous administrative area. To do this, you will need to do these things in this specific order (details to follow):
Create an administrative user.
Set a password for the administrative user.
Create an administrative point, then
Create access control subentries under this administrative point, then
Add the
id-ar-accessControlSpecificArea
value to theadministrativeRole
attribute of the administrative point, and set theaccessControlScheme
attribute of the administrative point.basicAccessControlScheme
simplifiedAccessControlScheme
rule-based-access-control
rule-and-basic-access-control
rule-and-simple-access-control
If you create the administrative point with an ACSA role before creating the subentries, you might be locked out, unable to read or write anything including and below that administrative point! This is because an absence of Access Control Information (ACI) items, as would be present in subentries, indicates a denial of access. Creating the ACSA administrative point is the switch that turns access control on. Ensure you configure your ACI items in your ACSA and ACIA subentries are configured to allow you to continue to set up your DSA!
Creating the administrative user
You will need to create a DSE of type entry
that will represent the
administrator of the DSA. There are no requirements as to what object classes
this entry must have.
Set a password for the administrative user
This administrator's DSE should have a password set through the
administerPassword
operation, which will set a password for this entry. The
password SHOULD NOT be set using the modifyEntry
or addEntry
operation.
Creating the administrative point
You may use an existing administrative point if you'd like, but, again, anything
in your DSA that is not enclosed by an ACSA admininstrative point will be
world-readable and world-writeable. This administrative point MUST NOT have the
id-ar-accessControlSpecificArea
role value present in its administrativeRole
attribute (for right now).
Creating access control subentries
You will need to create access control subentries beneath your soon-to-be access control administrative point. These subentries contain Access Control Information (ACI) items. These subentries shall:
- Have an
objectClass
attribute having a valueaccessControlSubentry
. - Have a
prescriptiveACI
attribute with values.
Defining what ACI items are here is outside of scope for this documentation, but the ACI items that you define SHOULD:
- Allow administrators all permissions to all entries.
- Allow users to read and write to their own entries,
- Including:
- Changing their passwords
- Deleting their entry
- Excluding:
- Modifying operational attributes
- Including:
- Allow unauthenticated / anonymous users to only read non-sensitive entries and attributes, if any.
When defining ACI items, keep in mind that the server will apply a configurable
local qualifier to the calculated AuthenticationLevel
for a user based on
whether the connection is secured through Transport Layer Security (TLS) or some
other means. The "points" that Meerkat assigns to a connection secured as such
is determined by the value of the environment variable
AUTH_LEVEL_LOCAL_QUALIFIER_POINTS_FOR_TLS
. This environment variable shall
contain a reasonably-sized (not extremely large) integer.
The ACI items you define SHOULD be few in number, and, for performance reasons,
all ACI items within an ACSA SHOULD have distinct precedence
values.
Making the administrative point an access control administrative point
You should then define an access control administrative point. This can overlap
with your autonomous administrative point. This is a DSE of type admPoint
that
has an administrativeRole
attribute having value
id-ar-accessControlSpecificArea
.
If you do not have access control administrative points defined, your DSA will be world-readable and world-writeable!
One this point exists, your access control will activate.