Likvido.Kubesec
2.0.2
dotnet tool install --global Likvido.Kubesec --version 2.0.2
dotnet new tool-manifest
dotnet tool install --local Likvido.Kubesec --version 2.0.2
#tool dotnet:?package=Likvido.Kubesec&version=2.0.2
nuke :add-package Likvido.Kubesec --version 2.0.2
Likvido.Kubesec
Tool to ease the management of Kubernetes secrets
Requirements
- .NET 10 SDK or later
- kubectl needs to be installed and configured for your cluster
Installation
Install this tool via dotnet global tools:
dotnet tool install --global Likvido.Kubesec
https://www.nuget.org/packages/Likvido.Kubesec
How to pull secrets
This is the command to pull secrets:
kubesec pull <secret-name> --namespace <kubectl-namespace> --context <kubectl-context-name> --unwrap-key <key-name> --port-forward --output <output-file> --remove-json-field <field-to-remove>
This example will pull the secrets stored with the name sync-creditors from a namespace called likvido-api in a cluster with the kubectl context name staging, and then output them to a file called secrets.yaml:
kubesec pull sync-creditors --namespace likvido-api --context staging --output secrets.yaml
If you do not specify --context, then it will use whatever context is currently active in kubectl
If you do not specify --namespace, then it will use default namespace
If you do not specify --output, then it will display the data inside the console in a table format
If you do not specify --unwrap-key then it will fetch all keys and output them with both their key name and value
If you do not specify --port-forward then it won't do any port forwarding
If you do not specify --remove-json-field then no fields will be removed (duh!). This option can be specified multiple times, in case you have multiple fields you want to remove, see the example further down this readme.
Unwrap key
This example will pull the secrets stored with the name sync-creditors from a namespace called likvido-api in a cluster with the kubectl context name staging, and then unwrap the key app.json and output the value of this key to a file called appsettings.Development.json:
kubesec pull sync-creditors --namespace likvido-api --context staging --unwrap-key app.json --output appsettings.Development.json
Port forwarding
This example will pull the secrets stored with the name sync-creditors from a namespace called likvido-api in a cluster with the kubectl context name staging, and then unwrap the key app.json and output the value of this key to a file called appsettings.Development.json. In addition to this, it will look through all URLs in the value and detect any URLs that point to "local" Kubernetes services in your cluster with this format: http://{service-name}.{namespace}.svc.cluster.local{optional port}. For all of the URLs it finds, it will parse them and set up port forwarding to them on your localhost. After setting up port forwarding, it will replace the URLs in the outputted text, such that they point to the localhost port forward:
kubesec pull sync-creditors --namespace likvido-api --context staging --unwrap-key app.json --port-forward --output appsettings.Development.json
Remove JSON field
In case your secret value is a JSON object, and you would like to remove specific fields from the object before you write the file to the output, then you can do this with the --remove-json-field option. This example will pull the secrets stored with the name sync-creditors from a namespace called likvido-api in a cluster with the kubectl context name staging, unwrap the key app.json, remove the JSON fields Events.Created.Name & ApplicationInsights and output the resulting value to a file called appsettings.Development.json:
kubesec pull sync-creditors --namespace likvido-api --context staging --unwrap-key app.json --output appsettings.Development.json --remove-json-field Events.Created.Name --remove-json-field ApplicationInsights
So, to be clear, if the value of the app.json secret field in the secret looks like this:
{
"FieldA": "ValueA",
"ApplicationInsights": {
"InstrumentationKey": "blabla"
},
"Events": {
"Created": {
"Type": "something",
"Name": "The created event"
}
}
}
The resulting output (which would be written to the appsettings.Development.json file in this case), would look like this:
{
"FieldA": "ValueA",
"Events": {
"Created": {
"Type": "something"
}
}
}
How to push secrets
This is the command to push secrets:
kubesec push <file> --namespace <kubectl-namespace> --context <kubectl-context-name> --secret <secret-name> --skip-prompts --auto-create-missing-namespace
This is an example command that will push the secrets stored in the file secret.yaml to a namespace called likvido-api in a cluster with the kubectl context name staging using the secret name sync-creditors:
kubesec push secrets.yaml --namespace likvido-api --context staging --secret sync-creditors
If you do not specify --context, then it will use whatever context is currently active in kubectl
If you do not specify --namespace, then it will use default namespace
If you do not specify --skip-prompts, then it will ask you for confirmation before pushing the secrets
If you do not specify --auto-create-missing-namespace, then it will not create the namespace if it does not exist
File header
When you pull secrets using kubesec and store them in a file, then it will include a file header looking something like this:
#######################################
# Context: staging
# Secret: sync-creditors
# Namespace: likvido-api
#######################################
If you later need to modify the secrets, and then push the changes, then kubesec will read the header and use that for some sanity checks before actually applying the changes to Kubernetes. If you provide a --context and/or --secret when calling the push command, then kubesec will compare those to the ones in the file header, and if they diverge, it will ask you if you are sure you wish to push the secrets with the context and secret name you specified.
We recommend keeping the header in the file, and not modifying it.
Backup
To backup all the secrets in your cluster you can use the following command.
kubesec backup --context <kubectl-context-name>
There are three more options that you can add to the command:
--namespace <kubectl-namespace>- Will look for a specific namespace in a cluster--namespace-include <keyword>- Will look for namespaces that includes the specified keyword--namespace-regex <regex>- Will look for namespaces that matches the specified regex--excluded-namespaces- Will exclude the specified namespaces from the backup
Only one of the above namespace options will take effect. The above order also defines their priority.
If you do not specify --context, then it will use whatever context is currently active in kubectl.
When using backup command a folder will be created in the directory you run the command from called Kubesec_Backup_<context>_<datestamp>. Inside the created folder one or more folders will be created with the name of namespaces that satisfy one of the conditions related to namespace options in command which will hold secret files defined in kubernetes (like if you were pulling each one manually).
Examples
- This is an example command that will backup secrets from the namespace called
likvido-apiwhich is part of a cluster with the kubectl context namestaging
kubesec backup --namespace likvido-api --context staging
- This command will backup secrets from the namespaces that include
likvidokeyword on their names and are part of a cluster with the kubectl context namestaging
kubesec backup --namespace-includes likvido --context staging
- This command will backup secrets from the namespaces that contain numbers on their names and are part of a cluster with the kubectl context name
staging
kubesec backup --namespace-regex \d --context staging
- This command will backup secrets from all namespaces except
kube-systemandprometheuswith the kubectl context namestaging
kubesec backup --excluded-namespace kube-system --excluded-namespace prometheus --context staging
Restore
To restore the secrets you have created with the backup command, you can run the following command. It will loop through each file in the provided directory and push them in turn
kubesec restore <folder> --context <kubectl-context-name> --recursive --skip-prompts --auto-create-missing-namespaces
If you do not specify --context, then it will use whatever context is currently active in kubectl
If you do not specify --recursive, then it will only restore the files in the folder you specified
If you do not specify --skip-prompts, then it will ask you for confirmation before pushing the secrets
If you do not specify --auto-create-missing-namespaces, then it will not create the namespaces if they do not exist
Find
Search for secrets containing a specific value across all secrets in the cluster. This is useful for discovering which secrets contain a particular API key, password, or configuration value before rotating it.
kubesec find <search-term> --context <kubectl-context-name>
There are three more options that you can add to the command:
--namespace <kubectl-namespace>- Will search in a specific namespace--namespace-includes <keyword>- Will search in namespaces that include the specified keyword--namespace-regex <regex>- Will search in namespaces that match the specified regex
If you do not specify --context, then it will use whatever context is currently active in kubectl.
Examples
- This command will search for "OpenAI" in all secrets in a cluster with the kubectl context name
production:
kubesec find "OpenAI" --context production
- This command will search for an API key in all secrets within the
likvido-apinamespace:
kubesec find "sk-<your-api-key>" --namespace likvido-api --context production
The output shows each matching secret with context lines around the match:
Finding: OpenAI
=============================================
> default/likvidoapp-internalapi
Key: appsettings.json
Line 57:
},
> "OpenAI": {
"ApiKey": "sk-..."
},
Update Value
Replace a specific value across all secrets in the cluster. This is useful for rotating API keys, passwords, or other credentials that are used by multiple services.
kubesec update-value --old <old-value> --new <new-value> --context <kubectl-context-name>
The command will:
- Create an automatic backup to
kubesec-rollback-<timestamp>/ - Search for all secrets containing the old value
- Show a preview of all changes that will be made
- Ask for confirmation before applying
- Apply the changes to the cluster
- Show rollback instructions
Additional options:
--namespace <kubectl-namespace>- Only update secrets in a specific namespace--namespace-includes <keyword>- Only update secrets in namespaces that include the specified keyword--namespace-regex <regex>- Only update secrets in namespaces that match the specified regex--skip-prompts- Skip the confirmation prompt (useful for CI/CD)--dry-run- Show what would be changed without making actual changes
If you do not specify --context, then it will use whatever context is currently active in kubectl.
Examples
- Preview what would be changed when rotating an API key (dry run):
kubesec update-value --old "sk-oldkey123" --new "sk-newkey456" --context production --dry-run
- Rotate an API key across all secrets:
kubesec update-value --old "sk-oldkey123" --new "sk-newkey456" --context production
- Rotate an API key only in a specific namespace:
kubesec update-value --old "sk-oldkey123" --new "sk-newkey456" --namespace likvido-api --context production
The output shows a preview of all changes and asks for confirmation:
=============================================
Replace Values
=============================================
Old value: sk-oldkey123
New value: sk-newkey456
Creating backup to kubesec-rollback-20260115-143022/
Finding secrets containing the old value...
Found 3 secret(s) containing the value
> default/likvidoapp-internalapi
1 occurrence(s) will be replaced
Line 58:
- "ApiKey": "sk-oldkey123"
+ "ApiKey": "sk-newkey456"
...
Apply changes? [y/N] y
Updating secrets...
OK default/likvidoapp-internalapi
OK default/likvidoapp-webappapi
=============================================
Done! Updated 3 secret(s).
=============================================
Rollback: kubesec restore -c production kubesec-rollback-20260115-143022/
If something goes wrong, you can rollback using the restore command with the backup folder that was created:
kubesec restore kubesec-rollback-20260115-143022/ --context production --recursive
Running the tests
dotnet test Likvido.Kubesec/Likvido.Kubesec.sln
The same tests run on pull requests targeting master via the Test Runner workflow, which uses the shared
likvido/action-test action. Failures show up as
annotations directly on the pull request.
Releasing a new version
Releasing is automated, so there is nothing to pack or upload by hand:
- Bump
<Version>inLikvido.Kubesec/version.props - Update
PackageReleaseNotesinLikvido.Kubesec/Likvido.Kubesec/Likvido.Kubesec.csproj - Merge to
master
The Publish to nuget workflow then packs the tool and pushes it to nuget.org, using the shared
likvido/action-nuget action. It triggers on changes to
version.props or to the workflow itself, so an ordinary merge — a dependency bump, say — never
attempts a publish. A version that is already on nuget.org is skipped rather than treated as a
failure, which is what makes it safe to re-run: if a release fails for some unrelated reason, fixing
the workflow and merging that fix retries the publish without needing another version bump.
Authentication uses Trusted Publishing:
nuget.org issues a short-lived key at publish time, so no API key is stored in this repository. The
matching policy is registered on nuget.org under the package owner and is tied to the nuget.yml
file name — renaming that workflow breaks publishing until the policy is updated to match.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.2 | 89 | 8/14/2026 |
| 2.0.1 | 94 | 8/14/2026 |
| 2.0.0 | 186 | 1/15/2026 |
| 1.1.0 | 276 | 5/7/2025 |
| 1.0.2 | 295 | 3/12/2024 |
| 1.0.1 | 272 | 3/8/2024 |
| 1.0.0 | 295 | 3/8/2024 |
| 0.12.2 | 708 | 5/3/2022 |
| 0.12.1 | 631 | 5/3/2022 |
| 0.12.0 | 648 | 5/3/2022 |
| 0.11.0 | 663 | 4/20/2022 |
| 0.10.1 | 650 | 4/4/2022 |
| 0.10.0 | 638 | 4/1/2022 |
| 0.9.0 | 621 | 4/1/2022 |
| 0.8.0 | 576 | 9/21/2021 |
| 0.7.0 | 631 | 12/16/2020 |
| 0.6.0 | 706 | 8/26/2020 |
| 0.5.0 | 665 | 8/21/2020 |
| 0.4.0 | 706 | 6/4/2020 |
| 0.3.0 | 717 | 6/3/2020 |
Ship the README, license and a real description with the package, so the nuget.org page documents the tool instead of showing a placeholder.