diff --git a/docs/json_schemas/secrets/v0/provider.json b/docs/json_schemas/secrets/v0/provider.json new file mode 100644 index 00000000..6a1fa7b3 --- /dev/null +++ b/docs/json_schemas/secrets/v0/provider.json @@ -0,0 +1,81 @@ +{ + "title": "ProviderSchema", + "description": "The schema for the provider side of this interface.", + "type": "object", + "properties": { + "unit": { + "$ref": "#/definitions/BaseModel" + }, + "app": { + "$ref": "#/definitions/SecretsProviderSchema" + } + }, + "required": [ + "app" + ], + "definitions": { + "BaseModel": { + "title": "BaseModel", + "type": "object", + "properties": {} + }, + "UnitCredentialsSchema": { + "title": "UnitCredentialsSchema", + "type": "object", + "properties": { + "role_id": { + "title": "Role Id", + "description": "The role ID to use to authenticate to Vault.", + "type": "string" + }, + "role_secret_id": { + "title": "Role Secret Id", + "description": "The role secret ID to use to authenticate to Vault.", + "type": "string" + } + }, + "required": [ + "role_id", + "role_secret_id" + ] + }, + "CredentialsSchema": { + "title": "CredentialsSchema", + "default": "Units' credentials", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/UnitCredentialsSchema" + } + }, + "SecretsProviderSchema": { + "title": "SecretsProviderSchema", + "type": "object", + "properties": { + "vault_url": { + "title": "Vault Url", + "description": "The URL of the Vault server to connect to.", + "type": "string" + }, + "kv_mountpoint": { + "title": "Kv Mountpoint", + "description": "The mountpoint of the KV store to use.", + "type": "string" + }, + "credentials": { + "title": "Credentials", + "description": "The credentials to use to authenticate to Vault.", + "allOf": [ + { + "$ref": "#/definitions/CredentialsSchema" + } + ] + } + }, + "required": [ + "vault_url", + "kv_mountpoint", + "credentials" + ] + } + } +} \ No newline at end of file diff --git a/docs/json_schemas/secrets/v0/requirer.json b/docs/json_schemas/secrets/v0/requirer.json new file mode 100644 index 00000000..f509aa40 --- /dev/null +++ b/docs/json_schemas/secrets/v0/requirer.json @@ -0,0 +1,41 @@ +{ + "title": "RequirerSchema", + "description": "The schema for the requirer side of this interface.", + "type": "object", + "properties": { + "unit": { + "$ref": "#/definitions/UnitSecretsRequirerSchema" + }, + "app": { + "$ref": "#/definitions/AppSecretsProviderSchema" + } + }, + "required": [ + "unit", + "app" + ], + "definitions": { + "UnitSecretsRequirerSchema": { + "title": "UnitSecretsRequirerSchema", + "type": "object", + "properties": { + "egress_subnet": { + "title": "Egress Subnet", + "default": "Egress subnet to use.", + "type": "string" + } + } + }, + "AppSecretsProviderSchema": { + "title": "AppSecretsProviderSchema", + "type": "object", + "properties": { + "secret_backend": { + "title": "Secret Backend", + "default": "The name of the secret backend to use.", + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/interfaces/secrets/v0/README.md b/interfaces/secrets/v0/README.md new file mode 100644 index 00000000..4a4ed0b0 --- /dev/null +++ b/interfaces/secrets/v0/README.md @@ -0,0 +1,67 @@ +# `secrets` + +## Usage + +Some charms require a secure key value store. This relation interface describes the expected behavior of any charm claiming to interact with Vault Key Value stores. + +## Direction + +```mermaid +flowchart TD + Requirer -- secret_backend, egress_subnet --> Provider + Provider -- vault_url, kv_mountpoint, credentials --> Requirer +``` + +## Behavior + +Both the Requirer and the Provider need to adhere to criteria to be considered compatible with the interface. + +### Provider + +Provider expectations + +- Must provide the vault url +- Must provide a key value mountpoint +- Must provide a role_id and role_secret_id for each unit, with access protected by unit's egress_subnet + +### Requirer + +Requirer expectations + +- Must provide a secret backend name, which must start with "charm-" +- Must provide an egress subnet for each unit used to protect access to the secret backend + +## Relation Data + +Describe the contents of the databags, and provide schemas for them. + +[\[Pydantic Schema\]](./schema.py) + +#### Example + +```yaml +provider: + app: + vault_url: http://10.152.183.104:8200 + kv_mountpoint: charm-barbican + credentials: | + { + "barbican-0": { + "role_id": 158778a2-04fc-39c5-ba13-0cb5faddb5eb", + "role_secret_id": "41c3e4eb-39ec-5c68-2f41-fbc1bc1e9c52" + }, + "barbican-1": { + "role_id": "38eb72db-60d0-082a-4847-6b9d1690cf02", + "role_secret_id": "fa1db047-3c90-e614-7ca0-76ce2ec1b6fc" + } + } + unit: {} +requirer: + app: + secret_backend: charm-barbican + unit: + barbican-0: + egress_subnet: 10.1.166.206/32 + barbican-1: + egress_subnet: 10.1.166.230/32 +``` diff --git a/interfaces/secrets/v0/charms.yaml b/interfaces/secrets/v0/charms.yaml new file mode 100644 index 00000000..b499b64e --- /dev/null +++ b/interfaces/secrets/v0/charms.yaml @@ -0,0 +1,5 @@ +providers: [] + +# list of charms using this interface as requirers. +# same structure as providers +requirers: [] diff --git a/interfaces/secrets/v0/schema.py b/interfaces/secrets/v0/schema.py new file mode 100644 index 00000000..751f13dd --- /dev/null +++ b/interfaces/secrets/v0/schema.py @@ -0,0 +1,52 @@ +"""This file defines the schemas for the provider and requirer sides of this relation interface. + +It must expose two interfaces.schema_base.DataBagSchema subclasses called: +- ProviderSchema +- RequirerSchema +""" + +from typing import Mapping + +from pydantic import BaseModel, Field, Json + +from interface_tester.schema_base import DataBagSchema + + +class UnitCredentialsSchema(BaseModel): + role_id: str = Field(description="The role ID to use to authenticate to Vault.") + role_secret_id: str = Field( + description="The role secret ID to use to authenticate to Vault." + ) + + +class CredentialsSchema(BaseModel): + __root__: Mapping[str, UnitCredentialsSchema] = Field("Units' credentials") + + +class SecretsProviderSchema(BaseModel): + vault_url: str = Field(description="The URL of the Vault server to connect to.") + kv_mountpoint: str = Field(description="The mountpoint of the KV store to use.") + credentials: Json[CredentialsSchema] = Field( + description="The credentials to use to authenticate to Vault." + ) + + +class AppSecretsProviderSchema(BaseModel): + secret_backend: str = Field("The name of the secret backend to use.") + + +class UnitSecretsRequirerSchema(BaseModel): + egress_subnet: str = Field("Egress subnet to use.") + + +class ProviderSchema(DataBagSchema): + """The schema for the provider side of this interface.""" + + app: SecretsProviderSchema + + +class RequirerSchema(DataBagSchema): + """The schema for the requirer side of this interface.""" + + app: AppSecretsProviderSchema + unit: UnitSecretsRequirerSchema