maidn-cli/docs/secret-grants.md

5 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 declared apps/<app>/<secret> entries tekton-pipelines Read-only dependency credentials
publish declared apps/<app>/<secret> entries tekton-pipelines One app's artifact repository credential
runtime declared apps/<app>/<secret> entries staging or production 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
	  secrets:
	    - registry
	  shared:
	    - internal-npm
  - application: orders-api
	  consumer: runtime
	  environment: staging
	  secrets:
	    - database-staging
    shared:
      - rabbitmq
  - application: orders-api
	  consumer: runtime
	  environment: production
	  secrets:
	    - database-production
    shared:
      - rabbitmq

MaidnCLI validates application, consumer, environment, application-secret, 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 exact apps/<app>/<secret> paths and shared/<name>/* paths listed in its declaration. The CLI stores one property named value at each apps/<app>/<secret> or shared/<group>/<secret> path. A shared value is stored once, for example at shared/rabbitmq/password, and each service requiring it declares that 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: value
      remoteRef:
        key: shared/rabbitmq/password
        property: value

The workload references only orders-api-rabbitmq in its own namespace. Each application gets a dedicated ServiceAccount, SecretStore, and target Secret in the shared environment namespace; do not use another application's identity.

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 with cicd-tool app secret set using stdin, --file, or --generate. Use a least-privilege --token-file or a bootstrap-provisioned --identity; never put a value or token in YAML, a URL, a command argument, output, 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.