Leveraging TSB service accounts
TSB service accounts can be leveraged internally within the platform to manage the cluster onboarding tctl install cluster-service-account and GitOps functionality, as well as externally for the 3rd-party systems to perform the configuration of various TSB features leveraging TSB API interface. The given article will focus on how TSB service accounts can be created and consumed by the external automation software leveraging tctl utility as a handler.
Working with TSB service accounts using tctl utility
Most of the interactions you need for service accounts are already available in the tctl service-account command:
tctl service-account -h
Commands to manage TSB service accounts
Usage:
tctl service-account [command]
Aliases:
service-account, sa
Available Commands:
get Get one or multiple service accounts
create Creates a new service account
delete Deletes a service account
gen-key Generate a new key pair for the given service account
add-key Register a customer-supplied public key for the given service account
list-keys List the key pairs for the given service account
revoke-key Revoke one or more key pairs for the given service account
token Generate a new token that can be used to authenticate to TSB
Create a TSB service account using tctl service-account create. Private keys are returned when service accounts are created, but TSB will not store them. It is up to the client to store them securely. To learn more, please refer to YAML API Reference Guide:
tctl service-account create pipeline-sa1 > pipeline-sa1-jwk-private-key.jwk
cat pipeline-sa1-jwk-private-key.jwk
{
"alg": "RS256",
"d": "DXxlZZcNodMTZv0XIYXglgNilwyL4gxnmu6e1zZetmtbm0oHKUx4CTlnWt_nBAinlxTzirEXClBNoDPqCh27Jg-WwbBeW01l2RPoSO7g4eM9Sz1r2KCy5o7NgptAq-_uZLy609gWDPgk8EjFT1QWMtGVXICi5StR9D0RbKazFVpgekIBPAlKoMDqwMUVM5nldIXyI6iwy4C19ZAdf0cW2HHw8rKBEMQ-bqXuD7RVkMWp18wPrnxbMpR8Xw1n4F_Wj7DqAepYezk8Vp1-uuUEnIP3rtMYbFVL1wn-nupQSAyIQIQsqvwSsGU-RD00YuPQ6hbeRTb201Ev-DvFYA1XUQ",
"dp": "lZdU20cP-G8q9dCEbFAYt15pVfzAfjy82cRlfGLjcYJFiTRyc-J8zj4VjDJSDg5CQfufQ_q_0duQi40HQH-8ihK1mPe-OZlvDc7syxbVlWIiwD4w1if-YuNWEvfyWOfa6nHsZY3utW5_SL4nvw2E-9iv_HJIJ3MkLEhZDysGvZE",
"dq": "v--gNJHrSbUMgZEuy3jfjmrgHjBM3ee6141zL3KmfeWrEK6OW8TYrVV0HBzk7Whj7ehxQmLGHVH-MykyrlKGggGtnQ1OgUpTPBhKE8j5QaXmAuO7pY1oDcOWQmqg8qu1X0X61-LmMQ42he8gGSBvcL3jWxpDSGuGeYwPJeJ9FZc",
"e": "AQAB",
"kid": "zuAiwPFQu2eI3GAGddaS1UHG08A01BA4XStF2C45uiA",
"kty": "RSA",
"n": "s5ENuvPJ9C2gMsnqFUXosXYY4k8AcnCjfUFQgUJc1FBpM15EnrgwkArZNsgHscH7ngnqIvwIf7SvM10CSkKj7dWZ6oabmdY-IFaeKIZ96EoFicNpRgkhJQREunLNtwHjvZZ_j86Vbnt4YGn6Y09y42HlEAT2NjUBiZI9C_gUmWl7smW-gZBGa4U6PsAOpi0H6Ct5dKpYJUO0qj1JLqC739nG2Exr4QEQGkFo-UaBBTTq1miHXfs1ptytYqfd64xTg0PIX0-9CfjtKrXS3hWEAWHHcChl9eHp89RU7a3bjWHbVJJVjYwcht6kFR_GX6oScGGnM4vQSR2ifh034vSA3w",
"p": "y4ynCbHHJW984_nC4UKCSF3kFjqAWG4E7K4_qJ7b5sXN7aQsWgBi6Jt6c9Paf4X3HUPDs9rbQ8ab4PJNP4r3JNc90wpvSR0b_w3E_bOtfQhbLbG5T17eO2laEpJCYWK71EVuZ2ykvuf6rkgTi4T27c9KdgJHMKQGNH7TwQFJKUU",
"q": "4dZZugK6vTlt_i2ySEuvRTAErLAVK7UWIuLQN9eeO8viX_vgoNe1L1rEN1Lb-OjdV4j5hyGMqkJ3kbCm0awDmxaR4nXVZ-GKC_mvilpfuyoYK4rm9iod_ZSuLytqr9LPnvtalaYeToNT9U7KqbzVsFY0nKTF6_ujRfqD8g282dM",
"qi": "anAZOAEZNUHf9HjqVeZiMExSZf7_OhHDceyKQ3KKI7CZSHaSj-aRtXqfAzArwpi3jDkiVQK79pt5zYKg0K47Z-X2PJ_W1tqqzAQX3Fqkdvs1c3L3Fy3w_C59N_B_QiA5e-y9J5qM1Qk12jnhlCn0DnlolwadfrkciUIS4ZdHMcs"
}
When JWK private key is acquired through the TSB service account creation step, generate an access token for the session authentication using tctl service-account token --key-path with the defined duration:
tctl service-account token pipeline-sa1 --key-path pipeline-sa1-jwk-private-key.jwk --expiration 1h30m0s
eyJhbGciOiJSUzI1NiIsImtpZCI6Inp1QWl3UEZRdTJlSTNHQUdkZGFTMVVIRzA4QTAxQkE0WFN0RjJDNDV1aUEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE2NTcwNTIyNTksImlhdCI6MTY1NzA1MDQ1OSwic3ViIjoibXktc2EjenVBaXdQRlF1MmVJM0dBR2RkYVMxVUhHMDhBMDFCQTRYU3RGMkM0NXVpQSIsInRzYi50ZXRyYXRlLmlvL3VzZSI6InRjdGwifQ.PRN5noVwB5RT0kFL75XjBe8pO3l90QvqpeUrR-Cw_Wt3-I4jTEWOVZXwkg6BJp0sL3cdq4wBPOCjQ8FXKrd527bIujh8f0E0Cj0obhbbSGUmAFwJO2UrvovjfXr1Ra35KHsFY6HCnTjKRxFVZ_czdYAc4s3YbOYRhiz74v1O6U9nX5jgTLl_vg9dxDUxiYYeUn1gR9_Jf0APkM48JSiZa4Bz0Ly6oGKm_GkUY003xPl4PSMFhR-4i1rYrcFH2YYP_6uUieToTrCSNchPk8S6Mh3rnkMiKTazrUnAuO5Anc3C6UlbDw9-ax18dvyKKi47wdRcjeDNPxjCSX27Qe-ryA
And configure that token in the desired tctl user profile. You can also do it all in once:
tctl config users set pipeline-sa1 --token $(tctl service-account token pipeline-sa1 --key-path pipeline-sa1-jwk-private-key.jwk --expiration 1h30m0s)
For more details how to leverage tctl to connect to TSB, please consult Connect to TSB with tctl
Bringing your own key
By default, TSB generates a service account's key pair itself and returns the private half once, as shown above. You can instead generate the key pair yourself and register only the public half with TSB, so the private key never reaches TSB at all.
To create a service account this way, pass its public key (in JWK format) to --key-path:
tctl service-account create pipeline-sa1 --key-path pipeline-sa1-public-key.jwk
A service account created this way has no TSB-generated key, so nothing is printed to standard output except the ID of
the key you registered. To add a customer-supplied key to a service account that already exists — the way you'd add a
second key ahead of a rotation, or bring your own key to a service account TSB originally generated a key for — use
add-key instead:
tctl service-account add-key pipeline-sa1 --key-path pipeline-sa1-public-key.jwk
Whether a service account's first key came from TSB or from a customer-supplied --key-path is recorded on the service
account as keyManagement, TSB or CLIENT. It's decided once, when the service account is created, and doesn't
change afterwards — you can still add keys either way after that.
The public key you supply must:
- Carry a
kid. This becomes the key's ID — the same IDlist-keysandrevoke-key --iduse — so unlike a TSB-generated key, you choose it. It's limited to 128 letters, digits,-,.and_, and must not collide with the ID of another key already on the service account. - Be a public key, not a private one.
- Be strong enough to be trusted, and use the same signature algorithm TSB will verify it with.
Configuring the algorithm and key size of generated keys
When TSB generates a service account's key pair itself, the algorithm and — for RSA — the key size are controlled by
spec.serviceAccountKeySettings on the Organization resource:
apiVersion: api.tsb.tetrate.io/v2
kind: Organization
metadata:
name: tetrate
spec:
serviceAccountKeySettings:
algorithm: RS256 # RS256 (default), ES256, ES384 or ES512
rsaKeySize: 3072 # 2048 (default), 3072 or 4096; RSA algorithms only
This only affects keys generated after you change it — existing service account keys are left as they are.
Listing and rotating keys
list-keys shows every key pair on a service account, including when each one was added (keys created before this
feature has no timestamp):
tctl service-account list-keys pipeline-sa1
A service account accepts a token signed by any key it holds until that key is revoked, which is what makes rotation safe: add the replacement key before removing the old one, rather than replacing it in place.
- Generate or register a new key:
tctl service-account gen-key <name>, oradd-keywith a key you generated yourself. - Install the new key wherever tokens for this service account are signed — for a CI/CD pipeline or external tool, wherever that tool reads its key from; for a control plane's service account, see below.
- Use
list-keysto find the key ID (kid) of the key(s) you're replacing. - Once nothing signs with the old key anymore and every token it issued has expired, revoke it:
tctl service-account revoke-key <name> --id <old-kid>.--idcan be repeated to revoke several keys in one command.
revoke-key refuses to remove every key from a service account — leaving it with none would leave it unable to
authenticate — unless you pass --force. Revoking a key ID the service account doesn't have is reported and skipped
rather than treated as an error, so the command is safe to repeat.
There's no single command that rotates a key for you: TSB usually needs to keep accepting tokens signed by the old key for a while after the new one is installed, and how long that takes depends on what the service account is used for.
Rotating a control plane's service account key
Each onboarded cluster has its own service account, which its control plane uses to authenticate to the management plane. Rotate it with the same add-then-revoke pattern as any other service account, using the cluster-specific commands from onboarding a cluster:
-
Generate a new key for the cluster and render it into the control plane secrets manifest:
tctl install cluster-service-account \
--cluster <cluster-name-in-tsb> \
> cluster-<cluster-name-in-tsb>-service-account.jwk
tctl install manifest control-plane-secrets \
--cluster <cluster-name-in-tsb> \
--cluster-service-account="$(cat cluster-<cluster-name-in-tsb>-service-account.jwk)" \
> controlplane-secrets.yamltctl install cluster-service-accountadds this key alongside the cluster's existing one rather than replacing it, so the cluster keeps authenticating with its current key until you apply the new secret. -
Apply the regenerated secrets to the target control plane cluster, and confirm the control plane has picked up the new key — for example by checking that it's still successfully refreshing its agent tokens against the management plane.
kubectl apply -f controlplane-secrets.yaml -
Find the cluster's service account and the ID of its previous key:
tctl service-account get
tctl service-account list-keys <cluster-service-account-name> -
Once you've confirmed the control plane is using the new key, revoke the old one:
tctl service-account revoke-key <cluster-service-account-name> --id <old-kid>
Revoke the old key only after confirming the control plane has switched to the new one. Revoking it too early breaks the cluster's connection to the management plane, since a control plane that hasn't picked up the new key yet has nothing valid left to authenticate with.