Skip to content

Commit

Permalink
feat: add secrets interface
Browse files Browse the repository at this point in the history
  • Loading branch information
gboutry committed Aug 18, 2023
1 parent c2427e6 commit 3399ded
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 0 deletions.
81 changes: 81 additions & 0 deletions docs/json_schemas/secrets/v0/provider.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
}
}
41 changes: 41 additions & 0 deletions docs/json_schemas/secrets/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/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"
}
}
}
}
}
67 changes: 67 additions & 0 deletions interfaces/secrets/v0/README.md
Original file line number Diff line number Diff line change
@@ -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
```
5 changes: 5 additions & 0 deletions interfaces/secrets/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: []
52 changes: 52 additions & 0 deletions interfaces/secrets/v0/schema.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3399ded

Please sign in to comment.