convoy docs
Search

Security

How convoy authenticates and authorizes requests, which identities it uses, and how to limit access.

convoy is an aggregated API server. The host cluster authenticates and authorizes each request to the convoy API. The convoy controllers act with two kinds of identity. On the host cluster, they use their own service account. On a target cluster, they use the identity of the Cluster. This page tells how to control the access to each part.

Authentication and authorization#

A client sends a convoy request to the host kube-apiserver. The kube-aggregator sends it to the convoy apiserver with the identity of the user. The convoy apiserver then asks the host cluster:

  • TokenReview and the extension-apiserver-authentication ConfigMap, to authenticate.
  • SubjectAccessReview, to authorize.

Thus you control the access to convoy objects with RBAC on the host cluster. The API groups are core.convoy.kumodo.io, source.convoy.kumodo.io and extensions.convoy.kumodo.io. The apiserver service account needs the system:auth-delegator ClusterRole and the extension-apiserver-authentication-reader Role in kube-system.

RBAC for Release subresources#

RBAC controls each subresource of a Release separately:

ResourceVerbsGives
releases/synccreateRequest a reconcile, and an apply in manual sync mode.
releases/pinget, update, patchRead, set or clear the pin.
releases/mutationsget, update, patchRead or replace the mutations.
releases/lifecycleget, update, patchRead or replace the lifecycle hooks.
releases/previewgetRead the desired render.
releases/diffgetRead the desired and the live objects.
releases/healthgetRead the health of each resource.
releases/historygetRead the applied renders.
releases/statusupdate, patchWrite the status. Give it only to convoy components.

Treat update and patch on releases as full control of the Release. Give these verbs only to the owners of the Release. For a user who needs only one part, for example the pin, give only the subresource.

preview and diff can show the values of rendered Secrets. Give get on these subresources only to users who can read the Secrets in the target namespaces.

Example: a Role that lets a user pin and sync, but not edit the Release.

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: release-operator
  namespace: team-a
rules:
  - apiGroups: ["core.convoy.kumodo.io"]
    resources: ["releases"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["core.convoy.kumodo.io"]
    resources: ["releases/pin"]
    verbs: ["get", "update", "patch"]
  - apiGroups: ["core.convoy.kumodo.io"]
    resources: ["releases/sync"]
    verbs: ["create"]

See Subresources.

Same-namespace references#

A Release can refer only to objects in its own namespace. The apiserver rejects a Release with a namespace in one of these references, when the namespace is not the namespace of the Release:

  • spec.clusterRef
  • spec.source.gitRepository, spec.source.helmRegistry and spec.source.ociRegistry
  • spec.content.helm.values[].gitRepository
  • mutations[].from

The reason is credential borrowing. A Cluster or a source can hold credentials. The controllers read these objects with their own identity, not with the identity of the user. Without the rule, a user could deploy with a Cluster in a namespace that the user cannot read.

convoy reads each referenced Secret and ConfigMap in the namespace of the object that refers to it:

  • A Cluster kubeconfig Secret, in the namespace of the Cluster.
  • Source credentials, in the namespace of the GitRepository, HelmRegistry or OCIRegistry.
  • Helm values and mutation sources from a Secret or a ConfigMap, in the namespace of the Release.

Identities of the controllers#

On the host cluster, the controller-manager and the observer use their own service account. They need these rights:

  • Read the convoy objects through the aggregated API.
  • Write the status subresources and the ReleaseInventory objects.
  • get on Secrets and ConfigMaps in each namespace that has convoy objects.
  • The lease rights. See Scaling and high availability.

The dev ClusterRoles for the controllers are not a complete least-privilege set. The cluster-admin bindings hide the missing rules.

On a target cluster, the identity depends on spec.connectionMode of the Cluster:

ModeIdentity on the target cluster
inClusterThe service account of the convoy process: the controller-manager for apply and prune, the observer for drift and health.
agentlessThe credentials in the kubeconfig Secret of the Cluster.

Give write access to the kubeconfig Secrets of your Clusters only to cluster administrators. A kubeconfig can contain credential plugins, and the convoy components use the kubeconfig as it is.

Dry run needs write rights#

The pre-apply dry run and the drift check of the observer use Server-Side Apply with dry run. The target cluster authorizes a dry run as a real write. Thus the observer needs the same write rights on the target cluster as the controller-manager. For agentless, the two components use the same kubeconfig. For inCluster, give the observer service account the same rights as the controller-manager service account. See Apply and prune.

The observer endpoint#

The apiserver authorizes preview, diff, health and history requests, and then sends them to the observer at --observer-url over HTTP. Let only the apiserver pods connect to the observer port. Use a NetworkPolicy for this.

Render store#

The render store contains each applied render, also rendered Secrets. Give access to the bucket or the volume only to the controller-manager and the observer. See Render store backends.

Planned#

  • Cross-namespace references with a ReferenceGrant object in the target namespace. See ReferenceGrant. Not built
  • A least-privilege identity for each target cluster, used for the apply and the dry run. Not built

In the code

convoy v0.9.0