N18 Cross model relations

Cross-model Relations (CMR) allow applications in different models to be related. Models may be hosted on the same controller, different controllers, and different clouds.

What is a relation?: If you are unsure what the terms model and relation mean in the context of Juju, then you should read the Models and Managing relations pages for introductions.


In this section command syntax may be simplified to keep complexity to a minimum. See the above CLI help text for full syntax and more examples.

Intended use cases

CMR addresses the case where one may wish to centralise a service. This can allows your models to become more targeted and can reduce their needs.

Some services that can benefit from central administration:

  • Certificate Authorities, such as the easyrsa charm
  • secret management, such as Vault
  • logging and monitoring
  • block storage management
  • databases

Another use case would be when you are simply using different cloud types.


An offer is an application that an administrator makes available to applications residing in remote models. The model in which the offer resides is known as the offering model.

The application (and model) that utilizes the offer is called the consuming application (and consuming model).

Like traditional Juju applications,

  • an offer has one or more endpoints that denote the features available for that offer.

  • a fully-qualified offer endpoint includes the associated offer name:

    <offer name>:<offer endpoint>

  • a reference to an offer endpoint will often omit the ‘offer name’ if the context presupposes it.

  • an endpoint has an interface that satisfies a particular protocol.


How to create an offer

An offer stems from an application endpoint. This is how an offer is created:

juju offer <application>:<application endpoint>

Although an offer may have multiple (offer) endpoints it is always expressed as a single URL:


If the ‘controller’ portion is omitted the current controller is assumed.

How to remove an offer

An offer can be removed providing a relation has not been made to it. To override this behaviour the --force option is required, in which case the relation is also removed. This is how an offer is removed:

juju remove-offer [--force] <offer-url>

Note that if the offer resides in the current model then the shorter offer name can be used instead of the longer URL.

Similarly, if an application is being offered it cannot be deleted until all its offers are removed.

How do I control access to an offer?

Offers can have one of three access levels:

  • read (a user can see the offer when searching)
  • consume (a user can relate an application to the offer)
  • admin (a user can manage the offer)

These are applied similarly to how standard model access is applied, via the juju grant and juju revoke commands:

juju grant <user> <access-level> <offer-url>
juju revoke <user> <access level> <offer-url>

Revoking a user’s consume access will result in all relations for that user to that offer to be suspended. If the consume access is granted anew, each relation will need to be individually resumed. Suspending and resuming relations are explained in more detail later.

Relating to offers

If a user has consume access to an offer, they can deploy an application in their model and establish a relation to the offer by way of its URL. The controller part of the URL is optional if the other model resides in the same controller.

juju add-relation <application>[:<application endpoint>] <offer-url>[:<offer endpoint>]

Specifying the endpoint for the application and the offer is analogous to normal relations. They can be added but are often unnecessary:

juju add-relation <application> <offer-url>

When an offer is related to, a proxy application is made in the consuming model, named after the offer.

Note that the relations block in status shows any relevant status information about the relation to the offer in the Message field. This includes any error information due to rejected ingress, or if the relation is suspended etc.

An offer can be consumed without relating to it. This workflow sets up the proxy application in the consuming model and creates a user-defined alias for the offer. This latter is what’s used to subsequently relate to. Having an offer alias can avoid a namespace conflict with a pre-existing application.

juju consume <offer-url> <offer-alias>
juju add-relation <application> <offer alias>

Offers which have been consumed show up in juju status in the SAAS section. Such an object can be removed in the consuming model with:

juju remove-saas <offer alias>

Relations and firewalls

When the consuming model is behind a NAT firewall its traffic will typically exit (egress) that firewall with a modified address/network. In this case, the --via option can be used with the juju relate command to request the firewall on the offering side to allow this traffic. This option specifies the NATed address (or network) in CIDR notation:

juju add-relation <application> <offer url> --via <cidr subnet>

It’s possible to set this up in advance at the model level in this way:

juju model-config egress-subnets=<cidr subnet>

To be clear, the above command is applied to the consuming model.

However, an administrator can control what incoming traffic is allowed to contact the offering model by whitelisting subnets:

juju set-firewall-rule juju-application-offer --whitelist <cidr subnet>

Where ‘juju-application-offer’ is a well-known string that denotes the firewall rule to apply to any offer in the current model.

The above command is applied to the offering model.

The juju set-firewall-rule command only affects subsequently created relations, not existing ones.

Suspending and resuming relations

A relation to an offer may be temporarily suspended, causing the consuming application to no longer have access to the offer:

juju suspend-relation <id1>

A suspended relation is resumed by an admin on the offering side:

juju resume-relation <id1>

Command juju offers provides the relation ids.

Removing relations

To remove a relation entirely:

juju remove-relation <id1>

Removing a relation on the offering side will trigger a removal on the consuming side. A relation can also be removed from the consuming side, as well as the application proxy, resulting in all relations being removed.

Example scenarios

The following CMR scenarios will be examined:

  • Scenario #1
    A MediaWiki deployment, based within the same controller, used by the admin user, but consumed by multiple models.
  • Scenario #2
    A MediaWiki deployment, based within multiple controllers, used by a non-admin user, and consumed by a single model.

Commands used with Cross-model Relations

The commands related specifically to this subject are:

: Accepts an offer to a model but does not relate to it.

: Finds URLs and endpoints of available offers.

: Lists the firewall rules.

: Creates an offer.

: Lists connected (related to) offers.

: Removes an offer.

: Removes a SAAS object created with the juju consume command.

: Resumes a suspended relation to an offer.

: Sets a firewall rule.

: Shows details for a connected (related to) offer.

: Suspends a relation to an offer.

Maybe we should call CMR “Multi cloud relations”

Creating offers by default uses the app name but they can also be aliased

There’s a fair bit more material in this document also

I like that term :slight_smile:

For consumers of offers, it’s worth mentioning that the SAAS section of status shows the offers that have been consumed in the model that their status. These named SAAS entries can be related to just like any other application. Or the relation to the offer can be done in one step using the juju relate command.

For offer admins, I’d also include material on list-offers etc as that’s where the relation id is found.

For examples, may be worth including nagios/nrpe and prometheus/telegraf as common scenarios people use CMR for.

I think this is mentioned here:

But not here:

Would this be correct?

juju offer <application>:<application endpoint> offer-name

Can you please point where in the docs this should be added? Also, can you please provide an example of status output?

Same here, can you please draft some material to add there?

Same here. Could you please draft something about these common scenarios?

I haven’t got any real world examples to hand - bootstack or IS folks who do this stuff for real would though.
Very simplistic examples (not checked live, just a thought bubble):


juju bootstrap google bigbrother
juju bootstrap aws monitorme
juju switch bigbrother
juju deploy prometheus
juju expose prometheus
juju offer prometheus:target offerprom
juju switch monitorme
juju deploy ubuntu
juju deploy telegraf
juju relate ubuntu:juju-info telegraf
juju consume bigbrother:/admin/default.offerprom promed
juju relate telegraf:prometheus-client promed:target

nagios (single controller example, adapt for multi)

juju bootstrap aws
juju switch controller
juju deploy nagios
juju expose nagios
juju offer nagios:monitors
juju switch default
juju deploy ubuntu
juju deploy nrpe
juju add-relation ubuntu nrpe
juju add-relation nrpe:monitors controller.nagios

The caveat is that a lot of CMR are actually within the same cloud, but aggregating models. (eg, common prometheus scraping source in one model, and separate deployments feeding that into the common target).

1 Like

Indeed. The multi-cloud examples were more to show that it is possible. But yeah, real world is more targetted at models in the same cloud.


There are plenty of good suggestions here of material and content to add. I will leave these for later as the priority atm is to make sure people will be able to follow the guides as they are, at least.