Channel Revision Published Runs on
1/stable 34 05 Aug 2025
Ubuntu 22.04
1/candidate 34 08 Jul 2025
Ubuntu 22.04
1/beta 34 26 Jun 2025
Ubuntu 22.04
1/edge 34 24 Jun 2025
Ubuntu 22.04
2/edge 45 11 Sep 2025
Ubuntu 22.04
juju deploy istio-beacon-k8s --channel 1/stable
Show information

Platform:

charms.istio_beacon_k8s.v0.service_mesh

Service Mesh Library.

This library facilitates adding your charmed application to a service mesh, leveraging the service_mesh and cross_model_mesh interfaces to provide secure, policy-driven traffic management between applications.

Overview

Service meshes provide capabilities for routing, controlling, and monitoring traffic between applications. A key feature is the ability to restrict traffic between Pods. For example, you can define that Pod MetricsScraper can GET from Pod MetricsProducer at /metrics on port 9090, while preventing SomeOtherPod from accessing it.

Consumer

The ServiceMeshConsumer object subscribes a charm and its workloads to a related service mesh. Since application relations often indicate traffic flow patterns (e.g., DbConsumer requiring DbProducer), ServiceMeshConsumer provides automated creation of traffic rules based on application relations. The ServiceMeshConsumer implements the requirer side of the juju relation.

Setup

First, add the required relations to your charmcraft.yaml:

requires:
  service-mesh:
    limit: 1
    interface: service_mesh
    description: |
      Subscribe this charm into a service mesh to enforce authorization policies.
  require-cmr-mesh:
    interface: cross_model_mesh
    description: |
      Allow a cross-model application access to catalogue via the service mesh.
      This relation provides additional data required by the service mesh to enforce cross-model authorization policies.

provides:
  provide-cmr-mesh:
    interface: cross_model_mesh
    description: |
      Access a cross-model application from catalogue via the service mesh.
      This relation provides additional data required by the service mesh to enforce cross-model authorization policies.

Instantiate a ServiceMeshConsumer object in your charm's __init__ method:

from charms.istio_beacon_k8s.v0.service_mesh import Method, Endpoint, AppPolicy, UnitPolicy, ServiceMeshConsumer

class MyCharm(CharmBase):
    def __init__(self, *args):
        super().__init__(*args)
        self._mesh = ServiceMeshConsumer(
            self,
            policies=[
                AppPolicy(
                    relation="data",
                    endpoints=[
                        Endpoint(
                            ports=[HTTP_LISTEN_PORT],
                            methods=[Method.get],
                            paths=["/data"],
                        ),
                    ],
                ),
                UnitPolicy(
                    relation="metrics",
                    ports=[HTTP_LISTEN_PORT],
                ),
            ],
        )

This example creates two policies:

  • An app policy - When related over the data relation, allow the related application to GET this application's /data endpoint on the specified port through the app's Kubernetes service.
  • A unit policy - When related over the metrics relation, allow the related application to access this application's unit pods directly on the specified port without any other restriction. UnitPolicy does not support fine-grained access control on the methods and paths via Endpoints.

An AppPolicy can be used to control how the source application can communicate with the target application via the app address. A UnitPolicy allows access to the specified port but only to the unit pods of the charm via individual unit addresses.

Cross-Model Relations

To request service mesh policies for cross-model relations, additional information is required.

For any charm that wants to grant access to a related application (say, the above example charm providing a data relation), these charms must also implement and relate over the cross_model_mesh relation. For cross_model_mesh, the charm granting access should be the provider, and the charm trying to communicate should be the requirer.

Joining the Mesh

For most charms, instantiating ServiceMeshConsumer automatically configures the charm to join the mesh. For legacy "podspec" style charms or charms deploying custom Kubernetes resources, you must manually apply the labels returned by ServiceMeshConsumer.labels() to your pods.

Provider

The ServiceMeshProvider implements the provider side of the juju relation. To provide a service mesh, instantiate ServiceMeshProvider in your charm's __init__ method:

from charms.istio_beacon_k8s.v0.service_mesh import ServiceMeshProvider

class MyServiceMeshCharm(CharmBase):
    def __init__(self, *args):
        super().__init__(*args)
        self._mesh = ServiceMeshProvider(
            charm=self,
            labels={"istio.io/dataplane-mode": "ambient"},
            mesh_relation_name="service-mesh",
        )
Configuration

The labels argument specifies the labels that indicate to the service mesh that a Pod should be subscribed to the mesh. These labels are service-mesh specific, for eg.:

  • For Istio ambient mesh: {"istio.io/dataplane-mode": "ambient"}
  • For Istio sidecar mesh: {"istio-injection": "enabled"}
Accessing Mesh Policies

The provider exposes the mesh_info() method that returns a list of MeshPolicy objects for configuring the service mesh:

for policy in self._mesh.mesh_info():
    configure_service_mesh_policy(policy)
Data Models
  • Method: Defines enum for HTTP methods (GET, POST, PUT, etc.)
  • Endpoint: Defines traffic endpoints with hosts, ports, methods, and paths
  • AppPolicy: Defines application level authorization policy for the consumer
  • UnitPolicy: Defines unit level authorization policy for the consumer
  • MeshPolicy: Contains complete policy information for mesh configuration
  • CMRData: Contains cross-model relation metadata

class Method

Description

HTTP method. None

class Endpoint

Description

Data type for a policy endpoint. None

class PolicyTargetType

Description

Target type for Policy classes. None

class Policy

Description

Data type for defining a policy for your charm. None

Methods

Policy. __init__( self )

class AppPolicy

Description

Data type for defining a policy for your charm application. None

class UnitPolicy

Description

Data type for defining a policy for your charm unit. None

class MeshPolicy

Description

Data type for storage service mesh policy information. None

class CMRData

Description

Data type containing the info required for cross-model relations. None

class ServiceMeshConsumer

Description

Class used for joining a service mesh. None

Methods

ServiceMeshConsumer. __init__( self , charm: CharmBase , mesh_relation_name: str , cross_model_mesh_requires_name: str , cross_model_mesh_provides_name: str , policies , auto_join: bool )

Class used for joining a service mesh.

Arguments

charm

The charm instantiating this object.

mesh_relation_name

The relation name as defined in metadata.yaml or charmcraft.yaml for the relation which uses the service_mesh interface.

cross_model_mesh_requires_name

The relation name as defined in metadata.yaml or charmcraft.yaml for the relation which requires the cross_model_mesh interface.

cross_model_mesh_provides_name

The relation name as defined in metadata.yaml or charmcraft.yaml for the relation which provides the cross_model_mesh interface.

policies

List of access policies this charm supports.

auto_join

Automatically join the mesh by applying labels to charm pods.

ServiceMeshConsumer. update_service_mesh( self )

Update the service mesh.

Description

Gathers information from all relations of the charm and updates the mesh appropriately to allow communication.

ServiceMeshConsumer. labels( self )

Description

Labels required for a pod to join the mesh. None

ServiceMeshConsumer. lightkube_client( self )

Returns a lightkube client configured for this library.

Description

This indirection is implemented to avoid complex mocking in integration tests, allowing the integration tests to do something equivalent to: ```python mesh_consumer = ServiceMeshConsumer(...) mesh_consumer._lightkube_client = mocked_lightkube_client

class ServiceMeshProvider

Description

Provide a service mesh to applications. None

Methods

ServiceMeshProvider. __init__( self , charm: CharmBase , labels , mesh_relation_name: str )

Class used to provide information needed to join the service mesh.

Arguments

charm

The charm instantiating this object.

mesh_relation_name

The relation name as defined in metadata.yaml or charmcraft.yaml for the relation which uses the service_mesh interface.

labels

The labels which related applications need to apply to use the mesh.

ServiceMeshProvider. update_relations( self )

Description

Update all relations with the labels needed to use the mesh. None

ServiceMeshProvider. mesh_info( self )

Description

Return the relation data that defines Policies requested by the related applications. None

def build_mesh_policies(
    relation_mapping: RelationMapping,
    target_app_name: str,
    target_namespace: str,
    policies,
    cmr_application_data
)

Generate MeshPolicy that implement the given policies for the currently related applications.

Arguments

relation_mapping

Charm's RelatioMapping object, for example self.model.relations.

target_app_name

The name of the target application, for example self.app.name.

target_namespace

The namespace of the target application, for example self.model.name.

policies

List of AppPolicy, or UnitPolicy objects defining the access rules.

cmr_application_data

Data for cross-model relations, mapping app names to CMRData.

def reconcile_charm_labels(
    client: Client,
    app_name: str,
    namespace: str,
    label_configmap_name: str,
    labels
)

Reconciles zero or more user-defined additional Kubernetes labels that are put on a Charm's Kubernetes objects.

Arguments

client

The lightkube Client to use for Kubernetes API calls.

app_name

The name of the application (Charm) to reconcile labels for.

namespace

The namespace in which the application is running.

label_configmap_name

The name of the ConfigMap that stores the labels.

labels

A dictionary of labels to set on the Charm's Kubernetes objects. Any labels that were previously created by this method but omitted in labels now will be removed from the Kubernetes objects.

Description

This function manages a group of user-defined labels that are added to a Charm's Kubernetes objects (the charm Pods (via editing the StatefulSet) and Service). Its primary uses are:

  • adding labels to a Charm's objects
  • updating or removing labels on a Charm's Kubernetes objects that were previously set by this method

To enable removal of labels, we also create a ConfigMap that stores the labels we last set. This way the function itself can be stateless.

This function takes a little care to avoid removing labels added by other means, but it does not provide exhaustive guarantees for safety. It is up to the caller to ensure that the labels they pass in are not already in use.