maidn-cli/docs/secret-grants.md
2026-09-08 15:24:10 +02:00

4.6 KiB

Application secret grants

Maidn stores secret values in OpenBao. Git contains only references and access policy. A repository does not get OpenBao access: one named workload identity gets one reviewed grant.

Grant classes

Consumer OpenBao path Kubernetes namespace Intended use
build apps/<app>/build/* tekton-pipelines Read-only dependency credentials
publish apps/<app>/publish/* tekton-pipelines One app's artifact repository credential
runtime apps/<app>/runtime/<environment>/* <app>-<environment> Service runtime credentials
shared shared/<name>/* Granted consumer only Deliberately shared broker, database, or API credentials

build code is repository-controlled. Anything granted to it is readable by a pull request author. Do not grant deployment, production, Git write, or administrator credentials to a build.

Bootstrap configuration

Declare access in the private bootstrap configuration. This declaration has no secret values and is reviewed with the platform configuration:

secretGrants:
  - application: orders-api
    consumer: publish
    shared:
      - internal-npm
  - application: orders-api
    consumer: runtime
    environment: staging
    shared:
      - rabbitmq
  - application: orders-api
    consumer: runtime
    environment: production
    shared:
      - rabbitmq

MaidnCLI validates application, consumer, environment, and shared-grant names. It creates one OpenBao policy and Kubernetes-auth role for every declaration. The role names are deterministic:

maidn-<app>-build
maidn-<app>-publish
maidn-<app>-runtime-<environment>

The policy permits only the consumer's own path and the exact shared/<name> paths listed in its declaration. A shared value is stored once, for example at shared/rabbitmq, and each service requiring it declares that same shared grant. Do not copy it into application paths.

GitOps resources

The application environment manifests create the matching ServiceAccount, SecretStore, and ExternalSecret. These resources are reviewed GitOps content; never create them with kubectl apply.

For orders-api staging, use the matching identity and namespace:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: maidn-orders-api-runtime-staging
  namespace: orders-api-staging
---
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
  name: openbao-orders-api-staging
  namespace: orders-api-staging
spec:
  provider:
    vault:
      server: http://openbao.openbao.svc:8200
      path: secret
      version: v2
      auth:
        kubernetes:
          mountPath: kubernetes
          role: maidn-orders-api-runtime-staging
          serviceAccountRef:
            name: maidn-orders-api-runtime-staging
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
  name: orders-api-rabbitmq
  namespace: orders-api-staging
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: openbao-orders-api-staging
    kind: SecretStore
  target:
    name: orders-api-rabbitmq
    creationPolicy: Owner
  data:
    - secretKey: password
      remoteRef:
        key: shared/rabbitmq
        property: password

The workload references only orders-api-rabbitmq in its own namespace. Each application/environment needs a separate namespace; do not put runtime secrets in shared staging or production namespaces.

Artifact repositories

Create one credential per application and artifact target. Its upstream permissions must be limited to the exact package, hosted repository, or object prefix. Examples: one npm scope, one Maven hosted repository, one OCI image, or S3 PutObject for one prefix.

Use publish for credentials needed to upload a completed artifact. Use build only for credentials that a build must read, such as a private package registry. A custom build upload is an exception: it exposes the token to build code and therefore requires a narrowly scoped, disposable credential.

Operations

  1. Create the least-privilege upstream credential.
  2. Write its value to the declared OpenBao path through a secure stdin-based operator workflow. Never put it in YAML, a URL, a command argument, or Git.
  3. Add the reviewed grant and GitOps resources.
  4. Bootstrap or reconcile to create the OpenBao role and policy.
  5. Verify the target ExternalSecret becomes Ready without printing its Secret.
  6. On revocation, remove the grant and ExternalSecret, revoke the upstream credential, then restart affected workloads.

See secrets.md for encrypted operational-material rules and runbooks/credential-rotation.md for rotation.