Addons
An Addon to CIVITAS/CORE is served in a separate Git repository that can be submodule into the core's core_platform/addons/ directory to include it in a deployment. For more details on how to deploy and configure an addon, see the Addon Deployment section of the documentation.
Quickstart and Structure
The easiest way to start a new addon for CIVITAS/CORE is to use the Copier template. After answering a few questions, it creates a minimal repository structure for an addon with meaningful file naming and the necessary Ansible tasks to get started.
my_civitas_addon/
├─ tasks/
│ ├─ my_civitas_addon.yml
├─ vars/
│ ├─ default.yml
│ ├─ software_references.yml
├─ default_inventory.yml
├─ LICENSE
├─ README.md
├─ tasks.yml
Branching Model
To ensure compatibility with the core platform, addon development follows the same branching model, such that an addon release tag v1.5 is tested for compatibility with the core platform version v1.5.
Mandatory Addon features
Software References
Formalizing the software references of both the core platform and its addons is essential to automated vulnerability checks within dependencies and the ability to use a private registry to pull container images. All images used by the addon must therefore be listed in vars/software_references.yml and follow a given structure:
software:
my_civitas_addon:
helm_chart_name: some_helm_chart
helm_release_name: some_helm_release_name
helm_repo_name: "some_helm_repo_name"
helm_repo_url: "https://hub.example.com/helm-chart/"
helm_chart_version: "1.0.0"
some_component_a_of_the_addon:
registry: ...
repository: ...
tag: ...
some_component_b_of_the_addon:
...
While the most apparent usage of these definitions is within the Helm values file of the addon itself and its naming might appear independent, the paths
software.*.*.registrysoftware.*.*.repositorysoftware.*.*.tag
will be picked up by the software references of the platform core and are therefore non-optional.
The installation of the given Helm chart can then be simplified by using the core repository's task tasks/templates/k8s-helm.yml:
- name: "[Helm] Create the installation of My Civitas Addon"
include_tasks: tasks/templates/k8s-helm.yml
vars:
helm_repo_name: "{{ software.my_civitas_addon.helm_repo_name }}"
helm_repo_url: "{{ software.my_civitas_addon.helm_repo_url }}"
helm_chart_name: "{{ software.my_civitas_addon.helm_chart_name }}"
helm_release_name: "{{ software.my_civitas_addon.helm_release_name }}"
helm_chart_reference: "{{ helm_repo_name }}/{{ helm_chart_name }}"
helm_chart_version: "{{ software.my_civitas_addon.helm_chart_version }}"
helm_values_file: "{{ addon_dir|default('') + 'templates/my_civitas_addon_values.yml' }}"
helm_create_namespace: false
when: inv_addons.my_civitas_addon.enable == true
No root access
For security reasons, it is mandatory that all containers and their dependencies use non-root access.
Default Inventory
Configuration values that are exposed to the user must be given meaningful and secure defaults. The default values must be listed in a file called default_inventory.yml in the root of the addon repository and will automatically be picked up by the platform core.
all:
children:
controller:
vars:
inv_addons:
my_civitas_addon:
enable: true
ns_create: true
ns_name: "{{ ENVIRONMENT }}-mycivitasaddon"
ns_kubeconfig: "{{ kubeconfig_file }}"
subdomain: my_civitas_addon
Customizing of these values will be from the user's inventory file. The inv_addons section will support a separate subsection for each addon:
inv_addons:
import: true
addons:
- "addons/my_civitas_addon/tasks.yml"
my_civitas_addon:
ns_create: false
subdomain: mycustomsubdomain
Routing
- Routing through API management or
- Routing using Ingress
Routing through API Management
Creating an API route for the addon can be done using the core repository's task tasks/access/apis/add_api.yaml.
The definition files for individual routes
- are in
templates/access/apis/, - start with
my_civitas_addon_and - end in
.ymlor.yaml.
Examples for route definition files can be found in the respective directories of the core repository.
The task to add API routes can then be added like this:
- name: "APIs: Add HTTP API to APISIX"
include_tasks:
file: "tasks/access/apis/add_api.yaml"
vars:
api_enable: true
api_name: "My Civitas Addon"
api_prefix: "my_civitas_addon_"
api_portal_name: "My Civitas Addon"
api_path: "/"
api_rewrite_path: ""
api_portal_description: "API for My Civitas Addon"
api_upstream_host: "my_civitas_addon.{{ inv_addons.my_civitas_addon.ns_name }}.svc.cluster.local"
api_upstream_port: "7878"
api_upstream_health_check_path: "/"
api_upstream_health_check_type: "http"
api_upstream_timeout_send: 60
api_upstream_timeout_read: 60
api_type: "http"
Routing using Ingress
Alternatively, traffic to the addon can be routed through a separate ingress. The ingress can be generated using the application's Helm chart or created using a separate Kubernetes task in Ansible, depending on the specific situation.
IDM Integration
One of CIVITAS/CORE's key features is a central identity management used for all authenticated access to both platform and addon functionality. Addons must therefore implement integration with Keycloak either by direct OpenID Connect configuration of the application or by securing its endpoints using the API management's OpenID connect plugin.
The IDM integration process is as follows:
- receival of Keycloak's admin credentials from a Kubernetes secret
- receival of a Keycloak authentication token using the admin credentials
- creation of a separate API client for the addon's main application
- assignment of special Keycloak roles to the API client if necessary
- receival of credentials (client ID, client secret) for the newly created API client
- configuration of OpenID Connect in the addon's main application with the given credentials
Optional Addon features
Private Registry Support
Consumption of private registry images requires
- pointing to the private registry if available and
- using pull secrets if necessary.
Private registry support can be enabled by prefixing image repositories with the global private registry URL if defined.
image: "{{ inv_op_stack.private_registry.registry_full_url | default(software.inv_addons.my_civitas_addon.registry ) }}/{{ software.inv_addons.my_civitas_addon.repository }}:{{ software.inv_addons.my_civitas_addon.tag }}"
Configuring pull secrets in the addon's namespace can be done by including the respective task from the core repository.
- name: "My Civitas Addon: Ensure registry secret for private registry is available"
include_tasks: tasks/templates/registry_secret.yml