# Local Secret CLI

> Seal Secrets, unseal manifests with cluster keys, and read values for local commands.

The local Secret CLI seals Secrets, unseals manifests with cluster keys, and
reads existing Kubernetes Secrets through your kubeconfig. Use it from an
`apoxy-cloud` checkout with Bazel. It uses the upstream Sealed Secrets library
and does not need the `kubeseal` or `kubectl` executables.

## Seal a Secret

Encrypt a Kubernetes Secret with the controller's public certificate:

```bash
bazel run //run/sealed-secrets/cli:cli -- \
  seal --context <context> --file secret.yaml > sealed-secret.yaml
```

Input can be YAML or JSON. Omit `--file` to read stdin. The input must contain
one `v1` Secret with a name and data. Values in `stringData` override matching
keys in `data`. Labels, annotations, type, and the immutable setting are
preserved; server metadata and last-applied annotations are removed.

The default scope binds each value to the Secret's name and namespace. Set
`--scope namespace-wide` to allow another name within that namespace, or
`--scope cluster-wide` to allow any name and namespace. A missing namespace
uses your selected kubeconfig namespace. An explicit `-n` must match a
namespace already present in the input.

Use a local certificate to seal without connecting to a cluster:

```bash
bazel run //run/sealed-secrets/cli:cli -- \
  seal --cert cert.pem --file secret.yaml > sealed-secret.yaml
```

The certificate must contain an RSA public key and be within its validity period.
For a PEM bundle, the CLI uses the first certificate and skips other PEM block types.

## Unseal with cluster keys

Decrypt a SealedSecret manifest with keys from its controller:

```bash
bazel run //run/sealed-secrets/cli:cli -- \
  unseal --context <context> --file sealed-secret.yaml
```

The CLI reads the controller's key Secrets and decrypts in memory. It supports
rotated keys and does not save or print private keys. Your Kubernetes identity
needs permission to list these Secrets and get the original key Secret in the
controller namespace. The CLI combines labeled keys with `sealed-secrets-key`,
which older installations can use without a label. Set `--key-name` to use a
different name, or `--key-name=` to read only keys that match the selector.

Output is a `v1` Secret with base64-encoded `data`. Treat it as plaintext
credentials. `--format json` selects JSON instead of the default YAML. A failed
decryption produces no Secret output. Neither command changes the cluster.

## List keys

List a Secret's data keys in alphabetical order:

```bash
bazel run //run/sealed-secrets/cli:cli -- \
  --context <context> -n <namespace> \
  keys <secret-name>
```

You should see one key name per line. This command does not print values.
Omit `keys` for the same result.

## Read a value

Write one decoded value to standard output:

```bash
bazel run //run/sealed-secrets/cli:cli -- \
  --context <context> -n <namespace> \
  get <secret-name> <key>
```

The output contains the exact bytes, with no added newline. A missing key returns
an error. An existing key with an empty value succeeds with empty output.

## Run a command

Map Secret keys to environment variables for a child command:

```bash
bazel run //run/sealed-secrets/cli:cli -- \
  exec <secret-name> --context <context> -n <namespace> \
  --env CLIENT_ID=client_id \
  --env CLIENT_SECRET=client_secret \
  -- <command> <args>
```

The CLI reads the Secret once and checks every mapping before starting the
command. Mapped variables replace inherited values in the child environment.
Other environment variables, the working directory, and standard input and
output are preserved. The CLI returns the child's exit status. It does not print
credential values, but the child command controls its own output.

Environment values cannot contain zero bytes. Use `get` for binary data.

## Flags

Flags can appear before or after the subcommand. For `exec`, put CLI flags
before `--`; everything after `--` belongs to the child command.
Use `cli <subcommand> --help` to show that command's flags.

- `--kubeconfig PATH` - Select a kubeconfig file. The default uses `KUBECONFIG` or `~/.kube/config`.
- `--context NAME` - Select a context. The default uses the current context.
- `--namespace NAME`, `-n NAME` - Select a namespace. The default uses the context namespace.
- `--env NAME=KEY` - Map a Secret key to a child environment variable. Repeat with `exec`.
- `--file PATH`, `-f PATH` - Input manifest for `seal` or `unseal`. The default `-` reads stdin.
- `--cert PATH` - Local PEM certificate for `seal`. The default fetches the controller certificate.
- `--scope SCOPE` - Scope for `seal`: `strict` (default), `namespace-wide`, or `cluster-wide`.
- `--format FORMAT` - Output for `seal` or `unseal`: `yaml` (default) or `json`.
- `--controller-name NAME` - Controller Service for certificate retrieval. Defaults to `sealed-secrets-controller`.
- `--controller-namespace NAME` - Namespace for the controller Service and key Secrets. Defaults to `kube-system`.
- `--key-selector SELECTOR` - Key Secret label selector for `unseal`. Defaults to `sealedsecrets.bitnami.com/sealed-secrets-key=active`.
- `--key-name NAME` - Additional controller key Secret for `unseal`. Defaults to `sealed-secrets-key`. An empty name disables this lookup.
- `--help` - Show command usage.

Kubernetes requests have a 30-second timeout. The CLI does not apply or update
resources.

---

**Navigation** (Reference)

- Previous: [CLI](/docs/reference/cli.md)
- Next: [MCP server](/docs/reference/mcp.md)
- All pages: [index](/docs/llms.txt)
