Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
MD024: # no-duplicate-heading
siblings_only: true
MD033: # no-inline-html
allowed_elements:
- br
- summary
- details
- strong
MD013: false # Line length
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency and to adhere to POSIX standards, it's a good practice to end files with a newline character.

MD013: false # Line length

1 change: 1 addition & 0 deletions code_samples/authorization/get_decision.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import (
"log"

"github.com/opentdf/platform/protocol/go/authorization"
"github.com/opentdf/platform/protocol/go/entity"
"github.com/opentdf/platform/protocol/go/policy"
"github.com/opentdf/platform/sdk"
)
Expand Down
26 changes: 13 additions & 13 deletions docs/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,37 @@ graph TD
class POLICY,AUTHZ,ERS,KAS opentdfService
class ATTR_SOURCES,IDP,CLIENT externalSystem

click POLICY "components/policy/" "Go to Policy Service docs"
click AUTHZ "components/authorization" "Go to Authorization Service docs"
click ERS "components/entity_resolution" "Go to Entity Resolution Service docs"
click KAS "components/key_access" "Go to Key Access Server docs"
click POLICY "components/policy/"
click AUTHZ "components/authorization"
click ERS "components/entity_resolution"
click KAS "components/key_access"
```

### [Policy Service](components/policy/)

The **Policy Service** is where all access control policies are defined and managed. It provides the tools and APIs to create a rich set of policies that govern data access. This includes not only attributes and their values, but also the definitions of **actions, obligations, and key access mappings**.
The Policy Service is where all access control policies are defined and managed. It provides the tools and APIs to create a rich set of policies that govern data access. This includes not only attributes and their values, but also the definitions of **actions, obligations, and key access mappings**.

In the context of the NIST ABAC model, the Policy Service functions as the **Policy Administration Point (PAP)**.
In the context of the NIST ABAC model, the Policy Service functions as the [Policy Administration Point (PAP)](https://csrc.nist.gov/glossary/term/policy_administration_point).

### [Authorization Service](components/authorization)

The **Authorization Service** is the core decision-making engine of the platform. It is responsible for evaluating the rich policies from the Policy Service against a set of attributes to render an authorization decision.
The Authorization Service is the core decision-making engine of the platform. It is responsible for evaluating the rich policies from the Policy Service against a set of attributes to render an authorization decision.

In the context of the NIST ABAC model, it functions as the **Policy Decision Point (PDP)**.
In the context of the NIST ABAC model, it functions as the [Policy Decision Point (PDP)](https://csrc.nist.gov/glossary/term/policy_decision_point).

### [Entity Resolution Service (ERS)](components/entity_resolution)

The **Entity Resolution Service** is responsible for gathering the attributes about a subject needed for a decision. By default, it can derive attributes from claims in an authentication token. Optionally, it can be configured to connect to external attribute sources (LDAP, SQL) to "hydrate" the entity with more attributes.
The Entity Resolution Service is responsible for gathering the attributes about a subject needed for a decision. By default, it can derive attributes from claims in an authentication token. Optionally, it can be configured to connect to external attribute sources (LDAP, SQL) to "hydrate" the entity with more attributes.

In the context of the NIST ABAC model, the ERS functions as the **Policy Information Point (PIP)**.
In the context of the NIST ABAC model, the ERS functions as the [Policy Information Point (PIP)](https://csrc.nist.gov/glossary/term/policy_information_point).

### [Key Access Server (KAS)](components/key_access)

The **Key Access Server (KAS)** enforces access control decisions. Its role is more extensive than a typical enforcement point:
The Key Access Server (KAS) enforces access control decisions. Its role is more extensive than a typical enforcement point:

- **Cryptographic Enforcement:** It enforces decisions by granting or withholding cryptographic keys for TDF decryption.
- **Encryption Enablement:** It manages key exchanges and enables various TDF encryption modes.

In the context of the NIST ABAC model, the KAS functions as the **Policy Enforcement Point (PEP)**.
In the context of the NIST ABAC model, the KAS functions as the [Policy Enforcement Point (PEP)](https://csrc.nist.gov/glossary/term/policy_enforcement_point).

Furthermore, the OpenTDF platform is designed for flexibility. Developers can **build and integrate their own custom PEPs**. These custom enforcement points can leverage the platform's robust Authorization (PDP) and Policy (PAP) services while implementing enforcement logic tailored to specific applications. These custom PEPs can also optionally interface with the KAS to take advantage of its powerful cryptographic capabilities.
Furthermore, the OpenTDF platform is designed for flexibility. Developers can **build and integrate their own custom PEPs**. These custom enforcement points can leverage the platform's robust Authorization ([PDP](https://csrc.nist.grov/glossary/term/policy_decision_point)) and Policy ([PAP](https://csrc.nist.gov/glossary/term/policy_administration_point)) services while implementing enforcement logic tailored to specific applications. These custom PEPs can also optionally interface with the KAS to take advantage of its powerful cryptographic capabilities.
23 changes: 20 additions & 3 deletions docs/components/policy/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,26 @@ slug: /components/policy
Policy is the all-encompassing name for configuration of cryptographically-bound Attribute Based Access Control (ABAC) within the Platform.

```mermaid
graph LR;
Data<-- Resource Mappings -->Attributes;
Attributes<-- Subject Mappings -->Entities;
graph TD;
subgraph "Policy Framework"
Data["Data/Resources"]
Attributes["Attributes<br/>(Namespaces, Definitions, Values)"]
Entities["Entities/Subjects"]
Actions["Actions<br/>(decrypt, transmit, etc.)"]
end

Data -.->|Resource Mappings| Attributes
Entities -.->|Subject Mappings| Attributes
Actions -.->|Subject Mappings| Entities

subgraph "Access Decision"
Decision{"Access Control<br/>Decision"}
end

Attributes --> Decision
Actions --> Decision
Entities --> Decision
Data --> Decision
```

TDF creation and decryption are driven by the Policy within a Platform instance and the TDF manifest. In other words, on a TDF decryption request, the platform services (KAS, Authorization) compare attributes on the TDF against the requester's entitlements to make a decision to release the key or not.
Expand Down
243 changes: 225 additions & 18 deletions docs/components/policy/keymanagement/base_key.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,238 @@
---
sidebar_position: 1
sidebar_position: 4
slug: /components/policy/keymanagement/base_key
---

# Base Key
# Base Keys

A base key, or default key, is a key that will be used when no grants or key mappings are found from the attributes passed in. Base keys are set by an admin for the purpose of ensuring that insecure keys are not used by default when no mappings/grants are found.
Base Keys provide a system-wide default encryption key that serves as a fallback when no specific key mappings are found for the requested attributes. This ensures consistent encryption behavior and prevents the use of potentially insecure default keys.

## How to get/set a base key
## Base Key Management

:::important
You must have admin permission to use any key operations.
Base keys are managed through the OpenTDF platform's key management system. The platform ensures that:

- **Only one base key exists at any time** - Setting a new base key automatically replaces the previous one
- **No manual cleanup required** - The system handles base key replacement automatically
- **Seamless transitions** - Applications continue working during base key updates
- **Active key enforcement** - Only active keys can be designated as base keys

### Automatic Replacement Behavior

When you set a new base key using `otdfctl`, the platform:

1. **Validates** the new key is active and accessible
2. **Replaces** the existing base key reference automatically
3. **Updates** all internal references immediately
4. **Confirms** the change through the API response

Check failure on line 26 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'NPE' instead of 'API'. Raw Output: {"message": "[Vale.Terms] Use 'NPE' instead of 'API'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 26, "column": 40}}}, "severity": "ERROR"}

No additional cleanup or management steps are required.

## Managing Base Keys

### Set a Base Key

**Using Key ID:**

```bash
# Set base key by key UUID
otdfctl policy kas-registry key base set --id "550e8400-e29b-41d4-a716-446655440000"
```

**Using KAS and Key ID:**

```bash
# Set base key by KAS name and key ID
otdfctl policy kas-registry key base set \
--kas-name "production-kas" \
--key-id "prod-rsa-2024"

# Set base key by KAS URI and key ID
otdfctl policy kas-registry key base set \
--kas-uri "https://kas.example.com" \
--key-id "prod-rsa-2024"
```

### Get Current Base Key

```bash
# Get the current base key information
otdfctl policy kas-registry key base get
```

**Example Response:**

```json
{
"base_key": {
"kas_uri": "https://kas.example.com",
"public_key": {
"algorithm": "ALGORITHM_RSA_2048",
"kid": "prod-rsa-2024",
"pem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n"
},
"kas_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}
```

## Base Key Requirements

### Key Status Requirement

:::important Active Keys Only

Check failure on line 82 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Repetition] 'Only' is repeated! Raw Output: {"message": "[Vale.Repetition] 'Only' is repeated!", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 82, "column": 26}}}, "severity": "ERROR"}
Only keys with `KEY_STATUS_ACTIVE` status can be set as base keys. The system will reject attempts to set rotated or inactive keys as the base key.
:::

When using the [kas-registry proto](https://github.com/opentdf/platform/blob/main/service/policy/kasregistry/key_access_server_registry.proto#L659-L662) and an active connection to the platform you can use the above base key rpcs to set and retrieve the base key.
### Automatic Rotation Updates

When a base key is rotated:

1. The old key status changes to `KEY_STATUS_ROTATED`
2. The new key becomes `KEY_STATUS_ACTIVE`
3. **The base key reference is automatically updated** to point to the new active key
4. Applications continue using the rotated key seamlessly

```bash
# After rotation, the base key automatically points to the new key
# No manual base key update required
otdfctl policy kas-registry key rotate --id "current-base-key-uuid" ...
```

## SDK Behavior with Base Keys

Check failure on line 101 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'proto' instead of 'SDK'. Raw Output: {"message": "[Vale.Terms] Use 'proto' instead of 'SDK'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 101, "column": 4}}}, "severity": "ERROR"}

### Key Resolution Priority

The SDK follows this precedence when resolving keys for TDF operations:

Check failure on line 105 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'Keycloak' instead of 'TDF'. Raw Output: {"message": "[Vale.Terms] Use 'Keycloak' instead of 'TDF'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 105, "column": 57}}}, "severity": "ERROR"}

Check failure on line 105 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'proto' instead of 'SDK'. Raw Output: {"message": "[Vale.Terms] Use 'proto' instead of 'SDK'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 105, "column": 5}}}, "severity": "ERROR"}

1. **Attribute Value** key mappings (most specific)
2. **Attribute Definition** key mappings
3. **Namespace** key mappings

Check failure on line 109 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'Autoconfigure' instead of 'Namespace'. Raw Output: {"message": "[Vale.Terms] Use 'Autoconfigure' instead of 'Namespace'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 109, "column": 6}}}, "severity": "ERROR"}
4. **Base Key** (system fallback)
5. ~~Passed-in KAS info~~ (deprecated behavior)

### Information Override

When a base key is configured, the SDK will:

Check failure on line 115 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'proto' instead of 'SDK'. Raw Output: {"message": "[Vale.Terms] Use 'proto' instead of 'SDK'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 115, "column": 36}}}, "severity": "ERROR"}

✅ **Override client-provided KAS information** with base key's KAS details
✅ **Override client-provided key algorithm** with base key's algorithm
✅ **Use base key for all encryption operations** when no specific mappings exist

### NanoTDF Compatibility

:::warning ECC Requirement for NanoTDF
**NanoTDF requires Elliptic Curve keys** for optimal performance and compatibility.

- ✅ If base key is ECC (`ALGORITHM_EC_P256`, `ALGORITHM_EC_P384`, `ALGORITHM_EC_P521`) → NanoTDF works
- ❌ If base key is RSA (`ALGORITHM_RSA_2048`, `ALGORITHM_RSA_4096`) → SDK falls back to client-provided key or errors

Check failure on line 127 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'proto' instead of 'SDK'. Raw Output: {"message": "[Vale.Terms] Use 'proto' instead of 'SDK'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 127, "column": 71}}}, "severity": "ERROR"}

**Recommendation:** Use ECC keys as base keys to ensure full NanoTDF compatibility.
:::

### Future Strict Mode

:::note Upcoming Changes
In future SDK versions (post v0.5.0), the platform will enforce **strict mode**:

Check failure on line 135 in docs/components/policy/keymanagement/base_key.md

View workflow job for this annotation

GitHub Actions / Vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'proto' instead of 'SDK'. Raw Output: {"message": "[Vale.Terms] Use 'proto' instead of 'SDK'.", "location": {"path": "docs/components/policy/keymanagement/base_key.md", "range": {"start": {"line": 135, "column": 11}}}, "severity": "ERROR"}

- SDKs will **require** a base key to be set
- No fallback to client-provided KAS information
- Encryption will **fail** if no base key or key mappings are found

This ensures consistent security policy enforcement across all TDF operations.
:::

## Operational Examples

### Complete Base Key Setup

```bash
# 1. Register KAS
KAS_ID=$(otdfctl policy kas-registry create \
--uri "https://kas.example.com" \
--name "production-kas" \
--output json | jq -r '.key_access_server.id')

# 2. Create an ECC key for broad compatibility
KEY_ID=$(otdfctl policy kas-registry key create \
--kas-id "$KAS_ID" \
--key-id "base-ec-2024" \
--algorithm "ALGORITHM_EC_P256" \
--key-mode "KEY_MODE_CONFIG_ROOT_KEY" \
--public-key-pem "$(cat ec_public_key.pem)" \
--wrapping-key-id "root-kek" \
--wrapped-key "$(base64 < wrapped_ec_key.bin)" \
--output json | jq -r '.kas_key.key.id')

# 3. Set as base key
otdfctl policy kas-registry key base set --id "$KEY_ID"

# 4. Verify configuration
otdfctl policy kas-registry key base get
```

### Base Key Rotation

```bash
# Get current base key ID
CURRENT_BASE_KEY=$(otdfctl policy kas-registry key base get --output json | jq -r '.base_key.kas_id')

# Rotate the base key (automatically updates base key reference)
otdfctl policy kas-registry key rotate \
--id "$CURRENT_BASE_KEY" \
--new-key-id "base-ec-2025" \
--algorithm "ALGORITHM_EC_P384" \
--key-mode "KEY_MODE_CONFIG_ROOT_KEY" \
--wrapping-key-id "root-kek" \
--wrapping-key "$(base64 < new_wrapped_key.bin)"

# Verify base key now points to new key
otdfctl policy kas-registry key base get
```

## Monitoring and Troubleshooting

### Check Base Key Status

```bash
# Get current base key details
BASE_KEY_INFO=$(otdfctl policy kas-registry key base get --output json)
echo "$BASE_KEY_INFO" | jq '.base_key'

# Check if base key is active
KEY_STATUS=$(otdfctl policy kas-registry key get \
--id "$(echo "$BASE_KEY_INFO" | jq -r '.base_key.kas_id')" \
--output json | jq -r '.kas_key.key.key_status')

if [ "$KEY_STATUS" != "KEY_STATUS_ACTIVE" ]; then
echo "⚠️ Base key is not active: $KEY_STATUS"
else
echo "✅ Base key is active and ready"
fi
```

### Common Issues

**Base Key Not Found:**

- Verify a base key has been set: `otdfctl policy kas-registry key base get`
- Ensure the referenced key still exists and is active

**NanoTDF Failures:**

- Check if base key uses an ECC algorithm
- Consider setting an ECC base key for NanoTDF compatibility

**SDK Fallback Behavior:**

- Review SDK logs for base key resolution attempts
- Verify platform connectivity and authentication
- Check if key mappings exist for specific attributes

[otdfctl base key](https://github.com/opentdf/otdfctl/tree/main/docs/man/policy/kas-registry/key/base) provides documentation on how to set / get base keys with the OpenTDF CLI.
## API Reference

## Effects of using base key
The base key functionality is provided through these RPC endpoints:

1. When a base key is specified the SDK will prefer to use it over the passed in kas info list. The SDK will **overwrite** the following information if a base key is registered with the platform:
1. The passed in kas information list
2. The key algorithm
2. If a base key is not present, the SDK will fallback to using the passed in kas information list and key algorithm.
3. If the base key is not of type ECC, it **cannot** be used with NanoTDF.
1. If the registered base key is not of type ECC, the SDK will fallback to using the passed in kas url and key type.
- **`SetBaseKey`** - Set a new base key (upserts automatically)
- **`GetBaseKey`** - Retrieve current base key information

:::note
In upcoming versions of the SDK, post v0.5.0, the SDK will prefer to error when no base key is set; instead of falling back.
:::
Both endpoints are defined in the [KAS Registry service](https://github.com/opentdf/platform/blob/main/service/policy/kasregistry/key_access_server_registry.proto#L693-L696).
Loading
Loading