Convenience for generating API keys for automation
Proposed Feature
Kargo should have a convenience for creating long-lived "API keys" for interacting with Kargo API. This should be manageable from the UI either as a separate tab, or incorporated into the existing Roles tab.
Motivation
It will be desired for some automated systems to interface with Kargo API. For example, I would like for my CI system to refresh a Warehouse as soon as it pushed an image is pushed so that Kargo knows about it right away.
Suggested Implementation
"API Keys" would really just be Kubernetes ServiceAccount Bearer Tokens under the covers. The tokens would be bound to Kargo Roles (which are just K8s ServiceAccounts). This feature is simply a UI & API convenience for creating a ServiceAccount token Secret:
https://kubernetes.io/docs/concepts/configuration/secret/#serviceaccount-token-secrets
apiVersion: v1
kind: Secret
metadata:
name: secret-sa-sample
annotations:
kubernetes.io/service-account.name: "sa-name"
type: kubernetes.io/service-account-token
And then returning data.token to the user.
Other considerations
-
Alternative to this approach, we may instead consider using TokenRequest API to achieve the use case.
-
ServiceAccount tokens do not have expiry. I propose that we add our own expiry metadata to the secret, and a controller will ensure that the Secret is purged or invalidated after the expiry.
@jessesuen if the token we issue is a k8s bearer token, then we're talking about "client auth" to the API Server?
https://github.com/akuity/kargo/blob/08b394f6a060e20b90e29499a8717cf9094c8a5c/internal/api/option/auth.go#L397-L406
One possible issue with this is that we don't really get any information about the principal in that case, which makes audit logs incomplete, but we may be able to figure something out.
if the token we issue is a k8s bearer token, then we're talking about "client auth" to the API Server?
That's correct. Yes, service account namespace/name is in the JWT and is available to the webhook, and API server, so I think we have sufficient information to enrich the audit events.
Another requirement: since I intend to use this from my CI system, kargo CLI should accept an env var to use this token.
That's correct. Yes, service account namespace/name is in the JWT and is available to the webhook, and API server, so I think we have sufficient information to enrich the audit events.
I should have been more clear. I knew the info would be there. The thing that's a little bit of a problem is unless we have a way to validate the token ourselves, we can't trust its claims. But I still think we'll be able to figure something out.
@jessesuen, I would caution against having token issuer/validator features in Kargo itself. If you're looking for an API for service account token creation with TTL, I've done this in our environment using HashiCorp Vault + kubernetes auth + kubernetes secret backend, and works like a charm.
If you couple that with eg. vault-secrets-webhook you can inject the token using an API call like so:
apiVersion: v1
kind: Config
preferences: {}
clusters:
- cluster:
server: https://kargo.control-plane.svc.cluster.com
certificate-authority-data:
name: control-plane-cluster
contexts:
- context:
cluster: control-plane-cluster
namespace: kargo-system
user: kargo-controller
name: control-plane
current-context: control-plane
users:
- name: kargo-controller
user:
# Issue a Vault write to generate a short-lived service account
token: '${>>vault:/kubernetes/creds/kargo-controller#service_account_token#{"kubernetes_namespace": "kargo", "ttl": "1h"}}'
This is just an example, but you can extrapolate to other service account token uses. Similarly, you can use the Vault CLI to generate short-lived tokens for your CI if needed.
cc @krancour
We forgot we had this issue open and created a new one. Closing this one as the newer one has some more up-to-date discussion.