# 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//` entries | `tekton-pipelines` | Read-only dependency credentials | | `publish` | declared `apps//` entries | `tekton-pipelines` | One app's artifact repository credential | | `runtime` | declared `apps//` entries | `-` | Service runtime credentials | | shared | `shared//*` | 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: ```yaml 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: ```text maidn--build maidn--publish maidn--runtime- ``` The policy permits only the exact `apps//` paths and `shared//*` paths listed in its declaration. The CLI stores one property named `value` at each `apps//` or `shared//` 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: ```yaml 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/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 with `cicd-tool app secret set` using stdin or `--file` and a least-privilege `--token-file`. 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](secrets.md) for encrypted operational-material rules and [runbooks/credential-rotation.md](runbooks/credential-rotation.md) for rotation.