Skip to content
DocsAll docs
Console

Secrets

Set, replace, show and delete your secrets, the secrets of a team, and your own secrets in a team.

Last updated

On this page

Description and operation

General

A secret is a named value in a secret store. There is one store for you, one for each team, and one for you in each team that you are a member of. The name is the key in that store. A value goes into the store and never comes out: no call, list or log returns it. A resource uses a secret through a reference. See Env Vars.

PartDescription
NameThe key of the secret, for example DB_URL. Unique for one owner.
ValueThe text that a process gets in its variable. It is never shown.
updated_atThe time of the last change.
updated_byThe handle of who made the last change.

You manage secrets with kloudlite secrets (alias kloudlite secret), the SDK or the API. The CLI reads the value only from standard input, never from an argument, because other processes and the shell history can read an argument. It removes one trailing line break, and it refuses an empty value.

StoreCLI optionsSet, replace and deleteShow the names
Your secretsNo --owner, or your handleYouYou
Your secrets in a team--owner TEAMYou, as an active member of the teamYou only
The secrets of a team--owner TEAM --scope teamA member with the role admin or higher, whose access is not pausedAny member whose access is not paused
Another ownerNobody. The call fails with 404.Nobody. The call fails with 404.
NOTE

--owner TEAM alone sets YOUR secret in the team. To set the secret that all the team uses, add --scope team. The SDK has the same rule: give scope="team" for the secret of the team.

Your secrets in a team are for your own resources in that team. See Personal secrets in a team.

Parameters

ParameterRequiredDescription
ownerYesYour handle or the slug of a team. The CLI uses your handle when you give no --owner.
scopeNoteam for the secret of the team. Without it, a team owner means your own secret in the team. It is refused without a team owner.
nameYesA to Z, 0 to 9 and _. It does not start with a digit.
valueYes, to setUp to 64 KiB (65536 bytes). From standard input in the CLI.

Lifecycle

  • Set. A new name adds a secret. The owner then has it for all its resources. Your secret in a team is for your own resources in that team only.
  • Replace. Setting an existing name replaces its value. A workspace or a service that uses the secret gets the new value at its next start. Until then, it shows restart_required. See When a new value takes effect.
  • Delete. A delete is refused with 409 while a workspace, a sandbox or a service of the owner refers to the secret. The message names each one. A pipeline also stops the delete when its newest version, or a queued or running run, refers to the secret.
  • Delete your secret in a team. A delete is refused with 409 while your resource in the team refers to the name, and the team has no such secret. When the team has the name, the reference reads the secret of the team.
  • Removed owner. When a team is deleted, its secrets and the secrets of its members in it are deleted. When you leave a team, your secrets in it are deleted after 7 days. If you join again in that time, they are kept.

Quota and limits

ItemLimit
Secrets100 for each store. A new name above 100 fails with 409.
Value64 KiB.
NameA to Z, 0 to 9 and _, not starting with a digit.

Tasks

Set or replace a secret

Reason for the task: Store a value under a name, or change the value of an existing secret.

Job set-up

NOTE

A replaced value does not restart a resource. Restart each resource that shows restart_required to apply the value.

Procedure

  1. Read the value into the shell variable DB_URL. The terminal does not show what you type.

    CLI
    read -rs DB_URL && export DB_URL
  2. Send the value of the secret DB_URL of the team acme. For your own secret, use your handle and no scope.

    Python
    import osfrom kloudlite import Kloudlitekl = Kloudlite()kl.secrets.set(owner="acme", name="DB_URL", value=os.environ["DB_URL"], scope="team")
    TypeScript
    import { Kloudlite } from "./index.ts";const kl = new Kloudlite();await kl.secrets.set({ owner: "acme", name: "DB_URL", value: process.env.DB_URL!, scope: "team" });
    Go
    kl := kloudlite.New(kloudlite.Options{})if err := kl.Secrets.Set("acme", "DB_URL", os.Getenv("DB_URL"), kloudlite.SecretOptions{Scope: "team"}); err != nil {    log.Fatal(err)}
    Ruby
    require_relative "kloudlite"kl = Kloudlite::Client.newkl.secrets.set(owner: "acme", name: "DB_URL", value: ENV.fetch("DB_URL"), scope: "team")
    Java
    var kl = new Kloudlite();kl.secrets().set("acme", "DB_URL", System.getenv("DB_URL"), "team");
    CLI
    printf %s "$DB_URL" | kloudlite secrets set DB_URL --owner acme --scope team
  3. Remove the value from the shell.

    CLI
    unset DB_URL

Close-out

  1. Show the secrets as in task 002. Make sure that DB_URL shows the time of this change.

Show the secrets

Reason for the task: Find the names of the secrets of an owner, and who changed each one and when.

Job set-up

Procedure

  1. Show the names of the secrets of the team acme. The list never holds a value.

    Python
    for s in kl.secrets.list(owner="acme", scope="team"):    print(s["name"], s["updated_at"], s["updated_by"])
    TypeScript
    for (const s of await kl.secrets.list({ owner: "acme", scope: "team" })) {  console.log(s.name, s.updated_at, s.updated_by);}
    Go
    secrets, err := kl.Secrets.List("acme", kloudlite.SecretOptions{Scope: "team"})if err != nil {    log.Fatal(err)}for _, s := range secrets {    fmt.Println(s["name"], s["updated_at"], s["updated_by"])}
    Ruby
    kl.secrets.list(owner: "acme", scope: "team").each do |s|  puts "#{s["name"]} #{s["updated_at"]} #{s["updated_by"]}"end
    Java
    System.out.println(kl.secrets().list("acme", "team"));
    CLI
    kloudlite secrets list --owner acme --scope team

Close-out

  1. Read the output. The CLI shows none for an owner with no secret.

Delete a secret

Reason for the task: Remove a secret that nothing uses.

Job set-up

CAUTION

A run of an older pipeline version that names the secret fails to start.

Procedure

  1. Delete the secret DB_URL of the team acme.

    Python
    kl.secrets.delete(owner="acme", name="DB_URL", scope="team")
    TypeScript
    await kl.secrets.delete({ owner: "acme", name: "DB_URL", scope: "team" });
    Go
    if err := kl.Secrets.Delete("acme", "DB_URL", kloudlite.SecretOptions{Scope: "team"}); err != nil {    log.Fatal(err)}
    Ruby
    kl.secrets.delete(owner: "acme", name: "DB_URL", scope: "team")
    Java
    kl.secrets().delete("acme", "DB_URL", "team");
    CLI
    kloudlite secrets delete DB_URL --owner acme --scope team

Close-out

  1. Show the secrets as in task 002. Make sure that DB_URL is not in the list.

Set a personal secret in a team

Reason for the task: Keep your own value, such as an access token, for your resources in a team.

Job set-up

NOTE

Your value replaces the secret of the team with the same name, but only in your own workspaces, benches and sandboxes of the team. See Personal secrets in a team.

Procedure

  1. Read the value into the shell variable GITHUB_TOKEN. The terminal does not show what you type.

    CLI
    read -rs GITHUB_TOKEN && export GITHUB_TOKEN
  2. Send the value. This example sets your secret GITHUB_TOKEN in the team acme.

    Python
    import osfrom kloudlite import Kloudlitekl = Kloudlite()kl.secrets.set(owner="acme", name="GITHUB_TOKEN", value=os.environ["GITHUB_TOKEN"])
    TypeScript
    import { Kloudlite } from "./index.ts";const kl = new Kloudlite();await kl.secrets.set({ owner: "acme", name: "GITHUB_TOKEN", value: process.env.GITHUB_TOKEN! });
    Go
    kl := kloudlite.New(kloudlite.Options{})if err := kl.Secrets.Set("acme", "GITHUB_TOKEN", os.Getenv("GITHUB_TOKEN")); err != nil {    log.Fatal(err)}
    Ruby
    require_relative "kloudlite"kl = Kloudlite::Client.newkl.secrets.set(owner: "acme", name: "GITHUB_TOKEN", value: ENV.fetch("GITHUB_TOKEN"))
    Java
    var kl = new Kloudlite();kl.secrets().set("acme", "GITHUB_TOKEN", System.getenv("GITHUB_TOKEN"));
    CLI
    printf %s "$GITHUB_TOKEN" | kloudlite secrets set GITHUB_TOKEN --owner acme
  3. Remove the value from the shell.

    CLI
    unset GITHUB_TOKEN

Close-out

  1. Show your secrets in the team as in task 005. Make sure that GITHUB_TOKEN shows the time of this change.

Show your personal secrets in a team

Reason for the task: Find the names of your own secrets in a team.

Job set-up

Procedure

  1. Show the names. The list holds only your names, and never a value.

    Python
    for s in kl.secrets.list(owner="acme"):    print(s["name"], s["updated_at"], s["updated_by"])
    TypeScript
    for (const s of await kl.secrets.list({ owner: "acme" })) {  console.log(s.name, s.updated_at, s.updated_by);}
    Go
    secrets, err := kl.Secrets.List("acme")if err != nil {    log.Fatal(err)}for _, s := range secrets {    fmt.Println(s["name"], s["updated_at"], s["updated_by"])}
    Ruby
    kl.secrets.list(owner: "acme").each do |s|  puts "#{s["name"]} #{s["updated_at"]} #{s["updated_by"]}"end
    Java
    System.out.println(kl.secrets().list("acme"));
    CLI
    kloudlite secrets list --owner acme

Close-out

  1. Read the output. The CLI shows none when you have no secret in the team.

Delete a personal secret in a team

Reason for the task: Remove your own secret in a team.

Job set-up

CAUTION

When the team has a secret of that name, your resources read the value of the team at their next start.

Procedure

  1. Delete your secret GITHUB_TOKEN in the team acme.

    Python
    kl.secrets.delete(owner="acme", name="GITHUB_TOKEN")
    TypeScript
    await kl.secrets.delete({ owner: "acme", name: "GITHUB_TOKEN" });
    Go
    if err := kl.Secrets.Delete("acme", "GITHUB_TOKEN"); err != nil {    log.Fatal(err)}
    Ruby
    kl.secrets.delete(owner: "acme", name: "GITHUB_TOKEN")
    Java
    kl.secrets().delete("acme", "GITHUB_TOKEN");
    CLI
    kloudlite secrets delete GITHUB_TOKEN --owner acme

Close-out

  1. Show your secrets in the team as in task 005. Make sure that GITHUB_TOKEN is not in the list.

Troubleshooting

SymptomPossible causeCorrective action
the value is empty: pipe it in on stdin, e.g. ...The value on standard input is empty.Make sure that the variable holds the value, then set the secret again.
422 with `db-url` is not a secret name: use A-Z, 0-9 and _, not starting with a digitThe name has lowercase letters, a hyphen or a leading digit.Use a name such as DB_URL.
422 with a secret value is at most 64 KiBThe value is larger than 65536 bytes.Use a smaller value.
409 with secrets: 100 of 100 in useThe owner has 100 secrets and the name is new.Delete a secret that you do not use.
409 with secrets are being changed; try againAnother change to the secrets of the owner ran at the same time.Do the task again.
409 with DB_URL is referenced by environment dev service api, workspace apiA resource still refers to the secret.Remove the reference from each resource named, then delete again.
403 with your access to acme is pausedAn admin paused your access.Ask a team admin to restore your access.
404 with not foundThe team or the secret does not exist, or you are not in the team (or you left it).Check the value of --owner and the name.
--scope team is the team's shared secret: pass --owner TEAM (your own handle has no team)You gave --scope team with no team --owner.Add --owner and the slug of the team.
403 with only a team admin can change team secrets after --scope teamYou tried to change the secret of the team, and your role is lower than admin.Ask a team admin. For a value that only you use, set your own secret in the team.
A secret that you set with --owner acme is not in the list of the teamWithout --scope team, the secret is yours in the team.Show your secrets in the team. To share the secret, set it with --scope team.
409 with DB_URL is referenced by workspace api after a delete of your secret in a teamYour workspace refers to the name, and the team has no secret of that name.Remove the reference from the workspace, then delete again.