Connections
Modules on a Dedicated tenant sometimes talk to each other, or to the tenant’s GitLab instance. Your module declares the peer modules it initiates connections to, and Runway delivers to your pods what each connection needs. Today that is one secret per peer, which Dedicated’s Instrumentor publishes for the modules it has been configured for: a service token that both ends must agree on, for example. When Runway deploys your module it copies the secret of each peer into your module’s namespace, mounts it into your pods at a well-known path, and tells your service where to find it.
Your module also always receives its own secret, without declaring it. That’s the other end of the connections that peers initiate to your module: your service uses it to verify the token a caller presents.
Runway doesn’t know what the connection is for. It copies the secret as it is and leaves it to the two ends to agree on what the token authorises.
Declare the peers your module connects to
Section titled “Declare the peers your module connects to”List the peer modules under spec.connections.modules.set in the module manifest, by their Runway service ID.
The module manifest is the runway/v3 Runway manifest of your module on Dedicated, in .runway/ in a file named module.yaml or module-<suffix>.yaml (.yml works too), and names your Dedicated service ID in metadata.name:
apiVersion: runway/v3kind: RunwayManifestmetadata: name: example-service-dedicatedspec: connections: modules: set: - name: iam-data-dedicatedEach entry of modules.set needs a name, the peer’s Runway service ID. Names must be unique, and a name can’t
start with s3-, rds- or redis-: Runway reserves those prefixes for the Secrets of your module’s own
infrastructure. A module can’t list itself: Runway always delivers its own secret, so there’s nothing to declare.
Leave connections out if your module needs no peers; it still receives its own secret. runwayctl catalog create
validates the declaration in the merge request pipeline and copies it into the
Module Catalog entry of each release. The catalog
entry is the allow-list: on a tenant, Runway copies the secrets of the peers it names, your module’s own, and nothing
else. catalog create reads every module*.yaml file under .runway/ to find yours, so if several modules share the directory, an
invalid manifest of another module fails your pipeline too.
What Runway creates
Section titled “What Runway creates”When Runway deploys a release to a tenant, it reads the secret of each peer, and then your module’s own, from the
tenant’s AWS Secrets Manager at runway/shared/<name>, where Instrumentor stores it as a JSON object of strings. For
each of them, it then:
- creates a
Secretnamed<name>in your module’s namespace, with the source’s keys as they are, today the singletoken; - adds a
secretVolumesentry to your Helm values that mounts theSecretat/secrets/connections/modules/<name>; - sets the environment variable
MODULE_CONNECTION_SECRETS_PATHto/secrets/connections/modules.
For the manifest above, your service reads the peer’s token from
$MODULE_CONNECTION_SECRETS_PATH/iam-data-dedicated/token, that is
/secrets/connections/modules/iam-data-dedicated/token, and its own token from
$MODULE_CONNECTION_SECRETS_PATH/example-service-dedicated/token. The directory is fixed, like
/secrets/infrastructure for the backend secrets; read the variable rather than hard-coding the path.
The Secrets are created together with the other Runway resources, before the module’s Helm chart is installed, so
they exist when your pods start. Runway copies them on every deployment: a token that Instrumentor changes reaches
your module at the next deployment of the module on that tenant. Runway doesn’t force a restart of your pods when it
copies a changed token: your module is expected to detect the change at runtime, by re-reading the file, which the
kubelet refreshes when the Secret changes.
A secret, your module’s own or a peer’s, that doesn’t exist on the tenant, or isn’t a JSON object of strings with at least one key, fails the deployment before anything is changed in the cluster. The error names the secret, never its value. A missing secret usually means that Instrumentor hasn’t been configured to publish it on that tenant. Because every module receives its own secret, Instrumentor must publish one for every module deployed to the tenant, even a module without peers.
Overrides in the Tenant Model
Section titled “Overrides in the Tenant Model”A tenant can change a module’s connections with values_override.connections in its
Tenant Model. It has the same shape as the manifest’s connections, with one
more option: modules.add appends peers to the release’s list instead of replacing it.
{ "modular_features": { "modules": { "example-service-dedicated": { "enabled": true, "version": "v1.25.0", "values_override": { "connections": { "modules": { "add": [{ "name": "artifact-registry-dedicated" }] } } } } } }}| Override | Effect |
|---|---|
modules absent |
The release’s peers are kept. |
modules.set |
Replaces the release’s peers. |
modules.add |
Appends to the release’s peers. Names must stay unique. |
modules: {} |
Removes every peer. Your module still receives its own secret. |
As with Helm value overrides, this is an escape hatch for one tenant. Peers that every tenant needs belong in your manifest, where they are released and reviewed with the module.