Providers

Cluster-level configuration for secrets, DNS, and routing

Overview

Providers configure cluster-level concerns that affect all child components. They follow a hierarchical pattern: wrap your app (or part of it) in providers to set the context. Each provider declares its required operators automatically.

SecretProvider

Secrets backend: OpenBao, Vault, Sealed Secrets, or plain Kubernetes Secrets.

DnsProvider

DNS management: ExternalDNS with RFC 2136 (TSIG) or cloud providers.

EndpointProvider

Routing: nginx Ingress or Envoy Gateway (Gateway API).

01

SecretProvider

Configures how secrets are managed: OpenBao, Vault, Sealed Secrets, or plain Kubernetes Secrets. Required for TSIG DNS updates and Vault secrets in apps.

import { SecretProvider, OpenBao, Database } from '@r8s/recipes';

// Simple — string provider
export const Simple = () => (
  <SecretProvider provider="openbao">
    <Database name="app-db" />
  </SecretProvider>
);

// Advanced — component provider
export const Advanced = () => (
  <SecretProvider provider={<OpenBao mount="secret" path="infra" authRef="custom-auth" />}>
    <Database name="app-db" />
  </SecretProvider>
);

Available providers:

  • openbao — OpenBao Vault Secrets Operator (recommended)
  • vault — HashiCorp Vault Secrets Operator
  • sealed-secrets — Bitnami Sealed Secrets
  • kubernetes — Plain Kubernetes Secrets (CNPG-managed)
02

DnsProvider

Configures DNS management via ExternalDNS. Supports RFC 2136 (TSIG) for secure updates or cloud providers (Route53, Cloudflare, Google Cloud DNS).

import { DnsProvider, ExternalDns, SecretProvider, App } from '@r8s/recipes';

// Simple — string provider
export const Simple = () => (
  <SecretProvider provider="openbao">
    <DnsProvider provider="external-dns">
      <App name="api" image="myapp:v1" host="api.example.com" />
    </DnsProvider>
  </SecretProvider>
);

// Advanced — component provider with TSIG
export const Advanced = () => (
  <SecretProvider provider="openbao">
    <DnsProvider provider={
      <ExternalDns
        server="ns1.example.com"
        zone="example.com"
        tsig={{ path: 'dns/tsig', key: 'secret' }}
      />
    }>
      <App name="api" image="myapp:v1" host="api.example.com" />
    </DnsProvider>
  </SecretProvider>
);

Available providers:

  • external-dns — ExternalDNS operator

Configuration components:

  • <ExternalDns /> — RFC 2136 or cloud provider config
03

EndpointProvider

Configures routing: nginx Ingress or Envoy Gateway (Gateway API). All Endpoint and App children use this routing mode.

import { EndpointProvider, Nginx, EnvoyGateway, App } from '@r8s/recipes';

// Simple — string provider
export const Simple = () => (
  <EndpointProvider provider="nginx">
    <App name="api" image="myapp:v1" host="api.example.com" />
  </EndpointProvider>
);

// Advanced — component provider
export const Advanced = () => (
  <EndpointProvider provider={
    <Nginx className="nginx-internal" tls={{ clusterIssuer: 'letsencrypt' }} />
  }>
    <App name="api" image="myapp:v1" host="api.example.com" />
  </EndpointProvider>
);

// Envoy Gateway
export const Gateway = () => (
  <EndpointProvider provider={
    <EnvoyGateway className="eg" tls={{ clusterIssuer: 'letsencrypt-prod' }} />
  }>
    <App name="api" image="myapp:v1" host="api.example.com" />
  </EndpointProvider>
);

Available providers:

  • nginx — nginx Ingress (default)
  • envoy-gateway — Envoy Gateway (Gateway API)

Configuration components:

  • <Nginx /> — Custom ingress class, TLS
  • <EnvoyGateway /> — Custom gateway class, TLS
04

Full Hierarchy

Compose all providers for a complete production setup. Each layer is independent — swap providers without changing your app.

import { SecretProvider, OpenBao, DnsProvider, ExternalDns, EndpointProvider, Nginx, App, Database, Monitoring } from '@r8s/recipes';

export default () => (
  <SecretProvider provider={<OpenBao mount="secret" path="myapp" />}>
    <DnsProvider provider={<ExternalDns server="ns1.example.com" tsig={{ path: 'dns/tsig', key: 'secret' }} />}>
      <EndpointProvider provider={<Nginx tls={{ clusterIssuer: 'letsencrypt-prod' }} />}>
        <Database name="myapp-db" storage="20Gi" />
        <App name="myapp" image="myapp:v1" host="myapp.example.com" replicas={3} cache />
        <Monitoring name="myapp-monitor" selector={{ app: 'myapp' }} logs />
      </EndpointProvider>
    </DnsProvider>
  </SecretProvider>
);

Compatibility

Which providers work with which recipes:

ProviderCompatible RecipesNotes
SecretProviderDatabase, Auth, AppRequired for TSIG, Vault secrets
DnsProviderEndpoint, AppAuto-creates DNS records
EndpointProviderEndpoint, AppRouting (nginx/gateway)

Ready to use providers?

Check out the Getting Started guide for a step-by-step walkthrough, or browse all recipes to see providers in action.