Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add vault-kv interface #97

Merged
merged 13 commits into from
Sep 13, 2023
Merged
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ To quickly get started, see the [template interface](https://github.com/canonica
| Security | [`mutual_tls`](interfaces/mutual_tls/v0/README.md) | ![Status: Draft](https://img.shields.io/badge/Status-Draft-orange) |
| | [`tls_certificates/v0`](interfaces/tls_certificates/v0/README.md) | ![Status: Live](https://img.shields.io/badge/Status-Live-darkgreen) |
| | [`tls_certificates/v1`](interfaces/tls_certificates/v1/README.md) | ![Status: Draft](https://img.shields.io/badge/Status-Draft-orange) |
| | [`vault-kv`](interfaces/vault_kv/v0/README.md) | ![Status: Draft](https://img.shields.io/badge/Status-Draft-orange) |
| Metadata | [`k8s-service`](interfaces/k8s-service/v0/README.md) | ![Status: Draft](https://img.shields.io/badge/Status-Draft-orange) |
| Storage | [`s3`](interfaces/s3/v0/README.md) | ![Status: Draft](https://img.shields.io/badge/Status-Draft-orange) |

Expand Down
52 changes: 52 additions & 0 deletions docs/json_schemas/vault_kv/v0/provider.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"title": "ProviderSchema",
"description": "The schema for the provider side of this interface.",
"type": "object",
"properties": {
"unit": {
"$ref": "#/definitions/BaseModel"
},
"app": {
"$ref": "#/definitions/VaultKvProviderSchema"
}
},
"required": [
"app"
],
"definitions": {
"BaseModel": {
"title": "BaseModel",
"type": "object",
"properties": {}
},
"VaultKvProviderSchema": {
"title": "VaultKvProviderSchema",
"type": "object",
"properties": {
"vault_url": {
"title": "Vault Url",
"description": "The URL of the Vault server to connect to.",
"type": "string"
},
"mount": {
"title": "Mount",
"description": "The KV mount available for the requirer application, respecting the pattern 'charm-<requirer app>-<user provided suffix>'.",
"type": "string"
},
"credentials": {
"title": "Credentials",
"description": "Mapping of unit name and credentials for that unit. Credentials are a juju secret containing a role-id and role-secret-id.",
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"required": [
"vault_url",
"mount",
"credentials"
]
}
}
}
41 changes: 41 additions & 0 deletions docs/json_schemas/vault_kv/v0/requirer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"title": "RequirerSchema",
"description": "The schema for the requirer side of this interface.",
"type": "object",
"properties": {
"unit": {
"$ref": "#/definitions/UnitVaultKvRequirerSchema"
},
"app": {
"$ref": "#/definitions/AppVaultKvRequirerSchema"
}
},
"required": [
"unit",
"app"
],
"definitions": {
"UnitVaultKvRequirerSchema": {
"title": "UnitVaultKvRequirerSchema",
"type": "object",
"properties": {
"egress_subnet": {
"title": "Egress Subnet",
"default": "Egress subnet to use, in CIDR notation.",
"type": "string"
}
}
},
"AppVaultKvRequirerSchema": {
"title": "AppVaultKvRequirerSchema",
"type": "object",
"properties": {
"mount_suffix": {
"title": "Mount Suffix",
"default": "Suffix to append to the mount name to get the KV mount.",
"type": "string"
}
}
}
}
}
62 changes: 62 additions & 0 deletions interfaces/vault_kv/v0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# `vault-kv`

## 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 -- mount_suffix, egress_subnet --> Provider
Provider -- vault_url, mount, 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 mount, the mount name shall respect the following pattern: `charm-<requirer app>-<user provided suffix>`
- Must create an approle restricted to the requiring unit's egress subnet.
- Must create a Juju secret containing a role-id and role-secret-id for each unit
- Must provide the Juju secret ID in the relation data.

### Requirer

Requirer expectations

- Must provide a mount suffix
- Must provide an egress subnet for each unit requiring access to the vault key value store.
The unit's egress_subnet shall be used to restrict access to the secret backend.

## Relation Data

[\[Pydantic Schema\]](./schema.py)

#### Example

```yaml
provider:
app:
vault_url: http://10.152.183.104:8200
mount: charm-barbican-secrets
credentials: |
gruyaume marked this conversation as resolved.
Show resolved Hide resolved
{
"barbican-0": "secret://4f7cc474-a23d-49a2-8b6e-9835c1e08325/cjk5slcrl3uc767oebp0",
"barbican-1": "secret://4f7cc474-a23d-49a2-8b6e-9835c1e08325/cjk5slcrl3uc767oebpg"
gboutry marked this conversation as resolved.
Show resolved Hide resolved
}
unit: {}
requirer:
app:
mount_suffix: secrets
unit:
barbican-0:
egress_subnet: 10.1.166.206/32
barbican-1:
egress_subnet: 10.1.166.230/32
```
5 changes: 5 additions & 0 deletions interfaces/vault_kv/v0/charms.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
providers: []

# list of charms using this interface as requirers.
# same structure as providers
requirers: []
49 changes: 49 additions & 0 deletions interfaces/vault_kv/v0/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""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 VaultKvProviderSchema(BaseModel):
vault_url: str = Field(description="The URL of the Vault server to connect to.")
mount: str = Field(
description=(
"The KV mount available for the requirer application, "
"respecting the pattern 'charm-<requirer app>-<user provided suffix>'."
)
)
credentials: Json[Mapping[str, str]] = Field(
description=(
"Mapping of unit name and credentials for that unit."
" Credentials are a juju secret containing a role-id and role-secret-id."
)
)


class AppVaultKvRequirerSchema(BaseModel):
mount_suffix: str = Field("Suffix to append to the mount name to get the KV mount.")


class UnitVaultKvRequirerSchema(BaseModel):
egress_subnet: str = Field("Egress subnet to use, in CIDR notation.")


class ProviderSchema(DataBagSchema):
"""The schema for the provider side of this interface."""

app: VaultKvProviderSchema


class RequirerSchema(DataBagSchema):
"""The schema for the requirer side of this interface."""

app: AppVaultKvRequirerSchema
unit: UnitVaultKvRequirerSchema